#ifndef STANDALONE
#include <stdio.h>
#ifdef MSDOS
#include <dir.h>
#include <dos.h>
#endif
#include <string.h>
#include <time.h>
#include "config.h"
#include "global.h"
#include "files.h"
#include "mailbox.h"
#include "socket.h"
#include "ftp.h"
#include "ax25.h"
#include "session.h"
#include "dirutil.h"
#include "cmdparse.h"
#include "usock.h"
#include "pktdrvr.h"
#include "commands.h"
#endif

#ifdef TUTOR
static struct world	{
	int mode;
	char color;
	char colorblock;
	char last[2];
	char inescape;
	char ipconnect;
	char *subdir;
	char *call;
	long starttime;
	int  ischild;
#ifndef STANDALONE
	struct mbx *m;
#endif
	FILE *fp;
	FILE *out;
	char *Tutors[100];
	int maxselect;
	char *variables[10];
	long indexes[10];
#ifdef old
	int socket[10];
#else
	int *socket;
#endif
	int user;
	int whichsocket;
	int background;
	int goback;
	char Error[80];
};

#ifndef STANDALONE
int Tutored = 0;
extern int Stutor, Sinfo, Snews, Tutorlogins[];
extern char Tcall[AXALEN], Icall[AXALEN], Ncall[AXALEN];
extern int rdaemon __ARGS((FILE *data,char *from, char *to, char *msg, char msgtype, int mode));
#endif
#endif

extern int colorchange __ARGS((register char *input, register char *last));
extern int colorprintf __ARGS((char *escapeflag, char usecolor, unsigned char *str));
extern void colorfile __ARGS((char *filenm, char *last));
extern int sockblock __ARGS((int s, int value));
extern void parseheader __ARGS((FILE *fp,char *from, char *subject, char *buf,long *startat));

static void mycolorchange __ARGS((struct world *here,char *input, char *last));
static void mytprintf __ARGS((struct world *here,unsigned char *str));
char *skipwhite __ARGS((char *cp));
char *skipnonwhite __ARGS((char *cp));
#ifdef TUTOR
#ifndef STANDALONE
static void mygets __ARGS((char *buf,int size,struct world *here));
#else
void mygets __ARGS((char *buf, int size, struct world *here));
#endif
static char *nextarg __ARGS((char *cp,long *i));
static char *nextnum __ARGS((char *cp,int defval,struct world *here,long *i));
static long getnum __ARGS((char *cp,int defval,struct world *here));
static int scriptconn __ARGS((int argc,char *argv[],void *p));
static char *getnext __ARGS((char *cp, char **put,struct world *here));
static void process __ARGS((struct world *here));
static void buildmenu __ARGS((struct world *here));
#ifndef STANDALONE
void tutorserv __ARGS((char *call,struct mbx *m,int mode, int color, int ip));
#else
void tutorserv __ARGS((char *call,int mode, int color, int ip));
#endif
int scriptcmd __ARGS((struct world *inherited,FILE *fp,char *name));
int doscript __ARGS((int argc,char *argv[],void *p));
#ifndef STANDALONE
int dombscript __ARGS((int argc,char *argv[],void *p));
int proxy __ARGS((FILE *fp,char *from));
void mbscripthook __ARGS((struct mbx *m,char *hookfile));
#endif
#endif /* TUTOR */


static void
mycolorchange (here, input, last)
struct world *here;
char *input, *last;
{
	if (here->color)
		colorchange (input, last);
}


static void
mytprintf (here, str)
struct world *here;
unsigned char *str;
{
	if (here->background && !here->whichsocket)
		return;
	if (!here->colorblock)
		tprintf (str);
	else
		if (colorprintf (&here->inescape, here->color, str))
			here->last[0] = 0;
}


char *
skipwhite (cp)
char *cp;
{
	while (*cp && (*cp == ' ' || *cp == '\t'))
		cp++;
	return (cp);
}


char *
skipnonwhite (cp)
char *cp;
{
	while (*cp && *cp != ' ' && *cp != '\t')
		cp++;
	return (cp);
}


#ifdef TUTOR
#ifndef STANDALONE
#if 1
int
tutor_recvline(s, buf, size)
int s;
char *buf;
unsigned size;
{
char *origbuf = buf;
int c, cnt = 0, opt, cl;

	usflush(Curproc->output);
	while((c = recvchar(s)) != EOF){
		pwait(NULL);
		if(c == IAC){		/* Telnet command escape */
			if((c = recvchar(s)) == EOF)
				break;
			if(c >= 250 && c < 255 && (opt = recvchar(s)) != EOF){
			    switch(c){
				case SB:
					opt=recvchar(s);
					if(opt==EOF)	break;
					cl=opt;
					c=recvchar(s);
					while((c!=EOF) && !(cl==IAC && c==SE)){
						cl=c;
						c=recvchar(s);
					}
					break;
				case WILL:
					if(opt==TN_LINEMODE){
						tprintf("%c%c%c",IAC,DO,opt);
						tprintf("%c%c%c%c%c%c%c",IAC,SB,TN_LINEMODE,1,1,IAC,SE);
					}
					else	{
						tprintf("%c%c%c",IAC,DONT,opt);
					}
					break;
				case WONT:
					tprintf("%c%c%c",IAC,DONT,opt);
					break;
				case DO:
					tprintf("%c%c%c",IAC,WONT,opt);
					break;
				case DONT:
					tprintf("%c%c%c",IAC,WONT,opt);
			    }
			    usflush(Curproc->output);
			    pwait(NULL);
			    continue;
			}
			if(c != IAC && (c = recvchar(s)) == EOF)
				break;
		}
		*buf++ = c;
		++cnt;
		if(c == '\n')
			break;
	        if(cnt == (size - 1))	{
        		cnt = -2;
			break;
		}
		/* the following is a special case HACK for telnet logins */
		if (!strncmp (origbuf, "login: ", 7) || !strncmp (origbuf, "Password: ", 10))
			break;
	}
	if(c == EOF && cnt == 0)
		return -1;
	*buf = '\0';
    return cnt;
}
#endif



