911 lines
22 KiB
C
911 lines
22 KiB
C
/*
|
||
** $Id$
|
||
**
|
||
** Copyright 1996-1998 Michael 'Ghandi' Herold <michael@abadonna.mayn.de>
|
||
*/
|
||
|
||
#ifdef HAVE_CONFIG_H
|
||
# include "../config.h"
|
||
#endif
|
||
|
||
#if TIME_WITH_SYS_TIME
|
||
# include <sys/time.h>
|
||
# include <time.h>
|
||
#else
|
||
# if HAVE_SYS_TIME_H
|
||
# include <sys/time.h>
|
||
# else
|
||
# include <time.h>
|
||
# endif
|
||
#endif
|
||
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/wait.h>
|
||
#include <fcntl.h>
|
||
#include <string.h>
|
||
#include <errno.h>
|
||
|
||
#include "voice.h"
|
||
#include "log.h"
|
||
#include "modem.h"
|
||
#include "stringutils.h"
|
||
#include "vboxrc.h"
|
||
#include "vboxgetty.h"
|
||
#include "tclscript.h"
|
||
#include "control.h"
|
||
#include "audio.h"
|
||
#include "breaklist.h"
|
||
|
||
/** Variables ************************************************************/
|
||
|
||
static struct vboxuser *voicevboxuser;
|
||
static struct vboxcall *voicevboxcall;
|
||
|
||
static int voicedesc = -1;
|
||
static int voicevbox = 0;
|
||
static int voicestat = VBOXVOICE_STAT_OK;
|
||
static int audiodesc = -1;
|
||
|
||
static unsigned char voicename_ulaw[PATH_MAX + 1];
|
||
static unsigned char voicename_vbox[PATH_MAX + 1];
|
||
static unsigned char voicename_call[PATH_MAX + 1];
|
||
|
||
unsigned char voice_touchtone_sequence[VBOXVOICE_SEQUENCE + 1];
|
||
|
||
/** Prototypes ***********************************************************/
|
||
|
||
static void voice_stop_vtxrtx(void);
|
||
static void voice_create_vboxcall(void);
|
||
static void voice_remove_vboxcall(void);
|
||
static void voice_mkdir(unsigned char *);
|
||
static int voice_check_touchtone(int);
|
||
|
||
/*************************************************************************
|
||
** voice_init(): Beantwortet den Anruf und startet das Tcl-Skript. **
|
||
*************************************************************************
|
||
** => vboxuser Zeiger auf die vboxuser-Struktur **
|
||
** => vboxcall Zeiger auf die vboxcall-Struktur **
|
||
*************************************************************************/
|
||
|
||
int voice_init(struct vboxuser *vboxuser, struct vboxcall *vboxcall)
|
||
{
|
||
unsigned char tempconnect[12];
|
||
unsigned char msgsavetime[32];
|
||
time_t currenttime;
|
||
char *stop;
|
||
int rc;
|
||
|
||
struct vbox_tcl_variable vars[] =
|
||
{
|
||
{ "vbxv_savetime" , msgsavetime },
|
||
{ "vbxv_callerid" , vboxuser->incomingid },
|
||
{ "vbxv_callername" , vboxcall->name },
|
||
{ "vbxv_localphone" , vboxuser->localphone },
|
||
{ "vbxv_username" , vboxuser->name },
|
||
{ "vbxv_userhome" , vboxuser->home },
|
||
{ "vbxv_usedscript" , vboxcall->script },
|
||
{ "vbxv_saveulaw" , voicename_ulaw },
|
||
{ "vbxv_savevbox" , voicename_vbox },
|
||
{ NULL , NULL }
|
||
};
|
||
|
||
printstring(msgsavetime, "%d", vboxcall->savetime);
|
||
|
||
/* Die beiden <20>bergebenen Strukturen global machen, damit alle */
|
||
/* Voice Funktionen sie benutzen k<>nnen. */
|
||
|
||
voicevboxuser = vboxuser;
|
||
voicevboxcall = vboxcall;
|
||
|
||
/* Die Namen der beiden Dateien (*.ulaw und *.vbox) erzeugen. */
|
||
/* Eine Datei enth<74>lt die Audiodaten, die andere die Inform- */
|
||
/* ationen <20>ber den Benutzer. */
|
||
|
||
currenttime = time(NULL);
|
||
|
||
printstring(voicename_ulaw, "%s/new/%11.11lu-%8.8lu.ulaw", vboxuser->home, (unsigned long)currenttime, (unsigned long)getpid());
|
||
printstring(voicename_vbox, "%s/new/%11.11lu-%8.8lu.vbox", vboxuser->home, (unsigned long)currenttime, (unsigned long)getpid());
|
||
|
||
/* Den Namen der Call Datei erzeugen, in dem sp<73>ter Daten zum */
|
||
/* aktuellen Anruf gesichert werden. */
|
||
|
||
printstring(voicename_call, "%s/vboxcall-%s", vboxuser->home, savettydname);
|
||
|
||
/* Userspool Verzeichnisstruktur erzeugen. Wenn eines der */
|
||
/* Verzeichnisse bereits existiert, bleibt es unver<65>ndert. */
|
||
|
||
voice_mkdir(NULL );
|
||
voice_mkdir("new");
|
||
voice_mkdir("msg");
|
||
voice_mkdir("tcl");
|
||
|
||
/* Variablen f<>r Tcl erzeugen, Kompression setzen, Full Duplex */
|
||
/* Audio Modus starten und das Skript aufrufen. */
|
||
|
||
log_line(LOG_A, "Answering call...\n");
|
||
|
||
voicevbox = 0;
|
||
voicedesc = -1;
|
||
audiodesc = -1;
|
||
|
||
*voice_touchtone_sequence = '\0';
|
||
|
||
if (scr_init_variables(vars) == 0)
|
||
{
|
||
if (modem_command(&vboxmodem, "ATA", "VCON") > 0)
|
||
{
|
||
log_line(LOG_D, "Setting voice compression to \"ulaw\"...\n");
|
||
|
||
if (modem_command(&vboxmodem, "AT+VSM=6+VLS=2", "OK") > 0)
|
||
{
|
||
log_line(LOG_D, "Starting full duplex audio mode...\n");
|
||
|
||
if (modem_command(&vboxmodem, "AT+VTX+VRX", "CONNECT") > 0)
|
||
{
|
||
voice_hear(0);
|
||
voice_save(0);
|
||
|
||
/* Bevor das Skript gestartet wird, werden die */
|
||
/* ersten 11 Byte vom Modem eingelesen. Damit */
|
||
/* wird ein Fehler in i4l umgangen, der die */
|
||
/* Connectmessage bei Full Duplex 2x in den Mo- */
|
||
/* dembuffer schreibt. */
|
||
|
||
modem_set_timeout(2);
|
||
vboxmodem_raw_read(&vboxmodem, tempconnect, 11);
|
||
modem_set_timeout(0);
|
||
|
||
voice_create_vboxcall();
|
||
|
||
{
|
||
int r, pid, wstat;
|
||
if ((pid =fork()) == -1) {
|
||
log_line(LOG_E, "fork failed.\n");
|
||
exit(1);
|
||
}
|
||
if (pid == 0) {
|
||
if (seteuid(0) == -1) {
|
||
log_line(LOG_E, "seteuid failed.\n");
|
||
exit(1);
|
||
}
|
||
if (setgid(vboxuser->gid) == -1) {
|
||
log_line(LOG_E, "setgid failed.\n");
|
||
exit(1);
|
||
}
|
||
if (setuid(vboxuser->uid) == -1) {
|
||
log_line(LOG_E, "setuid failed.\n");
|
||
exit(1);
|
||
}
|
||
|
||
rc = scr_execute(vboxcall->script, vboxuser);
|
||
|
||
exit(rc);
|
||
}
|
||
do
|
||
r =waitpid(pid, &wstat, 0);
|
||
while ((r == -1) && (errno == EINTR));
|
||
if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) == 0))
|
||
rc =0;
|
||
else
|
||
rc =-1;
|
||
}
|
||
|
||
voice_remove_vboxcall();
|
||
|
||
voice_hear(0);
|
||
voice_save(0);
|
||
|
||
voice_stop_vtxrtx();
|
||
|
||
if ((stop = ctrl_exists(vboxuser->home, "suspend", savettydname)))
|
||
{
|
||
ctrl_remove(vboxuser->home, "suspend", savettydname);
|
||
|
||
if (!vboxmodem.nocarrier)
|
||
{
|
||
log_line(LOG_A, "Suspending call to number %s...\n", stop);
|
||
|
||
if (modem_command(&vboxmodem, "AT+S1", "OK") > 0) {
|
||
log_line(LOG_D, "Call suspended to number %s.\n", stop);
|
||
} else {
|
||
log_line(LOG_E, "Can't suspend call to number %s.\n", stop);
|
||
}
|
||
}
|
||
}
|
||
|
||
return(rc);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
log_line(LOG_E, "Unable to answer call!\n");
|
||
|
||
return(-1);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** voice_wait(): Liest eine angegebene Zeit lang Audiodaten vom Modem. **
|
||
*************************************************************************
|
||
** => timeout Timeout in Sekunden **
|
||
*************************************************************************
|
||
** <= 0 wenn der Timeout eingetreten ist. **
|
||
** 1 wenn eine g<>ltige Touchtonesequenz gefunden wurde. **
|
||
** 2 wenn der Anruf suspended werden soll. **
|
||
** -1 bei einem Fehler oder Remote hangup **
|
||
*************************************************************************/
|
||
|
||
int voice_wait(int timeout)
|
||
{
|
||
unsigned char modem_line_i[1];
|
||
unsigned char modem_line_o[VBOXVOICE_BUFSIZE + 1];
|
||
int total_byte_i;
|
||
int total_byte_o;
|
||
int modem_byte_i;
|
||
int modem_byte_o;
|
||
int last_was_dle;
|
||
int result;
|
||
char *stop;
|
||
|
||
total_byte_i = 0;
|
||
total_byte_o = 0;
|
||
last_was_dle = 0;
|
||
voicestat = VBOXVOICE_STAT_OK;
|
||
|
||
log(LOG_D, "Reading voice datas (%ds timeout)...\n", timeout);
|
||
|
||
modem_set_timeout(timeout);
|
||
|
||
while (voicestat == VBOXVOICE_STAT_OK)
|
||
{
|
||
modem_byte_i = 0;
|
||
modem_byte_o = 0;
|
||
result = 0;
|
||
|
||
while ((modem_byte_o < (VBOXVOICE_BUFSIZE - 2)) && (voicestat == VBOXVOICE_STAT_OK))
|
||
{
|
||
if ((result = vboxmodem_raw_read(&vboxmodem, modem_line_i, 1)) == 1)
|
||
{
|
||
modem_byte_i++;
|
||
|
||
if (last_was_dle)
|
||
{
|
||
switch (*modem_line_i)
|
||
{
|
||
case DLE:
|
||
modem_line_o[modem_byte_o++] = DLE;
|
||
break;
|
||
|
||
case ETX:
|
||
voicestat |= VBOXVOICE_STAT_HANGUP;
|
||
break;
|
||
|
||
default:
|
||
if (voice_check_touchtone(*modem_line_i) == 0) voicestat |= VBOXVOICE_STAT_TOUCHTONE;
|
||
break;
|
||
}
|
||
|
||
last_was_dle = 0;
|
||
}
|
||
else
|
||
{
|
||
if (*modem_line_i == DLE) last_was_dle = 1;
|
||
|
||
modem_line_o[modem_byte_o++] = *modem_line_i;
|
||
}
|
||
}
|
||
else break;
|
||
}
|
||
|
||
total_byte_o += modem_byte_o;
|
||
total_byte_i += modem_byte_i;
|
||
|
||
if (modem_byte_o > 0)
|
||
{
|
||
if (voicedesc != -1) write(voicedesc, modem_line_o, modem_byte_o);
|
||
if (audiodesc != -1) write(audiodesc, modem_line_o, modem_byte_o);
|
||
|
||
/* Einmal in der Sekunde die Logmessage ausgeben und die */
|
||
/* Controls checken. */
|
||
|
||
if ((total_byte_o >= VBOXVOICE_SAMPLERATE) || (voicestat != VBOXVOICE_STAT_OK))
|
||
{
|
||
log_line(LOG_D, "Wait: incoming %04d; outgoing %04d...\n", total_byte_i, total_byte_o);
|
||
|
||
total_byte_i = 0;
|
||
total_byte_o = 0;
|
||
|
||
if ((stop = ctrl_exists(voicevboxuser->home, "suspend", savettydname)))
|
||
{
|
||
log(LOG_D, "Control \"vboxctrl-suspend-%s\" detected: %s.\n", savettydname, stop);
|
||
|
||
voicestat |= VBOXVOICE_STAT_SUSPEND;
|
||
}
|
||
|
||
if ((stop = ctrl_exists(voicevboxuser->home, "audio", savettydname)))
|
||
{
|
||
log(LOG_D, "Control \"vboxctrl-audio-%s\" detected: %s.\n", savettydname, stop);
|
||
|
||
if (strcasecmp(stop, "stop") == 0) voice_hear(0);
|
||
if (strcasecmp(stop, "start") == 0) voice_hear(1);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((result != 1) || (modem_get_timeout()))
|
||
{
|
||
if (!modem_get_timeout())
|
||
{
|
||
log_line(LOG_W, "Can't read voice data (%s).\n", strerror(errno));
|
||
|
||
voicestat |= VBOXVOICE_STAT_TIMEOUT;
|
||
}
|
||
else voicestat |= VBOXVOICE_STAT_TIMEOUT;
|
||
}
|
||
}
|
||
|
||
modem_set_timeout(0);
|
||
|
||
result = 0;
|
||
|
||
if (voicestat & VBOXVOICE_STAT_TOUCHTONE)
|
||
{
|
||
log_line(LOG_D, "Full touchtone sequence found!\n");
|
||
|
||
result = 1;
|
||
}
|
||
|
||
if (voicestat & VBOXVOICE_STAT_SUSPEND) result = 2;
|
||
|
||
if ((voicestat & VBOXVOICE_STAT_HANGUP) || (vboxmodem.nocarrier))
|
||
{
|
||
log_line(LOG_D, "*** Remote hangup ***\n");
|
||
|
||
voice_save(0);
|
||
voice_hear(0);
|
||
|
||
modem_command(&vboxmodem, "", "NO CARRIER");
|
||
|
||
result = -1;
|
||
}
|
||
|
||
return(result);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** voice_play(): Spielt eine Nachricht ab und liest dabei Voicedaten **
|
||
** vom Modem. **
|
||
*************************************************************************
|
||
** name Name der Nachricht die gespielt werden soll. **
|
||
*************************************************************************
|
||
** <= 0 wenn der Timeout eingetreten ist. **
|
||
** 1 wenn eine g<>ltige Touchtonesequenz gefunden wurde. **
|
||
** 2 wenn der Anruf suspended werden soll. **
|
||
** -1 bei einem Fehler oder Remote hangup **
|
||
*************************************************************************/
|
||
|
||
int voice_play(unsigned char *name)
|
||
{
|
||
unsigned char modem_line_i[1];
|
||
unsigned char modem_line_o[VBOXVOICE_BUFSIZE + 1];
|
||
int total_byte_i;
|
||
int total_byte_o;
|
||
int modem_byte_i;
|
||
int modem_byte_o;
|
||
int last_was_dle;
|
||
int result;
|
||
int desc;
|
||
char *stop;
|
||
int i;
|
||
|
||
if ((!name) || (!*name))
|
||
{
|
||
log(LOG_W, "No message to play selected (ignored).\n");
|
||
|
||
return(0);
|
||
}
|
||
|
||
if ((stop = rindex(name, '/'))) name = ++stop;
|
||
|
||
log(LOG_D, "Playing \"%s\"...\n", name);
|
||
|
||
printstring(temppathname, "%s/msg/%s", voicevboxuser->home, name);
|
||
|
||
errno = 0;
|
||
desc = open(temppathname, O_RDONLY);
|
||
|
||
if (desc == -1)
|
||
{
|
||
printstring(temppathname, "%s/msg/%s", PKGDATADIR, name);
|
||
|
||
errno = 0;
|
||
desc = open(temppathname, O_RDONLY);
|
||
}
|
||
|
||
if (desc == -1)
|
||
{
|
||
log(LOG_W, "Can't open \"%s\" (%s).\n", name, strerror(errno));
|
||
|
||
return(0);
|
||
}
|
||
|
||
last_was_dle = 0;
|
||
total_byte_i = 0;
|
||
total_byte_o = 0;
|
||
voicestat = VBOXVOICE_STAT_OK;
|
||
|
||
while (voicestat == VBOXVOICE_STAT_OK)
|
||
{
|
||
modem_byte_i = 0;
|
||
modem_byte_o = 0;
|
||
result = 0;
|
||
|
||
modem_set_timeout(5);
|
||
|
||
while ((modem_byte_o < (VBOXVOICE_BUFSIZE - 2)) && (voicestat == VBOXVOICE_STAT_OK))
|
||
{
|
||
if ((i = read(desc, modem_line_i, 1)) != 1)
|
||
{
|
||
if (i != 0) log(LOG_W, "Can't read \"%s\" [%d] (%s).\n", name, i, strerror(errno));
|
||
|
||
voicestat |= VBOXVOICE_STAT_DONE;
|
||
}
|
||
else vboxmodem_raw_write(&vboxmodem, modem_line_i, 1);
|
||
|
||
if ((result = vboxmodem_raw_read(&vboxmodem, modem_line_i, 1)) == 1)
|
||
{
|
||
modem_byte_i++;
|
||
|
||
if (last_was_dle)
|
||
{
|
||
switch (*modem_line_i)
|
||
{
|
||
case DLE:
|
||
modem_line_o[modem_byte_o++] = DLE;
|
||
break;
|
||
|
||
case ETX:
|
||
voicestat |= VBOXVOICE_STAT_HANGUP;
|
||
break;
|
||
|
||
default:
|
||
if (voice_check_touchtone(*modem_line_i) == 0) voicestat |= VBOXVOICE_STAT_TOUCHTONE;
|
||
break;
|
||
}
|
||
|
||
last_was_dle = 0;
|
||
}
|
||
else
|
||
{
|
||
if (*modem_line_i == DLE) last_was_dle = 1;
|
||
|
||
modem_line_o[modem_byte_o++] = *modem_line_i;
|
||
}
|
||
}
|
||
else break;
|
||
}
|
||
|
||
modem_set_timeout(0);
|
||
|
||
total_byte_o += modem_byte_o;
|
||
total_byte_i += modem_byte_i;
|
||
|
||
if (modem_byte_o > 0)
|
||
{
|
||
if (voicedesc != -1) write(voicedesc, modem_line_o, modem_byte_o);
|
||
if (audiodesc != -1) write(audiodesc, modem_line_o, modem_byte_o);
|
||
|
||
/* Einmal in der Sekunde die Logmessage ausgeben und die */
|
||
/* Controls checken. */
|
||
|
||
if ((total_byte_o >= VBOXVOICE_SAMPLERATE) || (voicestat != VBOXVOICE_STAT_OK))
|
||
{
|
||
log_line(LOG_D, "Play: incoming %04d; outgoing %04d...\n", total_byte_i, total_byte_o);
|
||
|
||
total_byte_i = 0;
|
||
total_byte_o = 0;
|
||
|
||
if ((stop = ctrl_exists(voicevboxuser->home, "suspend", savettydname)))
|
||
{
|
||
log(LOG_D, "Control \"vboxctrl-suspend-%s\" detected: %s.\n", savettydname, stop);
|
||
|
||
voicestat |= VBOXVOICE_STAT_SUSPEND;
|
||
}
|
||
|
||
if ((stop = ctrl_exists(voicevboxuser->home, "audio", savettydname)))
|
||
{
|
||
log(LOG_D, "Control \"vboxctrl-audio-%s\" detected: %s.\n", savettydname, stop);
|
||
|
||
if (strcasecmp(stop, "stop") == 0) voice_hear(0);
|
||
if (strcasecmp(stop, "start") == 0) voice_hear(1);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((result != 1) || (modem_get_timeout()))
|
||
{
|
||
if (!modem_get_timeout())
|
||
{
|
||
log_line(LOG_W, "Can't read voice data (%s).\n", strerror(errno));
|
||
|
||
voicestat |= VBOXVOICE_STAT_TIMEOUT;
|
||
}
|
||
else voicestat |= VBOXVOICE_STAT_TIMEOUT;
|
||
}
|
||
}
|
||
|
||
modem_set_timeout(0);
|
||
|
||
if (desc != -1) close(desc);
|
||
|
||
result = 0;
|
||
|
||
if (voicestat & VBOXVOICE_STAT_TOUCHTONE)
|
||
{
|
||
log_line(LOG_D, "Full touchtone sequence found!\n");
|
||
|
||
result = 1;
|
||
}
|
||
|
||
if (voicestat & VBOXVOICE_STAT_SUSPEND) result = 2;
|
||
|
||
if ((voicestat & VBOXVOICE_STAT_HANGUP) || (vboxmodem.nocarrier))
|
||
{
|
||
log_line(LOG_D, "*** Remote hangup ***\n");
|
||
|
||
voice_save(0);
|
||
voice_hear(0);
|
||
|
||
modem_command(&vboxmodem, "", "NO CARRIER");
|
||
|
||
result = -1;
|
||
}
|
||
|
||
return(result);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** voice_save(): Schaltet das mitspeichern der eingehenden Voicedaten **
|
||
** ein oder aus. **
|
||
*************************************************************************
|
||
** => save > 0 um das mitspeichern einzuschalten; alle anderen **
|
||
** Werte schaltes es aus. **
|
||
*************************************************************************/
|
||
|
||
int voice_save(int save)
|
||
{
|
||
FILE *vbox;
|
||
|
||
if (save > 0)
|
||
{
|
||
if (voicedesc == -1)
|
||
{
|
||
log(LOG_D, "Starting voice recording...\n");
|
||
log(LOG_D, "Opening \"%s\"...\n", voicename_ulaw);
|
||
|
||
errno = 0;
|
||
|
||
if ((voicedesc = open(voicename_ulaw, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) == -1)
|
||
{
|
||
log(LOG_E, "Can't open/append \"%s\" (%s).\n", voicename_ulaw, strerror(errno));
|
||
|
||
return(-1);
|
||
}
|
||
}
|
||
|
||
if (!voicevbox)
|
||
{
|
||
/* Wenn die *.vbox Datei noch nicht existiert wird sie */
|
||
/* jetzt erzeugt. Die Datei enth<74>lt die Informationen */
|
||
/* wer wann wie die Nachricht gesprochen hat. */
|
||
|
||
log(LOG_D, "Creating \"%s\"...\n", voicename_vbox);
|
||
|
||
errno = 0;
|
||
|
||
if ((vbox = fopen(voicename_vbox, "w")))
|
||
{
|
||
fprintf(vbox, "Name: %s\n" , voicevboxcall->name );
|
||
fprintf(vbox, "ID : %s\n" , voicevboxuser->incomingid);
|
||
fprintf(vbox, "Time: %ld\n", time(NULL) );
|
||
|
||
fclose(vbox);
|
||
|
||
voicevbox = 1;
|
||
}
|
||
else log(LOG_E, "Can't create \"%s\" (%s).\n", voicename_vbox, strerror(errno));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (voicedesc != -1)
|
||
{
|
||
log(LOG_D, "Stopping voice recording...\n");
|
||
log(LOG_D, "Closing \"%s\"...\n", voicename_ulaw);
|
||
|
||
close(voicedesc);
|
||
}
|
||
|
||
voicedesc = -1;
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** voice_hear(): Schaltet das mith<74>ren der Voicedaten <20>ber /dev/audio **
|
||
** ein oder aus. **
|
||
*************************************************************************
|
||
** => mode > 0 um das Mith<74>ren einzuschalten; alle anderen Werte **
|
||
** schalten das Mith<74>ren aus. **
|
||
** **
|
||
** Die Funktion gibt 0 zur<75>ck wenn die Aktion ausgef<65>hrt werden konnte **
|
||
** oder -1 wenn nicht. **
|
||
*************************************************************************/
|
||
|
||
int voice_hear(int mode)
|
||
{
|
||
if (mode > 0)
|
||
{
|
||
if (audiodesc == -1)
|
||
{
|
||
log(LOG_D, "Starting audio playback...\n");
|
||
|
||
if ((audiodesc = audio_open_dev("/dev/audio")) == -1) return(-1);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (audiodesc != -1)
|
||
{
|
||
log(LOG_D, "Stopping audio playback...\n");
|
||
|
||
audio_close_dev(audiodesc);
|
||
}
|
||
|
||
audiodesc = -1;
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** FIXME
|
||
*************************************************************************/
|
||
|
||
static void voice_stop_vtxrtx(void)
|
||
{
|
||
unsigned char line[4];
|
||
int have;
|
||
|
||
if (!vboxmodem.nocarrier)
|
||
{
|
||
/* DLE/DC4 an den Modememluator schicken um den Record-Modus */
|
||
/* zu stoppen. Der Emulator sollte mit DLE/ETX antworten. */
|
||
|
||
log_line(LOG_D, "Sending \"<DLE><DC4>\" to stop record mode...\n");
|
||
|
||
printstring(line, "%c%c", DLE, DC4);
|
||
|
||
vboxmodem_raw_write(&vboxmodem, line, 2);
|
||
|
||
have = 0;
|
||
|
||
modem_set_timeout(modemsetup.commandtimeout);
|
||
|
||
while (vboxmodem_raw_read(&vboxmodem, line, 1) == 1)
|
||
{
|
||
log_char(LOG_D, *line);
|
||
|
||
if (*line != DLE)
|
||
{
|
||
if ((*line == ETX) && (have))
|
||
{
|
||
have++;
|
||
|
||
break;
|
||
}
|
||
else have = 0;
|
||
}
|
||
else have = 1;
|
||
}
|
||
|
||
modem_set_timeout(0);
|
||
|
||
if (have == 2) log_line(LOG_D, "Found <DLE><ETX>!\n");
|
||
|
||
log_line(LOG_D, "Sending \"<DLE><ETX>\" to stop playback mode...\n");
|
||
|
||
printstring(line, "%c%c", DLE, ETX);
|
||
|
||
vboxmodem_raw_write(&vboxmodem, line, 2);
|
||
|
||
have = 0;
|
||
|
||
modem_set_timeout(modemsetup.commandtimeout);
|
||
|
||
while (vboxmodem_raw_read(&vboxmodem, line, 1) == 1)
|
||
{
|
||
log_char(LOG_D, *line);
|
||
|
||
if (*line != DLE)
|
||
{
|
||
if ((*line == DC4) && (have))
|
||
{
|
||
have++;
|
||
|
||
break;
|
||
}
|
||
else have = 0;
|
||
}
|
||
else have = 1;
|
||
}
|
||
|
||
modem_set_timeout(0);
|
||
|
||
if (have == 2) log_line(LOG_D, "Found <DLE><DC4>!\n");
|
||
}
|
||
}
|
||
|
||
/*************************************************************************
|
||
** voice_create_vboxcall(): Erzeugt eine Call Datei mit Informationen **
|
||
** <09>ber den aktuellen Anruf. **
|
||
*************************************************************************/
|
||
|
||
static void voice_create_vboxcall(void)
|
||
{
|
||
FILE *call;
|
||
|
||
log(LOG_D, "Creating \"%s\"...\n", voicename_call);
|
||
|
||
if ((call = fopen(voicename_call, "w")))
|
||
{
|
||
/* CallerID, Name, tty-Device und die aktuelle PID in der */
|
||
/* Datei speichern. */
|
||
|
||
fprintf(call, "%s:%s:%s:%d\n", voicevboxuser->incomingid, voicevboxuser->name, savettydname, getpid());
|
||
|
||
fclose(call);
|
||
}
|
||
else log(LOG_E, "Can't create \"%s\" (%s)!\n", voicename_call, strerror(errno));
|
||
}
|
||
|
||
/*************************************************************************
|
||
** voice_remove_vboxcall(): L<>scht die Call Datei. **
|
||
*************************************************************************/
|
||
|
||
static void voice_remove_vboxcall(void)
|
||
{
|
||
log(LOG_D, "Removing \"%s\"...\n", voicename_call);
|
||
|
||
if (remove(voicename_call) != 0)
|
||
{
|
||
if (errno != ENOENT) log(LOG_E, "Can't remove \"%s\" (%s)!\n", voicename_call, strerror(errno));
|
||
}
|
||
}
|
||
|
||
/*************************************************************************
|
||
** voice_mkdir(): Erzeugt die Verzeichnisse im Userspool. **
|
||
*************************************************************************/
|
||
|
||
static void voice_mkdir(unsigned char *name)
|
||
{
|
||
if (name)
|
||
printstring(temppathname, "%s/%s", voicevboxuser->home, name);
|
||
else
|
||
printstring(temppathname, "%s", voicevboxuser->home);
|
||
|
||
log(LOG_D, "Creating directory \"%s\"...\n", temppathname);
|
||
|
||
errno = 0;
|
||
|
||
if (mkdir(temppathname, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH) == -1)
|
||
{
|
||
if (errno != EEXIST)
|
||
{
|
||
log(LOG_E, "Can't create \"%s\" (%s).\n", temppathname, strerror(errno));
|
||
}
|
||
}
|
||
}
|
||
|
||
/*************************************************************************
|
||
** voice_check_touchtone(): Pr<50>ft ob es sich bei einem Zeichen um **
|
||
** einen Touchtone handelt. **
|
||
*************************************************************************
|
||
** => c Zeichen **
|
||
** **
|
||
** R<>ckgabe ist 0 wenn es ein Touchtone war oder -1 wenn nicht. **
|
||
*************************************************************************/
|
||
|
||
static int voice_check_touchtone(int c)
|
||
{
|
||
unsigned char tone[2];
|
||
unsigned char *stop;
|
||
int i;
|
||
|
||
switch (c)
|
||
{
|
||
case '0':
|
||
case '1':
|
||
case '2':
|
||
case '3':
|
||
case '4':
|
||
case '5':
|
||
case '6':
|
||
case '7':
|
||
case '8':
|
||
case '9':
|
||
case 'A':
|
||
case 'B':
|
||
case 'C':
|
||
case 'D':
|
||
case '#':
|
||
case '*':
|
||
{
|
||
if (c != '*')
|
||
{
|
||
tone[0] = c;
|
||
tone[1] = 0;
|
||
|
||
if (*voice_touchtone_sequence == '*')
|
||
{
|
||
/* Wenn das erste Zeichen in der Sequenz ein '*' */
|
||
/* ist (Sequenzstart) wird der neue Touchtone am */
|
||
/* Ende angeh<65>ngt - es sei denn die Sequenz ent- */
|
||
/* h<>lt ein '#' (Sequenzende). */
|
||
|
||
if (!(stop = rindex(voice_touchtone_sequence, '#')))
|
||
{
|
||
if (strlen(voice_touchtone_sequence) >= VBOXVOICE_SEQUENCE)
|
||
{
|
||
/* Die Sequenz ist bereits voll; der neue */
|
||
/* Touchtone wird nicht angeh<65>ngt! */
|
||
|
||
log(LOG_E, "Internal touchtone sequence is full (touchtone ignored).\n");
|
||
}
|
||
else strcat(voice_touchtone_sequence, tone);
|
||
}
|
||
else strcpy(voice_touchtone_sequence, tone);
|
||
}
|
||
else
|
||
{
|
||
/* Erstes Zeichen in der Sequenz ist kein '*', der */
|
||
/* Touchtone ersetzt die alte Sequenz. */
|
||
|
||
strcpy(voice_touchtone_sequence, tone);
|
||
}
|
||
}
|
||
else strcpy(voice_touchtone_sequence, "*");
|
||
|
||
log(LOG_I, "Touchtone \"%c\" entered (%s).\n", c, voice_touchtone_sequence);
|
||
|
||
/* Pr<50>fen ob die eingegebene Sequenz in der Breakliste */
|
||
/* vorkommt. */
|
||
|
||
for (i = 0; i < VBOXBREAK_MAX_ENTRIES; i++)
|
||
{
|
||
if (breaklist[i])
|
||
{
|
||
if (strcmp(breaklist[i], voice_touchtone_sequence) == 0) return(0);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 'q': /* Quiet */
|
||
case 's': /* Silence */
|
||
case 'c': /* Fax calling tone */
|
||
case 'b': /* Busy tone */
|
||
break;
|
||
|
||
default:
|
||
log_line(LOG_W, "Illegal \"<DLE>\" shielded code \"");
|
||
log_char(LOG_W, c);
|
||
log_text(LOG_W, "\" (ignored)...\n");
|
||
break;
|
||
}
|
||
|
||
return(-1);
|
||
}
|