2519 lines
62 KiB
C
2519 lines
62 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
|
|
|
|
substantially revised for asynchronous I/O
|
|
|
|
Mark Koennecke, January 2009
|
|
|
|
Removed old cruft including SCStore. Added accessor functions to make the
|
|
connection object more private
|
|
|
|
Mark Koennecke, October 2016
|
|
-----------------------------------------------------------------------------*/
|
|
#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 "status.h"
|
|
#include "interrupt.h"
|
|
#include "ifile.h"
|
|
#include "token.h"
|
|
#include "uubuffer.h"
|
|
#include "stptok.h"
|
|
#include "statusfile.h"
|
|
#include "sicshipadaba.h"
|
|
#include "protocol.h"
|
|
#include "sicsvar.h"
|
|
#include <json-c/json.h>
|
|
|
|
/*
|
|
Greetings from protocol.c for SCLogWrite...
|
|
*/
|
|
extern struct json_object *mkJSON_Object(SConnection * pCon, char *pBuffer,
|
|
int iOut);
|
|
|
|
/* from loglisten.c */
|
|
void LogListenRegister(SConnection * pCon);
|
|
|
|
/*
|
|
#define UUDEB 1
|
|
define UUDEB , for buffer writing for checking encoding */
|
|
|
|
extern pServer pServ;
|
|
|
|
#include "outcode.h" /* text for OutCode */
|
|
|
|
int KillCapture(SConnection * pCon);
|
|
|
|
int LogCapture(SConnection * pCon, SicsInterp * pInter, void *pData,
|
|
int argc, char *argv[]);
|
|
|
|
int LogOutput(SConnection * pCon, SicsInterp * pInter, void *pData,
|
|
int argc, char *argv[]);
|
|
|
|
/*------ 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 long lastIdent = 0;
|
|
|
|
/*
|
|
* This will return the value of a SICS int variable called "sicsdebug"
|
|
* If sicsdebug is not defined it will return 1
|
|
* TODO Maybe define debugging levels.
|
|
*
|
|
* return 0=debug off, 1=debug on or sicsdebug not defined.
|
|
*/
|
|
int sicsdebug() {
|
|
pSicsVariable debug;
|
|
|
|
debug = FindVariable(pServ->pSics, "sicsdebug");
|
|
if (debug) {
|
|
return debug->iVal;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
/*===========================================================================*/
|
|
static char *ConName(long ident)
|
|
{
|
|
static char name[32];
|
|
snprintf(name, sizeof(name), "CON%ld", ident);
|
|
return name;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
char *ConID(SConnection *pCon)
|
|
{
|
|
static char id[132];
|
|
char host[80];
|
|
|
|
if(ANETvalidHandle(pCon->sockHandle)){
|
|
ANETinfo(pCon->sockHandle, host, sizeof(host));
|
|
snprintf(id,sizeof(id),"%s:sock%3.3d", host, pCon->sockHandle);
|
|
} else {
|
|
snprintf(id,sizeof(id),"disconnected:con%ld", pCon->ident);
|
|
}
|
|
return id;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static void FreeConnection(SConnection * pCon)
|
|
{
|
|
free(pCon);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static SConnection *SCMakeConnection()
|
|
{
|
|
SConnection *pRes = NULL;
|
|
|
|
pRes = (SConnection *) malloc(sizeof(SConnection));
|
|
if (!pRes) {
|
|
/* This is a serious, very serious error! */
|
|
Log(ERROR,"sys","%s","No memory to allocate connection!!");
|
|
return NULL;
|
|
}
|
|
memset(pRes, 0, sizeof(SConnection));
|
|
return pRes;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static SConnection *CreateConnection(SicsInterp * pSics)
|
|
{
|
|
int i;
|
|
SConnection *pRes = NULL;
|
|
char pBueffel[253];
|
|
char pHost[132];
|
|
|
|
pRes = SCMakeConnection();
|
|
|
|
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! */
|
|
Log(FATAL,"sys""%s","Run out of connection identifiers!!");
|
|
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! */
|
|
Log(ERROR,"sys","%s","No memory to allocate connection!!");
|
|
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! */
|
|
Log(ERROR,"sys","%s","No memory to allocate connection!!");
|
|
DeleteDescriptor(pRes->pDes);
|
|
FreeConnection(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
pRes->iOutput = eInError; /* gets everything except internal messages */
|
|
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;
|
|
pRes->runLevel = RUNDRIVE;
|
|
pRes->remote = 0;
|
|
|
|
/* 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, int sockHandle,
|
|
int iUser)
|
|
{
|
|
SConnection *pRes = NULL;
|
|
char pBueffel[253];
|
|
char pHost[132];
|
|
|
|
pRes = CreateConnection(pSics);
|
|
|
|
SetCommandStackMaxSize(pRes->pStack, MAXSTACK);
|
|
|
|
pRes->sockHandle = sockHandle;
|
|
pRes->iUserRights = iUser;
|
|
pRes->iGrab = TokenGrabActive();
|
|
return pRes;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SConnection *SCCreateDummyConnection(SicsInterp * pSics)
|
|
{
|
|
SConnection *pRes = NULL;
|
|
|
|
pRes = CreateConnection(pSics);
|
|
if(pRes == NULL){
|
|
return pServ->dummyCon;
|
|
}
|
|
|
|
pRes->sockHandle = -1;
|
|
pRes->iUserRights = usInternal;
|
|
pRes->iGrab = 0;
|
|
|
|
/* Log(INFO,"SYS","%s","Accepted dummy connection "); */
|
|
|
|
return pRes;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int VerifyConnection(SConnection * self)
|
|
{
|
|
static SConnection *previous = NULL;
|
|
if (!self) {
|
|
Log(ERROR,"sys","%s","MAGICERROR: Invalid call to NULL connection");
|
|
return 0;
|
|
}
|
|
if (self->lMagic != CONMAGIC) {
|
|
if (self != previous) {
|
|
previous = self;
|
|
Log(ERROR,"sys","%s","MAGICERROR: corrupted connection object");
|
|
}
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
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;
|
|
/* SCPrintf(self,eError, "SCsetMacro = %lx, %d\n", (long int)self, iMode); */
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void SCDeleteMasterFields(SConnection * pVictim)
|
|
{
|
|
int iRet;
|
|
Item sItem;
|
|
pHdb root = NULL;
|
|
char pBueffel[512];
|
|
|
|
if (pVictim->pDes == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (SCActive(pVictim)) {
|
|
SCnoSock(pVictim);
|
|
ANETclose(pVictim->sockHandle);
|
|
Log(ERROR,"sys","%s","Erraneous deletion of used Connection stopped");
|
|
pVictim->sockHandle = -1;
|
|
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->sockHandle >= 0 && pVictim->iLogin == 1 &&
|
|
pVictim->iUserRights < 3) {
|
|
sprintf(pBueffel, "Deleting connection %d", pVictim->sockHandle);
|
|
Log(DEBUG,"sys","%s", pBueffel);
|
|
}
|
|
|
|
/* close all open files and sockets */
|
|
if (pVictim->sockHandle > 0) {
|
|
ANETwrite(pVictim->sockHandle, "SICSCLOSE", sizeof("SICSCLOSE"));
|
|
ANETprocess();
|
|
ANETclose(pVictim->sockHandle);
|
|
}
|
|
RemoveCommand(pServ->pSics, ConName(pVictim->ident));
|
|
/* 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);
|
|
LLDdelete(pVictim->contextStack);
|
|
DeleteDescriptor(pVictim->pDes);
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
void SCDeleteConnection(void *pData)
|
|
{
|
|
int i, iRet;
|
|
char pBueffel[132];
|
|
SConnection *pVictim = NULL;
|
|
|
|
pVictim = (SConnection *) pData;
|
|
if (!VerifyConnection(pVictim)) {
|
|
return;
|
|
}
|
|
|
|
SCDeleteMasterFields(pVictim);
|
|
|
|
/* remove command stack */
|
|
if (pVictim->pStack != NULL) {
|
|
DeleteCommandStack(pVictim->pStack);
|
|
}
|
|
|
|
/* remove possible buffers */
|
|
if (pVictim->data != NULL && pVictim->dataOwner == 1) {
|
|
DeleteDynString(pVictim->data);
|
|
}
|
|
|
|
pVictim->lMagic = 0; /* make a write to a freed connection harmless */
|
|
/* finally free pVictim */
|
|
FreeConnection(pVictim);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SConnection *SCCopyConnection(SConnection * pCon)
|
|
{
|
|
SConnection *result = NULL;
|
|
|
|
result = SCMakeConnection();
|
|
if (result == NULL) {
|
|
return NULL;
|
|
}
|
|
result->sockHandle = pCon->sockHandle;
|
|
result->lMagic = pCon->lMagic;
|
|
result->iUserRights = pCon->iUserRights;
|
|
result->ident = pCon->ident;
|
|
result->iMacro = pCon->iMacro;
|
|
result->iTelnet = pCon->iTelnet;
|
|
result->iOutput = pCon->iOutput;
|
|
if (pCon->oldWriteFunc != NULL)
|
|
result->write = pCon->oldWriteFunc;
|
|
else
|
|
result->write = pCon->write;
|
|
result->listening = pCon->listening;
|
|
result->eInterrupt = pCon->eInterrupt;
|
|
result->inUse = pCon->inUse;
|
|
result->sicsError = pCon->sicsError;
|
|
result->iCmdCtr = pCon->iCmdCtr;
|
|
result->conEventType = pCon->conEventType;
|
|
result->conStatus = pCon->conStatus;
|
|
result->iProtocolID = pCon->iProtocolID;
|
|
result->transID = pCon->transID;
|
|
strcpy(result->deviceID, pCon->deviceID);
|
|
result->conStart = pCon->conStart;
|
|
result->contextStack = -1;
|
|
result->iList = -1;
|
|
result->runLevel = pCon->runLevel;
|
|
result->data = pCon->data;
|
|
result->remote = pCon->remote;
|
|
return result;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
SConnection *SCfindMaster(SConnection * pCon)
|
|
{
|
|
SConnection *result = NULL;
|
|
result =
|
|
(SConnection *) FindCommandData(pServ->pSics, ConName(pCon->ident),
|
|
"Connection");
|
|
if (result == NULL) {
|
|
printf("VERY, Very, very serious programming error!\n");
|
|
printf("I continue but things may be wrong! Please debug ASAP!\n");
|
|
if (pServ->dummyCon == NULL) {
|
|
pServ->dummyCon = SCCreateDummyConnection(pServ->pSics);
|
|
}
|
|
result = pServ->dummyCon;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int SCisConnected(SConnection * pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return ANETvalidHandle(pCon->sockHandle);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
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 TelnetWriteANET(int sockHandle, 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 = ANETwrite(sockHandle, pStart, iCount);
|
|
iRet = ANETwrite(sockHandle, "\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 = ANETwrite(sockHandle, pStart, iCount);
|
|
iRet = ANETwrite(sockHandle, "\r\n", 2);
|
|
}
|
|
return iRet;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static int mustWrite(int iOut)
|
|
{
|
|
switch(iOut) {
|
|
case eLog:
|
|
case eLogError:
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
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;
|
|
int transID;
|
|
char oldDevice[256];
|
|
|
|
transID = pCon->transID;
|
|
strcpy(oldDevice, pCon->deviceID);
|
|
pCon->transID = cc.transID;
|
|
strlcpy(pCon->deviceID, cc.deviceID, SCDEVIDLEN);
|
|
status = SCWrite(pCon, pBuffer, out);
|
|
pCon->transID = transID;
|
|
strlcpy(pCon->deviceID, oldDevice, SCDEVIDLEN);
|
|
return status;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SCPrintf(SConnection * self, int iOut, char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char buf[256];
|
|
char *dyn;
|
|
unsigned 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);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SCPf(writeFunc func, SConnection * self, int iOut, char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char buf[256];
|
|
char *dyn;
|
|
unsigned 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 = func(self, dyn, iOut);
|
|
free(dyn);
|
|
return res;
|
|
}
|
|
}
|
|
return func(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->sockHandle >= 0) {
|
|
if (self->iTelnet) {
|
|
iRet = TelnetWriteANET(self->sockHandle, buffer);
|
|
} else {
|
|
iRet = ANETwrite(self->sockHandle, buffer, strlen(buffer));
|
|
if (!HasNL(buffer)) {
|
|
iRet = ANETwrite(self->sockHandle, "\n", strlen("\n"));
|
|
}
|
|
}
|
|
if (!iRet) {
|
|
SCnoSock(self);
|
|
if (!self->listening && self->iLogin == 1 &&
|
|
self->iUserRights < 3) {
|
|
Log(ERROR,"sys","%s", "Connection broken on send");
|
|
}
|
|
}
|
|
} else {
|
|
if (HasNL(buffer)) {
|
|
fputs(buffer, stdout);
|
|
} else {
|
|
puts(buffer);
|
|
}
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static void testAndStoreInTcl(SConnection * pCon, char *buffer, int iOut)
|
|
{
|
|
if (SCinMacro(pCon)) {
|
|
if (iOut == eValue || iOut == eError) {
|
|
InterpWrite(pServ->pSics, buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int testAndWriteSocket(SConnection * pCon, char *buffer, int iOut)
|
|
{
|
|
switch (iOut) {
|
|
case eStatus:
|
|
case eStart:
|
|
case eFinish:
|
|
case eEvent:
|
|
case eHdbValue:
|
|
case eHdbEvent:
|
|
case eLog:
|
|
case eLogError:
|
|
return doSockWrite(pCon, buffer);
|
|
break;
|
|
case eValue:
|
|
case eError:
|
|
case eWarning:
|
|
if (!SCinMacro(pCon) && iOut >= pCon->iOutput) {
|
|
return doSockWrite(pCon, buffer);
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
printf("Unrecognized ouput code %d in testAndWriteSocket: FIX!!!\n", iOut);
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int isOK(const char *buffer)
|
|
{
|
|
if ((buffer[0] == 'O' && buffer[1] == 'K')
|
|
&& (buffer[2] == '\0' || buffer[2] == '\r' || buffer[2] == '\n'))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static void testAndWriteLog(SConnection * self, char *buffer, int iOut)
|
|
{
|
|
unsigned int severity;
|
|
|
|
/*
|
|
first those which allways go into the log
|
|
*/
|
|
|
|
if(SCGetRights(self) > usUser) {
|
|
severity = DEBUG;
|
|
} else {
|
|
severity = INFO;
|
|
}
|
|
|
|
switch(iOut){
|
|
case eInternal:
|
|
Log(ERROR,"sys","%s",buffer);
|
|
break;
|
|
case eCommand:
|
|
if(!SCinMacro(self)){
|
|
Log(DEBUG,"sys","%s",buffer);
|
|
}
|
|
break;
|
|
case eHWError:
|
|
case eInError:
|
|
Log(ERROR,"dev","%s",buffer);
|
|
break;
|
|
case eStatus:
|
|
Log(DEBUG,"io","%s",buffer);
|
|
break;
|
|
case eEvent:
|
|
if(strstr(buffer,"ERROR") != NULL){
|
|
Log(ERROR,"notify",buffer);
|
|
}else if(strstr(buffer,"WARNING") != NULL) {
|
|
Log(WARN,"notify",buffer);
|
|
} else {
|
|
Log(DEBUG,"notify",buffer);
|
|
}
|
|
break;
|
|
case eHdbEvent:
|
|
case eHdbValue:
|
|
Log(INFO,"notify","%s",buffer);
|
|
break;
|
|
case eLog:
|
|
Log(severity,"com","sock%03.3d:%s",self->sockHandle,buffer);
|
|
break;
|
|
case eLogError:
|
|
Log(ERROR,"com","sock%03.3d:%s",self->sockHandle,buffer);
|
|
break;
|
|
case eError:
|
|
if(!SCinMacro(self)){
|
|
if(severity == DEBUG){
|
|
Log(DEBUG,"com","sock%03.3d:%s",self->sockHandle,buffer);
|
|
} else {
|
|
Log(ERROR,"com","sock%03.3d:%s",self->sockHandle,buffer);
|
|
}
|
|
}
|
|
break;
|
|
case eWarning:
|
|
if(!SCinMacro(self)){
|
|
if(severity == DEBUG){
|
|
Log(DEBUG,"com","sock%03.3d:%s",self->sockHandle,buffer);
|
|
} else {
|
|
Log(WARN,"com","sock%03.3d:%s",self->sockHandle,buffer);
|
|
}
|
|
}
|
|
break;
|
|
case eValue:
|
|
if(!SCinMacro(self)){
|
|
Log(severity,"com","sock%03.3d:%s",self->sockHandle,buffer);
|
|
}
|
|
break;
|
|
default:
|
|
Log(DEBUG,"sys","Unknown outcode %d detected, FIXME ASAP!!!", iOut);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SCNormalWrite(SConnection * self, char *buffer, int iOut)
|
|
{
|
|
int i, iPtr, iRet;
|
|
|
|
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 */
|
|
testAndWriteLog(self, buffer, iOut);
|
|
|
|
testAndStoreInTcl(self, buffer, iOut);
|
|
|
|
testAndWriteSocket(self, buffer, iOut);
|
|
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int SCAllWrite(SConnection * self, char *buffer, int iOut)
|
|
{
|
|
int i, iPtr, iRet;
|
|
|
|
if (!VerifyConnection(self)) {
|
|
return 0;
|
|
}
|
|
|
|
if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) {
|
|
return 1; /* do not write empty line */
|
|
}
|
|
|
|
testAndWriteLog(self, buffer, iOut);
|
|
|
|
testAndStoreInTcl(self, buffer, iOut);
|
|
|
|
doSockWrite(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 */
|
|
testAndWriteLog(self, buffer, iOut);
|
|
|
|
testAndStoreInTcl(self, buffer, iOut);
|
|
|
|
/*
|
|
* copy in ACT
|
|
*/
|
|
if (strlen(buffer) + 30 > 1024) {
|
|
pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char));
|
|
memset(pPtr, 0, strlen(buffer) + 20);
|
|
}
|
|
sprintf(pPtr, "%d::>%s<::", self->transID, buffer);
|
|
|
|
testAndWriteSocket(self, pPtr, iOut);
|
|
|
|
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 */
|
|
testAndWriteLog(self, buffer, iOut);
|
|
|
|
testAndStoreInTcl(self, buffer, iOut);
|
|
/*
|
|
prepare the message with the outcode appended.
|
|
*/
|
|
length = strlen(buffer) + strlen(pCode[iOut]) + 10;
|
|
bufPtr = (char *) malloc(length * sizeof(char));
|
|
if (!bufPtr) {
|
|
Log(ERROR,"sys","%s","out of memory in SCWriteWithOutcode");
|
|
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");
|
|
|
|
testAndWriteSocket(self, bufPtr, iOut);
|
|
|
|
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");
|
|
}
|
|
testAndStoreInTcl(self, buffer, iOut);
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SCStartBuffering(SConnection * pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
if (pCon->data != NULL && pCon->dataOwner == 1) {
|
|
DeleteDynString(pCon->data);
|
|
}
|
|
pCon->data = CreateDynString(128, 128);
|
|
if (pCon->data == NULL) {
|
|
return 0;
|
|
}
|
|
pCon->oldWriteFunc = pCon->write;
|
|
pCon->write = SCBufferWrite;
|
|
pCon->dataOwner = 1;
|
|
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 */
|
|
testAndWriteLog(self,buffer,iOut);
|
|
|
|
testAndStoreInTcl(self, buffer, iOut);
|
|
|
|
testAndWriteSocket(self, buffer, iOut);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SCPureSockWrite(SConnection * self, char *buffer, int iOut)
|
|
{
|
|
char pBueffel[1024];
|
|
char *pPtr;
|
|
json_object *myJson = NULL;
|
|
|
|
/* for commandlog tail */
|
|
if (!VerifyConnection(self)) {
|
|
return 0;
|
|
}
|
|
|
|
if(self->iProtocolID == PROTACT) { /* act */
|
|
if (strlen(buffer) + 30 > 1024) {
|
|
pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char));
|
|
memset(pPtr, 0, strlen(buffer) + 20);
|
|
} else {
|
|
pPtr = pBueffel;
|
|
}
|
|
sprintf(pPtr, "%d::>%s<::", self->transID, buffer);
|
|
testAndWriteSocket(self, pPtr, iOut);
|
|
if(pPtr != pBueffel){
|
|
free(pPtr);
|
|
}
|
|
} else if(self->iProtocolID == PROTJSON) {
|
|
myJson = mkJSON_Object(self,buffer,iOut);
|
|
if(myJson != NULL){
|
|
SCDoSockWrite(self,(char *)json_object_to_json_string(myJson));
|
|
json_object_put(myJson);
|
|
}
|
|
} else {
|
|
testAndWriteSocket(self, buffer, iOut);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------
|
|
special for ClientLog. Do not use elsewhere without check
|
|
----------------------------------------------------------------------------*/
|
|
int SCLogWrite(SConnection * self, char *buffer, int iOut)
|
|
{
|
|
char pBueffel[1024];
|
|
char *pPtr;
|
|
json_object *myJson = NULL;
|
|
|
|
if (!VerifyConnection(self)) {
|
|
return 0;
|
|
}
|
|
Log(INFO,"com","sock%03.3d:%s", self->sockHandle, buffer);
|
|
|
|
if(self->iProtocolID == PROTACT) { /* act */
|
|
if (strlen(buffer) + 30 > 1024) {
|
|
pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char));
|
|
memset(pPtr, 0, strlen(buffer) + 20);
|
|
} else {
|
|
pPtr = pBueffel;
|
|
}
|
|
sprintf(pPtr, "%d::>%s<::", self->transID, buffer);
|
|
testAndWriteSocket(self, pPtr, iOut);
|
|
if(pPtr != pBueffel){
|
|
free(pPtr);
|
|
}
|
|
} else if(self->iProtocolID == PROTCODE) { /* withcode */
|
|
if (strlen(buffer) + 30 > 1024) {
|
|
pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char));
|
|
memset(pPtr, 0, strlen(buffer) + 20);
|
|
} else {
|
|
pPtr = pBueffel;
|
|
}
|
|
sprintf(pPtr,"%s@@%s",buffer,pCode[iOut]);
|
|
testAndWriteSocket(self, pPtr, iOut);
|
|
if(pPtr != pBueffel){
|
|
free(pPtr);
|
|
}
|
|
} else if(self->iProtocolID == PROTJSON) { /* json */
|
|
myJson = mkJSON_Object(self,buffer,iOut);
|
|
if(myJson != NULL){
|
|
SCDoSockWrite(self,(char *)json_object_to_json_string(myJson));
|
|
json_object_put(myJson);
|
|
}
|
|
} else {
|
|
testAndWriteSocket(self, buffer, iOut);
|
|
}
|
|
|
|
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
|
|
sprintf(pBueffel, "Next line intended for socket: %d", self->sockHandle);
|
|
SICSLogWrite(pBueffel, eInternal);
|
|
SICSLogWrite(buffer, iOut);
|
|
*/
|
|
|
|
testAndStoreInTcl(self, buffer, iOut);
|
|
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 */
|
|
|
|
testAndWriteLog(self, buffer, iOut);
|
|
|
|
testAndStoreInTcl(self, buffer, iOut);
|
|
|
|
testAndWriteSocket(self, buffer, iOut);
|
|
|
|
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) {
|
|
ANETwrite(pCon->sockHandle, pPtr, iLength);
|
|
} else {
|
|
ANETwrite(pCon->sockHandle, pPtr, iLength);
|
|
}
|
|
|
|
Log(DEBUG,"com","%s:out:UUData %s %d",ConID(pCon) ,pName, 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[65536], *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 protocol will corrupt 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;
|
|
}
|
|
|
|
|
|
pBuf = malloc(iDataLen*sizeof(char));
|
|
memset(pBuf,0,iDataLen*sizeof(char));
|
|
|
|
compStream.zalloc = (alloc_func) NULL;
|
|
compStream.zfree = (free_func) NULL;
|
|
compStream.opaque = (voidpf) NULL;
|
|
/* iRet = deflateInit(&compStream, Z_DEFAULT_COMPRESSION); */
|
|
iRet = deflateInit(&compStream, 1);
|
|
if (iRet != Z_OK) {
|
|
sprintf(outBuf, "ERROR: zlib error: %d", iRet);
|
|
SCWrite(self, outBuf, eError);
|
|
return 0;
|
|
}
|
|
|
|
compStream.next_in = (Bytef *) pData;
|
|
compStream.next_out = (Bytef *) pBuf;
|
|
compStream.avail_in = iDataLen;
|
|
compStream.avail_out = iDataLen;
|
|
iRet = deflate(&compStream, Z_FINISH);
|
|
if (iRet != Z_STREAM_END && iRet != Z_OK) {
|
|
sprintf(outBuf, "ERROR: zlib error: %d", iRet);
|
|
SCWrite(self, outBuf, eError);
|
|
return 0;
|
|
}
|
|
compressedLength = compStream.total_out;
|
|
|
|
/*
|
|
If data is large, test if we can do it
|
|
*/
|
|
if(compressedLength > 2*1000*1024) {
|
|
if(!ANETcanWrite(self->sockHandle,pData,compressedLength)){
|
|
SCWrite(self,"WARNING: skipping excessive data in SCWriteZipped",eLogError);
|
|
deflateEnd(&compStream);
|
|
free(pBuf);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* write header line */
|
|
memset(outBuf, 0, 65536);
|
|
|
|
protocolID = GetProtocolID(self);
|
|
if (protocolID == PROTACT) {
|
|
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;
|
|
}
|
|
Log(DEBUG,"com", "%s:out:SICSBIN ZIP %s %d", ConID(self), pName, compressedLength);
|
|
|
|
|
|
iRet = ANETwrite(self->sockHandle, pHeader, strlen(pHeader));
|
|
iRet = ANETwrite(self->sockHandle, pBuf, compStream.total_out);
|
|
if (iRet != 1) {
|
|
sprintf(outBuf, "ERROR: network error %d on zipped send", iRet);
|
|
SCWrite(self, outBuf, eError);
|
|
return 0;
|
|
}
|
|
/* printf("Sent zipped data: %s with %d\n", pHeader, iRet); */
|
|
|
|
deflateEnd(&compStream);
|
|
free(pHeader);
|
|
free(pBuf);
|
|
|
|
return 1;
|
|
}
|
|
/*------------------------------------------------------------------*/
|
|
int SCWriteBinary(SConnection * self, char *pName, void *pData,
|
|
int iDataLen)
|
|
{
|
|
char outBuf[65536], *pHeader = NULL;
|
|
int iRet, iRet2, iCount, protocolID;
|
|
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 protocol will corrupt 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;
|
|
}
|
|
|
|
/*
|
|
If data is large, test if we can do it
|
|
*/
|
|
if(iDataLen > 2*1000*1024) {
|
|
if(!ANETcanWrite(self->sockHandle,pData,iDataLen)){
|
|
SCWrite(self,"WARNING: skipping excessive data in SCWriteBinary",eLogError);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* write header line */
|
|
memset(outBuf, 0, 65536);
|
|
|
|
protocolID = GetProtocolID(self);
|
|
if (protocolID == PROTACT) {
|
|
cc = SCGetContext(self);
|
|
sprintf(outBuf, "SICSBIN BIN %s %d %d\r\n", pName,
|
|
iDataLen, cc.transID);
|
|
} else {
|
|
sprintf(outBuf, "SICSBIN BIN %s %d\r\n", pName, iDataLen);
|
|
}
|
|
pHeader = strdup(outBuf);
|
|
if (pHeader == NULL) {
|
|
SCWrite(self, "ERROR: out of memory in SCWriteBinary", eError);
|
|
return 0;
|
|
}
|
|
Log(DEBUG,"com","%s:out:SICSBIN BIN %s %d", ConID(self), pName, iDataLen);
|
|
|
|
iRet = ANETwrite(self->sockHandle, pHeader, strlen(pHeader));
|
|
iRet = ANETwrite(self->sockHandle, pData, iDataLen);
|
|
if (iRet != 1) {
|
|
sprintf(outBuf, "ERROR: network error %d on zipped send", iRet);
|
|
SCWrite(self, outBuf, eError);
|
|
return 0;
|
|
}
|
|
/* printf("Sent zipped data: %s with %d\n", pHeader, iRet); */
|
|
|
|
free(pHeader);
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int SCSendOK(SConnection * self)
|
|
{
|
|
return SCWrite(self, "OK", eValue);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int SCRead(SConnection * self, char *buffer, int iLen)
|
|
{
|
|
|
|
int iRet;
|
|
|
|
if (!VerifyConnection(self)) {
|
|
return 0;
|
|
}
|
|
|
|
if (self->sockHandle < 0) {
|
|
printf("SICS>> ");
|
|
fgets(buffer, iLen - 1, stdin);
|
|
return 1;
|
|
}
|
|
|
|
if (self->sockHandle >= 0) {
|
|
iRet = ANETread(self->sockHandle, buffer, iLen);
|
|
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;
|
|
SConnection *master = NULL;
|
|
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
|
|
SCWrite(pCon, pPrompt, eWarning);
|
|
master = SCfindMaster(pCon);
|
|
CostaUnlock(master->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(master->pStack, &pPtr);
|
|
if (iRet == 1) {
|
|
CostaLock(master->pStack);
|
|
strlcpy(pResult, pPtr, iLen);
|
|
Log(INFO,"sys","prompted%03.3d:", pCon->sockHandle, pPtr);
|
|
return 1;
|
|
}
|
|
}
|
|
CostaLock(master->pStack);
|
|
return 0;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
int SCPromptTMO(SConnection * pCon, char *pPrompt, char *pResult, int iLen, int timeout)
|
|
{
|
|
|
|
int iRet, i;
|
|
char *pPtr = NULL;
|
|
char pFrom[50];
|
|
Status eOld;
|
|
int oldMode;
|
|
SConnection *master = NULL;
|
|
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
|
|
SCWrite(pCon, pPrompt, eWarning);
|
|
master = SCfindMaster(pCon);
|
|
CostaUnlock(master->pStack);
|
|
for(i = 0; i < timeout; i++) {
|
|
/*
|
|
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(master->pStack, &pPtr);
|
|
if (iRet == 1) {
|
|
CostaLock(master->pStack);
|
|
strlcpy(pResult, pPtr, iLen);
|
|
Log(INFO,"com"," prompted%03.3d:", pCon->sockHandle, pPtr);
|
|
return 1;
|
|
}
|
|
}
|
|
CostaLock(master->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)
|
|
{
|
|
SConnection *pCon = NULL;
|
|
if (!VerifyConnection(self)) {
|
|
return;
|
|
}
|
|
pCon = SCfindMaster(self);
|
|
pCon->eInterrupt = eCode;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int SCGetInterrupt(SConnection * self)
|
|
{
|
|
SConnection *pCon = NULL;
|
|
if (!VerifyConnection(self)) {
|
|
return 0;
|
|
}
|
|
pCon = SCfindMaster(self);
|
|
return pCon->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;
|
|
SConnection *pCopy = NULL;
|
|
|
|
if (!VerifyConnection(self)) {
|
|
return 0;
|
|
}
|
|
assert(pInter);
|
|
|
|
|
|
/* 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) {
|
|
if (self->sockHandle >= 0) {
|
|
if(strstr(pCommand,"Poch") == NULL){
|
|
Log(INFO,"com","sock%03.3d:",self->sockHandle, pCommand);
|
|
}
|
|
} else {
|
|
Log(INFO,"sys","CRON:%s", pCommand);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* invoke */
|
|
self->inUse++;
|
|
self->eInterrupt = eContinue;
|
|
/*
|
|
get first word of command
|
|
*/
|
|
memset(pBueffel, 0, 80);
|
|
stptok(trim(pCommand), pBueffel, 79, " ");
|
|
self->iCmdCtr++;
|
|
if (self->iCmdCtr > 99998) {
|
|
self->iCmdCtr = 0;
|
|
}
|
|
self->transID = self->iCmdCtr;
|
|
pCopy = SCCopyConnection(self);
|
|
if (pCopy == NULL) {
|
|
SCWrite(self, "ERROR: out of memory in SCInvoke", eError);
|
|
return 0;
|
|
}
|
|
strlcpy(pCopy->deviceID, pBueffel, SCDEVIDLEN);
|
|
/*
|
|
do not log the log command; defeats log control
|
|
*/
|
|
if(strstr(pCommand,"log ") == NULL) {
|
|
if(SCGetRights(self) > usUser){
|
|
Log(DEBUG,"com","%s:in:%s", ConID(self),pCommand);
|
|
} else {
|
|
Log(INFO,"com", "%s:in:%s", ConID(self),pCommand);
|
|
}
|
|
}
|
|
iRet = InterpExecute(pInter, pCopy, pCommand);
|
|
SCDeleteConnection(pCopy);
|
|
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
|
|
config remote sets the remote connection flag
|
|
---------------------------------------------------------------------------*/
|
|
|
|
int ConfigCon(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
char pBueffel[512];
|
|
char pHost[132];
|
|
int i, iRet;
|
|
int iNum;
|
|
SConnection *pMaster = NULL;
|
|
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
assert(pSics);
|
|
|
|
/* check no of args */
|
|
if (argc < 2) {
|
|
snprintf(pBueffel,511, "Insufficient number of args to %s", argv[0]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pMaster = SCfindMaster(pCon);
|
|
|
|
/* 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, eValue);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "myname") == 0) {
|
|
snprintf(pBueffel,511, "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;
|
|
}
|
|
pMaster->listening = pCon->listening;
|
|
LogListenRegister(pMaster);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
} else if(strcmp(argv[1],"remote") == 0) {
|
|
pMaster->remote = 1;
|
|
pCon->remote = 1;
|
|
return 1;
|
|
}
|
|
|
|
/* check no or args */
|
|
if (argc < 3) {
|
|
snprintf(pBueffel,511, "Insufficient number of args to %s", argv[0]);
|
|
SCWrite(pCon, pBueffel, eInError);
|
|
return 0;
|
|
}
|
|
|
|
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) {
|
|
snprintf(pBueffel,511, "OutCode %s not recognized", argv[2]);
|
|
SCWrite(pCon, pBueffel, eInError);
|
|
return 0;
|
|
}
|
|
pCon->iOutput = i;
|
|
pMaster->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);
|
|
SCSetWriteFunc(pMaster, SCNormalWrite);
|
|
} else if (strcmp(argv[2], "withcode") == 0) {
|
|
SCSetWriteFunc(pCon, SCWriteWithOutcode);
|
|
SCSetWriteFunc(pMaster, SCWriteWithOutcode);
|
|
} else if (strcmp(argv[2], "act") == 0) {
|
|
SCSetWriteFunc(pCon, SCACTWrite);
|
|
SCSetWriteFunc(pMaster, 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) {
|
|
snprintf(pBueffel,511, "Insufficient number of args to %s", argv[0]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
i = IsValidUser(argv[2], argv[3]);
|
|
if (i < 0) {
|
|
snprintf(pBueffel,511,
|
|
" %s with password ****** is NO valid User on SICS",
|
|
argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
snprintf(pBueffel, 511, "User %s handle %d switched to %d privilege",
|
|
argv[2], pCon->sockHandle, i);
|
|
Log(INFO,"sys","%s", pBueffel);
|
|
pCon->iUserRights = i;
|
|
pMaster->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;
|
|
SConnection *pMaster = NULL;
|
|
|
|
pInter = (pICallBack) pData;
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
assert(pSics);
|
|
assert(pInter);
|
|
|
|
sItem.lID = lID;
|
|
sItem.pInterface = pInter;
|
|
pMaster = SCfindMaster(pCon);
|
|
LLDnodeAppendFrom(pMaster->iList, &sItem);
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
int SCUnregister(SConnection * pCon, void *pData)
|
|
{
|
|
int iRet;
|
|
Item sItem;
|
|
pICallBack pInter;
|
|
SConnection *pMaster = NULL;
|
|
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
pInter = (pICallBack) pData;
|
|
pMaster = SCfindMaster(pCon);
|
|
|
|
iRet = LLDnodePtr2First(pMaster->iList);
|
|
while (iRet != 0) {
|
|
LLDnodeDataTo(pMaster->iList, &sItem);
|
|
if (sItem.pInterface == pInter) {
|
|
LLDnodeDelete(pMaster->iList);
|
|
LLDnodePtr2Prev(pMaster->iList);
|
|
}
|
|
iRet = LLDnodePtr2Next(pMaster->iList);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
int SCUnregisterID(SConnection * pCon, long ID)
|
|
{
|
|
int iRet;
|
|
Item sItem;
|
|
SConnection *pMaster = NULL;
|
|
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
pMaster = SCfindMaster(pCon);
|
|
iRet = LLDnodePtr2First(pMaster->iList);
|
|
while (iRet != 0) {
|
|
LLDnodeDataTo(pMaster->iList, &sItem);
|
|
if (sItem.lID == ID) {
|
|
LLDnodeDelete(pMaster->iList);
|
|
LLDnodePtr2Prev(pMaster->iList);
|
|
}
|
|
iRet = LLDnodePtr2Next(pMaster->iList);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
long SCgetCallbackID(SConnection * pCon, void *pData)
|
|
{
|
|
int iRet;
|
|
Item sItem;
|
|
pICallBack pInter;
|
|
SConnection *pMaster = NULL;
|
|
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
pMaster = SCfindMaster(pCon);
|
|
pInter = (pICallBack) pData;
|
|
iRet = LLDnodePtr2First(pMaster->iList);
|
|
while (iRet != 0) {
|
|
LLDnodeDataTo(pMaster->iList, &sItem);
|
|
if (sItem.pInterface == pInter) {
|
|
return sItem.lID;
|
|
}
|
|
iRet = LLDnodePtr2Next(pMaster->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->pCon) {
|
|
SCDeleteConnection(self->pCon);
|
|
}
|
|
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)
|
|
{
|
|
pCBAction self = NULL;
|
|
|
|
self = (pCBAction) pUserData;
|
|
assert(self);
|
|
|
|
/* check kill condition */
|
|
if (self->pCon == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (self->pAction) {
|
|
InterpExecute(pServ->pSics, self->pCon, self->pAction);
|
|
}
|
|
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) {
|
|
snprintf(pBueffel,1024, "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) {
|
|
snprintf(pBueffel,1023, "ERROR: %s does not support CallBacks", argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* get Event */
|
|
iEvent = Text2Event(argv[3]);
|
|
if (iEvent < 0) {
|
|
snprintf(pBueffel,1023, "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 = SCCopyConnection(pCon);
|
|
if (!pCB->pCon) {
|
|
SCWrite(pCon, "ERROR: memory exhausted in SConnection", eError);
|
|
return 0;
|
|
}
|
|
pCB->pSics = pSics;
|
|
pCB->pAction = script;
|
|
sItem.pInterface = pInterface;
|
|
sItem.lID = RegisterCallback(pInterface, iEvent, ConCallBack,
|
|
pCB, CBKill);
|
|
LLDnodeAppendFrom(self->iList, &sItem);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void hookFunc(const char *pText, OutCode eOut, void*pData)
|
|
{
|
|
SConnection *pCon = (SConnection *) pData;
|
|
int text_len = strlen(pText);
|
|
char txt[5];
|
|
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
if (!ANETvalidHandle(pCon->sockHandle)) {
|
|
return;
|
|
}
|
|
snprintf(txt, 5, "%3s:", OutCodeToTxt(eOut));
|
|
ANETwrite(pCon->sockHandle, txt, 4);
|
|
ANETwrite(pCon->sockHandle, (char *)pText, text_len);
|
|
if (pText[text_len - 1] != '\n')
|
|
ANETwrite(pCon->sockHandle, "\n", 1);
|
|
}
|
|
|
|
int KillCapture(SConnection * pCon)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
the command function:
|
|
Syntax:
|
|
LogOutput [OutCode] <text>
|
|
Logs <text> with outcode OutCode default eLog
|
|
-------------------------------------------------------------------------- */
|
|
|
|
int LogOutput(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
char pBueffel[512];
|
|
char *pBuff;
|
|
int i, result, start;
|
|
size_t len;
|
|
OutCode outcode;
|
|
|
|
/* check no af args */
|
|
if (argc < 2) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "Insufficient number of arguments to %s", argv[0]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* assume default eLog unless told otherwise */
|
|
start = 1;
|
|
outcode = eLog;
|
|
if (argv[1][0] == '@') {
|
|
result = OutCodeFromText(&argv[1][1], &outcode);
|
|
if (result >= 0) {
|
|
start = 2;
|
|
}
|
|
}
|
|
|
|
/* make it a string */
|
|
for (i = start, len = 0; i < argc; ++i)
|
|
len += strlen(argv[i]) + 1;
|
|
if (len > sizeof(pBueffel))
|
|
pBuff = malloc(len+10);
|
|
else
|
|
pBuff = pBueffel;
|
|
if (pBuff == NULL) {
|
|
SCWrite(pCon, "Out of memory in LogOutput\n", eError);
|
|
return 1;
|
|
}
|
|
for (i = start, len = 0; i < argc; ++i) {
|
|
if (i > start)
|
|
pBuff[len++] = ' ';
|
|
strcpy(&pBuff[len], argv[i]);
|
|
len += strlen(argv[i]);
|
|
}
|
|
Log(INFO,"com","%s",pBuff);
|
|
if (pBuff != pBueffel)
|
|
free(pBuff);
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
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->iEnd) {
|
|
if (SCActive(self)) {
|
|
return 1;
|
|
} else {
|
|
Log(INFO,"sys","Handle %d disconnected", self->sockHandle);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (!SCisConnected(self)) {
|
|
self->iEnd = 1;
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* a timeout check on logins */
|
|
if (!self->iLogin && time(NULL) > self->conStart + 120) {
|
|
ANETclose(self->sockHandle);
|
|
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) {
|
|
ANETclose(self->sockHandle);
|
|
self->iEnd = 1;
|
|
Log(INFO,"sys","Handle %d loging off", self->sockHandle);
|
|
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);
|
|
ANETprocess();
|
|
ANETclose(self->sockHandle);
|
|
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", eLog);
|
|
self->iLogin = 1;
|
|
SCSetRights(self, iRet);
|
|
pHost[0] = '\0';
|
|
ANETinfo(self->sockHandle, pHost, 131);
|
|
snprintf(pBueffel, 511,
|
|
"Accepted connection %s on socket %d from %s",
|
|
ConName(self->ident), self->sockHandle, pHost);
|
|
Log(INFO,"sys","%s",pBueffel);
|
|
free(pPtr);
|
|
return 1;
|
|
} else {
|
|
SCPrintf(self, eError, "ERROR: Bad login: %s", 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) {
|
|
SCPureSockWrite(self, pPtr, eWarning);
|
|
}
|
|
} 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;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
int SCVerifyConnection(SConnection * self)
|
|
{
|
|
return VerifyConnection(self);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SCDoSockWrite(SConnection * self, char *buffer)
|
|
{
|
|
return doSockWrite(self, buffer);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SCPushContext(SConnection * self, int ID, char *deviceID)
|
|
{
|
|
commandContext neu;
|
|
|
|
if (!VerifyConnection(self)) {
|
|
return 0;
|
|
}
|
|
|
|
neu.transID = ID;
|
|
strlcpy(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;
|
|
}
|
|
neu.transID = pCon->transID;
|
|
strlcpy(neu.deviceID, pCon->deviceID, SCDEVIDLEN);
|
|
return neu;
|
|
}
|
|
|
|
/*-----------------------------------------------------*/
|
|
int SCPopContext(SConnection * pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
if (LLDnodePtr2Last(pCon->contextStack) != 0) {
|
|
LLDnodeDelete(pCon->contextStack);
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
int SCGetRunLevel(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->runLevel;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
long SCGetIdent(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->ident;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
int SCGetSicsError(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->sicsError;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
int SCGetTransID(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->transID;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
int SCGetProtocolID(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->iProtocolID;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
int SCGetSockHandle(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->sockHandle;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
int SCGetConStatus(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->conStatus;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
char *SCGetDeviceID(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->deviceID;
|
|
}
|
|
/*-------------------------------------------------------*/
|
|
int SCGetEnd(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return pCon->iEnd;
|
|
}
|
|
/*-------------------------------------------------------*/
|
|
void SCSetConStatus(SConnection *pCon, int conStatus)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
pCon->conStatus = conStatus;
|
|
}
|
|
/*-------------------------------------------------------*/
|
|
void SCSetEventType(SConnection *pCon, int eventType)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
pCon->conEventType = eventType;
|
|
}
|
|
/*-------------------------------------------------------*/
|
|
void SCSetSicsError(SConnection *pCon, int sicsError)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
pCon->sicsError = sicsError;
|
|
}
|
|
/*-------------------------------------------------------*/
|
|
void SCSetProtocolID(SConnection *pCon, int id)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
pCon->iProtocolID = id;
|
|
}
|
|
/*--------------------------------------------------------*/
|
|
void SCCostaLock(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
CostaLock(pCon->pStack);
|
|
}
|
|
/*---------------------------------------------------------*/
|
|
void SCCostaUnLock(SConnection *pCon){
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
CostaUnlock(pCon->pStack);
|
|
}
|
|
/*---------------------------------------------------------*/
|
|
int SCCostaLocked(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return CostaLocked(pCon->pStack);
|
|
}
|
|
/*----------------------------------------------------------*/
|
|
int SCCostaTop(SConnection *pCon, char *command)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return 0;
|
|
}
|
|
return CostaTop(pCon->pStack, command);
|
|
}
|
|
/*----------------------------------------------------------*/
|
|
void SCSetGrab(SConnection *pCon, int iGrab)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
pCon->iGrab = iGrab;
|
|
}
|
|
/*------------------------------------------------------------*/
|
|
void SCSetEnd(SConnection *pCon, int val)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
pCon->iEnd = val;
|
|
}
|
|
/*------------------------------------------------------------*/
|
|
void SCSetTelnet(SConnection *pCon, int val)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
pCon->iTelnet = val;
|
|
}
|
|
/*------------------------------------------------------------*/
|
|
void SCClose(SConnection *pCon)
|
|
{
|
|
if (!VerifyConnection(pCon)) {
|
|
return;
|
|
}
|
|
ANETclose(pCon->sockHandle);
|
|
pCon->iEnd = 1;
|
|
}
|