static void
mygets (buf, size, here)
char *buf;
int size;
struct world *here;
{
	if ((here->background && !here->whichsocket) || here->user < 0)	{
		buf[0] = 0;
		return;
	}
	usflush(Curproc->output);
#ifdef MBXTDISC
	/* Restart the inactivity timer */
	if (here->m != NULLMBX)
		start_timer(&here->m->tdisc);
#endif


#if 1
	if((size = tutor_recvline (here->user ? here->user : Curproc->input, buf, (unsigned)size)) < 0)	{
#else
	if((size = recvline (here->user ? here->user : Curproc->input, buf, (unsigned)size)) <= 0)	{
#endif
		if (here->user > 0)	{
			here->socket[here->whichsocket] = here->user = -1;
			Curproc->output = here->socket[0];
		}
		buf[0] = 0;
	}
	rip (buf);
}
#endif /* STANDALONE */


static char *
nextarg (cp, i)
char *cp;
long *i;
{
	cp = skipnonwhite(cp);
	cp = skipwhite (cp);
	*i = atol (cp);
	return (cp);
}


static char *
nextnum (cp, defval, here, i)
char *cp;
int defval;
long *i;
struct world *here;
{
	cp = skipnonwhite(cp);
	cp = skipwhite (cp);
	*i = getnum (cp, defval, here);
	return (cp);
}


static long
getnum (cp, defval, here)
char *cp;
int defval;
struct world *here;
{
long l = defval;

