/*
	                    UUPoll -- uucico polling server

	  This programm is designed to provide us with the ability to
	control the UUCP polling procedure in a comfortable way.  It
	controls the uucico command automatically, so you have not to think
	about it.  Intead of invoking uucico manually with the desired
	options all you have to do is calling this program with optional
	arguments.

 	Genesis     : Fri Sep 20 23:26:29 1991
 	Last Change : Wed Feb  5 13:57:30 1992

	Developed and debugged with SAS/C Compiler V5.10a
	running under Kickstart 34.5, Workbench 34.20 and ARP 39.1
	on an european PAL-Amiga 2000 B Rev 4.3 with 3MB RAM.

	                        ___  _______
	Ralf S. Engelschall,    /__)(_  /_              rse@angle.muc.sub.org
	 Weblinger Weg 28,     / \____)(___           rse@cyvaned.muc.sub.org
	  8060 Dachau,        /
	   West Germany          ...!smurf.sub.org!brumuc!{angle,cyvaned}!rse
																			*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <devices/timer.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

#include "cus.h"
#include "proto.h"
#include "defines.h"
#include "debug.h"
#include "rev.h"

#define DEFAULT_RETRIES		0
#define DEFAULT_DELAY		0
#define DEFAULT_RESTRICTION 0
#define DEFAULT_ARGS		"-7"

#define LOG			"uuspool:logfile"
#define MODEMSETUP	"uulib:modemsetup"
#define LSYS		"uulib:l.sys"
#define CONFIG		"uulib:config"
#define FIELD		"DefaultNode"

#define UUXQT_DOSNAME	"uuxqt"
#define UUCICO_DOSNAME	"uucico"

/* dependend return codes from uucico release 1.15d */
#define UUCICORC_SUCCESS						0
#define UUCICORC_FAILURE-IN-CALL-OR-PROTOCOL	5
#define UUCICORC_BREAK-OR-SOFTWARE-ERROR		10

#define TIMERMODE_RESTRICTION  1
#define TIMERMODE_SURVIVAL     TIMERMODE_RESTRICTION << 1
#define TIMERMODE_DELAY        TIMERMODE_SURVIVAL << 1

#define SURVIVALMODE_WHOLESESSION	1
#define SURVIVALMODE_ABORTION		SURVIVALMODE_WHOLESESSION << 1
#define SURVIVALTIME_WHOLESESSION	60*60*2	/*  2 hours   */
#define SURVIVALTIME_ABORTION		30		/* 30 seconds */

static char caSystem[RANGE_6BIT];
static char caCmnd[RANGE_7BIT];
static char caTmp[RANGE_7BIT];
static char *cpaArgv[RANGE_7BIT];
static char caEnvname[RANGE_6BIT];

struct timermsg {
	struct timerequest tm_timereq;
	UBYTE tm_timermode;
};


