isdn4k-utils/vbox3/vboxgetty/tclscript.c

461 lines
10 KiB
C
Raw Blame History

/*
** $Id: tclscript.c,v 1.7 1998/08/30 17:32:07 michael Exp $
**
** Copyright 1996-1998 Michael 'Ghandi' Herold <michael@abadonna.mayn.de>
**
** $Log: tclscript.c,v $
** Revision 1.7 1998/08/30 17:32:07 michael
** - Total new audio setup - now it works correct and don't crash the
** machine.
** - Example answercall.tcl added.
** - Reduced in-/outgoing data logging. Now only around all 8000 bytes a
** line ist logged.
** - Added control file check to play and record function.
**
** Revision 1.6 1998/08/29 15:35:09 michael
** - Removed audio setup - it will crash my machine. Kernel mailing list says
** there are many bugs in the sound ioctl's :-( But audio will work correct
** without the settings.
** - Added voice play function. Played messages are *not* recorded or piped to
** the audio device.
**
** Revision 1.5 1998/08/28 13:06:15 michael
** - Removed audio full duplex mode. Sorry, my soundcard doesn't support
** this :-)
** - Added Fritz's /dev/audio setup. Pipe to /dev/audio now works great
** (little echo but a clear sound :-)
** - Added better control support. The control now has the ttyname appended
** (but there are some global controls without this) for controlling
** more than one vboxgetty for a user.
** - Added support for "vboxcall" in the user spool directory. The file
** stores information about the current answered call (needed by vbox,
** vboxctrl or some other programs to create the right controls).
** - Added support for Karsten's suspend mode (support for giving a line
** number is included also, but currently not used since hisax don't use
** it).
**
** Revision 1.4 1998/07/06 09:05:31 michael
** - New control file code added. The controls are not longer only empty
** files - they can contain additional informations.
** - Control "vboxctrl-answer" added.
** - Control "vboxctrl-suspend" added.
** - Locking mechanism added.
** - Configuration parsing added.
** - Some code cleanups.
**
** Revision 1.3 1998/06/18 12:38:17 michael
** - 2nd part of the automake/autoconf implementation (now compiles again).
**
** Revision 1.2 1998/06/17 17:01:24 michael
** - First part of the automake/autoconf implementation. Currently vbox will
** *not* compile!
**
*/
#include "../config.h"
#include <tcl.h>
#include <string.h>
#include <unistd.h>
#include "vboxgetty.h"
#include "log.h"
#include "modem.h"
#include "tclscript.h"
#include "stringutils.h"
static Tcl_Interp *interpreter = NULL;
int vbox_block(VBOX_TCLFUNC_PROTO);
int vbox_log(VBOX_TCLFUNC_PROTO);
int vbox_modem_command(VBOX_TCLFUNC_PROTO);
int vbox_voice(VBOX_TCLFUNC_PROTO);
static struct vbox_tcl_function vbox_tcl_functions[] =
{
{ "exit", vbox_block },
{ "vbox_log", vbox_log },
{ "vbox_modem_command", vbox_modem_command },
{ "vbox_voice" , vbox_voice },
{ NULL, NULL }
};
static int scr_init_functions(void);
int scr_create_interpreter(void)
{
log_line(LOG_D, "Initializing tcl interpreter...\n");
if (TCL_MAJOR_VERSION >= 8)
{
if ((interpreter = Tcl_CreateInterp()))
{
if (scr_init_functions() == 0) return(0);
}
}
return(-1);
}
void scr_remove_interpreter(void)
{
int rc;
if (interpreter)
{
log_line(LOG_D, "Removing tcl interpreter...\n");
if ((rc = Tcl_InterpDeleted(interpreter)) == 0)
{
Tcl_DeleteInterp(interpreter);
}
else log_line(LOG_W, "Tcl interpreter can't be removed (returns %d).\n", rc);
}
}
/*************************************************************************/
/** scr_execute(): Executes a tcl script. **/
/*************************************************************************/
/** => name Name of the script to execute **/
/** => user User name (if set, script is first searched in **/
/** users spooldir) **/
/** <= 0 on success or -1 on error **/
/*************************************************************************/
int scr_execute(char *name, struct vboxuser *user)
{
int canrun = 0;
if (user)
{
printstring(temppathname, "%s/tcl/%s", user->home, name);
if (access(temppathname, F_OK|R_OK) == 0) canrun = 1;
}
if (!canrun)
{
printstring(temppathname, "%s/tcl/%s", PKGDATADIR, name);
if (access(temppathname, F_OK|R_OK) == 0) canrun = 1;
}
if (canrun)
{
log_line(LOG_D, "Running \"%s\"...\n", temppathname);
if (Tcl_EvalFile(interpreter, temppathname) == TCL_OK)
{
log_line(LOG_D, "Tcl script returns without errors.\n");
return(0);
}
else log_line(LOG_E, "%s: %s [line %d]!\n", name, Tcl_GetStringResult(interpreter), interpreter->errorLine);
}
else log_line(LOG_E, "Tcl script \"%s\" not found.\n", name);
return(-1);
}
/*************************************************************************/
/** scr_tcl_version(): Returns current tcl version number. **/
/*************************************************************************/
/** <= Tcl version string **/
/*************************************************************************/
char *scr_tcl_version(void)
{
return(TCL_VERSION);
}
/*************************************************************************/
/** scr_init_functions(): Adds the vbox functions to the interpreter. **/
/*************************************************************************/
/** <= 0 on success or -1 on error **/
/*************************************************************************/
static int scr_init_functions(void)
{
int i = 0;
while (vbox_tcl_functions[i].name)
{
if (!Tcl_CreateObjCommand(interpreter, vbox_tcl_functions[i].name, vbox_tcl_functions[i].proc, NULL, NULL))
{
log_line(LOG_E, "Can't add new tcl command \"%s\".\n", vbox_tcl_functions[i].name);
return(-1);
}
else log_line(LOG_D, "New tcl command \"%s\" added.\n", vbox_tcl_functions[i].name);
i++;
}
return(0);
}
/*************************************************************************/
/** scr_init_variables(): Initialize global tcl variables. **/
/*************************************************************************/
/** => vars Pointer to a filled variable structure **/
/** <= 0 on success or -1 on error **/
/*************************************************************************/
int scr_init_variables(struct vbox_tcl_variable *vars)
{
int i = 0;
while (vars[i].name)
{
if (Tcl_VarEval(interpreter, "set ", vars[i].name, " \"", vars[i].args, "\"", NULL) != TCL_OK)
{
log_line(LOG_E, "Can't set tcl variable \"%s\".\n", vars[i].name);
return(-1);
}
else log_line(LOG_D, "Tcl variable \"%s\" set to \"%s\".\n", vars[i].name, vars[i].args);
i++;
}
return(0);
}
int vbox_block(VBOX_TCLFUNC)
{
log_line(LOG_W, "Tcl command \"%s\" is blocked!\n", Tcl_GetStringFromObj(objv[0], NULL));
return(TCL_OK);
}
int vbox_log(VBOX_TCLFUNC)
{
char *levelv;
int levelc;
if (objc == 3)
{
levelv = Tcl_GetStringFromObj(objv[1], NULL);
levelc = LOG_E;
switch (levelv[0])
{
case 'W':
levelc = LOG_W;
break;
case 'I':
levelc = LOG_I;
break;
case 'A':
levelc = LOG_A;
break;
case 'D':
levelc = LOG_D;
break;
}
log_line(levelc, "%s\n", Tcl_GetStringFromObj(objv[2], NULL));
}
else log_line(LOG_E, "Bad vars %d\n", objc);
return(TCL_OK);
}
int vbox_modem_command(VBOX_TCLFUNC)
{
int i;
if (objc == 3)
{
i = modem_command(&vboxmodem, Tcl_GetStringFromObj(objv[1], NULL), Tcl_GetStringFromObj(objv[2], NULL));
printstring(temppathname, "%d", i);
Tcl_SetResult(intp, temppathname, NULL);
}
else log_line(LOG_E, "Bad vars %d\n", objc);
return(TCL_OK);
}
/*************************************************************************/
/** vbox_voice(): Tcl Kommando "vbox_voice". Die Funktion gibt immer **/
/** TCL_OK zur<75>ck. Das Ergebnis der jeweiligen Funktion **/
/** wird als R<>ckgabe des Tcl Kommandos geliefert. **/
/*************************************************************************/
int vbox_voice(VBOX_TCLFUNC)
{
char *cmd;
char *arg;
int rc;
int i;
if (objc >= 3)
{
cmd = Tcl_GetStringFromObj(objv[1], NULL);
arg = Tcl_GetStringFromObj(objv[2], NULL);
if ((cmd) && (arg))
{
switch (*cmd)
{
case 'W':
case 'w':
{
/* Zeitspanne warten und dabei auch eingehende */
/* Daten vom Modem bearbeiten. */
switch (voice_wait(xstrtol(arg, 60)))
{
case 0:
Tcl_SetResult(intp, "OK", NULL);
break;
case 1:
Tcl_SetResult(intp, "TOUCHTONE", NULL);
break;
case 2:
Tcl_SetResult(intp, "SUSPEND", NULL);
break;
default:
Tcl_SetResult(intp, "HANGUP", NULL);
break;
}
}
break;
case 'P':
case 'p':
{
/* Nachricht(en) abspielen und dabei auch eingeh- */
/* ende Daten vom Modem bearbeiten. */
rc = 0;
i = 2;
while (i < objc)
{
arg = Tcl_GetStringFromObj(objv[i], NULL);
if ((rc = voice_play(arg)) != 0) break;
i++;
}
switch (rc)
{
case 0:
Tcl_SetResult(intp, "OK", NULL);
break;
case 1:
Tcl_SetResult(intp, "TOUCHTONE", NULL);
break;
case 2:
Tcl_SetResult(intp, "SUSPEND", NULL);
break;
default:
Tcl_SetResult(intp, "HANGUP", NULL);
break;
}
}
break;
case 'R':
case 'r':
{
/* Speicherung der Audiodaten starten/stoppen */
/* (record). In diesem Fall wird ERROR bei ei- */
/* nem Fehler oder OK zur<75>ckgegeben. */
if (strcasecmp(arg, "stop") == 0) rc = voice_save(0);
if (strcasecmp(arg, "start") == 0) rc = voice_save(1);
switch (rc)
{
case 0:
Tcl_SetResult(intp, "OK", NULL);
break;
default:
Tcl_SetResult(intp, "ERROR", NULL);
break;
}
}
break;
case 'A':
case 'a':
{
/* Eingehende Audiodaten zum mith<74>ren an ein */
/* anderes Device schicken. */
if (strcasecmp(arg, "stop") == 0) rc = voice_hear(0);
if (strcasecmp(arg, "start") == 0) rc = voice_hear(1);
switch (rc)
{
case 0:
Tcl_SetResult(intp, "OK", NULL);
break;
default:
Tcl_SetResult(intp, "ERROR", NULL);
break;
}
}
break;
default:
Tcl_SetResult(intp, "ERROR", NULL);
break;
}
}
}
return(TCL_OK);
}