Files
sics/conman.c
2008-05-14 14:23:16 +00:00

2405 lines
61 KiB
C

/*--------------------------------------------------------------------------
Connection management for SICS. This is one the core files for
SICS. Does a lot. See the descriptions with individual functions
below.
Mark Koennecke, October 1996
SMInvoke added. Mark Koennecke, April 1997
Seriously revised and extended for new structure with Tasker:
Mark Koennecke, September 1997
Support for writing telnet compatible strings ins SCWrite added.
Mark Koennecke, January 1998
SCWriteBinary added. Mark Koennecke, April 1998
Revamped login to non telnet connection.
Added compressed writing method.
Mark Koennecke, October 2000
Added simulation mode
Mark Koennecke, March 2003
Refactored a bit, removed SCWriteBinary (never used anywhere), added
appending outcode to text,
Mark Koennecke, July 2004
Made use of unused connections secure (connections are not
freed, but reused on new connections).
Introduced new type SCStore and functions SCSave, SCLoad.
Introduced SCPrintf to avoid many of these pBueffel.
Markus Zolliker, Sept 2004.
Cleaned up conman data structure. Removed left over and unused
fields.
Mark Koennecke, December 2004
Aded buffering support, Mark Koennecke, July 2006
Copyright: see copyright.h
-----------------------------------------------------------------------------*/
#include "fortify.h"
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <zlib.h>
#include <tcl.h>
#include <time.h>
#include <limits.h>
#include <stdarg.h>
#include "lld.h"
#include "sics.h"
#include "passwd.h"
#include "splitter.h"
#include "macro.h"
#include "servlog.h"
#include "status.h"
#include "interrupt.h"
#include "ifile.h"
#include "token.h"
#include "uubuffer.h"
#include "commandlog.h"
#include "stptok.h"
#include "statusfile.h"
#include "sicshipadaba.h"
#include "protocol.h"
/*
#define UUDEB 1
define UUDEB , for buffer writing for checking encoding */
extern pServer pServ;
#include "outcode.c" /* text for OutCode */
/*------ Max Size of Command Stack */
#define MAXSTACK 1024
/*---------- Magic ID Header */
#define CONMAGIC 26051958
/*-------------------------------------------------------------------------
a structure for holding callback info
*/
typedef struct {
long lID;
pICallBack pInterface;
} Item;
/*------------- a number for generating automatic names --------------------*/
static int iName = 0;
static SConnection *freeConnections = NULL;
static long lastIdent = 0;
/*------------- sending connection (prevent double write when listening) ----*/
static SConnection *sendingConnection = NULL;
/*------------- storing connection and context for later use ----*/
struct SCStore {
SConnection *pCon;
long ident;
int inMacro;
int inMacroSave;
int pushLevel;
commandContext cc;
};
/*===========================================================================*/
static char *ConName(long ident) {
static char name[32];
snprintf(name, sizeof(name), "CON%ld", ident);
return name;
}
/*--------------------------------------------------------------------------*/
static void FreeConnection(SConnection *pCon)
{
memset(pCon,0,sizeof(SConnection));
pCon->ident = 0;
pCon->next = freeConnections;
pCon->listening = 0;
freeConnections = pCon;
}
/*--------------------------------------------------------------------------*/
static SConnection *CreateConnection(SicsInterp *pSics)
{
int i;
SConnection *pRes = NULL;
char pBueffel[253];
char pHost[132];
if (!freeConnections)
{ /* no more free connection: get one by malloc */
pRes = (SConnection *)malloc(sizeof(SConnection));
if(!pRes)
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
return NULL;
}
memset(pRes,0,sizeof(SConnection));
}
else
{ /* reuse an old connection */
pRes = freeConnections;
freeConnections = pRes->next;
}
do
{ /* loop until an unused ident is found. This test needed only for
the case there some object has already the name con<nnn>.
In a live cycle of SICS, no connection ever can get an earlier
used name */
if (lastIdent == LONG_MAX)
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: Run out of connection identifiers!!",eInternal);
return NULL;
}
lastIdent++;
} while (FindCommand(pSics, ConName(lastIdent)));
pRes->ident = lastIdent;
/* a descriptor */
pRes->pDes = CreateDescriptor("Connection");
if(!pRes->pDes)
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
FreeConnection(pRes);
return NULL;
}
/* the callback registry */
pRes->iList = LLDcreate(sizeof(Item));
/* the command stack */
pRes->pStack = CreateCommandStack();
if( (pRes->iList <0) || (!pRes->pStack))
{
/* This is a serious, very serious error! */
SICSLogWrite("ERROR: No memory to allocate connection!!",eInternal);
DeleteDescriptor(pRes->pDes);
FreeConnection(pRes);
return NULL;
}
pRes->iOutput = eInError; /* gets everything except internal messages */
pRes->iFiles = 0; /* default: no logfiles */
pRes->inUse = 0;
pRes->iMacro = 0;
pRes->iTelnet = 0;
pRes->eInterrupt = eContinue;
pRes->lMagic = CONMAGIC;
pRes->iLogin = 0;
pRes->listening = 0;
pRes->conStart = time(NULL);
pRes->write = SCNormalWrite;
for(i = 0; i < 10; i++)
{
pRes->pFiles[i] = NULL;
}
/* initialise context variables */
pRes->iCmdCtr = 0;
pRes->conEventType=-1;
pRes->conStatus=-1;
pRes->contextStack = LLDcreate(sizeof(commandContext));
/* install command */
AddCommand(pSics, ConName(pRes->ident), ConSicsAction, NULL,pRes);
return pRes;
}
/*--------------------------------------------------------------------------*/
SConnection *SCreateConnection(SicsInterp *pSics,mkChannel *pSock, int iUser)
{
SConnection *pRes = NULL;
char pBueffel[253];
char pHost[132];
assert(pSock);
pRes = CreateConnection(pSics);
SetCommandStackMaxSize(pRes->pStack,MAXSTACK);
pRes->pSock = pSock;
pRes->iUserRights = iUser;
pRes->iGrab = TokenGrabActive();
return pRes;
}
/*--------------------------------------------------------------------------*/
SConnection *SCCreateDummyConnection(SicsInterp *pSics)
{
SConnection *pRes = NULL;
pRes = CreateConnection(pSics);
pRes->pSock = NULL;
pRes->iUserRights = usInternal;
pRes->iGrab = 0;
SICSLogWrite("Accepted dummy connection ",eInternal);
return pRes;
}
/*--------------------------------------------------------------------------*/
static int VerifyConnection(SConnection *self)
{
if(!self)
{
SICSLogWrite("MAGICERROR: Invalid call to NULL connection",eError);
return 0;
}
if(self->lMagic != CONMAGIC)
{
SICSLogWrite("MAGICERROR: corrupted connection object",eError);
return 0;
}
return 1;
}
/*----------------------------------------------------------------------------*/
int SCAddLogFile(SConnection *self, char *name)
{
char pBueffel[256];
int iNum, i;
if(!VerifyConnection(self))
{
return 0;
}
/* find an empty number */
if(self->iFiles < MAXLOGFILES)
{
iNum = self->iFiles;
self->iFiles++;
}
else /* scan for an empty slot */
{
iNum = -1;
for(i = 0; i < self->iFiles; i++)
{
if(self->pFiles[i] == NULL)
{
iNum = i;
break;
}
}
}
/* nothing found ? */
if(iNum < 0)
{
SCWrite(self,"ERROR: maximum number of logfiles exhausted",eError);
return -1;
}
/* do the job */
self->pFiles[iNum] = fopen(name,"a+");
if(self->pFiles[iNum] == NULL)
{
sprintf(pBueffel,"ERROR Could not open logfile - %s -",name);
SCWrite(self,pBueffel, 10);
return -1; /* false */
}
else
{
return iNum; /* success */
}
}
/*--------------------------------------------------------------------------*/
int SCDelLogFile(SConnection *self, int iNum)
{
if(!VerifyConnection(self))
{
return 0;
}
if( (iNum >= 0) && (iNum < MAXLOGFILES) )
{
if(self->pFiles[iNum])
{
fclose(self->pFiles[iNum]);
self->pFiles[iNum] = NULL;
return 1;
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
void SCSetOutputClass(SConnection *self, int iClass)
{
if(!VerifyConnection(self))
{
return;
}
self->iOutput = iClass;
}
/*---------------------------------------------------------------------------*/
int SCinMacro(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
if(self->iMacro)
{
return 1;
}
else
{
return 0;
}
}
/*---------------------------------------------------------------------------*/
int SCsetMacro(SConnection *self, int iMode)
{
if(!VerifyConnection(self))
{
return 0;
}
assert( (iMode == 0) || (iMode == 1));
self->iMacro = iMode;
return 1;
}
/*---------------------------------------------------------------------------*/
void SCDeleteConnection(void *pData)
{
int i, iRet;
char pBueffel[132];
SConnection *pVictim = NULL;
Item sItem;
pHdb root = NULL;
pVictim = (SConnection *)pData;
if(!VerifyConnection(pVictim))
{
return;
}
if(SCActive(pVictim))
{
SCnoSock(pVictim);
if(pVictim->pSock)
{
NETClosePort(pVictim->pSock);
free(pVictim->pSock);
pVictim->pSock = NULL;
}
WriteToCommandLog("SYS>",
"ERROR: Erraneous deletion of used Connection stopped");
return;
}
/* remove the connection from the server log if it has captured
something
*/
KillCapture(pVictim);
/*
* remove any callbacks which might still be active in the Hipadaba
*/
root = GetHipadabaRoot();
if(root != NULL)
{
RemoveConnectionCallbacks(root,pVictim);
}
/*
If we have a grab, release it !
*/
if(!pVictim->iGrab)
{
if(pServ->pTasker)
{
TaskSignal(pServ->pTasker,TOKENRELEASE,NULL);
TokenRelease();
}
}
/* log the kill */
if(pVictim->pSock && pVictim->iLogin == 1 &&
(pVictim->iUserRights < 3 || !CompactCommandLog()) )
{
sprintf(pBueffel,"Deleting connection %d",pVictim->pSock->sockid);
WriteToCommandLog("SYS>",pBueffel);
SICSLogWrite(pBueffel,eInternal);
}
/* close all open files and sockets */
if(pVictim->pSock)
{
NETWrite(pVictim->pSock,"SICSCLOSE",sizeof("SICSCLOSE"));
NETClosePort(pVictim->pSock);
free(pVictim->pSock);
}
for(i = 0; i < pVictim->iFiles; i++)
{
if(pVictim->pFiles[i] != NULL)
{
fclose(pVictim->pFiles[i]);
}
}
RemoveCommand(pServ->pSics,ConName(pVictim->ident));
if(pVictim->pDes)
{
DeleteDescriptor(pVictim->pDes);
}
/* remove all callbacks on this connection */
iRet = LLDnodePtr2First(pVictim->iList);
while(iRet != 0)
{
LLDnodeDataTo(pVictim->iList,&sItem);
RemoveCallback(sItem.pInterface, sItem.lID);
iRet = LLDnodePtr2Next(pVictim->iList);
}
LLDdelete(pVictim->iList);
/* remove command stack */
if(pVictim->pStack)
{
DeleteCommandStack(pVictim->pStack);
}
/* remove possible buffers */
if(pVictim->data != NULL)
{
DeleteDynString(pVictim->data);
}
pVictim->lMagic=0; /* make a write to a freed connection harmless */
/* finally free pVictim*/
LLDdelete(pVictim->contextStack);
FreeConnection(pVictim);
}
/*---------------------------------------------------------------------------*/
static int HasNL(char *buffer)
{
int i;
for(i = strlen(buffer); i > 0; i--)
{
if(isprint(buffer[i]))
{
break;
}
if(buffer[i] == '\n')
{
return 1;
}
}
return 0;
}
/*-------------------------------------------------------------------------
TelnetWrite makes sure, that all lines are properly terminated with a
<cr><lf> as required by the telnet protocoll.
There may be a problem here at long messages. 7.5.1998 MK
--------------------------------------------------------------------------*/
#define TXT 0
#define LF 1
int TelnetWrite(mkChannel *pSock, char *pBuffer)
{
char *pStart = NULL, *pPtr;
int iCount, iState;
int iRet = 1;
pStart = pBuffer;
pPtr = pStart;
iState = TXT;
iCount = 0;
while(*pPtr != '\0')
{
switch(iState)
{
case TXT:
if( (*pPtr == '\r') || (*pPtr == '\n') )
{
iState = LF;
iRet = NETWrite(pSock,pStart,iCount);
iRet = NETWrite(pSock,"\r\n",2);
iCount = 0;
}
else
{
iCount++;
}
break;
case LF:
if( (*pPtr != '\r') && (*pPtr != '\n') )
{
pStart = pPtr;
iCount = 1;
iState = TXT;
}
else
{
/* do nothing */
}
break;
}
pPtr++;
}
if(iCount > 0)
{
iRet = NETWrite(pSock,pStart,iCount);
iRet = NETWrite(pSock,"\r\n",2);
}
return iRet;
}
/*-------------------------------------------------------------------------*/
int SCWrite(SConnection *self, char *pBuffer, int iOut)
{
if(!VerifyConnection(self))
{
return 0;
}
/*
Do not die if no data
*/
if(pBuffer == NULL)
{
return 0;
}
return self->write(self,pBuffer,iOut);
}
/*-----------------------------------------------------------------------*/
int SCWriteInContext(SConnection *pCon, char *pBuffer, int out, commandContext cc)
{
int status;
SCPushContext2(pCon,cc);
status = SCWrite(pCon,pBuffer,out);
SCPopContext(pCon);
return status;
}
/*-------------------------------------------------------------------------*/
int SCPrintf(SConnection *self, int iOut, char *fmt, ...)
{
va_list ap;
char buf[256];
char *dyn;
int l;
int res;
va_start(ap, fmt);
l = vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
if (l >= sizeof buf) {
/* we have probably a C99 conforming snprintf and
need a larger buffer
*/
dyn = malloc(l+1);
if (dyn != NULL) {
va_start(ap, fmt);
vsnprintf(dyn, l+1, fmt, ap);
va_end(ap);
res = SCWrite(self, dyn, iOut);
free(dyn);
return res;
}
}
return SCWrite(self, buf, iOut);
}
/*-------------------------------------------------------------------------*/
writeFunc SCGetWriteFunc(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->write;
}
/*-------------------------------------------------------------------------*/
void SCSetWriteFunc(SConnection *self, writeFunc x)
{
if(!VerifyConnection(self))
{
return;
}
self->write = x;
}
/*------------------------------------------------------------------------*/
static int doSockWrite(SConnection *self, char *buffer)
{
int iRet = 1;
if(self->pSock)
{
if(self->iTelnet)
{
iRet = TelnetWrite(self->pSock,buffer);
}
else
{
iRet = NETWrite(self->pSock,buffer,strlen(buffer));
if(!HasNL(buffer))
{
iRet = NETWrite(self->pSock,"\n",strlen("\n"));
}
}
if(!iRet)
{
SCnoSock(self);
if(!self->listening && self->iLogin == 1 &&
(self->iUserRights < 3 || !CompactCommandLog()) )
{
WriteToCommandLog("SYS>","Connection broken on send");
}
}
}
else
{
if (HasNL(buffer)) {
fputs(buffer, stdout);
} else {
puts(buffer);
}
}
return iRet;
}
/*-------------------------------------------------------------------------*/
static void writeToLogFiles(SConnection *self, char *buffer)
{
int i;
for(i = 0; i < self->iFiles; i++)
{
if(self->pFiles[i])
{
fputs(buffer,self->pFiles[i]);
if(! HasNL(buffer))
{
fputs("\n",self->pFiles[i]);
fflush(self->pFiles[i]);
}
}
}
}
/*--------------------------------------------------------------------------*/
int SCNormalWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
if(!VerifyConnection(self))
{
return 0;
}
if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) {
return 1; /* do not write empty line */
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser)
{
if(self->iMacro != 1)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
else
{
if(iOut == eError || iOut == eWarning)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
}
}
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(pServ->pSics,buffer);
/* print it to client if error message */
if((iOut== eError) || (iOut == eWarning) )
{
iRet = doSockWrite(self,buffer);
}
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
return 0;
/* first the socket */
iRet = doSockWrite(self,buffer);
writeToLogFiles(self,buffer);
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SCACTWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[1024];
char *pPtr = pBueffel;
commandContext cx;
if(!VerifyConnection(self))
{
return 0;
}
if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) {
return 1; /* do not write empty line */
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser)
{
if(self->iMacro != 1)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
else
{
if(iOut == eError || iOut == eWarning)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
}
}
/*
* copy in ACT
*/
if(strlen(buffer) + 30 > 1024){
pPtr = (char *)malloc((strlen(buffer)+30)*sizeof(char));
memset(pPtr,0,strlen(buffer)+20);
}
cx = SCGetContext(self);
sprintf(pPtr,"%d::>%s<::", cx.transID, buffer);
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(pServ->pSics,buffer);
/* print it to client if error message */
if((iOut== eError) || (iOut == eWarning) )
{
iRet = doSockWrite(self,pPtr);
}
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
return 0;
/* first the socket */
iRet = doSockWrite(self,pPtr);
writeToLogFiles(self,buffer);
}
if(pPtr != pBueffel){
free(pPtr);
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet, length;
char pBueffel[80];
char *bufPtr = NULL;
if(!VerifyConnection(self))
{
return 0;
}
if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) {
return 1; /* do not write empty line */
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser && self->iMacro != 1)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
/*
prepare the message with the outcode appended.
*/
length = strlen(buffer) + strlen(pCode[iOut]) + 10;
bufPtr = (char *)malloc(length * sizeof(char));
if(!bufPtr)
{
SICSLogWrite("SYS>>ERROR: out of memory in SCWriteWithOutcode",eError);
return 0;
}
memset(bufPtr,0,length*sizeof(char));
strcpy(bufPtr,buffer);
i = strlen(bufPtr);
while(i-- > 0)
{
if(!isspace(bufPtr[i]))
break;
}
i++;
bufPtr[i] = '\0';
strcat(bufPtr,"@@");
strcat(bufPtr,pCode[iOut]);
strcat(bufPtr,"\r\n");
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(pServ->pSics,buffer);
/* print it to client if error message */
if((iOut== eError) || (iOut == eWarning) )
{
iRet = doSockWrite(self,bufPtr);
}
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
{
free(bufPtr);
return 0;
}
/* first the socket */
iRet = doSockWrite(self,bufPtr);
writeToLogFiles(self,buffer);
}
free(bufPtr);
return 1;
}
/*-------------------------------------------------------------------------*/
static int SCBufferWrite(SConnection *self, char *buffer, int iOut)
{
if(!VerifyConnection(self))
{
return 0;
}
assert(self->data != NULL);
DynStringConcat(self->data,buffer);
if(strchr(buffer,'\n') == NULL){
DynStringConcat(self->data,"\n");
}
return 1;
}
/*-------------------------------------------------------------------------*/
int SCStartBuffering(SConnection *pCon)
{
if(!VerifyConnection(pCon))
{
return 0;
}
if(pCon->data != NULL)
{
DeleteDynString(pCon->data);
}
pCon->data = CreateDynString(128,128);
if(pCon->data == NULL)
{
return 0;
}
pCon->oldWriteFunc = pCon->write;
pCon->write = SCBufferWrite;
return 1;
}
/*-------------------------------------------------------------------------*/
pDynString SCEndBuffering(SConnection *pCon)
{
if(!VerifyConnection(pCon))
{
return 0;
}
assert(pCon->oldWriteFunc != NULL);
pCon->write = pCon->oldWriteFunc;
pCon->oldWriteFunc = NULL;
return pCon->data;
}
/*--------------------------------------------------------------------------*/
int SCOnlySockWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
if(!VerifyConnection(self))
{
return 0;
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(pServ->pSics,buffer);
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
return 0;
/* the socket */
iRet = doSockWrite(self,buffer);
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SCNotWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
if(!VerifyConnection(self))
{
return 0;
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(pServ->pSics,buffer);
}
return 1;
}
/*--------------------------------------------------------------------------
This version writes only to configured log files but not to sockets.
Used for automatic file execution for the WWW interface
*/
int SCFileWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
if(!VerifyConnection(self))
{
return 0;
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = -10;
}
/* put into Serverlog */
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser)
{
if(self->iMacro != 1)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
else
{
if(iOut == eError || iOut == eWarning)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
}
}
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(pServ->pSics,buffer);
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
return 0;
writeToLogFiles(self,buffer);
}
return 1;
}
/*-----------------------------------------------------------------------*/
int SCnoSock(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
self->write = SCFileWrite;
return 0;
}
/*------------------------------------------------------------------------*/
int SCWriteUUencoded(SConnection *pCon, char *pName, void *pData,
int iDataLen)
{
void *pPtr = NULL;
int iLength = 0;
int iRet = 1;
FILE *fd;
char *pTest;
iRet = UUencodeBuffer(pData,iDataLen,pName, &pPtr, &iLength);
if(iRet != 1)
{
SCWrite(pCon,"ERROR: no memory for uuencoder",eError);
return 0;
}
pTest = (char *)pPtr;
/* the uuencoder ensures proper telnet <cr><lf> */
if(pCon->iTelnet)
{
NETWrite(pCon->pSock,pPtr,iLength);
}
else
{
NETWrite(pCon->pSock,pPtr,iLength);
}
#ifdef UUDEB
fd = fopen("uubuffer.uu","w");
fputs(pPtr,fd);
fclose(fd);
#endif
free(pPtr);
return iRet;
}
/*------------------------------------------------------------------------*/
#define ZIPBUF 8192
int SCWriteZipped(SConnection *self, char *pName, void *pData, int iDataLen)
{
char outBuf[65546], *pBuf = NULL, noutBuf[ZIPBUF], *pHeader = NULL;
int compressedLength, iRet, iRet2, iCount, protocolID;
z_stream compStream;
commandContext cc;
/* check for a valid connection */
if(!VerifyConnection(self))
{
return 0;
}
/* a telnet connection will corrupt the compressed stream, so
stop it!
*/
if(self->iTelnet)
{
SCWrite(self,
"ERROR: the telnet protocoll will currupt compressed data!",
eError);
return 0;
}
/*
do nothing if no data
*/
if(pName == NULL || pData == NULL)
{
SCWrite(self,"ERROR: no data to write in SCWriteZiped",eError);
return 0;
}
/* initialize the compression stuff */
compStream.zalloc = (alloc_func)NULL;
compStream.zfree = (free_func)NULL;
compStream.opaque = (voidpf)NULL;
iRet = deflateInit(&compStream,Z_DEFAULT_COMPRESSION);
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
/* first pass: find out how the long the compressed buffer will be */
compressedLength = 0;
compStream.next_in = (Bytef *)pData;
compStream.next_out = (Bytef *)outBuf;
compStream.avail_in = iDataLen;
compStream.avail_out = 65536;
while(compStream.total_in < iDataLen)
{
iRet = deflate(&compStream,Z_NO_FLUSH);
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
compStream.next_out = (Bytef *)outBuf;
compStream.avail_out = 65536;
}
for(;;)
{
iRet = deflate(&compStream,Z_FINISH);
if(iRet == Z_STREAM_END) break;
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
}
compressedLength = compStream.total_out;
deflateEnd(&compStream);
/* write header line */
memset(outBuf,0,65536);
protocolID = GetProtocolID(self);
if(protocolID == 5){
cc = SCGetContext(self);
sprintf(outBuf,"SICSBIN ZIP %s %d %d\r\n",pName,
compressedLength, cc.transID);
} else {
sprintf(outBuf,"SICSBIN ZIP %s %d \r\n",pName,compressedLength);
}
pHeader = strdup(outBuf);
if(pHeader == NULL)
{
SCWrite(self,"ERROR: out of memory in SCWriteZipped",eError);
return 0;
}
/* now reset the deflater and do the same with writing data */
compStream.zalloc = (alloc_func)NULL;
compStream.zfree = (free_func)NULL;
compStream.opaque = (voidpf)NULL;
/*
This is writing everything in one go as I found that writing in
several chunks did not ensure that all the data arrived at the
Java side.
*/
iRet = deflateInit(&compStream,Z_DEFAULT_COMPRESSION);
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
pBuf = (char *)malloc((iDataLen + iDataLen/10 + 50)*sizeof(char));
memset(pBuf,0,(iDataLen + iDataLen/10 + 50)*sizeof(char) );
compStream.next_in = (Bytef *)pData;
compStream.next_out = (Bytef *)pBuf;
compStream.avail_in = iDataLen;
compStream.avail_out = iDataLen + iDataLen/10 + 50;
iRet = deflate(&compStream,Z_FINISH);
if(iRet != Z_STREAM_END)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
iRet = NETWrite(self->pSock,pHeader,strlen(pHeader));
iRet = NETWrite(self->pSock,pBuf,compStream.total_out);
if(iRet != 1)
{
sprintf(outBuf,"ERROR: network error %d on zipped send",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
deflateEnd(&compStream);
free(pHeader);
free(pBuf);
/*
Writing smaller buffers. Seems not to be working properly
with Java.
*/
/*
compStream.next_in = (Bytef *)pData;
compStream.avail_in = iDataLen;
compStream.avail_out = ZIPBUF;
compStream.next_out = (Bytef *)noutBuf;
iCount = 0;
while(compStream.total_in < iDataLen)
{
iRet = deflate(&compStream,Z_NO_FLUSH);
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
iRet = NETWrite(self->pSock,noutBuf,ZIPBUF - compStream.avail_out);
if(iRet != 1)
{
sprintf(outBuf,"ERROR: network error %d on zipped send",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
iCount += ZIPBUF - compStream.avail_out;
compStream.next_out = (Bytef *)noutBuf;
compStream.avail_out = ZIPBUF;
}
for(;;)
{
iRet = deflate(&compStream,Z_FINISH);
iRet2 = NETWrite(self->pSock,noutBuf,ZIPBUF - compStream.avail_out);
if(iRet2 != 1)
{
sprintf(outBuf,"ERROR: network error %d on zipped send",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
iCount += ZIPBUF - compStream.avail_out;
if(iRet == Z_STREAM_END) break;
if(iRet != Z_OK)
{
sprintf(outBuf,"ERROR: zlib error: %d",iRet);
SCWrite(self,outBuf,eError);
return 0;
}
compStream.next_out = (Bytef *)noutBuf;
compStream.avail_out = ZIPBUF;
}
deflateEnd(&compStream);
*/
return 1;
}
/*-------------------------------------------------------------------------*/
int SCSendOK(SConnection *self)
{
return SCWrite(self,"OK",eStatus);
}
/*--------------------------------------------------------------------------*/
int SCRead(SConnection *self, char *buffer, int iLen)
{
int iRet;
if(!VerifyConnection(self))
{
return 0;
}
if(self->pSock == NULL)
{
printf("SICS>> ");
fgets(buffer,iLen-1,stdin);
return 1;
}
if(self->pSock)
{
iRet = NETRead(self->pSock,buffer,iLen,10);
if(iRet == 0) /* no data */
{
return 0;
}
else if(iRet < 0) /* eof */
{
return EOF;
}
else /* data */
{
return 1;
}
}
else
{
return EOF;
/* fgets(buffer,iLen,stdin); */
}
return 1;
}
/*----------------------------------------------------------------------------*/
int SCMatchRights(SConnection *pCon, int iCode)
{
char pBueffel[132];
if(!VerifyConnection(pCon))
{
return 0;
}
if(iCode < SCGetRights(pCon))
{
sprintf(pBueffel,"ERROR: you are not authorised for this operation");
SCWrite(pCon, pBueffel, eError);
return 0;
}
if(pCon->iGrab)
{
sprintf(pBueffel,
"ERROR: Request refused, control has been grabbed by somebody else");
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}
/*----------------------------------------------------------------------------*/
int SCPrompt(SConnection *pCon, char *pPrompt, char *pResult, int iLen)
{
int iRet, i;
char *pPtr = NULL;
char pFrom[50];
Status eOld;
int oldMode;
if(!VerifyConnection(pCon))
{
return 0;
}
SCWrite(pCon,pPrompt,eWarning);
eOld = GetStatus();
SetStatus(eInput);
CostaUnlock(pCon->pStack);
while(1)
{
/*
wait a second. We want to wait even in a simulation, otherwise
we go into an endless loop. This is why there is the hack with
oldMode and pServ->simMode.
*/
oldMode = pServ->simMode;
pServ->simMode = 0;
SicsWait(1);
pServ->simMode = oldMode;
/* is there an interrupt pending ? */
if(SCGetInterrupt(pCon) != eContinue)
{
break;
}
/* do we have data ? */
iRet = CostaPop(pCon->pStack,&pPtr);
if(iRet == 1)
{
SetStatus(eOld);
CostaLock(pCon->pStack);
strncpy(pResult,pPtr,iLen);
WriteToCommandLogId(" prompted>", pCon->pSock->sockid, pPtr);
return 1;
}
}
SetStatus(eOld);
CostaLock(pCon->pStack);
return 0;
}
/*---------------------------------------------------------------------------*/
int SCGetRights(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->iUserRights;
}
/*---------------------------------------------------------------------------*/
int SCGetGrab(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->iGrab;
}
/*--------------------------------------------------------------------------*/
int SCSetRights(SConnection *self, int iNew)
{
if(!VerifyConnection(self))
{
return 0;
}
assert(iNew >= usInternal);
assert(iNew <= usSpy);
self->iUserRights = iNew;
return 1;
}
/*---------------------------------------------------------------------------*/
int SCGetOutClass(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->iOutput;
}
/*--------------------------------------------------------------------------*/
void SCSetInterrupt(SConnection *self, int eCode)
{
if(!VerifyConnection(self))
{
return;
}
self->eInterrupt = eCode;
}
/*---------------------------------------------------------------------------*/
int SCGetInterrupt(SConnection *self)
{
if(!VerifyConnection(self))
{
return 0;
}
return self->eInterrupt;
}
/*----------------------------------------------------------------*/
extern char *trim(char *in);
/* --------------------------------------------------------------------------*/
int SCInvoke(SConnection *self, SicsInterp *pInter, char *pCommand)
{
int iRet;
long lLen;
const char *pResult = NULL;
char *pBuffer = NULL, *pFile = NULL;
char pBueffel[80];
int i, iSpace;
if(!VerifyConnection(self))
{
return 0;
}
assert(pInter);
/* print command to log files */
for( i = 0; i < self->iFiles; i++)
{
if(self->pFiles[i])
{
fprintf(self->pFiles[i],"SICS>> %s\n",pCommand);
}
}
/* print to command log if user or manager */
if(SCGetRights(self) <= usUser)
{
/*
* This is a fix to suppress cron messages in the success
* case
*/
if(SCGetWriteFunc(self) != SCNotWrite)
{
sendingConnection = self;
if(self->pSock != NULL)
{
WriteToCommandLogCmd(self->pSock->sockid, pCommand);
} else {
WriteToCommandLog("CRON>>",pCommand);
}
sendingConnection = NULL;
}
}
/* invoke */
self->inUse++;
self->eInterrupt = eContinue;
/*
get first word of command
*/
memset(pBueffel,0,80);
stptok(trim(pCommand),pBueffel,79," ");
SCAdvanceContext(self,pBueffel);
iRet = InterpExecute(pInter,self,pCommand);
SCPopContext(self);
StatusFileTask(NULL); /* save changed parameters */
self->inUse--;
return iRet;
}
/*---------------------------------------------------------------------------
For configuring connections. Syntax:
config OutCode val sets an new output code
config Rights User Password sets and verifies new user rights
config File Filename Logs to another file
config output normal | withcode | ACT Sets output mode
config listen 0 | 1 enables commandlog listen mode
---------------------------------------------------------------------------*/
int ConfigCon(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pBueffel[512];
char pHost[132];
int i, iRet;
int iNum;
if(!VerifyConnection(pCon))
{
return 0;
}
assert(pSics);
/* check no of args */
if(argc < 2)
{
sprintf(pBueffel,"Insufficient number of args to %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* handle list*/
strtolower(argv[1]);
if(strcmp(argv[1],"list") == 0)
{
sprintf(pBueffel,"OutCode = %s\nUserRights = %d",
pCode[pCon->iOutput], SCGetRights(pCon));
SCWrite(pCon,pBueffel,eStatus);
return 1;
}
else if(strcmp(argv[1],"myname") == 0)
{
sprintf(pBueffel,"MyName = %s",ConName(pCon->ident));
SCWrite(pCon,pBueffel,eValue);
return 1;
}
else if(strcmp(argv[1],"myrights") == 0)
{
sprintf(pBueffel,"UserRights = %d",SCGetRights(pCon));
SCWrite(pCon,pBueffel,eValue);
return 1;
}
else if(strcmp(argv[1],"listen") == 0)
{
if(argc < 3)
{
snprintf(pBueffel,511,"listen = %d", pCon->listening);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
else
{
pCon->listening = atoi(argv[2]);
if(pCon->listening != 0 && pCon->listening != 1)
{
pCon->listening = 0;
SCWrite(pCon,"ERROR: config listen only accepts 0 or 1 as arguments",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
}
/* check no or args */
if(argc < 3)
{
sprintf(pBueffel,"Insufficient number of args to %s",argv[0]);
SCWrite(pCon,pBueffel,eInError);
return 0;
}
/* decide what to do */
if(strcmp(argv[1],"file") == 0)
{
iRet = SCAddLogFile(pCon,argv[2]);
if(iRet >= 0 )
{
sprintf(pBueffel,"File = %d",iRet);
SCWrite(pCon,pBueffel,eStatus);
return 1;
}
}
if(strcmp(argv[1],"close") == 0) /* close file */
{
iNum = atoi(argv[2]);
if( (iNum >= 0) && (iNum < MAXLOGFILES))
{
if(pCon->pFiles[iNum])
{
fclose(pCon->pFiles[iNum]);
pCon->pFiles[iNum] = NULL;
SCSendOK(pCon);
return 1;
}
}
else
{
SCWrite(pCon, "Invalid file number specified ",eError);
return 0;
}
}
else if(strcmp(argv[1],"outcode") == 0)
{
i = 0;
strtolower(argv[2]);
while(pCode[i] != NULL)
{
if(strcmp(pCode[i],argv[2]) == 0)
{
break;
}
i++;
}
if( i > iNoCodes)
{
sprintf(pBueffel,"OutCode %s not recognized",argv[2]);
SCWrite(pCon,pBueffel,eInError);
return 0;
}
pCon->iOutput = i;
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"output") == 0)
{
strtolower(argv[2]);
if(strcmp(argv[2],"normal") == 0)
{
SCSetWriteFunc(pCon,SCNormalWrite);
}
else if(strcmp(argv[2],"withcode") == 0)
{
SCSetWriteFunc(pCon,SCWriteWithOutcode);
}
else if(strcmp(argv[2],"act") == 0)
{
SCSetWriteFunc(pCon,SCACTWrite);
}
else
{
SCWrite(pCon,"ERROT: output mode not recognised",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"rights") == 0)
{
if(argc < 4)
{
sprintf(pBueffel,"Insufficient number of args to %s",argv[0]);
SCWrite(pCon,pBueffel,eInError);
return 0;
}
i = IsValidUser(argv[2],argv[3]);
if(i < 0)
{
sprintf(pBueffel," %s with password ****** is NO valid User on SICS",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
if (CompactCommandLog()) {
if (pCon->iUserRights < 3 || i < 3) {
NETInfo(pCon->pSock,pHost,sizeof pHost);
sprintf(pBueffel,"User %s from %s switched to %d privilege",
argv[2],pHost,i);
WriteToCommandLogId("SYS>",pCon->pSock->sockid,pBueffel);
}
} else {
sprintf(pBueffel,"User %s socket %d switched to %d privilege",
argv[2],pCon->pSock->sockid,i);
WriteToCommandLog("SYS>",pBueffel);
}
pCon->iUserRights = i;
SCWrite(pCon,"Change of Authorisation Acknowledged",eWarning);
return 1;
}
SCWrite(pCon,"Command not recognized",eError);
return 0;
}
/*----------------------------------------------------------------------*/
int SCRegister(SConnection *pCon, SicsInterp *pSics,
void *pData, long lID)
{
pICallBack pInter = NULL;
Item sItem;
pInter = (pICallBack)pData;
if(!VerifyConnection(pCon))
{
return 0;
}
assert(pSics);
assert(pInter);
sItem.lID = lID;
sItem.pInterface = pInter;
LLDnodeAppendFrom(pCon->iList,&sItem);
return 1;
}
/*----------------------------------------------------------------------*/
int SCUnregister(SConnection *pCon, void *pData)
{
int iRet;
Item sItem;
pICallBack pInter;
if(!VerifyConnection(pCon))
{
return 0;
}
pInter = (pICallBack)pData;
iRet = LLDnodePtr2First(pCon->iList);
while(iRet != 0)
{
LLDnodeDataTo(pCon->iList,&sItem);
if(sItem.pInterface == pInter)
{
LLDnodeDelete(pCon->iList);
LLDnodePtr2Prev(pCon->iList);
}
iRet = LLDnodePtr2Next(pCon->iList);
}
return 1;
}
/*----------------------------------------------------------------------*/
int SCUnregisterID(SConnection *pCon, long ID)
{
int iRet;
Item sItem;
if(!VerifyConnection(pCon))
{
return 0;
}
iRet = LLDnodePtr2First(pCon->iList);
while(iRet != 0)
{
LLDnodeDataTo(pCon->iList,&sItem);
if(sItem.lID == ID )
{
LLDnodeDelete(pCon->iList);
LLDnodePtr2Prev(pCon->iList);
}
iRet = LLDnodePtr2Next(pCon->iList);
}
return 1;
}
/*----------------------------------------------------------------------*/
long SCgetCallbackID(SConnection *pCon, void *pData)
{
int iRet;
Item sItem;
pICallBack pInter;
if(!VerifyConnection(pCon))
{
return 0;
}
pInter = (pICallBack)pData;
iRet = LLDnodePtr2First(pCon->iList);
while(iRet != 0)
{
LLDnodeDataTo(pCon->iList,&sItem);
if(sItem.pInterface == pInter)
{
return sItem.lID;
}
iRet = LLDnodePtr2Next(pCon->iList);
}
return -1;
}
/*---------------------- The callback data structure --------------------*/
typedef struct {
SConnection *pCon;
SicsInterp *pSics;
char *pAction;
} CBAction, *pCBAction;
/*---------------------- CBKill -----------------------------------------*/
static void CBKill(void *pData)
{
pCBAction self = NULL;
self = (pCBAction)pData;
if(self == NULL)
{
return;
}
if(self->pAction)
{
free(self->pAction);
}
free(self);
}
/*-------------------------------------------------------------------------
The callback function for connection callbacks. Invokes command
given at registration time.
*/
static int ConCallBack(int iEvent, void *pEventData, void *pUserData,
commandContext cc)
{
pCBAction self = NULL;
self = (pCBAction)pUserData;
assert(self);
if(self->pAction)
{
SCPushContext2(self->pCon,cc);
InterpExecute(pServ->pSics,self->pCon,self->pAction);
SCPopContext(self->pCon);
}
return 1;
}
/*--------------------------------------------------------------------------*/
int ConSicsAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
SConnection *self = NULL;
pICallBack pInterface = NULL;
char pBueffel[1024];
pDummy pDum;
int iEvent;
Item sItem;
pCBAction pCB = NULL;
CommandList *pCom = NULL;
int iMacro;
char *script;
self = (SConnection *)pData;
if(!VerifyConnection(self))
{
return 0;
}
if(argc > 1)
{
/* put */
if(strcmp(argv[1],"put") == 0)
{
Arg2Text(argc-2,&argv[2],pBueffel,1023);
iMacro = SCinMacro(pCon);
SCsetMacro(pCon,0);
SCWrite(self,pBueffel,eWarning);
SCsetMacro(pCon,iMacro);
return 1;
}
/* register object event action */
if(strcmp(argv[1],"register") == 0)
{
if(argc < 5)
{
SCWrite(pCon,"ERROR: Insufficient arguments to register",eError);
return 0;
}
/* get object */
pCom = FindCommand(pSics,argv[2]);
if(!pCom)
{
sprintf(pBueffel,"ERROR: object %s NOT found",argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* get CallBack interface */
pDum = (pDummy)pCom->pData;
assert(pDum);
pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,
CALLBACKINTERFACE);
if(!pInterface)
{
sprintf(pBueffel,"ERROR: %s does not support CallBacks",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* get Event */
iEvent = Text2Event(argv[3]);
if(iEvent < 0)
{
sprintf(pBueffel,"ERROR: Unknown event code %s",argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
script = Arg2Tcl(argc-4, &argv[4], NULL, 0);
/* now we can install the callback */
pCB = (pCBAction)malloc(sizeof(CBAction));
if(!pCB || !script)
{
SCWrite(pCon,"ERROR: memory exhausted in SConnection",eError);
return 0;
}
pCB->pCon = pCon;
pCB->pSics = pSics;
pCB->pAction = script;
sItem.pInterface = pInterface;
sItem.lID = RegisterCallback(pInterface, SCGetContext(pCB->pCon), iEvent, ConCallBack,
pCB, CBKill);
LLDnodeAppendFrom(self->iList,&sItem);
SCSendOK(pCon);
return 1;
}
}
return 0;
}
/*--------------------------------------------------------------------------*/
int SCTaskFunction(void *pData)
{
SConnection *self = NULL;
char *pPtr = NULL;
int iRet;
char *pUser = NULL, *pPassword = NULL;
char pHost[132], pBueffel[512];
self = (SConnection *)pData;
if(!VerifyConnection(self))
{
return 0;
}
if(self->pSock->iType == 0)
{
NetReadRemove(pServ->pReader,self->pSock);
self->iEnd = 1;
}
if(self->iEnd)
{
if(SCActive(self))
{
return 1;
}
else
{
return 0;
}
}
/* a timeout check on logins */
if(!self->iLogin && time(NULL) > self->conStart + 120)
{
NetReadRemove(pServ->pReader,self->pSock);
SCWrite(self, "No valid login in two minutes, closing..",eError);
self->iEnd = 1;
return 1;
}
/* pop and execute */
iRet = CostaPop(self->pStack,&pPtr);
if(iRet)
{
if(pPtr)
{
if(self->iLogin)
{
/*
normal processing, logged in
but check for logoff
*/
if(strstr(pPtr,"logoff") != NULL)
{
NetReadRemove(pServ->pReader,self->pSock);
self->iEnd = 1;
free(pPtr);
return 1;
}
/* invoke command */
CostaLock(self->pStack);
SCInvoke(self,pServ->pSics,pPtr);
CostaUnlock(self->pStack);
}
else
{
/* response for monit check */
if (strstr(pPtr,"How are you") == pPtr)
{
SCWrite(self,"I am fine",eError);
NetReadRemove(pServ->pReader,self->pSock);
self->iEnd = 1;
free(pPtr);
return 1;
}
/* check for username and password */
pUser = strtok(pPtr," \t");
pPassword = strtok(NULL," \t\r\n");
iRet = IsValidUser(pUser,pPassword);
if(iRet >= 0)
{
SCWrite(self,"Login OK",eError);
self->iLogin = 1;
SCSetRights(self,iRet);
pHost[0] = '\0';
if (CompactCommandLog()) {
if (iRet < 3) {
NETInfo(self->pSock,pHost,131);
sprintf(pBueffel,"Accepted connection %s from %s as %s",
ConName(self->ident), pHost, pUser);
SICSLogWrite(pBueffel,eInternal);
WriteToCommandLogId("SYS>", self->pSock->sockid, pBueffel);
}
} else {
NETInfo(self->pSock,pHost,131);
sprintf(pBueffel,"Accepted connection %s on socket %d from %s",
ConName(self->ident), self->pSock->sockid, pHost);
SICSLogWrite(pBueffel,eInternal);
WriteToCommandLog("SYS >", pBueffel);
}
free(pPtr);
return 1;
}
else
{
SCWrite(self,"ERROR: Bad login",eError);
printf("Bad login string %s\n", pPtr);
}
}
free(pPtr);
}
}
if(self->iEnd)
{
if(SCActive(self))
{
return 1;
}
else
{
return 0;
}
}
return 1;
}
/*---------------------------------------------------------------------------*/
void SCSignalFunction(void *pData, int iSignal, void *pSigData)
{
SConnection *self = NULL;
int *iInt;
char *pPtr;
self = (SConnection *)pData;
if(!VerifyConnection(self))
{
return;
}
if(iSignal == SICSINT)
{
iInt = (int *)pSigData;
SCSetInterrupt(self,*iInt);
if(*iInt == eEndServer)
{
self->iEnd = 1;
}
}
else if(iSignal == SICSBROADCAST)
{
pPtr = (char *)pSigData;
if(pPtr != NULL)
{
SCWrite(self,pPtr,eWarning);
}
}
else if(iSignal == COMLOG && self->listening == 1)
{
pPtr = (char *)pSigData;
if(pPtr != NULL && self != sendingConnection)
{
doSockWrite(self,pPtr);
}
}
else if(iSignal == TOKENRELEASE)
{
self->iGrab = 0;
}
else if(iSignal == TOKENGRAB)
{
self->iGrab = 1;
}
}
/*-----------------------------------------------------------------------*/
void SCparChange(SConnection *self)
{
StatusFileDirty();
}
/*------------------------------------------------------------------------*/
int SCActive(SConnection *self)
{
if(self->inUse != 0 )
{
return 1;
}
if(pServ->pExecutor != NULL)
{
if(GetExeOwner(pServ->pExecutor) == self)
{
return 1;
}
}
return 0;
}
/*--------------------------------------------------------------------------*/
SCStore *SCSave(SConnection *pCon, SCStore *oldStore) {
commandContext cc;
if (oldStore == NULL) {
oldStore = calloc(1,sizeof(*oldStore));
assert(oldStore);
}
oldStore->pCon = pCon;
if (pCon) {
oldStore->ident = pCon->ident;
oldStore->inMacro = pCon->iMacro;
oldStore->cc = SCGetContext(pCon);
oldStore->pushLevel = 0;
}
return oldStore;
}
/*--------------------------------------------------------------------------*/
SConnection *SCLoad(SCStore *conStore) {
SConnection *pCon = NULL;
commandContext old;
if (conStore) {
pCon = conStore->pCon;
}
if (pCon) {
if (conStore->ident != pCon->ident) {
conStore->pCon = NULL; /* connection is dead */
pCon = NULL;
}
}
if (pCon) {
return pCon;
}
return pServ->dummyCon;
}
/*--------------------------------------------------------------------------*/
SConnection *SCStorePush(SCStore *conStore) {
SConnection *pCon;
pCon = SCLoad(conStore);
if (conStore->pushLevel == 0) {
if (conStore->inMacro) {
conStore->inMacroSave = pCon->iMacro;
pCon->iMacro = conStore->inMacro;
}
}
conStore->pushLevel++;
SCPushContext2(pCon, conStore->cc);
return pCon;
}
/*--------------------------------------------------------------------------*/
void SCStorePop(SCStore *conStore) {
SConnection *pCon;
pCon = SCLoad(conStore);
if (conStore->pushLevel > 0) {
SCPopContext(pCon);
conStore->pushLevel--;
if (conStore->pushLevel == 0) {
pCon->iMacro = conStore->inMacroSave;
}
}
}
/*--------------------------------------------------------------------------*/
int SCStoreConnected(SCStore *conStore) {
return (conStore &&
conStore->pCon &&
conStore->pCon->ident == conStore->ident);
}
/*--------------------------------------------------------------------------*/
void SCStoreFree(SCStore *conStore) {
free(conStore);
}
/* --------------------------------------------------------------------------*/
long SCTagContext(SConnection *self, char *tagName)
{
commandContext a;
if(NULL==self) return -1;
a = SCGetContext(self);
strncpy(a.deviceID,tagName,SCDEVIDLEN);
/*
SCGetContext will already have advanced the stack pointer to the
last position
*/
LLDnodeDataTo(self->contextStack, &a);
return 1;
}
/* --------------------------------------------------------------------------*/
long SCAdvanceContext(SConnection *self, char *tagName)
{
if(NULL==self) return -1;
self->iCmdCtr++;
if(999999<self->iCmdCtr)
{
self->iCmdCtr = 0;
}
return SCPushContext(self, self->iCmdCtr, tagName);
}
/*------------------------------------------------------------------------*/
int SCVerifyConnection(SConnection *self)
{
return VerifyConnection(self);
}
/*------------------------------------------------------------------------*/
void SCWriteToLogFiles(SConnection *self, char *buffer)
{
writeToLogFiles(self,buffer);
}
/*------------------------------------------------------------------------*/
int SCDoSockWrite(SConnection *self, char *buffer)
{
return doSockWrite(self,buffer);
}
/*--------------------------------------------------------------------------*/
void KillFreeConnections(void) {
SConnection *next;
while (freeConnections) {
next = freeConnections->next;
free(freeConnections);
freeConnections = next;
}
}
/*-------------------------------------------------------------------------*/
int SCPushContext(SConnection *self, int ID, char *deviceID)
{
commandContext neu;
if(!VerifyConnection(self))
{
return 0;
}
neu.transID = ID;
strncpy(neu.deviceID,deviceID,SCDEVIDLEN);
LLDnodeAppendFrom(self->contextStack,&neu);
return 1;
}
/*------------------------------------------------------*/
int SCPushContext2(SConnection *self, commandContext cc)
{
return SCPushContext(self,cc.transID, cc.deviceID);
}
/*------------------------------------------------------*/
commandContext SCGetContext(SConnection *pCon)
{
commandContext neu;
neu.transID = 0;
strcpy(neu.deviceID,"Undefined");
if(!VerifyConnection(pCon))
{
return neu;
}
if(LLDnodePtr2Last(pCon->contextStack) == 1){
LLDnodeDataTo(pCon->contextStack, &neu);
}
return neu;
}
/*-----------------------------------------------------*/
int SCPopContext(SConnection *pCon)
{
if(!VerifyConnection(pCon))
{
return 0;
}
if(LLDnodePtr2Last(pCon->contextStack) != 0)
{
LLDnodeDelete(pCon->contextStack);
}
return 1;
}