1570 lines
46 KiB
C
1570 lines
46 KiB
C
|
|
#include "irc.h"
|
|
static char cvsrevision[] = "$Id: tcl_public.c 3 2008-02-25 09:49:14Z keaston $";
|
|
CVS_REVISION(tcl_public_c)
|
|
#include "ircaux.h"
|
|
#include "struct.h"
|
|
#include "commands.h"
|
|
#include "screen.h"
|
|
#include "server.h"
|
|
#include "tcl_bx.h"
|
|
#include "misc.h"
|
|
#include "userlist.h"
|
|
#include "output.h"
|
|
#include "log.h"
|
|
#include "dcc.h"
|
|
#include "timer.h"
|
|
#define MAIN_SOURCE
|
|
#include "modval.h"
|
|
|
|
cmd_t C_dcc[] =
|
|
{
|
|
{ "act", cmd_act, ADD_DCC, "Perform action on a channel"},
|
|
{ "adduser", cmd_adduser, ADD_DCC, "add a user to the userlist" },
|
|
{ "boot", cmd_boot, ADD_BAN, "boot user off the botnet" },
|
|
{ "chat", cmd_chat, 0, "add you to the chat network" },
|
|
{ "cmsg", cmd_cmsg, 0, "send a privmsg to someone on botnEt" },
|
|
{ "echo", cmd_echo, 0, "turn echo on/off" },
|
|
{ "help", cmd_help, 0, "help information [option cmd]" },
|
|
{ "invite", cmd_invite, ADD_INVITE,"invite <nick> to the chat network" },
|
|
{ "irc", cmd_ircii, ADD_TCL, "pass ircii commands to client" },
|
|
{ "msg", cmd_msg, ADD_DCC,"send msg to someone" },
|
|
{ "op", cmd_ops, ADD_OPS, "ops on a channel" },
|
|
{ "quit", cmd_quit, 0, "remove from chat network" },
|
|
{ "say", cmd_say, ADD_DCC, "say something on a channel" },
|
|
{ "tcl", cmd_tcl, ADD_TCL, "set a tcl variable" },
|
|
{ "who", send_who, 0, "find out who is on [option botnick]" },
|
|
{ "whoami", cmd_whoami, 0, "determines your userlevel" },
|
|
{ "whom", send_whom, 0, "find out who is on the botnet. global" },
|
|
{ "xlink", send_command, ADD_DCC, "send command to all on link" },
|
|
{ NULL, NULL, -1, NULL}
|
|
};
|
|
|
|
#ifdef WANT_TCL
|
|
#include <tcl.h>
|
|
|
|
/*
|
|
* I wish to thank vore!vore@domination.ml.org for pushing me
|
|
* todo something like this, although by-Tor requested
|
|
* something like this as well but not so succintly
|
|
*/
|
|
|
|
|
|
int tcl_bots STDVAR;
|
|
int tcl_ircii STDVAR;
|
|
int tcl_validuser STDVAR;
|
|
int tcl_pushmode STDVAR;
|
|
int tcl_flushmode STDVAR;
|
|
int Tcl_LvarpopCmd STDVAR;
|
|
int Tcl_LemptyCmd STDVAR;
|
|
int Tcl_LmatchCmd STDVAR;
|
|
int Tcl_KeyldelCmd STDVAR;
|
|
int Tcl_KeylgetCmd STDVAR;
|
|
int Tcl_KeylkeysCmd STDVAR;
|
|
int Tcl_KeylsetCmd STDVAR;
|
|
int tcl_maskhost STDVAR;
|
|
int tcl_onchansplit STDVAR;
|
|
int tcl_servers STDVAR;
|
|
int tcl_chanstruct STDVAR;
|
|
int tcl_channel STDVAR;
|
|
int tcl_channels STDVAR;
|
|
int tcl_isop STDVAR;
|
|
int tcl_getchanhost STDVAR;
|
|
int matchattr STDVAR;
|
|
int tcl_finduser STDVAR;
|
|
int tcl_findshit STDVAR;
|
|
int tcl_date STDVAR;
|
|
int tcl_getcomment STDVAR;
|
|
int tcl_setcomment STDVAR;
|
|
int tcl_time STDVAR;
|
|
int tcl_ctime STDVAR;
|
|
int tcl_onchan STDVAR;
|
|
int tcl_chanlist STDVAR;
|
|
int tcl_unixtime STDVAR;
|
|
int tcl_putlog STDVAR;
|
|
int tcl_putloglev STDVAR;
|
|
int tcl_rand STDVAR;
|
|
int tcl_timer STDVAR;
|
|
int tcl_killtimer STDVAR;
|
|
int tcl_utimer STDVAR;
|
|
int tcl_killutimer STDVAR;
|
|
int tcl_timers STDVAR;
|
|
int tcl_utimers STDVAR;
|
|
int tcl_putserv STDVAR;
|
|
int tcl_putscr STDVAR;
|
|
int tcl_putdcc STDVAR;
|
|
int tcl_putbot STDVAR;
|
|
int tcl_putallbots STDVAR;
|
|
int tcl_bind STDVAR;
|
|
int tcl_tellbinds STDVAR;
|
|
int tcl_bind STDVAR;
|
|
int tcl_strftime STDVAR;
|
|
int tcl_cparse STDVAR;
|
|
int tcl_userhost STDVAR;
|
|
int tcl_getchanmode STDVAR;
|
|
int tcl_msg STDVAR;
|
|
int tcl_say STDVAR;
|
|
int tcl_desc STDVAR;
|
|
int tcl_notice STDVAR;
|
|
int tcl_bots STDVAR;
|
|
int tcl_clients STDVAR;
|
|
int tcl_alias STDVAR;
|
|
int tcl_get_var STDVAR;
|
|
int tcl_set_var STDVAR;
|
|
int tcl_fget_var STDVAR;
|
|
int tcl_fset_var STDVAR;
|
|
int tcl_aliasvar STDVAR;
|
|
int tcl_cset STDVAR;
|
|
int tcl_dcc_stat STDVAR;
|
|
int tcl_dcc_close STDVAR;
|
|
|
|
extern void add_tcl_alias (Tcl_Interp *, void *, void *);
|
|
|
|
extern TimerList *tcl_Pending_timers;
|
|
extern TimerList *tcl_Pending_utimers;
|
|
static unsigned int timer_id = 1;
|
|
|
|
|
|
int msg_die (int, char *);
|
|
|
|
cmd_t C_msg[] =
|
|
{
|
|
/* { "die", msg_die, ADD_KILL, "kill a client. Needs Userlevel KILL" },*/
|
|
{ NULL, NULL, -1, NULL}
|
|
};
|
|
|
|
cmd_t C_ctcp[] =
|
|
{
|
|
{ NULL, NULL, -1, NULL}
|
|
};
|
|
|
|
cmd_t C_notice[] =
|
|
{
|
|
{ NULL, NULL, -1, NULL}
|
|
};
|
|
|
|
/*
|
|
* tclX has some keyed list functions which are useful.
|
|
* But because tclX is not on every system, we cut and paste them
|
|
* here for convenience sake.
|
|
*/
|
|
|
|
#define STREQU(str1, str2) \
|
|
(((str1) [0] == (str2) [0]) && (strcmp (str1, str2) == 0))
|
|
#define STRNEQU(str1, str2, cnt) \
|
|
(((str1) [0] == (str2) [0]) && (strncmp (str1, str2, cnt) == 0))
|
|
#define ISSPACE(c) (isspace ((unsigned char) c))
|
|
#define ISDIGIT(c) (isdigit ((unsigned char) c))
|
|
#define ISLOWER(c) (islower ((unsigned char) c))
|
|
|
|
extern int Tcl_KeyldelCmd (ClientData, Tcl_Interp*, int, char**);
|
|
|
|
extern int Tcl_KeylgetCmd (ClientData, Tcl_Interp *, int, char**);
|
|
|
|
extern int Tcl_KeylkeysCmd (ClientData, Tcl_Interp *, int, char**);
|
|
|
|
extern int Tcl_KeylsetCmd (ClientData, Tcl_Interp *, int, char **);
|
|
extern int TclFindElement (Tcl_Interp *, char *, char **, char **, int *, int *);
|
|
extern int Tcl_GetKeyedListField (Tcl_Interp *, char *, char *, char **);
|
|
extern int TclCopyAndCollapse (int, char *, char *);
|
|
|
|
char *tclXWrongArgs = "wrong # args: ";
|
|
|
|
typedef struct fieldInfo_t
|
|
{
|
|
int argc;
|
|
char **argv;
|
|
int foundIdx;
|
|
char *valuePtr;
|
|
int valueSize;
|
|
} fieldInfo_t;
|
|
|
|
|
|
static int CompareKeyListField (Tcl_Interp *,
|
|
char *,
|
|
char *,
|
|
char **,
|
|
int *,
|
|
int *);
|
|
|
|
static int SplitAndFindField (Tcl_Interp *,
|
|
char *,
|
|
char *,
|
|
fieldInfo_t *);
|
|
|
|
extern int Tcl_LmatchCmd (ClientData, Tcl_Interp*, int, char**);
|
|
|
|
|
|
/* BEGIN KEYED LIST */
|
|
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* CompareKeyListField --
|
|
* Compare a field name to a field (keyword/value pair) to determine if
|
|
* the field names match.
|
|
*
|
|
* Parameters:
|
|
* o interp (I/O) - Error message will be return in result if there is an
|
|
* error.
|
|
* o fieldName (I) - Field name to compare against field.
|
|
* o field (I) - Field to see if its name matches.
|
|
* o valuePtr (O) - If the field names match, a pointer to value part is
|
|
* returned.
|
|
* o valueSizePtr (O) - If the field names match, the length of the value
|
|
* part is returned here.
|
|
* o bracedPtr (O) - If the field names match, non-zero/zero to inficate
|
|
* that the value was/warn't in braces.
|
|
* Returns:
|
|
* TCL_OK - If the field names match.
|
|
* TCL_BREAK - If the fields names don't match.
|
|
* TCL_ERROR - If the list has an invalid format.
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int CompareKeyListField (tcl_interp, fieldName, field, valuePtr, valueSizePtr, bracedPtr)
|
|
Tcl_Interp *tcl_interp;
|
|
char *fieldName;
|
|
char *field;
|
|
char **valuePtr;
|
|
int *valueSizePtr;
|
|
int *bracedPtr;
|
|
{
|
|
char *elementPtr, *nextPtr;
|
|
int fieldNameSize, elementSize;
|
|
|
|
if (field [0] == '\0') {
|
|
tcl_interp->result =
|
|
"invalid keyed list format: list contains an empty field entry";
|
|
return TCL_ERROR;
|
|
}
|
|
if (TclFindElement (tcl_interp, (char *) field, &elementPtr, &nextPtr,
|
|
&elementSize, NULL) != TCL_OK)
|
|
return TCL_ERROR;
|
|
if (elementSize == 0) {
|
|
tcl_interp->result =
|
|
"invalid keyed list format: list contains an empty field name";
|
|
return TCL_ERROR;
|
|
}
|
|
if (nextPtr[0] == '\0') {
|
|
Tcl_AppendResult (tcl_interp, "invalid keyed list format or inconsistent ",
|
|
"field name scoping: no value associated with ",
|
|
"field \"", elementPtr, "\"", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
fieldNameSize = strlen ((char *) fieldName);
|
|
if (!((elementSize == fieldNameSize) &&
|
|
STRNEQU (elementPtr, ((char *) fieldName), fieldNameSize)))
|
|
return TCL_BREAK; /* Names do not match */
|
|
|
|
/*
|
|
* Extract the value from the list.
|
|
*/
|
|
if (TclFindElement (tcl_interp, nextPtr, &elementPtr, &nextPtr, &elementSize,
|
|
bracedPtr) != TCL_OK)
|
|
return TCL_ERROR;
|
|
if (nextPtr[0] != '\0') {
|
|
Tcl_AppendResult (tcl_interp, "invalid keyed list format: ",
|
|
"trailing data following value in field: \"",
|
|
elementPtr, "\"", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
*valuePtr = elementPtr;
|
|
*valueSizePtr = elementSize;
|
|
return TCL_OK;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* SplitAndFindField --
|
|
* Split a keyed list into an argv and locate a field (key/value pair)
|
|
* in the list.
|
|
*
|
|
* Parameters:
|
|
* o tcl_interp (I/O) - Error message will be return in result if there is an
|
|
* error.
|
|
* o fieldName (I) - The name of the field to find. Will validate that the
|
|
* name is not empty. If the name has a sub-name (seperated by "."),
|
|
* search for the top level name.
|
|
* o fieldInfoPtr (O) - The following fields are filled in:
|
|
* o argc - The number of elements in the keyed list.
|
|
* o argv - The keyed list argv is returned here, even if the key was
|
|
* not found. Client must free. Will be NULL is an error occurs.
|
|
* o foundIdx - The argv index containing the list entry that matches
|
|
* the field name, or -1 if the key was not found.
|
|
* o valuePtr - Pointer to the value part of the found element. NULL
|
|
* in not found.
|
|
* o valueSize - The size of the value part.
|
|
* Returns:
|
|
* Standard Tcl result.
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int SplitAndFindField (tcl_interp, fieldName, keyedList, fieldInfoPtr)
|
|
Tcl_Interp *tcl_interp;
|
|
char *fieldName;
|
|
char *keyedList;
|
|
fieldInfo_t *fieldInfoPtr;
|
|
{
|
|
int idx, result, braced;
|
|
|
|
if (fieldName == '\0') {
|
|
tcl_interp->result = "null key not allowed";
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
fieldInfoPtr->argv = NULL;
|
|
|
|
if (Tcl_SplitList (tcl_interp, (char *) keyedList, &fieldInfoPtr->argc,
|
|
&fieldInfoPtr->argv) != TCL_OK)
|
|
goto errorExit;
|
|
|
|
result = TCL_BREAK;
|
|
for (idx = 0; idx < fieldInfoPtr->argc; idx++) {
|
|
result = CompareKeyListField (tcl_interp, fieldName,
|
|
fieldInfoPtr->argv [idx],
|
|
&fieldInfoPtr->valuePtr,
|
|
&fieldInfoPtr->valueSize,
|
|
&braced);
|
|
if (result != TCL_BREAK)
|
|
break; /* Found or error, exit before idx is incremented. */
|
|
}
|
|
if (result == TCL_ERROR)
|
|
goto errorExit;
|
|
|
|
if (result == TCL_BREAK) {
|
|
fieldInfoPtr->foundIdx = -1; /* Not found */
|
|
fieldInfoPtr->valuePtr = NULL;
|
|
} else {
|
|
fieldInfoPtr->foundIdx = idx;
|
|
}
|
|
return TCL_OK;
|
|
|
|
errorExit:
|
|
if (fieldInfoPtr->argv != NULL)
|
|
ckfree ((char *) fieldInfoPtr->argv);
|
|
fieldInfoPtr->argv = NULL;
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Tcl_GetKeyedListKeys --
|
|
* Retrieve a list of keys from a keyed list. The list is walked rather
|
|
* than converted to a argv for increased performance.
|
|
*
|
|
* Parameters:
|
|
* o tcl_interp (I/O) - Error message will be return in result if there is an
|
|
* error.
|
|
* o subFieldName (I) - If "" or NULL, then the keys are retreved for
|
|
* the top level of the list. If specified, it is name of the field who's
|
|
* subfield keys are to be retrieve.
|
|
* o keyedList (I) - The list to search for the field.
|
|
* o keysArgcPtr (O) - The number of keys in the keyed list is returned
|
|
* here.
|
|
* o keysArgvPtr (O) - An argv containing the key names. It is dynamically
|
|
* allocated, containing both the array and the strings. A single call
|
|
* to ckfree will release it.
|
|
* Returns:
|
|
* TCL_OK - If the field was found.
|
|
* TCL_BREAK - If the field was not found.
|
|
* TCL_ERROR - If an error occured.
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
Tcl_GetKeyedListKeys (tcl_interp, subFieldName, keyedList, keysArgcPtr,
|
|
keysArgvPtr)
|
|
Tcl_Interp *tcl_interp;
|
|
char *subFieldName;
|
|
char *keyedList;
|
|
int *keysArgcPtr;
|
|
char ***keysArgvPtr;
|
|
{
|
|
char *scanPtr, *subFieldList;
|
|
int result, keyCount, totalKeySize, idx;
|
|
char *fieldPtr, *keyPtr, *nextByte, *dummyPtr;
|
|
int fieldSize, keySize;
|
|
char **keyArgv;
|
|
|
|
/*
|
|
* Skip leading white spaces in list. This keeps totally empty lists
|
|
* with some white-spaces from being confused with empty field entries
|
|
* later on in the parsing.
|
|
*/
|
|
for (; *keyedList != '\0'; keyedList++) {
|
|
if (ISSPACE (*keyedList) == 0)
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If the keys of a subfield are requested, the dig out that field's
|
|
* list and then rummage through it getting the keys.
|
|
*/
|
|
subFieldList = NULL;
|
|
|
|
if ((subFieldName != NULL) && (subFieldName [0] != '\0')) {
|
|
result = Tcl_GetKeyedListField (tcl_interp, subFieldName, keyedList,
|
|
&subFieldList);
|
|
if (result != TCL_OK)
|
|
return result;
|
|
keyedList = subFieldList;
|
|
}
|
|
|
|
/*
|
|
* Walk the list count the number of field names and their length.
|
|
*/
|
|
keyCount = 0;
|
|
totalKeySize = 0;
|
|
scanPtr = (char *) keyedList;
|
|
|
|
while (*scanPtr != '\0') {
|
|
result = TclFindElement (tcl_interp, scanPtr, &fieldPtr, &scanPtr,
|
|
&fieldSize, NULL);
|
|
if (result != TCL_OK)
|
|
goto errorExit;
|
|
result = TclFindElement (tcl_interp, fieldPtr, &keyPtr, &dummyPtr,
|
|
&keySize, NULL);
|
|
if (result != TCL_OK)
|
|
goto errorExit;
|
|
|
|
keyCount++;
|
|
totalKeySize += keySize + 1;
|
|
}
|
|
|
|
/*
|
|
* Allocate a structure to hold both the argv and strings.
|
|
*/
|
|
keyArgv = (char **) ckalloc (((keyCount + 1) * sizeof (char *)) +
|
|
totalKeySize);
|
|
keyArgv [keyCount] = NULL;
|
|
nextByte = ((char *) keyArgv) + ((keyCount + 1) * sizeof (char *));
|
|
|
|
/*
|
|
* Walk the list once more, copying in the strings and building up the
|
|
* argv.
|
|
*/
|
|
scanPtr = (char *) keyedList;
|
|
idx = 0;
|
|
|
|
while (*scanPtr != '\0') {
|
|
TclFindElement (tcl_interp, scanPtr, &fieldPtr, &scanPtr, &fieldSize,
|
|
NULL);
|
|
TclFindElement (tcl_interp, fieldPtr, &keyPtr, &dummyPtr, &keySize, NULL);
|
|
keyArgv [idx++] = nextByte;
|
|
strmcpy (nextByte, keyPtr, keySize);
|
|
nextByte [keySize] = '\0';
|
|
nextByte += keySize + 1;
|
|
}
|
|
*keysArgcPtr = keyCount;
|
|
*keysArgvPtr = keyArgv;
|
|
|
|
if (subFieldList != NULL)
|
|
ckfree (subFieldList);
|
|
return TCL_OK;
|
|
|
|
errorExit:
|
|
if (subFieldList != NULL)
|
|
ckfree (subFieldList);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Tcl_GetKeyedListField --
|
|
* Retrieve a field value from a keyed list. The list is walked rather than
|
|
* converted to a argv for increased performance. This if the name contains
|
|
* sub-fields, this function recursive.
|
|
*
|
|
* Parameters:
|
|
* o tcl_interp (I/O) - Error message will be return in result if there is an
|
|
* error.
|
|
* o fieldName (I) - The name of the field to extract. Will recusively
|
|
* process sub-field names seperated by `.'.
|
|
* o keyedList (I) - The list to search for the field.
|
|
* o fieldValuePtr (O) - If the field is found, a pointer to a dynamicly
|
|
* allocated string containing the value is returned here. If NULL is
|
|
* specified, then only the presence of the field is validated, the
|
|
* value is not returned.
|
|
* Returns:
|
|
* TCL_OK - If the field was found.
|
|
* TCL_BREAK - If the field was not found.
|
|
* TCL_ERROR - If an error occured.
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
int Tcl_GetKeyedListField (tcl_interp, fieldName, keyedList, fieldValuePtr)
|
|
Tcl_Interp *tcl_interp;
|
|
char *fieldName;
|
|
char *keyedList;
|
|
char **fieldValuePtr;
|
|
{
|
|
char *nameSeparPtr, *scanPtr, *valuePtr;
|
|
int valueSize, result, braced;
|
|
|
|
if (fieldName == '\0')
|
|
{
|
|
tcl_interp->result = "null key not allowed";
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Skip leading white spaces in list. This keeps totally empty lists
|
|
* with some white-spaces from being confused with empty field entries
|
|
* later on in the parsing.
|
|
*/
|
|
for (; *keyedList != 0; keyedList++)
|
|
if (ISSPACE (*keyedList) == 0)
|
|
break;
|
|
|
|
/*
|
|
* Check for sub-names, temporarly delimit the top name with a '\0'.
|
|
*/
|
|
nameSeparPtr = strchr ((char *) fieldName, '.');
|
|
if (nameSeparPtr != NULL)
|
|
*nameSeparPtr = 0;
|
|
|
|
/*
|
|
* Walk the list looking for a field name that matches.
|
|
*/
|
|
scanPtr = (char *) keyedList;
|
|
result = TCL_BREAK; /* Assume not found */
|
|
|
|
while (*scanPtr != '\0')
|
|
{
|
|
char *fieldPtr;
|
|
int fieldSize;
|
|
char saveChar = 0;
|
|
|
|
result = TclFindElement (tcl_interp, scanPtr, &fieldPtr, &scanPtr,
|
|
&fieldSize, NULL);
|
|
if (result != TCL_OK)
|
|
break;
|
|
|
|
saveChar = fieldPtr [fieldSize];
|
|
fieldPtr [fieldSize] = 0;
|
|
|
|
result = CompareKeyListField (tcl_interp, (char *) fieldName, fieldPtr,
|
|
&valuePtr, &valueSize, &braced);
|
|
fieldPtr [fieldSize] = saveChar;
|
|
if (result != TCL_BREAK)
|
|
break; /* Found or an error */
|
|
}
|
|
|
|
if (result != TCL_OK)
|
|
goto exitPoint; /* Not found or an error */
|
|
|
|
/*
|
|
* If a subfield is requested, recurse to get the value otherwise allocate
|
|
* a buffer to hold the value.
|
|
*/
|
|
if (nameSeparPtr != NULL)
|
|
{
|
|
char saveChar = 0;
|
|
|
|
saveChar = valuePtr [valueSize];
|
|
valuePtr [valueSize] = 0;
|
|
result = Tcl_GetKeyedListField (tcl_interp, nameSeparPtr+1, valuePtr,
|
|
fieldValuePtr);
|
|
valuePtr [valueSize] = saveChar;
|
|
}
|
|
else
|
|
{
|
|
if (fieldValuePtr != NULL)
|
|
{
|
|
char *fieldValue;
|
|
|
|
fieldValue = ckalloc (valueSize + 1);
|
|
if (braced)
|
|
{
|
|
strmcpy (fieldValue, valuePtr, valueSize);
|
|
fieldValue [valueSize] = 0;
|
|
}
|
|
else
|
|
TclCopyAndCollapse(valueSize, valuePtr, fieldValue);
|
|
*fieldValuePtr = fieldValue;
|
|
}
|
|
}
|
|
exitPoint:
|
|
if (nameSeparPtr != NULL)
|
|
*nameSeparPtr = '.';
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Tcl_SetKeyedListField --
|
|
* Set a field value in keyed list.
|
|
*
|
|
* Parameters:
|
|
* o tcl_interp (I/O) - Error message will be return in result if there is an
|
|
* error.
|
|
* o fieldName (I) - The name of the field to extract. Will recusively
|
|
* process sub-field names seperated by `.'.
|
|
* o fieldValue (I) - The value to set for the field.
|
|
* o keyedList (I) - The keyed list to set a field value in, may be an
|
|
* NULL or an empty list to create a new keyed list.
|
|
* Returns:
|
|
* A pointer to a dynamically allocated string, or NULL if an error
|
|
* occured.
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
char * Tcl_SetKeyedListField (tcl_interp, fieldName, fieldValue, keyedList)
|
|
Tcl_Interp *tcl_interp;
|
|
char *fieldName;
|
|
char *fieldValue;
|
|
char *keyedList;
|
|
{
|
|
char *nameSeparPtr;
|
|
char *newField = NULL, *newList;
|
|
fieldInfo_t fieldInfo;
|
|
char *elemArgv [2];
|
|
|
|
if (fieldName [0] == '\0') {
|
|
Tcl_AppendResult (tcl_interp, "empty field name", (char *) NULL);
|
|
return NULL;
|
|
}
|
|
|
|
if (keyedList == NULL)
|
|
keyedList = empty_string;
|
|
|
|
/*
|
|
* Check for sub-names, temporarly delimit the top name with a '\0'.
|
|
*/
|
|
nameSeparPtr = strchr ((char *) fieldName, '.');
|
|
if (nameSeparPtr != NULL)
|
|
*nameSeparPtr = 0;
|
|
|
|
if (SplitAndFindField (tcl_interp, fieldName, keyedList, &fieldInfo) != TCL_OK)
|
|
goto errorExit;
|
|
|
|
/*
|
|
* Either recursively retrieve build the field value or just use the
|
|
* supplied value.
|
|
*/
|
|
elemArgv [0] = (char *) fieldName;
|
|
if (nameSeparPtr != NULL) {
|
|
char saveChar = 0;
|
|
|
|
if (fieldInfo.valuePtr != NULL) {
|
|
saveChar = fieldInfo.valuePtr [fieldInfo.valueSize];
|
|
fieldInfo.valuePtr [fieldInfo.valueSize] = '\0';
|
|
}
|
|
elemArgv [1] = Tcl_SetKeyedListField (tcl_interp, nameSeparPtr+1,
|
|
fieldValue, fieldInfo.valuePtr);
|
|
|
|
if (fieldInfo.valuePtr != NULL)
|
|
fieldInfo.valuePtr [fieldInfo.valueSize] = saveChar;
|
|
if (elemArgv [1] == NULL)
|
|
goto errorExit;
|
|
newField = Tcl_Merge (2, elemArgv);
|
|
ckfree (elemArgv [1]);
|
|
} else {
|
|
elemArgv [1] = (char *) fieldValue;
|
|
newField = Tcl_Merge (2, elemArgv);
|
|
}
|
|
|
|
/*
|
|
* If the field does not current exist in the keyed list, append it,
|
|
* otherwise replace it.
|
|
*/
|
|
if (fieldInfo.foundIdx == -1) {
|
|
fieldInfo.foundIdx = fieldInfo.argc;
|
|
fieldInfo.argc++;
|
|
}
|
|
|
|
fieldInfo.argv [fieldInfo.foundIdx] = newField;
|
|
newList = Tcl_Merge (fieldInfo.argc, fieldInfo.argv);
|
|
|
|
if (nameSeparPtr != NULL)
|
|
*nameSeparPtr = '.';
|
|
ckfree ((char *) newField);
|
|
ckfree ((char *) fieldInfo.argv);
|
|
return newList;
|
|
|
|
errorExit:
|
|
if (nameSeparPtr != NULL)
|
|
*nameSeparPtr = '.';
|
|
if (newField != NULL)
|
|
ckfree ((char *) newField);
|
|
if (fieldInfo.argv != NULL)
|
|
ckfree ((char *) fieldInfo.argv);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Tcl_DeleteKeyedListField --
|
|
* Delete a field value in keyed list.
|
|
*
|
|
* Parameters:
|
|
* o tcl_interp (I/O) - Error message will be return in result if there is an
|
|
* error.
|
|
* o fieldName (I) - The name of the field to extract. Will recusively
|
|
* process sub-field names seperated by `.'.
|
|
* o fieldValue (I) - The value to set for the field.
|
|
* o keyedList (I) - The keyed list to delete the field from.
|
|
* Returns:
|
|
* A pointer to a dynamically allocated string containing the new list, or
|
|
* NULL if an error occured.
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
char *Tcl_DeleteKeyedListField (Tcl_Interp *tcl_interp, char *fieldName, char *keyedList)
|
|
{
|
|
char *nameSeparPtr;
|
|
char *newList;
|
|
int idx;
|
|
fieldInfo_t fieldInfo;
|
|
char *elemArgv [2];
|
|
char *newElement;
|
|
/*
|
|
* Check for sub-names, temporarly delimit the top name with a '\0'.
|
|
*/
|
|
nameSeparPtr = strchr ((char *) fieldName, '.');
|
|
if (nameSeparPtr != NULL)
|
|
*nameSeparPtr = '\0';
|
|
|
|
if (SplitAndFindField (tcl_interp, fieldName, keyedList, &fieldInfo) != TCL_OK)
|
|
goto errorExit;
|
|
|
|
if (fieldInfo.foundIdx == -1) {
|
|
Tcl_AppendResult (tcl_interp, "field name not found: \"", fieldName,
|
|
"\"", (char *) NULL);
|
|
goto errorExit;
|
|
}
|
|
|
|
/*
|
|
* If sub-field, recurse down to find the field to delete. If empty field
|
|
* returned or no sub-field, delete the found entry by moving everything
|
|
* up in the argv.
|
|
*/
|
|
elemArgv [0] = (char *) fieldName;
|
|
if (nameSeparPtr != NULL) {
|
|
char saveChar = 0;
|
|
|
|
if (fieldInfo.valuePtr != NULL) {
|
|
saveChar = fieldInfo.valuePtr [fieldInfo.valueSize];
|
|
fieldInfo.valuePtr [fieldInfo.valueSize] = '\0';
|
|
}
|
|
elemArgv [1] = Tcl_DeleteKeyedListField (tcl_interp, nameSeparPtr+1,
|
|
fieldInfo.valuePtr);
|
|
if (fieldInfo.valuePtr != NULL)
|
|
fieldInfo.valuePtr [fieldInfo.valueSize] = saveChar;
|
|
if (elemArgv [1] == NULL)
|
|
goto errorExit;
|
|
if (elemArgv [1][0] == '\0')
|
|
newElement = NULL;
|
|
else
|
|
newElement = Tcl_Merge (2, elemArgv);
|
|
ckfree (elemArgv [1]);
|
|
} else
|
|
newElement = NULL;
|
|
|
|
if (newElement == NULL) {
|
|
for (idx = fieldInfo.foundIdx; idx < fieldInfo.argc; idx++)
|
|
fieldInfo.argv [idx] = fieldInfo.argv [idx + 1];
|
|
fieldInfo.argc--;
|
|
} else
|
|
fieldInfo.argv [fieldInfo.foundIdx] = newElement;
|
|
|
|
newList = Tcl_Merge (fieldInfo.argc, fieldInfo.argv);
|
|
|
|
if (nameSeparPtr != NULL)
|
|
*nameSeparPtr = '.';
|
|
if (newElement != NULL)
|
|
ckfree (newElement);
|
|
ckfree ((char *) fieldInfo.argv);
|
|
return newList;
|
|
|
|
errorExit:
|
|
if (nameSeparPtr != NULL)
|
|
*nameSeparPtr = '.';
|
|
if (fieldInfo.argv != NULL)
|
|
ckfree ((char *) fieldInfo.argv);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Tcl_KeyldelCmd --
|
|
* Implements the TCL keyldel command:
|
|
* keyldel listvar key
|
|
*
|
|
* Results:
|
|
* Standard TCL results.
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
int Tcl_KeyldelCmd (ClientData clientData, Tcl_Interp *tcl_interp, int argc, char **argv)
|
|
{
|
|
char *keyedList, *newList;
|
|
char *varPtr;
|
|
|
|
if (argc != 3) {
|
|
Tcl_AppendResult (tcl_interp, tclXWrongArgs, argv [0],
|
|
" listvar key", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
keyedList = Tcl_GetVar (tcl_interp, argv[1], TCL_LEAVE_ERR_MSG);
|
|
if (keyedList == NULL)
|
|
return TCL_ERROR;
|
|
|
|
newList = Tcl_DeleteKeyedListField (tcl_interp, argv [2], keyedList);
|
|
if (newList == NULL)
|
|
return TCL_ERROR;
|
|
|
|
varPtr = Tcl_SetVar (tcl_interp, argv [1], newList, TCL_LEAVE_ERR_MSG);
|
|
ckfree ((char *) newList);
|
|
|
|
return (varPtr == NULL) ? TCL_ERROR : TCL_OK;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Tcl_KeylgetCmd --
|
|
* Implements the TCL keylget command:
|
|
* keylget listvar ?key? ?retvar | {}?
|
|
*
|
|
* Results:
|
|
* Standard TCL results.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
int Tcl_KeylgetCmd (ClientData clientData, Tcl_Interp *tcl_interp, int argc, char **argv)
|
|
{
|
|
char *keyedList;
|
|
char *fieldValue;
|
|
char **fieldValuePtr;
|
|
int result;
|
|
|
|
if ((argc < 2) || (argc > 4)) {
|
|
Tcl_AppendResult (tcl_interp, tclXWrongArgs, argv [0],
|
|
" listvar ?key? ?retvar | {}?", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
keyedList = Tcl_GetVar (tcl_interp, argv[1], TCL_LEAVE_ERR_MSG);
|
|
if (keyedList == NULL)
|
|
return TCL_ERROR;
|
|
|
|
/*
|
|
* Handle request for list of keys, use keylkeys command.
|
|
*/
|
|
if (argc == 2)
|
|
return Tcl_KeylkeysCmd (clientData, tcl_interp, argc, argv);
|
|
|
|
/*
|
|
* Handle retrieving a value for a specified key.
|
|
*/
|
|
if (argv [2] == '\0') {
|
|
tcl_interp->result = "null key not allowed";
|
|
return TCL_ERROR;
|
|
}
|
|
if ((argc == 4) && (argv [3][0] == '\0'))
|
|
fieldValuePtr = NULL;
|
|
else
|
|
fieldValuePtr = &fieldValue;
|
|
|
|
result = Tcl_GetKeyedListField (tcl_interp, argv [2], keyedList,
|
|
fieldValuePtr);
|
|
if (result == TCL_ERROR)
|
|
return TCL_ERROR;
|
|
|
|
/*
|
|
* Handle field name not found.
|
|
*/
|
|
if (result == TCL_BREAK) {
|
|
if (argc == 3) {
|
|
Tcl_AppendResult (tcl_interp, "key \"", argv [2],
|
|
"\" not found in keyed list", (char *) NULL);
|
|
return TCL_ERROR;
|
|
} else {
|
|
tcl_interp->result = zero;
|
|
return TCL_OK;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle field name found and return in the result.
|
|
*/
|
|
if (argc == 3) {
|
|
Tcl_SetResult (tcl_interp, fieldValue, TCL_DYNAMIC);
|
|
return TCL_OK;
|
|
}
|
|
|
|
/*
|
|
* Handle null return variable specified and key was found.
|
|
*/
|
|
if (argv [3][0] == '\0') {
|
|
tcl_interp->result = one;
|
|
return TCL_OK;
|
|
}
|
|
|
|
/*
|
|
* Handle returning the value to the variable.
|
|
*/
|
|
if (Tcl_SetVar (tcl_interp, argv [3], fieldValue, TCL_LEAVE_ERR_MSG) == NULL)
|
|
result = TCL_ERROR;
|
|
else
|
|
result = TCL_OK;
|
|
ckfree (fieldValue);
|
|
tcl_interp->result = one;
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Tcl_KeylkeysCmd --
|
|
* Implements the TCL keylkeys command:
|
|
* keylkeys listvar ?key?
|
|
*
|
|
* Results:
|
|
* Standard TCL results.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
int Tcl_KeylkeysCmd (ClientData clientData, Tcl_Interp *tcl_interp, int argc, char **argv)
|
|
{
|
|
char *keyedList, **keysArgv;
|
|
int result, keysArgc;
|
|
|
|
if ((argc < 2) || (argc > 3)) {
|
|
Tcl_AppendResult (tcl_interp, tclXWrongArgs, argv [0],
|
|
" listvar ?key?", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
keyedList = Tcl_GetVar (tcl_interp, argv[1], TCL_LEAVE_ERR_MSG);
|
|
if (keyedList == NULL)
|
|
return TCL_ERROR;
|
|
|
|
/*
|
|
* If key argument is not specified, then argv [2] is NULL, meaning get
|
|
* top level keys.
|
|
*/
|
|
result = Tcl_GetKeyedListKeys (tcl_interp, argv [2], keyedList, &keysArgc,
|
|
&keysArgv);
|
|
if (result == TCL_ERROR)
|
|
return TCL_ERROR;
|
|
if (result == TCL_BREAK) {
|
|
Tcl_AppendResult (tcl_interp, "field name not found: \"", argv [2],
|
|
"\"", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
Tcl_SetResult (tcl_interp, Tcl_Merge (keysArgc, keysArgv), TCL_DYNAMIC);
|
|
ckfree ((char *) keysArgv);
|
|
return TCL_OK;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Tcl_KeylsetCmd --
|
|
* Implements the TCL keylset command:
|
|
* keylset listvar key value ?key value...?
|
|
*
|
|
* Results:
|
|
* Standard TCL results.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
int Tcl_KeylsetCmd (ClientData clientData, Tcl_Interp *tcl_interp, int argc, char **argv)
|
|
{
|
|
char *keyedList, *newList, *prevList;
|
|
char *varPtr;
|
|
int idx;
|
|
|
|
if ((argc < 4) || ((argc % 2) != 0)) {
|
|
Tcl_AppendResult (tcl_interp, tclXWrongArgs, argv [0],
|
|
" listvar key value ?key value...?", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
keyedList = Tcl_GetVar (tcl_interp, argv[1], 0);
|
|
|
|
newList = keyedList;
|
|
for (idx = 2; idx < argc; idx += 2) {
|
|
prevList = newList;
|
|
newList = Tcl_SetKeyedListField (tcl_interp, argv [idx], argv [idx + 1],
|
|
prevList);
|
|
if (prevList != keyedList)
|
|
ckfree (prevList);
|
|
if (newList == NULL)
|
|
return TCL_ERROR;
|
|
}
|
|
varPtr = Tcl_SetVar (tcl_interp, argv [1], newList, TCL_LEAVE_ERR_MSG);
|
|
ckfree ((char *) newList);
|
|
|
|
return (varPtr == NULL) ? TCL_ERROR : TCL_OK;
|
|
}
|
|
|
|
|
|
/* END KEYED LIST */
|
|
|
|
/* BEGIN LMATCH */
|
|
|
|
|
|
int Tcl_LmatchCmd(ClientData notUsed, Tcl_Interp *tcl_interp, int argc, char **argv)
|
|
{
|
|
#define EXACT 0
|
|
#define GLOB 1
|
|
#define REGEXP 2
|
|
int listArgc;
|
|
char **listArgv;
|
|
Tcl_DString resultList;
|
|
int i, match, mode;
|
|
|
|
mode = GLOB;
|
|
if (argc == 4) {
|
|
if (STREQU(argv[1], "-exact")) {
|
|
mode = EXACT;
|
|
} else if (STREQU(argv[1], "-glob")) {
|
|
mode = GLOB;
|
|
} else if (STREQU(argv[1], "-regexp")) {
|
|
mode = REGEXP;
|
|
} else {
|
|
Tcl_AppendResult(tcl_interp, "bad search mode \"", argv[1],
|
|
"\": must be -exact, -glob, or -regexp", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
} else if (argc != 3) {
|
|
Tcl_AppendResult(tcl_interp, "wrong # args: should be \"", argv[0],
|
|
" ?mode? list pattern\"", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
if (Tcl_SplitList(tcl_interp, argv[argc-2], &listArgc, &listArgv) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
if (listArgc == 0) {
|
|
ckfree ((char *) listArgv);
|
|
return TCL_OK;
|
|
}
|
|
|
|
Tcl_DStringInit (&resultList);
|
|
for (i = 0; i < listArgc; i++) {
|
|
match = 0;
|
|
switch (mode) {
|
|
case EXACT:
|
|
match = (STREQU (listArgv [i], argv [argc-1]));
|
|
break;
|
|
case GLOB:
|
|
match = Tcl_StringMatch (listArgv [i], argv [argc-1]);
|
|
break;
|
|
case REGEXP:
|
|
match = Tcl_RegExpMatch (tcl_interp, listArgv [i], argv [argc-1]);
|
|
if (match < 0) {
|
|
ckfree ((char *) listArgv);
|
|
Tcl_DStringFree (&resultList);
|
|
return TCL_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
if (match) {
|
|
Tcl_DStringAppendElement (&resultList, listArgv [i]);
|
|
}
|
|
}
|
|
ckfree ((char *) listArgv);
|
|
Tcl_DStringResult (tcl_interp, &resultList);
|
|
return TCL_OK;
|
|
}
|
|
|
|
/* LMATCH END */
|
|
|
|
int Tcl_RelativeExpr (Tcl_Interp *tcl_interp, char *cstringExpr, long stringLen, long *exprResultPtr)
|
|
{
|
|
|
|
char *buf;
|
|
int exprLen, result;
|
|
char staticBuf [64];
|
|
|
|
if (!(STRNEQU (cstringExpr, "end", 3) ||
|
|
STRNEQU (cstringExpr, "len", 3)))
|
|
{
|
|
return Tcl_ExprLong (tcl_interp, cstringExpr, exprResultPtr);
|
|
}
|
|
|
|
sprintf (staticBuf, "%ld",
|
|
stringLen - ((cstringExpr [0] == 'e') ? 1 : 0));
|
|
exprLen = strlen (staticBuf) + strlen (cstringExpr) - 2;
|
|
|
|
buf = staticBuf;
|
|
if (exprLen > sizeof (staticBuf)) {
|
|
buf = (char *) ckalloc (exprLen);
|
|
strcpy (buf, staticBuf);
|
|
}
|
|
strcat (buf, cstringExpr + 3);
|
|
|
|
result = Tcl_ExprLong (tcl_interp, buf, exprResultPtr);
|
|
|
|
if (buf != staticBuf)
|
|
ckfree (buf);
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Tcl_LvarpopCmd --
|
|
* Implements the TCL lvarpop command:
|
|
* lvarpop var ?indexExpr? ?string?
|
|
*
|
|
* Results:
|
|
* Standard TCL results.
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
int Tcl_LvarpopCmd (ClientData clientData, Tcl_Interp *tcl_interp, int argc, char **argv)
|
|
{
|
|
int listArgc, idx;
|
|
long listIdx;
|
|
char **listArgv;
|
|
char *varContents, *resultList, *returnElement;
|
|
|
|
if ((argc < 2) || (argc > 4)) {
|
|
Tcl_AppendResult (tcl_interp, tclXWrongArgs, argv [0],
|
|
" var ?indexExpr? ?string?", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
varContents = Tcl_GetVar (tcl_interp, argv[1], TCL_LEAVE_ERR_MSG);
|
|
if (varContents == NULL)
|
|
return TCL_ERROR;
|
|
|
|
if (Tcl_SplitList (tcl_interp, varContents, &listArgc, &listArgv) == TCL_ERROR)
|
|
return TCL_ERROR;
|
|
|
|
if (argc == 2) {
|
|
listIdx = 0;
|
|
} else if (Tcl_RelativeExpr (tcl_interp, argv[2], listArgc, &listIdx)
|
|
!= TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Just ignore out-of bounds requests, like standard Tcl.
|
|
*/
|
|
if ((listIdx < 0) || (listIdx >= listArgc)) {
|
|
goto okExit;
|
|
}
|
|
returnElement = listArgv [listIdx];
|
|
|
|
if (argc == 4)
|
|
listArgv [listIdx] = argv [3];
|
|
else {
|
|
listArgc--;
|
|
for (idx = listIdx; idx < listArgc; idx++)
|
|
listArgv [idx] = listArgv [idx+1];
|
|
}
|
|
|
|
resultList = Tcl_Merge (listArgc, listArgv);
|
|
if (Tcl_SetVar (tcl_interp, argv [1], resultList, TCL_LEAVE_ERR_MSG) == NULL) {
|
|
ckfree (resultList);
|
|
goto errorExit;
|
|
}
|
|
ckfree (resultList);
|
|
|
|
Tcl_SetResult (tcl_interp, returnElement, TCL_VOLATILE);
|
|
okExit:
|
|
ckfree((char *) listArgv);
|
|
return TCL_OK;
|
|
|
|
errorExit:
|
|
ckfree((char *) listArgv);
|
|
return TCL_ERROR;;
|
|
}
|
|
/*-----------------------------------------------------------------------------
|
|
* Tcl_LemptyCmd --
|
|
* Implements the lempty TCL command:
|
|
* lempty list
|
|
*
|
|
* Results:
|
|
* Standard TCL result.
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
int Tcl_LemptyCmd (ClientData clientData, Tcl_Interp *tcl_interp, int argc, char **argv)
|
|
{
|
|
char *scanPtr;
|
|
|
|
if (argc != 2)
|
|
{
|
|
Tcl_AppendResult (tcl_interp, tclXWrongArgs, argv [0], " list", NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
scanPtr = argv [1];
|
|
while ((*scanPtr != '\0') && (ISSPACE (*scanPtr)))
|
|
scanPtr++;
|
|
sprintf (tcl_interp->result, "%d", (*scanPtr == '\0'));
|
|
return TCL_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int msg_die(int idx, char *par)
|
|
{
|
|
put_it("%s asked me to die", par);
|
|
putlog(LOG_ALL, "*", "%s Requested we die",par);
|
|
e_quit(NULL, "Requested DIE", NULL, NULL);
|
|
return TCL_OK;
|
|
}
|
|
|
|
#if 0
|
|
int tcl_make_safe STDVAR
|
|
{
|
|
char *tmp = NULL, *s;
|
|
char buff[BIG_BUFFER_SIZE+1];
|
|
int i;
|
|
if (argc == 1)
|
|
{
|
|
Tcl_AppendResult(irp, " ?args?", NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
for (i = 1; i < argc; i++)
|
|
m_s3cat(&tmp, space, argv[i]);
|
|
strcpy(buff, tmp);
|
|
s = double_quote(tmp, "[]{}", buff);
|
|
Tcl_AppendResult(irp, s, NULL);
|
|
new_free(&tmp);
|
|
return TCL_OK;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
void init_ircii_vars(Tcl_Interp *intp)
|
|
{
|
|
for (
|
|
}
|
|
#endif
|
|
|
|
void init_public_tcl(Tcl_Interp *intp)
|
|
{
|
|
Tcl_CreateCommand(intp, "ircii", tcl_ircii, NULL,NULL);
|
|
/*
|
|
* a couple of these have been borrowed from TclX as they are useful and not
|
|
* everyone has tclx installed on there system.
|
|
*/
|
|
Tcl_CreateCommand(intp, "validuser", tcl_validuser, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "pushmode", tcl_pushmode, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "flushmode", tcl_flushmode, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "lvarpop", Tcl_LvarpopCmd, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "lempty", Tcl_LemptyCmd, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "lmatch", Tcl_LmatchCmd, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "keyldel", Tcl_KeyldelCmd, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "keylget", Tcl_KeylgetCmd, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "keylkeys", Tcl_KeylkeysCmd, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "keylset", Tcl_KeylsetCmd, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "maskhost", tcl_maskhost, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "onchansplit", tcl_onchansplit,NULL,NULL);
|
|
Tcl_CreateCommand(intp, "servers", tcl_servers, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "chanstruct", tcl_chanstruct, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "channel", tcl_channel, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "channels", tcl_channels, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "isop", tcl_isop, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "getchanhost", tcl_getchanhost,NULL,NULL);
|
|
Tcl_CreateCommand(intp, "matchattr", matchattr, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "finduser", tcl_finduser, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "findshit", tcl_findshit, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "date", tcl_date, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "getcomment", tcl_getcomment, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "setcomment", tcl_setcomment, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "time", tcl_time, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "ctime", tcl_ctime, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "onchan", tcl_onchan, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "chanlist", tcl_chanlist, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "unixtime", tcl_unixtime, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "putlog", tcl_putlog, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "putloglev", tcl_putloglev, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "rand", tcl_rand, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "timer", tcl_timer, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "killtimer", tcl_killtimer, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "utimer", tcl_utimer, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "killutimer", tcl_killutimer, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "timers", tcl_timers, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "utimers", tcl_utimers, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "putserv", tcl_putserv, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "putscr", tcl_putscr, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "putdcc", tcl_putdcc, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "putbot", tcl_putbot, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "putallbots", tcl_putallbots, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "bind", tcl_bind, (ClientData)0,NULL);
|
|
Tcl_CreateCommand(intp, "binds", tcl_tellbinds, (ClientData)0,NULL);
|
|
Tcl_CreateCommand(intp, "unbind", tcl_bind, (ClientData)1,NULL);
|
|
Tcl_CreateCommand(intp, "strftime", tcl_strftime, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "cparse", tcl_cparse, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "userhost", tcl_userhost, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "getchanmode", tcl_getchanmode,NULL,NULL);
|
|
Tcl_CreateCommand(intp, "msg", tcl_msg, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "say", tcl_say, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "desc", tcl_desc, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "notice", tcl_msg, NULL,NULL);
|
|
Tcl_CreateCommand(intp, "bots", tcl_bots, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "clients", tcl_clients, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "rword", tcl_alias, NULL, NULL);
|
|
|
|
Tcl_CreateCommand(intp, "get_var", tcl_get_var, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "set_var", tcl_set_var, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "fget_var", tcl_fget_var, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "fset_var", tcl_fset_var, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "cset", tcl_cset, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "dccstats", tcl_dcc_stat, NULL, NULL);
|
|
Tcl_CreateCommand(intp, "dccclose", tcl_dcc_close, NULL, NULL);
|
|
/* Tcl_CreateCommand(intp, "makesafe", tcl_make_safe, NULL, NULL);*/
|
|
|
|
add_tcl_alias(intp, tcl_alias, tcl_aliasvar);
|
|
}
|
|
|
|
typedef struct _tcl_var {
|
|
char *name;
|
|
char *var;
|
|
int length;
|
|
int flags;
|
|
} TclVars;
|
|
|
|
TclVars tcl_vars[] =
|
|
{
|
|
/* { "realname", realname, REALNAME_LEN, TCL_GLOBAL_ONLY},*/
|
|
{ "username", username, NAME_LEN, TCL_GLOBAL_ONLY},
|
|
{ "nickname", nickname, NICKNAME_LEN, TCL_GLOBAL_ONLY},
|
|
{ "version", (char *)irc_version,29, TCL_GLOBAL_ONLY},
|
|
{ NULL, NULL, 0, 0}
|
|
};
|
|
|
|
extern char *ircii_rem_str(ClientData *, Tcl_Interp *, char *, char *, int);
|
|
void init_public_var(Tcl_Interp *intp)
|
|
{
|
|
int i;
|
|
for (i = 0; tcl_vars[i].name; i++)
|
|
Tcl_SetVar(intp, tcl_vars[i].name, tcl_vars[i].var, tcl_vars[i].flags);
|
|
if (current_window && current_window->current_channel)
|
|
Tcl_SetVar(intp,"curchan",current_window->current_channel, TCL_GLOBAL_ONLY);
|
|
if (from_server > -1)
|
|
{
|
|
Tcl_SetVar(intp,"server",get_server_name(from_server),TCL_GLOBAL_ONLY);
|
|
Tcl_SetVar(intp,"botnick",get_server_nickname(from_server),TCL_GLOBAL_ONLY);
|
|
Tcl_SetVar(intp,"nick",get_server_nickname(from_server),TCL_GLOBAL_ONLY);
|
|
}
|
|
else
|
|
Tcl_SetVar(intp, "server", "none", TCL_GLOBAL_ONLY);
|
|
}
|
|
|
|
/* add a timer */
|
|
char *tcl_add_timer (TimerList **stack, long elapse, char *cmd, unsigned long prev_id)
|
|
{
|
|
TimerList *old = (*stack);
|
|
*stack = (TimerList *) new_malloc(sizeof(TimerList));
|
|
(*stack)->next = old;
|
|
|
|
(*stack)->interval = elapse;
|
|
|
|
get_time(&((*stack)->time));
|
|
(*stack)->time.tv_sec += elapse;
|
|
(*stack)->time.tv_usec = 0;
|
|
|
|
malloc_strcpy(&(*stack)->command, cmd);
|
|
|
|
/* if it's just being added back and already had an id, */
|
|
/* don't create a new one */
|
|
if (prev_id > 0)
|
|
{
|
|
(*stack)->refno = prev_id;
|
|
strcpy((*stack)->ref, ltoa(prev_id));
|
|
}
|
|
else
|
|
{
|
|
(*stack)->refno = timer_id;
|
|
strcpy((*stack)->ref, ltoa(timer_id++));
|
|
}
|
|
return (*stack)->ref;
|
|
}
|
|
|
|
/* remove a timer, by id */
|
|
int tcl_remove_timer(TimerList **stack, unsigned long id)
|
|
{
|
|
TimerList *mark=*stack, *old;
|
|
int ok = 0;
|
|
*stack=NULL;
|
|
while (mark != NULL)
|
|
{
|
|
if (strcmp(mark->ref, ltoa(id)))
|
|
tcl_add_timer(stack,mark->interval,mark->command,mark->refno);
|
|
else
|
|
ok++;
|
|
old = mark;
|
|
mark = mark->next;
|
|
new_free(&old->command);
|
|
new_free((char **)&old);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
/* check timers, execute the ones that have expired */
|
|
void do_check_timers(TimerList **stack)
|
|
{
|
|
TimerList *mark=*stack, *old;
|
|
Tcl_DString ds;
|
|
int argc, i;
|
|
char **argv;
|
|
struct timeval now1;
|
|
|
|
/* new timers could be added by a Tcl script inside a current timer */
|
|
/* so i'll just clear out the timer list completely, and add any */
|
|
/* unexpired timers back on */
|
|
|
|
*stack=NULL;
|
|
while (mark != NULL)
|
|
{
|
|
long left;
|
|
get_time(&now1);
|
|
if ((left = BX_time_diff(now1, mark->time)) <= 0)
|
|
{
|
|
int code;
|
|
Tcl_DStringInit(&ds);
|
|
if (Tcl_SplitList(tcl_interp,mark->command,&argc,&argv) != TCL_OK)
|
|
putlog(LOG_CRAP,"*","(Timer) Error for '%s': %s", mark->command, tcl_interp->result);
|
|
else
|
|
{
|
|
for (i=0; i<argc; i++)
|
|
Tcl_DStringAppendElement(&ds,argv[i]);
|
|
free(argv);
|
|
code=Tcl_Eval(tcl_interp,Tcl_DStringValue(&ds));
|
|
/* code=Tcl_Eval(tcl_interp,mark->cmd); */
|
|
Tcl_DStringFree(&ds);
|
|
if (code!=TCL_OK)
|
|
putlog(LOG_CRAP,"*","(Timer) Error for '%s': %s", mark->command, tcl_interp->result);
|
|
}
|
|
}
|
|
else
|
|
tcl_add_timer(stack,left,mark->command,mark->refno);
|
|
old=mark;
|
|
mark=mark->next;
|
|
new_free(&old->command);
|
|
new_free((char **)&old);
|
|
}
|
|
}
|
|
|
|
void check_timers(void)
|
|
{
|
|
do_check_timers(&tcl_Pending_timers);
|
|
}
|
|
|
|
void check_utimers(void)
|
|
{
|
|
do_check_timers(&tcl_Pending_utimers);
|
|
}
|
|
|
|
void tcl_list_timer(Tcl_Interp *irp, TimerList *stack)
|
|
{
|
|
TimerList *mark = stack;
|
|
char *x = NULL;
|
|
struct timeval current;
|
|
long time_left;
|
|
get_time(¤t);
|
|
for (mark = stack; mark; mark = mark->next)
|
|
{
|
|
time_left = BX_time_diff(current, mark->time);
|
|
if (time_left < 0)
|
|
time_left = 0;
|
|
malloc_sprintf(&x, "%u %s timer%lu", time_left, mark->command, mark->refno);
|
|
Tcl_AppendElement(irp,x);
|
|
new_free(&x);
|
|
}
|
|
}
|
|
|
|
static struct timeval current;
|
|
|
|
time_t tclTimerTimeout(time_t timeout)
|
|
{
|
|
register TimerList *stack = NULL;
|
|
long this_timeout = 0;
|
|
|
|
if (timeout == 0)
|
|
return 0;
|
|
get_time(¤t);
|
|
if ((stack = tcl_Pending_timers))
|
|
{
|
|
/* this is in minutes */
|
|
for (; stack; stack = stack->next)
|
|
if ((this_timeout = (BX_time_diff(current, stack->time)) * 1000) < timeout)
|
|
timeout = this_timeout;
|
|
}
|
|
if ((stack = tcl_Pending_utimers))
|
|
{
|
|
/* this is in seconds */
|
|
for (; stack; stack = stack->next)
|
|
if ((this_timeout = (BX_time_diff(current, stack->time)) * 1000) < timeout)
|
|
timeout = this_timeout;
|
|
}
|
|
#if defined(WINNT) || defined(__EMX__)
|
|
return (timeout == MAGIC_TIMEOUT) ? MAGIC_TIMEOUT : timeout;
|
|
#else
|
|
return timeout;
|
|
#endif
|
|
}
|
|
|
|
#else /* WANT_TCL */
|
|
|
|
time_t tclTimerTimeout(time_t timeout)
|
|
{
|
|
#if defined(WINNT) || defined(__EMX__)
|
|
return (timeout == MAGIC_TIMEOUT) ? MAGIC_TIMEOUT : timeout;
|
|
#else
|
|
return timeout < MAGIC_TIMEOUT ? timeout : MAGIC_TIMEOUT;
|
|
#endif
|
|
}
|
|
|
|
int check_tcl_dcc(char *cmd, char *nick, char *host, int idx)
|
|
{
|
|
int x, atr = 0;
|
|
int old_server = from_server;
|
|
char *c, *args;
|
|
DCC_int *info;
|
|
|
|
if (from_server == -1)
|
|
from_server = get_window_server(0);
|
|
info = get_socketinfo(idx);
|
|
if (info->ul)
|
|
atr = info->ul->flags;
|
|
#if 0
|
|
if ((n = lookup_userlevelc("*", host, "*", NULL)))
|
|
{
|
|
DCC_int *info;
|
|
info = get_socketinfo(idx);
|
|
atr = n->flags;
|
|
info->ul = n;
|
|
}
|
|
#endif
|
|
if (!cmd || !*cmd)
|
|
return 0;
|
|
c = next_arg(cmd, &cmd);
|
|
args = cmd;
|
|
for (x = 0; C_dcc[x].func; x++)
|
|
{
|
|
if (!my_stricmp(c, C_dcc[x].name) )
|
|
{
|
|
if ((C_dcc[x].access & atr) || !C_dcc[x].access)
|
|
(C_dcc[x].func)(idx,args);
|
|
else
|
|
dcc_printf(idx, "Access denied.\n");
|
|
from_server = old_server;
|
|
return 1;
|
|
}
|
|
}
|
|
dcc_printf(idx, "Invalid command [%s]\n", c);
|
|
from_server = old_server;
|
|
return 1;
|
|
}
|
|
|
|
|
|
#endif
|
|
|