int main(int argc, char *argv[])
{
	unsigned int nRetriesMax = DEFAULT_RETRIES;
	unsigned int iRetries = 0;
	unsigned int nDelay = DEFAULT_DELAY;
	unsigned int nRestriction = DEFAULT_RESTRICTION;
	signed   int nRestrictionTmp;

	char *cpConfig = CONFIG;
	char *cpLsys = LSYS;
	char *cpArgs = DEFAULT_ARGS;
	char *cpLog = LOG;
	char *cpField = FIELD;
	char *cpSystem = NULL;
	char *cpModemsetup = MODEMSETUP;
	char *cpEnvvar = NULL;

	BOOL fModemsetup = FALSE;
	BOOL fInfo = FALSE;
	BOOL fAlways = FALSE;
	BOOL fProfane = FALSE;
	BOOL fUuxqt = FALSE;

	extern char caSystem[];
	extern char caCmnd[];
	extern char caTmp[];

	struct MsgPort *timerport = NULL;
	struct MsgPort *forkport = NULL;
	ULONG timerport_sigmask;
	ULONG forkport_sigmask;
	ULONG signals;
	struct timermsg *timermsg_restriction = NULL;
	struct timermsg *timermsg_survival = NULL;
	struct timermsg *timermsg_delay = NULL;
	struct timermsg *pMsg;
	UBYTE timerdeviceflag_restriction = 0;
	UBYTE timerdeviceflag_survival = 0;
	UBYTE timerdeviceflag_delay = 0;
	UBYTE active_timermsg = 0;
	UBYTE survivalmode = 0;
	struct ProcID *forkprocID = NULL;
	struct FORKENV *forkprocENV = NULL;

	struct Process *PID;
	char *cpProgname;

	int i;
	int rc = DOSRC_SUCCESS;


	cpProgname = strlwr(argv[0]);
	PID = (struct Process *)FindTask(NULL);
	ulog(cpLog, cpProgname, "-", "Startup Release %s.%02d (%s) [PID:%02d]",
		Version, Revision, Date, PID->pr_TaskNum);

	debug(2, "processing argument line\n");
	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch(argv[i][1]) {
				case 's':	fProfane = FALSE;
							debug(3, "fProfane = FALSE\n");
							if (argv[i][2] != NUL) {
								cpSystem = strcvt(&argv[i][2]);
								debug(3, "cpSystem = \"%s\"\n", cpSystem);
							}
							break;
				case 'S':	fProfane = TRUE;
							debug(3, "fProfane = TRUE\n");
							if (argv[i][2] != NUL) {
								cpSystem = strcvt(&argv[i][2]);
								debug(3, "cpSystem = \"%s\"\n", cpSystem);
							}
							break;
				case 'r':	nRetriesMax = abs(atoi(&argv[i][2]));
							debug(3, "nRetriesMax = %d\n", nRetriesMax);
							break;
				case 'd':	nDelay = abs(atoi(&argv[i][2]));
							debug(3, "nDelay = %d\n", nDelay);
							break;
				case 't':	nRestriction = abs(atoi(&argv[i][2]));
							debug(3, "nRestriction = %d\n", nRestriction);
							break;
				case 'u':	cpArgs = strcvt(&argv[i][2]);
							debug(3, "cpArgs = \"%s\"\n", cpArgs);
							break;
				case 'm':	fModemsetup= TRUE;
							debug(3, "fModemsetup = TRUE\n");
							break;
				case 'a':	fAlways = TRUE;
							debug(3, "fAlways = TRUE\n");
							break;
				case 'x':	setdebuglevel(abs(atoi(&argv[i][2])));
							break;
				case 'i':	fInfo = TRUE;
							debug(3, "fInfo = TRUE\n");
							break;
				case 'v':	debug(2, "giving version info\n");
							giveversioninfo(cpProgname);
							CU(DOSRC_SUCCESS);
				case '?':	debug(2, "giving usage info\n");
							giveusage(cpProgname);
							CU(DOSRC_SUCCESS);
				default :	ulog(cpLog, cpProgname, "-", "Ignored bad option '%s'", &argv[i][1]);
			}
		}
		else
			ulog(cpLog, cpProgname, "-", "Ignored bad arg '%s'", argv[i]);
	}

	if (cpSystem == NULL) {
		debug(2, "getting default system name\n");
		if ((cpSystem = getfield(cpConfig, cpField, caSystem)) == NULL) {
			ulog(cpLog, cpProgname, "-", "Failed because cannot get default hostname from '%s' field of '%s'", cpField, cpConfig);
			CU(DOSRC_FAIL);
		}
		truncdomain(cpSystem);
		debug(2, "cpSystem = \"%s\"\n", cpSystem);
		if (!inlsys(cpLsys, cpSystem)) {
			ulog(cpLog, cpProgname, "-", "Failed due to invalid hostname: %s", cpSystem);
			CU(DOSRC_FAIL);
		}
	}

	if (!fProfane) {
		debug(2, "calculating restriction time\n");
		if ((nRestrictionTmp = timerestriction(cpLsys, cpSystem)) == -1) {
			if (fInfo)
				printf("polling time violation for host %s\n", cpSystem);
			ulog(cpLog, cpProgname, cpSystem, "Failed due to polling time violation for host %s", cpSystem);
			CU(DOSRC_FAIL);
		} else {
			if (nRestriction == 0)
				nRestriction = nRestrictionTmp;
			debug(2, "nRestriction = %d\n", nRestriction);
		}
	} else {
		debug(2, "setting restriction time to zero because of profanation\n");
		nRestriction = 0;
	}


	if (fInfo) {
		debug(2, "giving restriction time info\n");
		if (nRestriction == 0) {
			printf("no restriction timeout for host %s would be activated\n", cpSystem);
			CU(DOSRC_SUCCESS);
		} else {
			printf("restriction timeout of %d minutes for host %s would be activated\n", nRestriction, cpSystem);
			CU(DOSRC_SUCCESS);
		}
	}

	if (fAlways) {
		debug(2, "setting enviroment of system \"%s\" to 'FAILED' because of 'always' option\n", cpSystem);
		sprintf(caEnvname, "%s_%s=FAILED", cpProgname, cpSystem);
		if (putenv(caEnvname) != 0)
			ulog(cpLog, cpProgname, cpSystem, "Failed to set enviroment %s", caEnvname);
	} else {
		debug(2, "getting enviroment of system \"%s\"\n", cpSystem);
		sprintf(caEnvname, "%s_%s", cpProgname, cpSystem);
		if ((cpEnvvar = getenv(caEnvname)) == NULL) {
			ulog(cpLog, cpProgname, cpSystem, "Failed to get enviroment %s", caEnvname);
			sprintf(caEnvname, "%s_%s=FAILED", cpProgname, cpSystem);
			if (putenv(caEnvname) != 0)
				ulog(cpLog, cpProgname, cpSystem, "Failed to set new enviroment %s", caEnvname);
		} else {
			if (strcmp(cpEnvvar, "SUCCESSFUL") == 0) {
				ulog(cpLog, cpProgname, cpSystem, "Abort because last time we had polled already successful");
				CU(DOSRC_SUCCESS);
			}
		}
	}

	ulog(cpLog, cpProgname, cpSystem, "OK Startup");


	debug(2, "create env of forkprocess\n");
	debug(3, "create fork msgport\n");
	if ((forkport = CreatePort(0, 0)) == NULL)
		CU(DOSRC_FAIL);
	debug(3, "alloc mem for forkprocess ID struct\n");
	if ((forkprocID = (struct ProcID *)calloc(sizeof(struct ProcID), 1)) == NULL)
		CU(DOSRC_FAIL);
	debug(3, "alloc mem for forkprocess ENV struct\n");
	if ((forkprocENV = (struct FORKENV *)calloc(sizeof(struct FORKENV), 1)) == NULL)
		CU(DOSRC_FAIL);


	debug(2, "create env of timers\n");
	debug(3, "create timer msgport");
	if ((timerport = CreatePort(0, 0)) == NULL)
		CU(DOSRC_FAIL);

	debug(3, "create IORequest struct for restriction timer\n");
	if ((timermsg_restriction = (struct timermsg *)CreateExtIO(timerport, sizeof(struct timermsg))) == NULL)
		CU(DOSRC_FAIL);
	debug(3, "open timer.device for restriction timer\n");
	if ((timerdeviceflag_restriction = OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timermsg_restriction, 0)) != NULL)
		CU(DOSRC_FAIL);

	debug(3, "create IORequest struct for survival timer\n");
	if ((timermsg_survival = (struct timermsg *)CreateExtIO(timerport, sizeof(struct timermsg))) == NULL)
		CU(DOSRC_FAIL);
	debug(3, "open timer.device for survival timer\n");
	if ((timerdeviceflag_survival = OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timermsg_survival, 0)) != NULL)
		CU(DOSRC_FAIL);

	debug(3, "create IORequest struct for delay timer\n");
	if ((timermsg_delay = (struct timermsg *)CreateExtIO(timerport, sizeof(struct timermsg))) == NULL)
		CU(DOSRC_FAIL);
	debug(3, "open timer.device for delay timer\n");
	if ((timerdeviceflag_delay = OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timermsg_delay, 0)) != NULL)
		CU(DOSRC_FAIL);


	if (nRestriction) {
		timermsg_restriction->tm_timereq.tr_node.io_Command = TR_ADDREQUEST;
		timermsg_restriction->tm_timereq.tr_time.tv_secs = nRestriction * 60;
		timermsg_restriction->tm_timereq.tr_time.tv_micro = 0;
		timermsg_restriction->tm_timermode = TIMERMODE_RESTRICTION;
		debug(2, "starting restriction timer with %d seconds\n", timermsg_restriction->tm_timereq.tr_time.tv_secs);
		SendIO((struct IORequest *)timermsg_restriction);
		active_timermsg = active_timermsg | TIMERMODE_RESTRICTION;
	}

	timermsg_survival->tm_timereq.tr_node.io_Command = TR_ADDREQUEST;
	timermsg_survival->tm_timereq.tr_time.tv_secs = SURVIVALTIME_WHOLESESSION;
	timermsg_survival->tm_timereq.tr_time.tv_micro = 0;
	timermsg_survival->tm_timermode = TIMERMODE_SURVIVAL;
	debug(2, "starting survival timer with %d seconds\n", timermsg_survival->tm_timereq.tr_time.tv_secs);
	SendIO((struct IORequest *)timermsg_survival);
	active_timermsg = active_timermsg | TIMERMODE_SURVIVAL;
	survivalmode = survivalmode | SURVIVALMODE_WHOLESESSION;


	if (fModemsetup) {
		debug(2, "setting up modem\n");
		if (!setupmodem(cpModemsetup, cpLsys, cpSystem)) {
			ulog(cpLog, cpProgname, cpSystem, "Modem setup failed");
			CU(DOSRC_FAIL);
		}
		ulog(cpLog, cpProgname, cpSystem, "Modem setup successful");
	}

	for ( ; ; ) {
		debug(2, "(re)entering outer loop (spawn loop)\n");

		if (iRetries == 0)
			ulog(cpLog, cpProgname, cpSystem, "Trying to poll host");
		else
			ulog(cpLog, cpProgname, cpSystem, "Retrying (#%d) to poll host", iRetries);

		forkprocENV->priority = (long)(PID->pr_Task.tc_Node.ln_Pri);
		forkprocENV->stack    = (long)(PID->pr_StackSize);
		forkprocENV->std_in   = (long)(PID->pr_CIS);
		forkprocENV->std_out  = (long)(PID->pr_COS);
		forkprocENV->console  = (long)(PID->pr_WindowPtr);
		forkprocENV->msgport  = forkport;

		sprintf(caCmnd, "%s -%s%s %s", UUCICO_DOSNAME, (fProfane) ? "S" : "s" ,cpSystem, cpArgs);
		debug(2, "forking: %s\n", caCmnd);
		splitarg(cpaArgv, caCmnd);

		if (forkv(UUCICO_DOSNAME, cpaArgv, forkprocENV, forkprocID) == -1) {
			ulog(cpLog, cpProgname, cpSystem, "FAILED because cannot fork %s %s", UUCICO_DOSNAME, caCmnd);
			CU(DOSRC_FAIL);
		}

		for ( ; ; ) {
			debug(2, "(re)entering inner loop (wait loop)\n");

			debug(2, "go sleeping until wakeup\n");
			timerport_sigmask = 1L << timerport->mp_SigBit;
			forkport_sigmask = 1L << forkport->mp_SigBit;
			signals = Wait( (ULONG)(timerport_sigmask | forkport_sigmask | SIGBREAKF_CTRL_C) );


			if (signals & timerport_sigmask) {
				debug(2, "awakened through timer interrupt\n");
				if (pMsg = (struct timermsg *)GetMsg(timerport)) {

					if (pMsg->tm_timermode == TIMERMODE_SURVIVAL) {
						active_timermsg = active_timermsg & ~(TIMERMODE_SURVIVAL);

						if (survivalmode == SURVIVALMODE_ABORTION) {
							ulog(cpLog, cpProgname, cpSystem, "interupted due to survival timeout for uucico abortion");
							survivalmode = survivalmode & ~(SURVIVALMODE_ABORTION);
							CU(DOSRC_FAIL);
                        }
						if (survivalmode == SURVIVALMODE_WHOLESESSION) {
							ulog(cpLog, cpProgname, cpSystem, "interupted due to survival timeout for whole session");
							survivalmode = survivalmode & ~(SURVIVALMODE_WHOLESESSION);
							CU(DOSRC_FAIL);
    					}
						continue;
					}

					if (pMsg->tm_timermode == TIMERMODE_RESTRICTION) {

						ulog(cpLog, cpProgname, cpSystem, "interupted due to restriction timeout of %d minute%s", nRestriction, (nRestriction != 1) ? "s" : "" );
						ulog(cpLog, cpProgname, cpSystem, "sending break signal to abort uucico process");
						Signal((struct Task *)(forkprocID->process), SIGBREAKF_CTRL_C);

						debug(2, "cancelling currently active survival timer\n");
						AbortIO((struct IORequest *)timermsg_survival);
						WaitIO((struct IORequest *)timermsg_survival);
						timermsg_survival->tm_timereq.tr_node.io_Command = TR_ADDREQUEST;
						timermsg_survival->tm_timereq.tr_time.tv_secs = SURVIVALTIME_ABORTION;
						timermsg_survival->tm_timereq.tr_time.tv_micro = 0;
						timermsg_survival->tm_timermode = TIMERMODE_SURVIVAL;
						debug(2, "starting survival timer with %d seconds for abortion process\n", timermsg_survival->tm_timereq.tr_time.tv_secs);
						SendIO((struct IORequest *)timermsg_survival);
						active_timermsg = active_timermsg | TIMERMODE_SURVIVAL;
						survivalmode = survivalmode | SURVIVALMODE_ABORTION;

						fUuxqt = TRUE;
						debug(3, "fUuxqt = TRUE\n");
						continue;
					}

					if (pMsg->tm_timermode == TIMERMODE_DELAY) {

						ulog(cpLog, cpProgname, cpSystem, "interupted due to delay timer of %d second%s", nDelay, (nDelay != 1) ? "s" : "" );
						active_timermsg = active_timermsg & ~(TIMERMODE_DELAY);
						break;
					}

				}
			}

			if (signals & SIGBREAKF_CTRL_C) {
				debug(2, "awakened through ctrl-c signal\n");

				ulog(cpLog, cpProgname, cpSystem, "interupted due to ctrl-c signal");
				ulog(cpLog, cpProgname, cpSystem, "sending break signal to abort uucico process");
				Signal((struct Task *)(forkprocID->process), SIGBREAKF_CTRL_C);

				debug(2, "cancelling currently active survival timer\n");
				AbortIO((struct IORequest *)timermsg_survival);
				WaitIO((struct IORequest *)timermsg_survival);
				timermsg_survival->tm_timereq.tr_node.io_Command = TR_ADDREQUEST;
				timermsg_survival->tm_timereq.tr_time.tv_secs = SURVIVALTIME_ABORTION;
				timermsg_survival->tm_timereq.tr_time.tv_micro = 0;
				timermsg_survival->tm_timermode = TIMERMODE_SURVIVAL;
				debug(2, "starting survival timer with %d seconds for abortion process\n", timermsg_survival->tm_timereq.tr_time.tv_secs);
				SendIO((struct IORequest *)timermsg_survival);
				active_timermsg = active_timermsg | TIMERMODE_SURVIVAL;
				survivalmode = survivalmode | SURVIVALMODE_ABORTION;

				fUuxqt = TRUE;
				debug(3, "fUuxqt = TRUE\n");
				continue;
			}


			if (signals & forkport_sigmask) {
				debug(2, "awakened through forkprocess termination\n");

				rc = wait(forkprocID);

				if (rc == 0) {
					debug(2, "uucico was succesfull\n");
					ulog(cpLog, cpProgname, cpSystem, "finished (polling was successful)");

					debug(2, "setting enviroment to 'SUCCESSFUL'\n");
					sprintf(caEnvname, "%s_%s=SUCCESSFUL", cpProgname, cpSystem);
					if (putenv(caEnvname) != 0)
						ulog(cpLog, cpProgname, cpSystem, "Failed to set enviroment %s", caEnvname);

					fUuxqt = TRUE;
					debug(3, "fUuxqt = TRUE\n");
					CU(DOSRC_SUCCESS);
				}

				if (rc == 5) {
					debug(2, "uucico failure in call and/or protocol\n");
					iRetries++;
					if (iRetries > nRetriesMax) {
						if (nRetriesMax != 0)
							ulog(cpLog, cpProgname, cpSystem, "stopped due to max retries of %d", nRetriesMax);
						debug(2, "setting enviroment to 'FAILED'\n");
						sprintf(caEnvname, "%s_%s=FAILED", cpProgname, cpSystem);
						if (putenv(caEnvname) != 0)
							ulog(cpLog, cpProgname, cpSystem, "Failed to set enviroment %s", caEnvname);

						CU(DOSRC_FAIL);
					}

					if (nDelay) {
						timermsg_delay->tm_timereq.tr_node.io_Command = TR_ADDREQUEST;
						timermsg_delay->tm_timereq.tr_time.tv_secs = nDelay;
						timermsg_delay->tm_timereq.tr_time.tv_micro = 0;
						timermsg_delay->tm_timermode = TIMERMODE_DELAY;
						debug(2, "starting delay timer with %d seconds for retry procedure\n", timermsg_delay->tm_timereq.tr_time.tv_secs);
						SendIO((struct IORequest *)timermsg_delay);
						active_timermsg = active_timermsg | TIMERMODE_DELAY;
						continue;
					}
					break;
				}

				debug(2, "uucico break/software failure\n");

				debug(2, "setting enviroment to 'FAILED'\n");
				sprintf(caEnvname, "%s_%s=FAILED", cpProgname, cpSystem);
				if (putenv(caEnvname) != 0)
					ulog(cpLog, cpProgname, cpSystem, "Failed to set enviroment %s", caEnvname);

				fUuxqt = TRUE;
				debug(3, "fUuxqt = TRUE\n");
    			CU(DOSRC_FAIL);
			}

		}
	}