	switch (*cp)	{
		case '~':	if (tolower (cp[1]) == 'i')	{
					l = here->indexes[cp[2] - '0'];
					break;
				}
				if (cp[1] >= '0' && cp[1] <= '9')	{
					l = atol (here->variables[cp[1] - '0']);
					break;
				}
		case 0:		break;
		default:	l = atol (cp);
				break;
	}
	return l;
}


static char SCONFail[] = "SCRIPT connect failed: ";
static char SCONFail2[] = "SCRIPT disconnect failed: ";


/* open a network connection based upon information in the cc line.
 * m->user is set to the socket number.
 */
static int
scriptconn(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct world *here;
char sock[MAXSOCKSIZE];
union sp sp;
char ctype;
struct iface *ifp;
char digis[MAXDIGIS][AXALEN];
char target[AXALEN];
int ndigis, i, len;

	here = (struct world *)p;
	sp.p = sock;
	here->Error[0] = 0;	/* null error string */
	ctype = tolower(*argv[0]);
	if (argc < 2)	{
		sprintf (here->Error, "%sSyntax Error", SCONFail);
		return -1;
	}

	switch (ctype)	{
#ifdef AX25
		case 'a':
		case 'c':	/* allow 'c' for 'connect' as well */
			if( ((ifp = if_lookup(argv[1])) == NULLIF) || (ifp->flags & HIDE_PORT)) {
			sprintf(here->Error, "%sUnknown port %s",SCONFail, argv[1]);
				return -1;
			}
			if(ifp->type != CL_AX25){
				sprintf(here->Error, "%sPort %s not usable for AX.25 connects",SCONFail, argv[1]);
				return -1;
			}
			if(setcall(target,argv[2]) == -1){
				sprintf(here->Error, "%sBad call %s",SCONFail, argv[2]);
				return -1;
			}

			/* If digipeaters are given, put them in the routing table */
			if(argc > 3)	{
				ndigis = argc - 3;
				if(ndigis > MAXDIGIS)	{
					sprintf (here->Error, "%sToo many digipeaters", SCONFail);
					return -1;
				}
				for(i=0;i<ndigis;i++)	{
					if(setcall(digis[i],argv[i+3]) == -1)	{
						sprintf(here->Error, "%sBad digipeater call %s",SCONFail, argv[i+3]);
						return -1;
					}
				}
				if(ax_add(target,AX_AUTO,digis,ndigis,ifp) == NULLAXR)	{
					sprintf(here->Error, "%sAX25 route add failed", SCONFail);
					return -1;
				}
			}

			sp.ax->sax_family = AF_AX25;
			strncpy(sp.ax->iface,argv[1],ILEN); /* the interface name */
			setcall(sp.ax->ax25_addr,argv[2]); /* the remote callsign */
			if((here->user = socket(AF_AX25,SOCK_STREAM,0)) == -1)	{
				sprintf (here->Error, "%sError allocating socket", SCONFail);
				return -1;
			}
			len = sizeof(*sp.ax);
			break;
#endif
		default:
			sp.in->sin_family = AF_INET;
			if((sp.in->sin_addr.s_addr = resolve(argv[1])) == 0)	{
				sprintf (here->Error, "%sHost Unknown", SCONFail);
				return -1;
			}
			/* get the optional port number */
			if(argc > 2)
				sp.in->sin_port = atoip(argv[2]);
			else
				sp.in->sin_port = IPPORT_TELNET;
			if((here->user = socket(AF_INET,SOCK_STREAM,0)) == -1)	{
				sprintf (here->Error, "%sError allocating socket", SCONFail);
				return -1;
			}
			len = sizeof(*sp.in);
	}

	sockmode(here->user,SOCK_ASCII);
#if 1
	sockblock(here->socket[0], SOCK_NOTXBLOCK);
	if(connect(here->user,sp.p,SOCKSIZE) == -1) {
#else
	if(connect(here->user,sp.p,len) == -1) {
#endif
		sprintf (here->Error, "SCRIPT connect failed: %s errno %d",
				sockerr(here->user),errno);
		close_s(here->user);
		return -1;
	}
	return here->user;
}


static struct cmds sconcmds[] = {
	"tcp",		scriptconn,	0, 0, NULLCHAR,
	"telnet",	scriptconn,	0, 0, NULLCHAR,
#ifdef AX25
	"ax25",		scriptconn,	0, 0, NULLCHAR,
	"connect",	scriptconn,	0, 0, NULLCHAR,
#endif
	NULLCHAR
};



static char *
getnext (cp, put, here)
char *cp, **put;
struct world *here;
{
char *retval = cp, buf[4], c;
time_t tm;

	buf[1] = 0;
	if (*cp != '~')		{
		buf[0] = *cp;
		*put = strdup (buf);
	} else	{
		cp++;
		retval++;
		c = tolower (*cp);
		time (&tm);
		cp = ctime (&tm);
		rip (cp);
		cp[10] = cp[19] = 0;
		switch (c)	{
			case 'l':	/* elapsed time of script */
					*put = malloc (20);
					sprintf (*put, "%-ld", (tm - here->starttime));
					break;
			case 'p':	/* current data file position */
					*put = malloc (20);
					if (here->out)
						sprintf (*put, "%-ld", ftell(here->out));
					else
						strcpy (*put, "-1");
					break;
			case 'c':	*put = strdup (here->call);
					break;
			case 'e':	*put = strdup (here->Error);
					break;
			case '~':	
			case 'b':	buf[0] = (c == 'b') ? '\007' : *retval;
					*put = strdup (buf);
					break;
			case 'h':	*put = strdup (Hostname);
					break;
			case 'd':	strcat (cp, ", ");
					strcat (cp, &cp[20]);
					*put = strdup (cp);
					break;
			case 't':	*put = strdup (&cp[11]);
					break;
			case 'n':	buf[0] = '\n';
					*put = strdup (buf);
					break;
			case 'u':	/* un-terminate this line */
					rip (retval);
					buf[0] = *(++retval);
					*put = strdup (buf);
					break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':	if (here->variables[c - '0'])
						*put = strdup (here->variables[c - '0']);
					else
						*put = strdup ("");
					break;
			case 'i':	if (retval[1] >= '0' &&  retval[1] <= '9')	{
						*put = malloc (20);
						sprintf (*put, "%-ld", here->indexes[*(++retval) - '0']);
						break;
					}
					/* else fall through */
			default:	sprintf (buf, "~%c", *retval);
					*put = strdup (buf);
					break;
		}
	}
	return (retval);
}


static void
process (here)
struct world *here;
{
FILE *fp;
int done = 0, skipping = 0, k, disconexit = 1;
long j, i, l;
char buf[256], c, *cp, lastresponse = 'y', *label = 0;
char *put;
long pos;

	time (&here->starttime);
	if (!here->ischild)	{
#if 0
		for (k = 0; k < 10; k++)	{
			here->variables[k] = 0;
			here->indexes[k] = 1;
			here->socket[k] = 0;
		}
#endif
	} else	{
		here->user = 0;
		disconexit = 0;
	}

	here->socket[0] = Curproc->output;
#if 0
	if (here->user)		{	/* inherited a socket from a parent script! */
		Curproc->output = here->socket[1] = here->user;
		here->whichsocket = 1;

		Curproc->output = here->socket[here->whichsocket];
		disconexit = 0;
	}
#endif

	while (!done && fgets (buf, 256, here->fp))	{
#ifdef MBXTDISC
		/* Restart the inactivity timer */
		if (here->m != NULLMBX)
			start_timer(&here->m->tdisc);
#endif
		pwait (NULL);
		if (buf[0] != '~' || ((buf[1] == '~') || isdigit(buf[1])))	{
			if (!skipping)	{
				cp = buf;
				while (*cp)	{
					cp = getnext (cp, &put, here);
					mytprintf (here, put);
					free (put);
					cp++;
				}
			}
			continue;
		}
		c = tolower (buf[1]);
		cp = skipwhite (&buf[2]);
		rip (cp);
		if (skipping && c != 'l')
			continue;
		k = *cp - '0';
		switch (c)	{
			case 'i':	/* modify an index counter
					   index array in k, already */
					cp++;
					rip (cp);
					cp = skipwhite (cp);
					c = *cp++;
					cp = skipwhite (cp);
					if (!strnicmp (cp, "~p", 2))	{
						if (here->out)
							l = ftell (here->out);
						else
							l = -1;
					} else
						l = getnum (cp, 1, here);
					switch (c)	{
						case '=':	/* assign */
								here->indexes[k] = l;
								break;
						case '+':	/* add */
								here->indexes[k] += l;
								break;
						case '-':	/* subtract */
								here->indexes[k] -= l;
								break;
						case '?':	/* compare */
								c = lastresponse = (here->indexes[k] == l) ? 'y' : 'n';
								cp = skipnonwhite (cp);
								cp = skipwhite (cp);
								if (*cp && c == 'y')
									goto another;
								break;
					}
					break;
another:		case 'y':	/* on yes, goto label */
			case 'n':	/* on no, goto label */
					if (lastresponse != c)
						break;
			case 'g':	/* goto label */
					skipping = 1;
					free (label);
					label = strdup (cp);
					rewind (here->fp);
					break;
			case 'l':	/* label line */
					if (skipping && !stricmp (cp, label))	{
						free (label);
						label = 0;
						skipping = 0;
					}
					break;
			case 'b':	/* output 'n' blank lines */
					k = (int) getnum (cp, 0, here);
					if (!k)
						k = 1;
					while (k--)
						mytprintf (here, "\n");
					break;
			case 'm':	/* more prompt */
					mytprintf (here, "\n---MORE (*y/n)---\n");
					mygets (buf, 256, here);
					pwait (NULL);
					if (tolower (buf[0]) != 'n')
						break;
			case 'x':	/* exit at this point */
/*					done = 1;	*/
					skipping = 1;
					free (label);
					label = strdup ("exit");
					break;
			case 'q':	/* query with string for y/n answer */
					mytprintf (here, cp);
					mytprintf (here, " (*y/n)\n");
					mygets (buf, 256, here);
					pwait (NULL);
					lastresponse = (tolower (buf[0]) == 'n') ? 'n' : 'y';
					break;
			case 'j':	/* just compare first characters */
			case 'c':	/* compare entire strings
					   first string value in k, already */
					cp = nextarg (cp, &l);
					if (!here->variables[l] || !here->variables[k])
						lastresponse = 'n';
					else	{
						if (c == 'c')
							c = lastresponse = (stricmp (here->variables[l], here->variables[k])) ? 'n' : 'y';
						else	{
							cp = nextnum (cp, 0, here, &j);
							c = lastresponse = (strnicmp (here->variables[l], here->variables[k], (unsigned)j)) ? 'n' : 'y';
						}
						cp = skipnonwhite (cp);
						cp = skipwhite (cp);
						if (*cp && c == 'y')
							goto another;
					}
					break;
			case 'h':	/* string has substring?
					   first string value in k, already */
					cp = nextarg (cp, &l);
					if (!here->variables[l] || !here->variables[k])
						lastresponse = 'n';
					else	{
						i = (int) strstr (here->variables[k], here->variables[l]);
						c = lastresponse = (!i) ? 'n' : 'y';
						if (i)
							i -= (int) here->variables[k];
						cp = nextarg (cp, &j);
						here->indexes[j] = i;
						cp = skipnonwhite (cp);
						cp = skipwhite (cp);
						if (*cp && c == 'y')
							goto another;
					}
					break;
			case 'p':	/* pick out a sub-string
					   to variable already in k */
					cp = nextarg (cp, &j);		/* from variable */
					cp = nextnum (cp, 0, here, &i);	/* start index */
					cp = nextnum (cp, 0, here, &l);	/* length */
					if ((strlen(here->variables[j]) - i) < l)
						l = strlen (here->variables[j]) - i;
					l++;	/* allow room for zero byte */
					free (here->variables[k]);
					here->variables[k] = malloc ((unsigned)l);
					strncpy (here->variables[k], &here->variables[j][i], (unsigned)l);
					here->variables[k][l - 1] = 0;
					break;
			case 't':	/* truncate a variable string */
					cp = nextnum (cp, 0, here, &j);
					if (strlen (here->variables[k]) > j)
						here->variables[k][j] = 0;
					break;
			case 'z':	/* get length of variable and place in index */
					cp = nextarg (cp, &j);
					here->indexes[j] = (here->variables[k]) ? strlen (here->variables[k]) : 0;
					break;
			case 'a':	/* assign a string to a variable */
					/* or append if 'ap str1 str2' */
					if ((cp == &buf[2]) && (tolower(*cp) == 'p'))	{
						cp = skipwhite(++cp);
						if (*cp)	{
							k = *cp - '0';
							cp = skipwhite(++cp);
							if (*cp)	{
								l = *cp - '0';
								cp = malloc (strlen(here->variables[k]) + 
									strlen(here->variables[l]) + 1);
								strcpy (cp, here->variables[k]);
								strcat (cp, here->variables[l]);
								free (here->variables[k]);
								here->variables[k] = cp;
							}
						}
						break;
					} /* else fall through */
			case 'v':	/* prompt and place result in variable */
					free (here->variables[k]);
					cp++;
					cp = skipwhite (cp);
					if (c == 'a')	{
						if (*cp == '~')
							getnext (cp, &here->variables[k], here);
						else
							here->variables[k] = strdup(cp);
					} else	{
						if (*cp)	{
							mytprintf (here, cp);
							mytprintf (here, "\n");
						}
						mygets (buf, 256, here);
						pwait (NULL);
						here->variables[k] = strdup (buf);
					}
					break;
			case 'd':	/* deliver a mail file */
					getnext(cp, &put, here);	/* allow ~c and ~# subs */
					if (strlen (put) == 1)	{
						char *cp2;
						free (put);
						put = strdup (cp);
						cp2 = strchr (put, ' ');
						*cp2 = 0;
					}
					lastresponse = 'n';	/* default to fails */
					/* get filename and open it */
					cp = strchr (cp, ' ');
					if (cp)		{	/* if filename given */
						FILE *out2;
						*cp++ = 0;
						out2 = NULLFILE;
						if (stricmp (cp, "null"))
							out2 = fopen (cp, READ_TEXT);
						/* save current pos, and get tutor description */
						pos = ftell(here->fp);
						rewind (here->fp);
						fgets (buf, 256, here->fp);
						fseek (here->fp, pos, SEEK_SET);
						cp = skipwhite (buf);
						rip (cp);
						/* now mail the file */
						rdaemon (out2, NULLCHAR, put, cp, 'P', 0);
						lastresponse = 'y';
						if (out2 != NULLFILE)
							fclose (out2);
					}
					free (put);
					break;
						
			case 'e':	/* is io file at end of file */
					if (here->out != NULLFILE)	{
						c = lastresponse = (feof (here->out)) ? 'y' : 'n';
						if (*cp && c == 'y')
							goto another;
					}
					break;
			case 's':	/* seek to start of io file */
					if (here->out != NULLFILE)	{
						switch (tolower (*cp))	{
							case 'e':	fseek (here->out, 0L, 2);
									break;
							case 'p':	cp = skipwhite(++cp);
									if (*cp)	{
										k = *cp - '0';
										fseek (here->out, here->indexes[k], 0);
										break;
									} /* else, fall through */
							default:	rewind (here->out);
						}
					}
					break;
			case 'u':	/* upload a text file */
					if ((fp = fopen (cp, READ_TEXT)) != NULLFILE)	{
#ifndef STANDALONE
						sendfile (fp, Curproc->output, ASCII_TYPE, 0);
#else
						sendfile (fp);
#endif
						fclose (fp);
					}
					break;
			case 'o':	/* open an old io file */
			case 'f':	/* create a new io file */
					if (here->out != NULLFILE)
						fclose (here->out);
					here->out = NULLFILE;
					if(*cp == '~' && isdigit(cp[1]))
						cp = here->variables[cp[1] - '0'];
					here->out = fopen (cp, (c == 'f') ? CREATE_TEXT : UPDATE_TEXT);
					lastresponse = (here->out == NULLFILE) ? 'n' : 'y';
					break;
			case 'w':	/* write a textline to the io file */
					if (here->out != NULLFILE)
						while (*cp)	{
							cp = getnext (cp, &put, here);
							fprintf (here->out, put);
 							free (put);
							cp++;
						}
					break;
			case 'r':	/* read a line from io file in var */
					if (here->out != NULLFILE)	{
						free (here->variables[k]);
						fgets (buf, 256, here->out);
						rip (buf);
						here->variables[k] = strdup(buf);
					}
					break;
			case 'k':	/* kill a file */
					unlink (cp);
					lastresponse = (access (cp, 0)) ? 'y' : 'n';
					break;
			case '?':	switch (tolower (*cp))	{
						case 'c':	lastresponse = (!here->color) ? 'n' : 'y';
								break;
						case 'i':	lastresponse = (here->ipconnect) ? 'y' : 'n';
								break;
					}
					break;
			case '!':	switch (tolower (*cp))	{
						case 'c':	here->color = 1;
								break;
					}
					break;
			case '*':	switch (tolower (*cp))	{
						case 'b':	here->colorblock = 1;
								break;
						case 'e':	here->colorblock = 0;
								break;
					}
					break;
			case '%':	lastresponse = (!here->color) ? 'n' : 'y';
					if (here->color)
						colorfile (cp, here->last);
					break;
			case '@':	mycolorchange (here, cp, here->last);
					break;
			case '$':	{
					char *args[2];
					int lastback;

						lastback = here->goback;
						here->goback = 0;
						if (*cp == '$')	{
							here->goback = 1;
							cp = skipwhite (++cp);
						}
						args[1] = cp;
						if(access(cp,4))
							lastresponse = 'n';
						else	{
							Curproc->output = here->socket[0];
							doscript (0, args, here);
							lastresponse = 'y';
							Curproc->output = here->socket[0];
						}
						here->goback = lastback;
					}
					break;
			case ')':	lastresponse = 'n';
					if (!k)
						sprintf (here->Error, "%scan't close stream 0", SCONFail2);
					else if (here->socket[k] <= 0)
						sprintf (here->Error, "%sstream %d not connected", SCONFail2, k);
					else	{
						lastresponse = 'y';
						here->Error[0] = 0;
						if(socklen(here->socket[k],0)) /* discard any remaining input */
							recv_mbuf(here->socket[k],NULL,0,NULLCHAR,0);
						shutdown(here->socket[k],1);
						close_s (here->socket[k]);
						if (Curproc->output == here->socket[k])	{
							Curproc->output = here->socket[0];
	 						here->user = here->whichsocket = 0;
						}
						here->socket[k] = 0;
					}
					break;
			case '#':	lastresponse = 'n';
					if (k && here->socket[k] < 0)
						sprintf (here->Error, "%sstream %d not connected", SCONFail, k);
					else	{
						lastresponse = 'y';
 						Curproc->output = here->socket[k];
 						here->user = (k) ? here->socket[k] : 0;
 						here->whichsocket = k;
					}
					break;
			case '(':	lastresponse = 'n';
					if (here->socket[k])
						sprintf (here->Error, "%sstream %d already connected", SCONFail2, k);
					else	{
						cp = skipnonwhite(cp);
						cp = skipwhite (cp);
						if ((here->socket[k] = cmdparse(sconcmds,cp,(void *)here)) != -1)
							lastresponse = 'y';
						else
							here->socket[k] = 0;
					}
					break;
			case '=':	lastresponse = (here->socket[k] > 0) ? 'y' : 'n';
					break;
			default:	break;
		}
	}
	if (here->out != NULLFILE)	{
		fclose (here->out);
		here->out = NULLFILE;
	}
	free (label);
/*	Curproc->output = here->socket[0]; */
	for (k = 0; k < 10; k++)	{
		if (here->variables[k])
			if (!here->ischild || k < 5)
				free (here->variables[k]);
#if 1
		if (disconexit && k && here->socket[k] > 0)	{	/* free connected streams */
			if(socklen(here->socket[k],0)) /* discard any remaining input */
				recv_mbuf(here->socket[k],NULL,0,NULLCHAR,0);
			shutdown(here->socket[k],1);
			close_s (here->socket[k]);
			here->socket[k] = 0;
		}
#endif
	}
	here->user = 0;	
	here->whichsocket = 0;
}


static char *tutorialName[] = {"Learning Center", "Information Center", "News Center"};
static char banner[] = "For %s, connect to '%s' using the same path...\n";

static void
buildmenu (here)
struct world *here;
{
FILE *fp;
char buf[80], buf2[256], *cp;
struct ffblk ff;

	here->maxselect = 0;
	if (here->subdir)
		tprintf ("Current Sub-directory: %s\n\n", here->subdir);
	mycolorchange (here, "0F", here->last);
	tprintf ("\nWelcome to the ");
	mycolorchange (here, "0C", here->last);
	tprintf ("TNOS %s ",tutorialName[here->mode]);
	mycolorchange (here, "0F", here->last);
	tprintf ("at ");
	mycolorchange (here, "05", here->last);
	tprintf ("%s\n\n     %c", Hostname,here->subdir ? 'E' : '0');
	mycolorchange (here, "07", here->last);
	tprintf (" -  Exit %s\n", tutorialName[here->mode]);
	mycolorchange (here, "05", here->last);
	tprintf ("     %c", (here->subdir) ? '0' : 'C');
	mycolorchange (here, "07", here->last);
	if (here->subdir)
		tputs (" -  Return to Previous Menu\n");
	else
		tprintf (" -  %sable ANSI Color Graphics\n", (here->color) ? "Dis" : "En");
	sprintf(buf,"%s/%s*.tut",(here->mode == 1) ? Info : (here->mode) ? News : Tutor, (here->subdir) ? here->subdir : "");
	if (findfirst(buf, &ff, 0) == 0) 	{
		do	{
			pwait(NULL);    /* Let others run */
			*(strchr(ff.ff_name,'.')) = '\0';
			sprintf (buf2, "%s/%s%s.tut", (here->mode == 1) ? Info : (here->mode) ? News : Tutor, (here->subdir) ? here->subdir : "", ff.ff_name);
			if ((fp = fopen (buf2,READ_TEXT)) != NULLFILE)	{
				do	{
					fgets (buf2, 256, fp);
					cp = skipwhite (buf2);
				} while (*cp == '\n');
				fclose (fp);
				if (*cp == '~')		/* subdir directing file */
					cp = skipwhite(skipnonwhite(skipwhite (++cp)));
				here->Tutors[here->maxselect++] = strdup (ff.ff_name);
				mycolorchange (here, "05", here->last);
				tprintf ("    %2d", here->maxselect);
				mycolorchange (here, "07", here->last);
				tprintf (" -  %s", cp);
				}
			} while (findnext(&ff) == 0);
	}
}


void
#ifndef STANDALONE
tutorserv (call, m, mode, color, ip)
char *call;
struct mbx *m;
int mode, color, ip;
#else
tutorserv (call, mode, color, ip)
char *call;
int mode, color, ip;
#endif
{
char selection[10], filename[80], *cp;
int k, select, inited = 0;
struct world here;
#ifndef STANDALONE
char tmp[AXBUF];

	Tutored++;
#endif
	here.mode = mode;
#ifndef STANDALONE
	Tutorlogins[here.mode]++;
#endif
	here.maxselect = 0;
	here.call = call;
#ifndef STANDALONE
	here.m = m;
#endif
	here.subdir = NULLCHAR;
#ifndef STANDALONE
	sockblock(Curproc->output,SOCK_NOTXBLOCK);   /* prevent backlogs ! */
#endif
	here.color = color;
	here.ipconnect = ip;
	here.inescape = 0;
	here.ischild = 0;
	here.Error[0] = 0;
	here.out = NULLFILE;
	here.whichsocket = here.background = 0;
	here.socket = calloc (10, sizeof(int));
	here.user = here.socket[0] = Curproc->output;
	if (m && color)
		memcpy (here.last, m->colorset, 2);
	else
		here.last[0] = 0;
	for ( ; ; )	{
		if (inited)
			tprintf ("\n\n\n\n");
		else
			inited = 1;
		buildmenu (&here);
		do	{
			mycolorchange (&here, "0F", here.last);
			tprintf ("\nEnter Selection:\n");
			mygets (selection, 10, &here);
			pwait (NULL);
			if (toupper (*selection) == 'E')	{
				free (here.subdir);
				here.subdir = NULLCHAR;
				select = 0;
				break;
			}
			if (toupper (*selection) == 'C')	{
				select = -1;
				here.color ^= 1;
				break;
			}
			select = atoi (selection);
			if (!select)
				break;
			if (select > here.maxselect)
				tprintf ("Invalid number... select 0 - %-d!\007\n", here.maxselect);
		} while (select > here.maxselect);
		if (select == -1)
			continue;
		if (select)
			sprintf (filename, "%s/%s%s.tut", (here.mode == 1) ? Info : (here.mode) ? News : Tutor, (here.subdir) ? here.subdir : "", here.Tutors[select - 1]);
		for (k = 0; k < here.maxselect; k++)
			free (here.Tutors[k]);
		if (!select)	{
			if (!here.subdir)	/* not in a sub-directory! */
				break;
			here.subdir[strlen(here.subdir) - 1] = 0; /* take off last "/" */
			cp = strrchr (here.subdir, '/');
			if (!cp)	{
				free (here.subdir);
				here.subdir = NULLCHAR;
			} else
				*(++cp) = 0;
			continue;
		}
		if ((here.fp = fopen (filename,READ_TEXT)) == NULLFILE)	{
			tprintf ("Sorry, but something seems to be wrong with that tutorial!\n");
			continue;
		}
		/* Let's check first line to see if this file describes a sub-directory */
		fgets (filename, 80, here.fp);
		cp = filename;
		if (*cp == '~')		{	/* Yep! Sub-directory time! */
			cp = skipwhite (++cp);
			for (k = 0; k < 8 && *cp && cp[k] != '\t' && cp[k] != ' '; k++)
				selection[k] = cp[k];
			selection[k++] = '/';
			selection[k] = 0;
			k += (here.subdir) ? strlen(here.subdir) : 0;
			cp = malloc ((unsigned)++k);
			*cp = 0;
			if (here.subdir)
				strcpy (cp, here.subdir);
			strcat (cp, selection);
			free (here.subdir);
			here.subdir = cp;
		} else	{
			rewind (here.fp);
			for (k = 0; k < 10; k++)	{
				here.variables[k] = NULLCHAR;
				here.indexes[k] = 0;
 				here.socket[k] = 0;
			}
			process (&here);
		}
		fclose (here.fp);
	}
	mycolorchange (&here, "09", here.last);
	tprintf ("\n\nThanks for using the ");
	mycolorchange (&here, "0C", here.last);
	tprintf ("TNOS %s ", tutorialName[here.mode]);
	mycolorchange (&here, "09", here.last);
	tprintf ("at ");
	mycolorchange (&here, "0E", here.last);
	tprintf ("%s\n\n", Hostname);
	mycolorchange (&here, "0F", here.last);
	if (m)
		mycolorchange (&here, m->colorset, here.last);
#ifndef STANDALONE
	pax25(tmp, Tcall);
	if (*tmp && mode && Stutor != -1)	/* if tutor server active, but not 'us */
		tprintf (banner,"tutorial assistance", tmp);
	pax25(tmp, Icall);
	if (*tmp && mode != 1 && Sinfo != -1)	/* if info server active, but not 'us' */
		tprintf (banner,"local/area information", tmp);
	pax25 (tmp, Ncall);
 	if (*tmp && mode != 2 && Snews != -1)	/* if news server active, but not 'us' */
		tprintf (banner, "Ham related NEWS", tmp);
	tputc ('\n');
	usflush(Curproc->output);
	sockblock(Curproc->output,SOCK_BLOCK);
	free (here.socket);
	Tutored--;
#endif
}


extern char NoRead[];
static short scriptmode = 0;
static struct mbx *MbxCalling = NULLMBX;
static short numCalling = 0;
static char **argsCalling;
static short proxyServer = 0;

int
scriptcmd(inherited,fp,name)
struct world *inherited;	/* non-zero, inherited world */
FILE *fp;
char *name;
{
struct session *sp = NULLSESSION;
int usesession = 0, k;
struct world here;

	/* Use a session if this comes from console - WG7J*/
	if(!scriptmode && Curproc->input == Command->input) {
		usesession = 1;
		if((sp = newsession(name,SCRIPT,0)) == NULLSESSION)	{
			return 1;
		}
	}

	here.background = scriptmode;
	if (!inherited || inherited == -1)	{
		here.ischild = 0;
		here.user = 0;
		here.whichsocket = 0;
		here.ipconnect = 1;
		here.goback = 0;
		here.socket = calloc (10, sizeof(int));
#ifndef STANDALONE
		if (inherited == -1)	{
			here.m = MbxCalling;
			if (here.m)
				here.call = here.m->name;
			else
				here.call = "NoName";
			MbxCalling = NULLMBX;
		} else	{
			here.m = NULLMBX;
#endif
			here.call = "NoName";
#ifndef STANDALONE
		}
#endif
		for (k = 0; k < 10; k++)	{
			here.indexes[k] = 0;
			here.variables[k] = NULLCHAR;
		}
		if (inherited == -1)	{
			for (k = 0; k < numCalling; k++)
				here.variables[k] = strdup (argsCalling[k]);
			here.indexes[0] = numCalling;
			inherited = 0;
			if (proxyServer)
				here.goback = proxyServer;
			proxyServer = 0;
		}
	} else	{
		here.ischild = 1;
		here.user = inherited->user;
		here.whichsocket = inherited->whichsocket;
		here.ipconnect = inherited->ipconnect;
		here.goback = inherited->goback;
		here.socket = inherited->socket;
		here.call = inherited->call;
		if (inherited->background)
			here.background = inherited->background;
#ifndef STANDALONE
		here.m = inherited->m;
#endif
		for (k = 0; k < 10; k++)	{
			here.indexes[k] = inherited->indexes[k];
			if (inherited->variables[k])
				here.variables[k] = strdup(inherited->variables[k]);
			else
				here.variables[k] = NULLCHAR;
		}
	}
	here.fp = fp;
	here.mode = 0;
	here.maxselect = 0;
	here.subdir = NULLCHAR;
	here.color = 0;
	here.out = NULLFILE;
	here.inescape = 0;
	here.last[0] = 0;
	here.Error[0] = 0;
	process (&here);
	fclose(here.fp);
	if (inherited)	{
		for (k = 5; k < 10; k++)	{
			if (!here.goback)	{
				if (inherited->variables[k])
					free (inherited->variables[k]);
				inherited->variables[k] = NULLCHAR;
				if (here.variables[k])
					inherited->variables[k] = here.variables[k];
				inherited->indexes[k] = here.indexes[k];
			} else
				free (here.variables[k]);
		}
		if (!here.goback)
			inherited->whichsocket = here.whichsocket;
	} else
		free (here.socket);
	if(usesession) {
		keywait(NULLCHAR,1);
		freesession(sp);
	}
	return 0;
}
		

int
doscript(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *fp;
int oldin, oldout;
int thisscriptmode;

	{
	char fname[256];
		strcpy(fname,make_fname(Command->curdirs->dir,argv[1]));
		if((fp = fopen(fname,READ_TEXT)) == NULLFILE){
			tprintf(NoRead,fname,sys_errlist[errno]);
			return 1;
		}
	}

	scriptmode = (argc > 2 && !strnicmp (argv[2], "back", 4)) ? 1 :
		 (!argc && ((struct world *)p)->goback) ? 1 : 0;
	oldin = Curproc->input;
	oldout = Curproc->output;
	if (scriptmode)
		Curproc->input = Curproc->output = -1;
	thisscriptmode = scriptmode;
	if(scriptmode || Curproc->input == Command->input)	{
		newproc("script",2048,(void (*)__ARGS((int,void *,void *)))scriptcmd,(argc > 1) ? 0 : (int) p,(void *)fp,(void *)strdup(argv[1]),2);
	} else {
		scriptcmd((argc > 1) ? 0: (struct world *) p,fp,argv[1]);
	}
	if (thisscriptmode)	{
		Curproc->input = oldin;
		Curproc->output = oldout;
	}
	return 0;
}


#ifndef STANDALONE
int
dombscript
(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char *args[2], buffer[128];

	m = (struct mbx *)p;
	if (argc == 1)	{
		/* listing of commands available */
		DisplayFile (UCmdsHelp, m->user);
		return 0;
	}
	sprintf (buffer, "%s/%s.cmd", UserCmds, argv[1]);
	if(!access(buffer,4))	{
		args[1] = buffer;
		numCalling = argc - 2;
		if (numCalling > 10)
			numCalling = 10;
		argsCalling = &argv[2];
		MbxCalling = m;
		doscript (1, args, (void *)-1);
	} else	{
		tprintf ("Unknown CMD: '%s'\n", argv[1]);
		DisplayFile (UCmdsHelp, m->user);
	}
	return 0;
}


void
mbscripthook(m, hookfile)
struct mbx *m;
char *hookfile;
{
char *args[2], buffer[128];
char *args2[2];

	sprintf (buffer, "%s/%s", UserCmds, hookfile);
	if(!access(buffer,4))	{
		args[1] = buffer;
		numCalling = 1;
		args2[0] = m->line;
		argsCalling = &args2[0];
		MbxCalling = m;
		doscript (1, args, (void *)-1);
	}
}


int
proxy (fp, from)
FILE *fp;
char *from;
{
char buf[512], subject[256], realfrom[128], *cp;
long startat;
FILE *out;
char *args[2];
int oldin, oldout;

	parseheader (fp, realfrom, subject, buf, &startat);
	cp = strchr(realfrom, '@');
	if (cp)
		*cp = 0;
	sprintf (buf, "%s/proxy.tmp", Spool);
	out = fopen (buf, "w");
	fprintf (out, "[%s]\n", realfrom);
	fseek(fp, startat, SEEK_SET);
	while(fgets(buf,512,fp) != NULLCHAR)
		fputs (buf, out);
	fclose (out);
	numCalling = 1;
	argsCalling = args;
	args[0] = "import";

	sprintf(buf,"%s/proxy.cmd", UserCmds);
	if((out = fopen(buf,READ_TEXT)) == NULLFILE)
		return 1;

	oldin = Curproc->input;
	oldout = Curproc->output;
	Curproc->input = Curproc->output = -1;
	scriptmode = 1;
	proxyServer = 1;

#if 0
	newproc("script",2048,(void (*)__ARGS((int,void *,void *)))scriptcmd,(int)-1,(void *)out,(void *)strdup("Proxy"),2);
#else
	scriptcmd((struct world *)-1,out,"Proxy");
#endif
	Curproc->input = oldin;
	Curproc->output = oldout;
	return 1;
}

#endif


#endif