CUS:
	if (fUuxqt) {
		ulog(cpLog, cpProgname, cpSystem, "Spawning %s", UUXQT_DOSNAME);
		sprintf(caCmnd, "run >nil: <nil: %s", UUXQT_DOSNAME);
		if (Execute(caCmnd, NULL, NULL) == 0)
			ulog(cpLog, cpProgname, cpSystem, "Error spawning %s", UUXQT_DOSNAME);
	}

	if (active_timermsg & TIMERMODE_DELAY) {
		debug(2, "aborting delay timer\n");
		AbortIO((struct IORequest *)timermsg_delay);
		WaitIO((struct IORequest *)timermsg_delay);
		active_timermsg = active_timermsg & ~(TIMERMODE_DELAY);
	}

	if (active_timermsg & TIMERMODE_RESTRICTION) {
		debug(2, "aborting restriction timer\n");
		AbortIO((struct IORequest *)timermsg_restriction);
		WaitIO((struct IORequest *)timermsg_restriction);
		active_timermsg = active_timermsg & ~(TIMERMODE_RESTRICTION);
	}

	if (active_timermsg & TIMERMODE_SURVIVAL) {
		debug(2, "aborting survival timer\n");
		AbortIO((struct IORequest *)timermsg_survival);
		WaitIO((struct IORequest *)timermsg_survival);
		active_timermsg = active_timermsg & ~(TIMERMODE_SURVIVAL);
	}

	debug(2, "delete env of timers\n");
	if (timerdeviceflag_delay) {
		debug(3, "closing timer.device of delay timer\n");
		CloseDevice((struct IORequest *)timermsg_delay);
	}
	if (timerdeviceflag_restriction) {
		debug(3, "closing timer.device of restriction timer\n");
		CloseDevice((struct IORequest *)timermsg_restriction);
	}
	if (timerdeviceflag_survival) {
		debug(3, "closing timer.device of survival timer\n");
		CloseDevice((struct IORequest *)timermsg_survival);
	}
	if (timerport) {
		debug(3, "delete timer msgport\n");
		DeletePort(timerport);
	}
	if (timermsg_delay) {
		debug(3, "delete IORequest struct of delay timer\n");
		DeleteExtIO((struct IORequest *)timermsg_delay);
	}
	if (timermsg_restriction) {
		debug(3, "delete IORequest struct of delay timer\n");
		DeleteExtIO((struct IORequest *)timermsg_restriction);
	}
	if (timermsg_survival) {
		debug(3, "delete IORequest struct of delay timer\n");
		DeleteExtIO((struct IORequest *)timermsg_survival);
	}

	debug(2, "delete env of forkprocess\n");
	if (forkport) {
		debug(3, "delete fork msgport\n");
		DeletePort(forkport);
	}
	if (forkprocENV) {
		debug(3, "freeing mem for ENV of forkprocess\n");
		free(forkprocENV);
	}
	if (forkprocID) {
		debug(3, "freeing mem for ENV of forkprocess\n");
		free(forkprocID);
	}

	ulog(cpLog, cpProgname, (cpSystem) ? cpSystem : "-", "OK Exit");
	debug(3, "rc = %d\n", rc);
	debug(2, "exit\n");
	return rc;
}

