home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / MAIN.C < prev    next >
C/C++ Source or Header  |  1994-08-30  |  58KB  |  2,183 lines

  1.  
  2. /* Main-level network program:
  3.  * initialization
  4.  * keyboard processing
  5.  * generic user commands
  6.  
  7.  8/94, wa2zkd,  trimmed displays to save ~.5K 
  8.  
  9.  *
  10.  * Copyright 1991 Phil Karn, KA9Q
  11.  */
  12. #include <time.h>
  13. #if defined(__TURBOC__) && defined(MSDOS)
  14. #include <fcntl.h>
  15. #include <dos.h>
  16. #include <io.h>
  17. #include <conio.h>
  18. #include <ctype.h>
  19. #include <dir.h>
  20. #include <alloc.h>
  21. #endif
  22. #ifdef LINUX
  23. #include <fcntl.h>
  24. #endif
  25. #include "global.h"
  26. #ifdef  ANSIPROTO
  27. #include <stdarg.h>
  28. #endif
  29. #include "mbuf.h"
  30. #include "timer.h"
  31. #include "proc.h"
  32. #include "iface.h"
  33. #include "ip.h"
  34. #include "tcp.h"
  35. #include "udp.h"
  36. #include "ax25.h"
  37. #include "kiss.h"
  38. #include "enet.h"
  39. #include "netrom.h"
  40. #include "ftpcli.h"
  41. #include "telnet.h"
  42. #include "tty.h"
  43. #include "session.h"
  44. #include "hardware.h"
  45. #include "bm.h"
  46. #include "usock.h"
  47. #include "socket.h"
  48. #ifdef LZW
  49. #include "lzw.h"
  50. #endif
  51. #include "cmdparse.h"
  52. #include "commands.h"
  53. #include "daemon.h"
  54. #include "devparam.h"
  55. #include "domain.h"
  56. #include "files.h"
  57. #include "main.h"
  58. #include "mailbox.h"
  59. #include "remote.h"
  60. #include "trace.h"
  61. #include "mailutil.h"
  62. #include "smtp.h"
  63. #include "index.h"
  64. #include "version.h"
  65. #ifdef XMS
  66. #include "xms.h"
  67. #endif
  68. #ifdef EMS
  69. #include "memlib.h"
  70. #endif
  71.   
  72. #undef BETA 1
  73.   
  74. #ifdef LINUX
  75. #define BETA 1
  76. #endif
  77. #ifdef BSAHAX
  78. #define BETA 1
  79. #endif
  80.   
  81. #if defined(__TURBOC__) || (defined __BORLANDC__)
  82. /* Don't even think about changing the following #pragma :-) - WG7J */
  83. #pragma option -a-
  84.   
  85. /* The following is from the Borland Runtime Library Version 3.0 :
  86.  * Copyright (c) 1987, 1990 by Borland International
  87.  */
  88. typedef struct
  89. {
  90.     unsigned char windowx1;
  91.     unsigned char windowy1;
  92.     unsigned char windowx2;
  93.     unsigned char windowy2;
  94.     unsigned char attribute;
  95.     unsigned char normattr;
  96.     unsigned char currmode;
  97.     unsigned char screenheight;
  98.     unsigned char screenwidth;
  99.     unsigned char graphicsmode;
  100.     unsigned char snow;
  101.     union {
  102.         char far * p;
  103.         struct { unsigned off,seg; } u;
  104.     } displayptr;
  105. } VIDEOREC;
  106. extern VIDEOREC _video;
  107.   
  108. char *Screen_Address(void){
  109.     /* Might have to add some code to get the address of the virtualized
  110.      * DV screen here, if we go that route.
  111.      */
  112.     return _video.displayptr.p;
  113. }
  114. #pragma option -a
  115.   
  116. #endif /* TURBOC || BORLANDC */
  117.   
  118. extern struct cmds DFAR Cmds[],DFAR Startcmds[],DFAR Stopcmds[],DFAR Attab[];
  119.   
  120. #if     (!defined(MSDOS) || defined(ESCAPE))    /* PC uses F-10 key always */
  121. static char Escape = 0x1d;      /* default escape character is ^] */
  122. #endif
  123.   
  124. #ifdef __TURBOC__
  125. int dofstat __ARGS((void));
  126. #endif
  127. static char Prompt[] = "jnos> ";
  128. char NoRead[] = "Can't read %s: %s\n";
  129. char Badhost[] = "Unknown host %s\n";
  130. char Badinterface[] = "Interface \"%s\" unknown\n";
  131. char Existingiface[] = "Interface %s already exists\n";
  132. char Nospace[] = "No space!!\n";    /* Generic malloc fail message */
  133. char Nosversion[] = "JNOS version %s\n";
  134. char NosLoadInfo[] = "NOS load info: CS=0x%04x DS=0x%04x";
  135. char Noperm[] = "Permission denied.\n";
  136. char Nosock[] = "Can't create socket\n";
  137. char SysopBusy[] = "Sysop is busy. Try again later.\n";
  138. char TelnetMorePrompt[] = "--more--";
  139. char BbsMorePrompt[] = "More(N=no)? ";
  140. char *Hostname;
  141. char *Motd;                     /* Message Of The Day */
  142. #if !defined MAILBOX || defined TTYLINKSERVER || defined TTYCALL
  143. int Attended = TRUE;            /* default to attended mode */
  144. #else
  145. int Attended;
  146. #endif
  147. int ThirdParty = TRUE;                  /* Allows 3rd party mail by default */
  148. int main_exit;          /* from main program (flag) */
  149. int DosPrompt;          /* Use a dos-like prompt */
  150. int Mprunning;          /* flag for other parts (domain) to signal
  151.              * that we are fully configured running.
  152.              */
  153. static int ErrorPause;
  154. static int Step;
  155. static int RmLocks = 1;
  156.   
  157. extern int StLen2;
  158. extern char *StBuf2;
  159. extern char *StBuf3;
  160. #ifdef MAILBOX
  161. #define MAXSTATUSLINES 3
  162. #else
  163. #define MAXSTATUSLINES 2
  164. #endif
  165. #ifdef STATUSWIN
  166. int StatusLines = MAXSTATUSLINES;
  167. #else
  168. int StatusLines = 0;
  169. #endif
  170.   
  171. struct proc *Cmdpp;
  172. #ifndef LINUX
  173. struct proc *Display;
  174. #endif
  175. #ifdef  LZW
  176. int Lzwmode = LZWCOMPACT;
  177. int16 Lzwbits = LZWBITS;
  178. #endif
  179.   
  180. #ifdef TRACE
  181. int Tracesession = 1;
  182. struct session *Trace = NULLSESSION;
  183. #endif
  184.   
  185. static char *DumpAddr = NULL;           /* Memory dump pointer */
  186. static FILE *Logfp;
  187. time_t StartTime;        /* Time that NOS was started */
  188. static int Verbose;
  189.   
  190. static void ctohex __ARGS((char *buf,int16 c));
  191. static void fmtline __ARGS((int16 addr,char *buf,int16 len));
  192. extern void assign_filenames __ARGS((char *));
  193. static void logcmd __ARGS((char *));
  194. char *Screen_Address(void);
  195.   
  196.   
  197. int Numrows,Numcols;    /* screen size at startup - WG7J */
  198. struct hist *Histry;    /* command recall stuff */
  199. int Histrysize;
  200. int Maxhistory = 10;
  201.   
  202. #ifdef EMS
  203. int EMS_Available;
  204. #endif
  205. #ifdef XMS
  206. int XMS_Available;
  207. #endif
  208.   
  209. #ifdef LINUX
  210. static char **origargv;
  211. #endif
  212.   
  213. /* The text_info before we start JNOS */
  214. struct text_info PrevTi;
  215. #ifdef STATUSWIN
  216. extern char MainStColors,SesStColors;
  217. #endif
  218. #ifdef SPLITSCREEN
  219. extern char MainColors,SplitColors;
  220. void GiveColor(char *s,char *attr);
  221. #endif
  222.   
  223. int
  224. main(argc,argv)
  225. int argc;
  226. char *argv[];
  227. {
  228.     int ForceIndex = 0;
  229.     char *inbuf,*intmp;
  230.     FILE *fp;
  231.     struct mbuf *bp;
  232.     int c,i;
  233. #ifdef LINUX
  234.     static int oops;
  235. #endif
  236.     struct cur_dirs dirs;
  237. #ifdef EMS
  238.     unsigned long emssize;
  239. #endif
  240. #ifdef XMS
  241.     long XMS_Ret;
  242. #endif
  243.   
  244. #ifdef LINUX
  245.     if (oops++)
  246.     {
  247.         iostop();
  248.         fprintf(stderr, "NOS PANIC: NOS main re-entered.\n");
  249.         fflush(stderr);
  250.         fflush(stdout);
  251.         kill(getpid(), 11);
  252.     }
  253.     origargv = argv;
  254. #endif
  255.   
  256.     StartTime = time(&StartTime);           /* NOS Start_Up time */
  257. #ifdef UNIX
  258.     SRANDOM((getpid() << 16) ^ time((long *) 0));
  259. #else
  260.     randomize();
  261. #endif
  262.   
  263. #if defined(__TURBOC__) || defined(__BORLANDC__)
  264.     /* Borland's library calls int10. Some vga mode utilities do not
  265.      * report the screen sizes correctly into the internal _video structure.
  266.      * This can cause the screen size to be faulty in the gettextinfo call.
  267.      * Instead, read the BIOS data area to get the correct screen info,
  268.      * and update the _video structure for later calls to
  269.      * gettextinfo(), clrscr(), etc... - WG7J
  270.      *
  271.      * If this doesn't work, you can now overwrite the values with
  272.      * the -r and -c command line options - WG7J
  273.      */
  274.     Numrows = (int) *(char far *)MK_FP(0x40,0x84) + 1;
  275.     gettextinfo(&PrevTi);
  276.     Numcols = PrevTi.screenwidth;
  277. #ifdef SPLITSCREEN
  278.     MainColors = PrevTi.attribute;
  279.     MainColors &= 0xf7; /* turn off highlite */
  280. #endif
  281. /*
  282.     Numrows = PrevTi.screenheight;
  283. */
  284.     if(Numrows == 1)
  285.         Numrows = 25;
  286.   
  287. #endif
  288.   
  289.     SwapMode = MEM_SWAP;
  290. #ifdef MSDOS
  291.     Screen = Screen_Address();
  292.   
  293.     /* If EMS is found, XMS is not used for swapping - WG7J */
  294. #ifdef EMS
  295.     if(ememavl(&emssize) == 0) {
  296.         EMS_Available = 1;
  297.         SwapMode = EMS_SWAP;
  298.     }
  299. #endif
  300.   
  301. #ifdef XMS
  302.     if((XMS_Available = Installed_XMS()) != 0)
  303. #ifdef EMS
  304.         if(!EMS_Available)
  305. #endif
  306.             SwapMode = XMS_SWAP;
  307. #endif
  308.   
  309. #endif /* MSDOS */
  310.   
  311.     while((c = getopt(argc,argv,"s:d:r:c:f:m:u:w:x:y:z:nbvelti")) != EOF){
  312.         switch(c){
  313. #ifdef  __TURBOC__
  314.             case 'b':       /* Use BIOS for screen output */
  315.                 directvideo = 0;
  316.                 break;
  317. #endif
  318.             case 'c':   /* Number of columns on screen */
  319.                 Numcols = atoi(optarg);
  320.                 break;
  321.             case 'd':   /* Root directory for various files */
  322.                 initroot(optarg);
  323.                 break;
  324.             case 'e':   /* Pause after error lines */
  325.                 ErrorPause = 1;
  326.                 break;
  327. #if defined(MSDOS) || defined(UNIX)
  328.             case 'f':
  329.                 assign_filenames(optarg);
  330.                 break;
  331. #endif
  332.             case 'i':
  333.                 ForceIndex = 1;
  334.                 break;
  335.             case 'l':   /* Don't remove mail locks */
  336.                 RmLocks = 0;
  337.                 break;
  338. #ifdef MSDOS
  339.             case 'm':   /* Swap mode, 0=EMS (default),1=XMS,2=MEM,3=FILE - WG7J */
  340.                 i = atoi(optarg);
  341. #ifdef XMS
  342.                 if(i == 1 && XMS_Available) {
  343.                     SwapMode = XMS_SWAP;
  344.                 } else
  345. #endif
  346.                     if(i == 2)
  347.                         SwapMode = MEM_SWAP;
  348.                     else if(i == 3)
  349.                         SwapMode = FILE_SWAP;
  350.                 break;
  351. #endif
  352. #ifdef TRACE
  353.             case 'n':
  354.                 Tracesession = 0; /* No session for tracing */
  355.                 break;
  356. #endif
  357.             case 'r':   /* Number of rows on screen */
  358.                 Numrows = atoi(optarg);
  359.                 break;
  360.             case 't':
  361.                 Step = 1;
  362.             /* note fallthrough */
  363. #ifdef STATUSWIN
  364.             case 'u':   /* No status lines */
  365.                 StatusLines = atoi(optarg);
  366.                 if(StatusLines > MAXSTATUSLINES)
  367.                     StatusLines = MAXSTATUSLINES;
  368.                 break;
  369. #endif
  370.             case 'v':
  371.                 Verbose = 1;
  372.                 break;
  373. #ifdef STATUSWIN
  374.         /* Color options - WG7J */
  375.             case 'w':
  376.                 GiveColor(optarg,&MainStColors);
  377.                 MainStColors |= 0x08; /* Turn on highlite, so it shows on b/w */
  378.                 break;
  379.             case 'x':
  380.                 GiveColor(optarg,&SesStColors);
  381.                 SesStColors |= 0x08; /* Turn on highlite, so it shows on b/w */
  382.                 break;
  383. #endif
  384. #ifdef SPLITSCREEN
  385.             case 'y':
  386.                 GiveColor(optarg,&MainColors);
  387.                 MainColors &= 0xf7; /* Turn off highlite, so high video shows! */
  388.                 textattr(MainColors);   /* Set the color for startup screen ! */
  389.                 break;
  390.             case 'z':
  391.                 GiveColor(optarg,&SplitColors);
  392.                 SplitColors |= 0x08;    /* Turn on higlite, so it shows on b/w */
  393.                 break;
  394. #endif
  395.         }
  396.     }
  397.   
  398. #if defined(__TURBOC__) || defined(__BORLANDC__)
  399.     /* Set the internal structure, in case there was a command
  400.      * line overwrite - WG7J
  401.      */
  402.     _video.screenheight = (unsigned char)Numrows;
  403.     _video.windowx2 = (unsigned char)(Numcols - 1);
  404.     _video.windowy2 = (unsigned char)(Numrows - 1);
  405. #endif
  406.   
  407.     ScreenSize = 2 * Numrows * Numcols;
  408.   
  409. #ifdef STATUSWIN
  410.     if(StatusLines > 1) {
  411. #ifdef MAILBOX
  412.         StBuf2 = mallocw(Numcols+3);
  413.         StLen2 = sprintf(StBuf2,"\r\nBBS:");
  414.         if(StatusLines > 2)
  415. #endif
  416.         {
  417.             StBuf3 = mallocw(Numcols+3);
  418.             sprintf(StBuf3,"\r\n");
  419.         }
  420.     }
  421. #endif
  422.   
  423. #ifdef MSDOS
  424. #ifdef XMS
  425.     if(XMS_Available)
  426.         /* Calculate space in kb for screen */
  427.         ScreenSizeK = (ScreenSize / 1024) + 1;
  428. #endif
  429. #endif
  430.   
  431.   
  432.     kinit();
  433.     ipinit();
  434.     ioinit();
  435.     Cmdpp = mainproc("cmdintrp");
  436.   
  437.     Sessions = (struct session *)callocw(Nsessions,sizeof(struct session));
  438. #ifdef TRACE
  439.     if(Tracesession)
  440.         Trace = newsession(NULLCHAR,TRACESESSION,0);
  441. #endif
  442.     Command = Lastcurr = newsession(NULLCHAR,COMMAND,0);
  443.     init_dirs(&dirs);
  444.     Command->curdirs=&dirs;
  445.   
  446.     /* Flow mode is set AFTER we've read the autoexec file !
  447.      * this keeps systems from locking up if the reboot is unattended - WG7J
  448.      */
  449. #ifndef LINUX
  450.     Display = newproc("display",250,display,0,NULLCHAR,NULL,0);
  451. #endif
  452.     tprintf(Nosversion,Version);
  453.     tputs(Version2);
  454.     tputs("Copyright 1991 by Phil Karn (KA9Q) and contributors.\n");
  455. #ifdef MSDOS
  456. #ifdef EMS
  457.     if(EMS_Available)
  458.         tputs("EMS detected.\n");
  459. #endif
  460. #ifdef XMS
  461.     if(XMS_Available)
  462.         tputs("XMS detected.\n");
  463. #endif
  464. #endif
  465.   
  466. #ifdef BETA
  467.     tputs("\007\007\007\n==> This is a BETA version; be warned ! <==\n\n");
  468. #endif
  469.   
  470.     rflush();
  471.   
  472.     /* Start background Daemons */
  473.     {
  474.         struct daemon *tp;
  475.   
  476.         for(tp=Daemons;;tp++){
  477.             if(tp->name == NULLCHAR)
  478.                 break;
  479.             newproc(tp->name,tp->stksize,tp->fp,0,NULLCHAR,NULL,0);
  480.         }
  481.     }
  482.   
  483.     if(optind < argc){
  484.         /* Read startup file named on command line */
  485.         if((fp = fopen(argv[optind],READ_TEXT)) == NULLFILE)
  486.             tprintf(NoRead,argv[optind],sys_errlist[errno]);
  487.     } else {
  488.         /* Read default startup file named in files.c (autoexec.nos) */
  489.         if((fp = fopen(Startup,READ_TEXT)) == NULLFILE)
  490.             tprintf(NoRead,Startup,sys_errlist[errno]);
  491.     }
  492.     if(fp != NULLFILE){
  493.         inbuf = mallocw(BUFSIZ);
  494.         intmp = mallocw(BUFSIZ);
  495.         while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  496.             strcpy(intmp,inbuf);
  497.             if(Verbose){
  498.                 tputs(intmp);
  499.                 rflush();
  500.             }
  501.             /* Are we stepping through autoexec.nos ? - WG7J */
  502.             if(Step) {
  503.                 int c;
  504.                 Command->ttystate.edit = Command->ttystate.echo = 0;
  505.                 c = toupper(keywait("Execute cmd ?",1));
  506.                 Command->ttystate.edit = Command->ttystate.echo = 1;
  507.                 if(c != 'Y')
  508.                     continue;
  509.             }
  510.             if(cmdparse(Cmds,inbuf,NULL) != 0){
  511.                 tprintf("input line: %s",intmp);
  512.                 if(ErrorPause)
  513.                     keywait(NULLCHAR,1);
  514.                 rflush();
  515.             }
  516.         }
  517.         fclose(fp);
  518.         free(inbuf);
  519.         free(intmp);
  520.     }
  521.   
  522.     /* Log that we started nos, but do this after the config file is read
  523.      * such that logging can be disabled - WG7J
  524.      */
  525.     log(-1,"JNOS %s was started",Version);
  526.   
  527.     /* Update .txt files that have old index files - WG7J */
  528.     UpdateIndex(NULL,ForceIndex);
  529.   
  530.     if(RmLocks)
  531.         RemoveMailLocks();
  532.   
  533.     Mprunning = 1;  /* we are on speed now */
  534.   
  535.     /* N7IPB - If lots of output generated during startup we have to wait
  536.      * for it all to be output before turning on 'more'
  537.      */
  538.     pause(1000);
  539.     Command->flowmode = 1;      /* set 'more' paging on command screen */
  540.   
  541.     /* Now loop forever, processing commands */
  542.     for(;;){
  543.         if(DosPrompt)
  544.             tprintf("%s ",dirs.dir);
  545.         if(!StatusLines)
  546.             tprintf("%lu ",coreleft());
  547.         tputs(Prompt);
  548.         usflush(Command->output);
  549.         if(recv_mbuf(Command->input,&bp,0,NULLCHAR,0) != -1){
  550.             logcmd(bp->data);
  551.             (void)cmdparse(Cmds,bp->data,Lastcurr);
  552.             free_p(bp);
  553.         }
  554.     }
  555. }
  556. /* Keyboard input process */
  557. /* Modified to support F-key session switching,
  558.  * from the WNOS3 sources - WG7J
  559.  */
  560. void
  561. keyboard(i,v1,v2)
  562. int i;
  563. void *v1;
  564. void *v2;
  565. {
  566.     int c;
  567.     struct mbuf *bp;
  568.     int j,k;
  569.     struct session *sp;
  570. #ifdef STATUSWIN
  571.     int newsession;
  572. #endif
  573.   
  574.     /* Keyboard process loop */
  575.     for(;;){
  576.         c = kbread();
  577. #ifdef STATUSWIN
  578.         newsession = 0;
  579. #endif
  580. #if(!defined(MSDOS) || defined(ESCAPE))
  581.         if(c == Escape && Escape != 0)
  582.             c = -2;
  583. #endif
  584.         if(c == -2 && Current != Command){
  585.             /* Save current tty mode and set cooked */
  586.             Lastcurr = Current;
  587.             Current = Command;
  588.             swapscreen(Lastcurr,Current);
  589. #ifdef STATUSWIN
  590.             newsession = 1;
  591. #endif
  592.             /* set 'more' paging on command screen */
  593.             Command->flowmode = 1;
  594.         }
  595.         if((c < -2) && (c > -12)) {             /* F1 to F9 pressed */
  596. #ifdef TRACE
  597.             /* If F9 is pressed, -11 is returned and we swap to Trace - WG7J */
  598.             if(c == -11 && Tracesession) {
  599.                 if(Current != Trace) {
  600.                     /* Save current tty mode and set cooked */
  601.                     swapscreen(Current,Trace);
  602.                     Lastcurr = Current;
  603.                     Current = Trace;
  604. #ifdef STATUSWIN
  605.                     newsession = 1;
  606. #endif
  607.                     /* turn off 'more' paging on trace screen */
  608.                     Trace->flowmode = 0;
  609.                 } else {
  610.                     /* Toggle back to previous session */
  611.                     Current = Lastcurr;
  612.                     Lastcurr = Trace;
  613.                     swapscreen(Lastcurr,Current);
  614. #ifdef STATUSWIN
  615.                     newsession = 1;
  616. #endif
  617.                 }
  618.             } else {
  619. #endif
  620.                 /* Swap directly to F-key session - WG7J */
  621.                 k = (-1 * c) - 2;
  622.                 for(sp = Sessions, j = 0; sp < &Sessions[Nsessions]; sp++) {
  623.                     if(sp->type == COMMAND)
  624.                         continue;
  625.                     j++;
  626.                     if(sp->type != FREE && j == k) {
  627.                         Lastcurr = Current;
  628.                         Current = sp;
  629.                         swapscreen(Lastcurr,Current);
  630. #ifdef STATUSWIN
  631.                         newsession = 1;
  632. #endif
  633.                         break;
  634.                     }
  635.                 }
  636. #ifdef TRACE
  637.             }
  638. #endif
  639.         }
  640. #ifdef STATUSWIN
  641.         if(newsession)
  642.             UpdateStatus();
  643. #endif
  644.         Current->row = Numrows - 1 - StatusLines;
  645.         psignal(&Current->row,1);
  646.         if(c >= 0){
  647. #ifdef LINUX
  648.             if (Current->morewait) /* end display pause, if any */
  649.                 Current->morewait = 2;
  650. #endif
  651.             /* If the screen driver was in morewait state, this char
  652.              * has woken him up. Toss it so it doesn't also get taken
  653.              * as normal input. If the char was a command escape,
  654.              * however, it will be accepted; this gives the user
  655.              * a way out of lengthy output.
  656.              */
  657.             if(!Current->morewait && (bp = ttydriv(Current,c)) != NULLBUF)
  658.                 send_mbuf(Current->input,bp,0,NULLCHAR,0);
  659.         }
  660.     }
  661. }
  662.   
  663. extern int Kblocked;
  664. extern char *Kbpasswd;
  665. #ifdef LOCK
  666.   
  667. /*Lock the keyboard*/
  668. int
  669. dolock(argc,argv,p)
  670. int argc;
  671. char *argv[];
  672. void *p;
  673. {
  674.   
  675.     extern char Noperm[];
  676.   
  677.     /*allow only keyboard users to access the lock command*/
  678.     if(Curproc->input != Command->input) {
  679.         tputs(Noperm);
  680.         return 0;
  681.     }
  682.     if(argc == 1) {
  683.         if(Kbpasswd == NULLCHAR)
  684.             tputs("Set password first\n");
  685.         else {
  686.             Kblocked = 1;
  687.             tputs("Keyboard locked\n");
  688.             Command->ttystate.echo = 0; /* Turn input echoing off! */
  689.         }
  690.         return 0;
  691.     }
  692.     if(argc == 3) {
  693.         if(*argv[1] == 'p') {   /*set the password*/
  694.             if(Kbpasswd != NULLCHAR){
  695.                 free(Kbpasswd);
  696.                 Kbpasswd = NULLCHAR;        /* reset the pointer */
  697.             }
  698.             if(!strlen(argv[2]))
  699.                 return 0;           /* clearing the buffer */
  700.             Kbpasswd = strdup(argv[2]);
  701.             return 0;
  702.         }
  703.     }
  704.   
  705.     tputs("Usage: lock password \"<unlock password>\"\n"
  706.     "or    'lock' to lock the keyboard\n");
  707.   
  708.     return 0;
  709. }
  710.   
  711. #endif
  712.   
  713. /*this is also called from the remote-server for the 'exit' command - WG7J*/
  714. void
  715. where_outta_here(resetme)
  716. int resetme;
  717. {
  718.     time_t StopTime;
  719.     FILE *fp;
  720.     char *inbuf,*intmp;
  721.   
  722.     /* Execute sequence of commands taken from file "~/onexit.nos" */
  723.     /* From iw0cnb */
  724.     if((fp = fopen(Onexit,READ_TEXT)) != NULLFILE){
  725.         inbuf = mallocw(BUFSIZ);
  726.         intmp = mallocw(BUFSIZ);
  727.         while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  728.             strcpy(intmp,inbuf);
  729.             if(Verbose){
  730.                 tputs(intmp);
  731.                 rflush();
  732.             }
  733.             if(cmdparse(Cmds,inbuf,NULL) != 0){
  734.                 tprintf("input line: %s",intmp);
  735.             }
  736.         }
  737.         fclose(fp);
  738.         free(inbuf);
  739.         free(intmp);
  740.     }
  741.     StopTime = time(&StopTime);
  742.     main_exit = TRUE;       /* let everyone know we're out of here */
  743.     reset_all();
  744.     if(Dfile_updater != NULLPROC)
  745.         alert(Dfile_updater,0); /* don't wait for timeout */
  746.     pause(3000);    /* Let it finish */
  747. #ifdef TRACE
  748.     shuttrace();
  749. #endif
  750.     log(-1,"JNOS was stopped");
  751. #ifdef LINUX
  752.     detach_all_asy();     /* make sure everything is unlocked */
  753.     pwait(NULL);
  754. #endif
  755.     iostop();
  756.     if(resetme)
  757. #ifdef LINUX
  758.     {
  759.         if (fork() == 0)
  760.             abort();
  761.         execvp(origargv[0], origargv); /* re-run NOS */
  762.     }
  763. #else
  764.     sysreset();
  765. #endif
  766. #ifdef MSDOS
  767. #ifdef EMS
  768.     effreeall();
  769. #endif
  770. #ifdef XMS
  771.     /* Free any possible XMS used for the screen */
  772.     Free_Screen_XMS();
  773. #endif
  774. #endif
  775.     window(1,1,Numcols,Numrows);
  776.     textattr(PrevTi.attribute);
  777.     clrscr();
  778.     exit(0);
  779. }
  780.   
  781. int
  782. doexit(argc,argv,p)
  783. int argc;
  784. char *argv[];
  785. void *p;
  786. {
  787.     time_t nowtime, elapsedtime;
  788. /*    unsigned int days,hrs,mins,secs;  */
  789.   
  790.     if(strnicmp(Curproc->name, "at ",3) == 0)   /* From the AT command */
  791.         where_outta_here(0);
  792.   
  793.     if(Curproc->input == Command->input) {  /* From keyboard */
  794.         Command->ttystate.edit = Command->ttystate.echo = 0;
  795.         if(toupper(keywait("Are you sure? ",0))=='Y') {
  796.         tprintf("Exiting, uptime: %s\n",tformat(secclock()));  /*zkd*/
  797.         where_outta_here(0); /*No reset!*/
  798.         }
  799.         Command->ttystate.edit = Command->ttystate.echo = 1;
  800.         return 0;
  801.     }
  802.    /* Anything else; probably mailbox-sysop */
  803.     return -2;
  804. }
  805.   
  806. extern char Chostname[];
  807.   
  808. int
  809. dohostname(argc,argv,p)
  810. int argc;
  811. char *argv[];
  812. void *p;
  813. {
  814. #ifdef CONVERS
  815.     char *cp;
  816. #endif
  817.   
  818.     if(argc < 2)
  819.         tprintf("%s\n",Hostname);
  820.     else {
  821.         struct iface *ifp;
  822.         char *name;
  823.   
  824.         if((ifp = if_lookup(argv[1])) != NULLIF){
  825.             if((name = resolve_a(ifp->addr, FALSE)) == NULLCHAR){
  826.                 tputs("Interface address not resolved\n");
  827.                 return 1;
  828.             } else {
  829.                 if(Hostname != NULLCHAR)
  830.                     free(Hostname);
  831.                 Hostname = name;
  832.                 tprintf("Hostname set to %s\n", name );
  833.             }
  834.         } else {
  835.             if(Hostname != NULLCHAR)
  836.                 free(Hostname);
  837.             Hostname = strdup(argv[1]);
  838.             /* Remove trailing dot */
  839.             if(Hostname[strlen(Hostname)] == '.')
  840.                 Hostname[strlen(Hostname)] = '.';
  841.         }
  842. #ifdef CONVERS
  843.     /* If convers hostname not set yet, set it to first 10 chars
  844.      * of the hostname. If there are '.' from the right, cut off
  845.      * before that. - WG7J
  846.      */
  847.         if(Chostname[0] == '\0') {
  848.             strncpy(Chostname,Hostname,CNAMELEN);
  849.             if((cp = strrchr(Chostname,'.')) != NULLCHAR)
  850.                 *cp = '\0';
  851.         }
  852. #endif
  853.     }
  854.     return 0;
  855. }
  856.   
  857. int Uselog = 1;
  858.   
  859. int
  860. dolog(argc,argv,p)
  861. int argc;
  862. char *argv[];
  863. void *p;
  864. {
  865.     return setbool(&Uselog,"disk logging",argc,argv);
  866. }
  867.  
  868.   
  869. void log(int s,char *fmt, ...)
  870. {
  871.     va_list ap;
  872.     char *cp, ML[FILE_PATH_SIZE];
  873.     time_t t;
  874.     int i;
  875.     struct sockaddr fsocket;
  876.     FILE *fp;
  877.   
  878.     if(!Uselog)
  879.         return;
  880.   
  881.     time(&t);
  882.     cp = ctime(&t);
  883.   
  884.     sprintf(ML,"%s/%2.2s%3.3s%2.2s",LogsDir,cp+8,cp+4,cp+22);
  885.     if ((fp = fopen(ML,APPEND_TEXT)) == NULLFILE)
  886.         return;
  887.   
  888.     i = SOCKSIZE;
  889.   
  890.     fprintf(fp,"%9.9s",cp+11);
  891.     if(getpeername(s,(char *)&fsocket,&i) != -1)
  892.         fprintf(fp, " %s",psocket(&fsocket));
  893.     fprintf(fp, " - ");
  894.     va_start(ap,fmt);
  895.     vfprintf(fp,fmt,ap);
  896.     va_end(ap);
  897.     fprintf(fp,"\n");
  898.     fclose(fp);
  899. }
  900.   
  901. int
  902. dohelp(argc,argv,p)
  903. int argc;
  904. char *argv[];
  905. void *p;
  906. {
  907.     register struct cmds *cmdp;
  908.     int i;
  909.     char buf[FILE_PATH_SIZE];
  910.     char **pargv;
  911.     FILE *fp;
  912.     struct mbx *m;
  913.   
  914. /* ?  => display compiled-command names 
  915.  * help   =or=   help ?  => show /help/help
  916.  * help X => show /help/X
  917.  */
  918.     if(*argv[0] == '?' ) {
  919.         tputs("Main commands:\n");
  920.         memset(buf,' ',sizeof(buf));
  921.         buf[75] = '\n';
  922.         buf[76] = '\0';
  923.         for(i=0,cmdp = Cmds;cmdp->name != NULL;cmdp++,i = (i+1)%5){
  924.             strncpy(&buf[i*15],cmdp->name,strlen(cmdp->name));
  925.             if(i == 4){
  926.                 tputs(buf);
  927.                 memset(buf,' ',sizeof(buf));
  928.                 buf[75] = '\n';
  929.                 buf[76] = '\0';
  930.             }
  931.         }
  932.         if(i != 0)
  933.             tputs(buf);
  934.     } else {
  935.         sprintf(buf,"%s/%s",CmdsHelpdir,"help");  /* default */
  936.         if(argc > 1) {
  937.             for(i=0; Cmds[i].name != NULLCHAR; ++i)
  938.                 if(!strncmp(Cmds[i].name,argv[1],strlen(argv[1]))) {
  939.                     if(*argv[1] != '?')
  940.                         sprintf(buf,"%s/%s",CmdsHelpdir,Cmds[i].name);
  941.                     break;
  942.                 }
  943.             if(Cmds[i].name == NULLCHAR) {
  944.                 tputs("Unknown command; type \"?\" for list\n");
  945.                 return 0;
  946.             }
  947.         }
  948. #if defined MORESESSION || defined DIRSESSION || defined FTPSESSION
  949.         pargv = (char **)callocw(2,sizeof(char *));
  950.         pargv[1] = strdup(buf);
  951.         if(Curproc->input == Command->input) {   /* from console? */
  952.             newproc("more",512,(void (*)__ARGS((int,void *,void *)))morecmd,2,(void *)pargv,p,1);
  953.         } else {
  954.             morecmd(2,pargv,p);
  955.             free(pargv[1]);
  956.             free(pargv);
  957.         }
  958. #else
  959.         if((fp = fopen(buf,READ_TEXT)) == NULLFILE)
  960.             tprintf(NoRead,buf,sys_errlist[errno]);
  961.         else {
  962.             for (m=Mbox; m!=NULLMBX; m=m->next)
  963.                 if (m->proc == Curproc) break;
  964.             sendfile(fp,Curproc->output,ASCII_TYPE,0,m);
  965.             fclose(fp);
  966.         }
  967. #endif
  968.     }
  969.     return 0;
  970. }
  971.   
  972. /* Attach an interface
  973.  * Syntax: attach <hw type> <I/O address> <vector> <mode> <label> <bufsize> [<speed>]
  974.  */
  975. int
  976. doattach(argc,argv,p)
  977. int argc;
  978. char *argv[];
  979. void *p;
  980. {
  981.     return subcmd(Attab,argc,argv,p);
  982. }
  983. /* Manipulate I/O device parameters */
  984. int
  985. doparam(argc,argv,p)
  986. int argc;
  987. char *argv[];
  988. void *p;
  989. {
  990.     int param,set;
  991.     int32 val;
  992.     register struct iface *ifp;
  993.   
  994.     if((ifp = if_lookup(argv[1])) == NULLIF){
  995.         tprintf(Badinterface,argv[1]);
  996.         return 1;
  997.     }
  998.     if(ifp->ioctl == NULL){
  999.         tputs("Not supported\n");
  1000.         return 1;
  1001.     }
  1002.     if(argc < 3){
  1003.         for(param=1;param<=16;param++){
  1004.             val = (*ifp->ioctl)(ifp,param,FALSE,0L);
  1005.             if(val != -1)
  1006.                 tprintf("%s: %ld\n",parmname(param),val);
  1007.         }
  1008.         return 0;
  1009.     }
  1010.     param = devparam(argv[2]);
  1011.     if(param == -1){
  1012.         tprintf("Unknown parameter %s\n",argv[2]);
  1013.         return 1;
  1014.     }
  1015.     if(argc < 4){
  1016.         set = FALSE;
  1017.         val = 0L;
  1018.     } else {
  1019.         set = TRUE;
  1020.         val = atol(argv[3]);
  1021.     }
  1022.     val = (*ifp->ioctl)(ifp,param,set,val);
  1023.     if(val == -1){
  1024.         tprintf("Parameter %s not supported\n",argv[2]);
  1025.     } else {
  1026.         tprintf("%s: %ld\n",parmname(param),val);
  1027.     }
  1028.     return 0;
  1029. }
  1030.   
  1031. /* Display or set IP interface control flags */
  1032. int
  1033. domode(argc,argv,p)
  1034. int argc;
  1035. char *argv[];
  1036. void *p;
  1037. {
  1038.     register struct iface *ifp;
  1039.   
  1040.     if((ifp = if_lookup(argv[1])) == NULLIF){
  1041.         tprintf(Badinterface,argv[1]);
  1042.         return 1;
  1043.     }
  1044.     if(argc < 3){
  1045.         tprintf("%s: %s\n",ifp->name,
  1046.         (ifp->flags & CONNECT_MODE) ? "VC mode" : "Datagram mode");
  1047.         return 0;
  1048.     }
  1049.     switch(argv[2][0]){
  1050.         case 'v':
  1051.         case 'c':
  1052.         case 'V':
  1053.         case 'C':
  1054.             ifp->flags |= CONNECT_MODE;
  1055.             break;
  1056.         case 'd':
  1057.         case 'D':
  1058.             ifp->flags &= ~CONNECT_MODE;
  1059.             break;
  1060.         default:
  1061.             tprintf("Usage: %s [vc | datagram]\n",argv[0]);
  1062.             return 1;
  1063.     }
  1064.     return 0;
  1065. }
  1066.   
  1067. #if     (!defined(MSDOS) || defined(ESCAPE))
  1068. int
  1069. doescape(argc,argv,p)
  1070. int argc;
  1071. char *argv[];
  1072. void *p;
  1073. {
  1074.     if(argc < 2)
  1075.         tprintf("0x%x\n",Escape);
  1076.     else
  1077.         Escape = *argv[1];
  1078.     return 0;
  1079. }
  1080. #endif  MSDOS
  1081.   
  1082.   
  1083. #ifdef REMOTESERVER
  1084. extern char *Rempass;   /* Remote access password */
  1085. char remote_options[] = "a:p:k:s:";
  1086. #else
  1087. char remote_options[] = "a:p:k:";
  1088. #endif
  1089.   
  1090. /* Generate system command packet. Synopsis:
  1091.  * remote [-p port#] [-k key] [-a hostname] <hostname> reset|exit|kickme
  1092.  */
  1093. int
  1094. doremote(argc,argv,p)
  1095. int argc;
  1096. char *argv[];
  1097. void *p;
  1098. {
  1099.     struct sockaddr_in fsock;
  1100.     int s,c;
  1101.     char *data,x;
  1102.     int16 port,len;
  1103.     char *key = NULLCHAR;
  1104.     int klen;
  1105.     int32 addr = 0;
  1106.     char *cmd,*host;
  1107.   
  1108.     port = IPPORT_REMOTE;   /* Set default */
  1109.     optind = 1;             /* reinit getopt() */
  1110.     while((c = getopt(argc,argv,remote_options)) != EOF){
  1111.         switch(c){
  1112.             case 'a':
  1113.                 if((addr = resolve(optarg)) == 0){
  1114.                     tprintf(Badhost,optarg);
  1115.                     return -1;
  1116.                 }
  1117.                 break;
  1118.             case 'p':
  1119.                 port = atoi(optarg);
  1120.                 break;
  1121.             case 'k':
  1122.                 key = optarg;
  1123.                 klen = strlen(key);
  1124.                 break;
  1125. #ifdef REMOTESERVER
  1126.             case 's':
  1127.                 Rempass = strdup(optarg);
  1128.                 return 0;       /* Only set local password */
  1129. #endif
  1130.         }
  1131.     }
  1132.     if(optind > argc - 2){
  1133.         tputs("Insufficient args\n");
  1134.         return -1;
  1135.     }
  1136.     host = argv[optind++];
  1137.     cmd = argv[optind];
  1138.     if((s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  1139.         tputs("socket failed\n");
  1140.         return 1;
  1141.     }
  1142.     len = 1;
  1143.     /* Did the user include a password or kickme target? */
  1144.     if(addr != 0 && cmd[0] == 'k')
  1145.         len += sizeof(int32);
  1146.   
  1147.     if(key != NULLCHAR && (cmd[0] == 'r' || cmd[0] == 'e'))
  1148.         len += klen;
  1149.   
  1150.     if(len == 1)
  1151.         data = &x;
  1152.     else
  1153.         data = mallocw(len);
  1154.   
  1155.     fsock.sin_family = AF_INET;
  1156.     if((fsock.sin_addr.s_addr = resolve(host)) == 0){
  1157.         tprintf(Badhost,host);
  1158.         goto cleanup;
  1159.     }
  1160.     fsock.sin_port = port;
  1161.   
  1162.     switch(cmd[0]){
  1163.         case 'r':
  1164.             data[0] = SYS_RESET;
  1165.             if(key != NULLCHAR)
  1166.                 strncpy(&data[1],key,klen);
  1167.             break;
  1168.         case 'e':
  1169.             data[0] = SYS_EXIT;
  1170.             if(key != NULLCHAR)
  1171.                 strncpy(&data[1],key,klen);
  1172.             break;
  1173.         case 'k':
  1174.             data[0] = KICK_ME;
  1175.             if(addr != 0)
  1176.                 put32(&data[1],addr);
  1177.             break;
  1178.         default:
  1179.             tprintf("Unknown command %s\n",cmd);
  1180.             goto cleanup;
  1181.     }
  1182.     /* Form the command packet and send it */
  1183.     if(sendto(s,data,len,0,(char *)&fsock,sizeof(fsock)) == -1){
  1184.         tprintf("sendto failed: %s\n",sys_errlist[errno]);
  1185.         goto cleanup;
  1186.     }
  1187.     cleanup:
  1188.     if(data != &x)
  1189.         free(data);
  1190.     close_s(s);
  1191.     return 0;
  1192. }
  1193.   
  1194. #if defined MORESESSION || defined DIRSESSION || defined FTPSESSION
  1195.   
  1196. int
  1197. morecmd(argc,argv,p)
  1198. int argc;
  1199. char *argv[];
  1200. void *p;
  1201. {
  1202.     struct session *sp;
  1203.     FILE *fp;
  1204.     char buf[81],fname[128];
  1205.     int row;
  1206.     int usesession = 0;
  1207.   
  1208.     /* Use a session if this comes from console - WG7J*/
  1209.     if(Curproc->input == Command->input) {
  1210.         usesession = 1;
  1211.         if((sp = newsession(argv[1],MORE,0)) == NULLSESSION){
  1212.             return 1;
  1213.         }
  1214.         /* Put tty into raw mode so single-char responses will work */
  1215.         sp->ttystate.echo = sp->ttystate.edit = 0;
  1216.         row = Numrows - 1 - StatusLines;
  1217.     }
  1218.   
  1219.     strcpy(fname,make_fname(Command->curdirs->dir,argv[1]));
  1220.     if((fp = fopen(fname,READ_TEXT)) == NULLFILE){
  1221.         tprintf(NoRead,fname,sys_errlist[errno]);
  1222.         if(usesession) {
  1223.             keywait(NULLCHAR,1);
  1224.             freesession(sp);
  1225.         }
  1226.         return 1;
  1227.     }
  1228.     while(fgets(buf,sizeof(buf),fp),!feof(fp)){
  1229.         if((argc < 3) || (strstr(buf,argv[2])!=NULLCHAR)) {
  1230.             tputs(buf);
  1231.             if(usesession) {
  1232.                 if(--row == 0){
  1233.                     row = keywait(TelnetMorePrompt,0);
  1234.                     switch(row){
  1235.                         case -1:
  1236.                         case 'q':
  1237.                         case 'Q':
  1238.                             goto done;
  1239.                         case '\n':
  1240.                         case '\r':
  1241.                             row = 1;
  1242.                             break;
  1243.                         case ' ':
  1244.                         default:
  1245.                             row = Numrows - 1 - StatusLines;
  1246.                     }
  1247.                 }
  1248.             }
  1249.         }
  1250.     }
  1251.     done:   fclose(fp);
  1252.     if(usesession) {
  1253.         keywait(NULLCHAR,1);
  1254.         freesession(sp);
  1255.     }
  1256.     return 0;
  1257. }
  1258. #endif /* MORE | DIR | FTP SESSION */
  1259.   
  1260. #ifdef MORESESSION
  1261. int
  1262. domore(argc,argv,p)
  1263. int argc;
  1264. char *argv[];
  1265. void *p;
  1266. {
  1267.     char **pargv;
  1268.     int i;
  1269.   
  1270.     if(Curproc->input == Command->input) {
  1271.         /* Make private copy of argv and args,
  1272.          * spawn off subprocess and return.
  1273.          */
  1274.         pargv = (char **)callocw(argc,sizeof(char *));
  1275.         for(i=0;i<argc;i++)
  1276.             pargv[i] = strdup(argv[i]);
  1277.         newproc("more",512,(void (*)__ARGS((int,void *,void *)))morecmd,argc,(void *)pargv,p,1);
  1278.     } else
  1279.         morecmd(argc,argv,p);
  1280.     return 0;
  1281. }
  1282. #endif /* MORESESSION */
  1283.   
  1284. #ifdef ALLCMD
  1285. int
  1286. dotaillog(argc,argv,p)
  1287. int argc;
  1288. char *argv[];
  1289. void *p;
  1290. {
  1291.     char logfile[129];
  1292.     time_t t;
  1293.     char *cp;
  1294.   
  1295.     /* Create the log file name */
  1296.     time(&t);
  1297.     cp = ctime(&t);
  1298.     sprintf(logfile,"%s/%2.2s%3.3s%2.2s",LogsDir,cp+8,cp+4,cp+22);
  1299.   
  1300.     argc = 2;   /* ignore any provided args */
  1301.     argv[1] = logfile;
  1302.     return dotail(argc,argv,p);
  1303. }
  1304.   
  1305. int
  1306. dotail(argc,argv,p)
  1307. int argc;
  1308. char *argv[];
  1309. void *p;
  1310. {
  1311.     register int handle, i;
  1312.     register unsigned line = 0, rdsize = 2000;
  1313.     long length;
  1314.     char *buffer;
  1315.   
  1316.     buffer = callocw(2000, sizeof (char));
  1317.   
  1318.     if ((handle = open (argv[1], O_BINARY | O_RDONLY)) == -1) {
  1319.         tprintf(NoRead,argv[1],sys_errlist[errno]);
  1320.         free(buffer);
  1321.         return -1;
  1322.     }
  1323.     length = filelength(handle);
  1324.   
  1325.     if (length > 2000) {
  1326.         length -= 2000;
  1327.     } else {
  1328.         rdsize = (int) length;
  1329.         length = 0;
  1330.     }
  1331.   
  1332.     lseek (handle, length, SEEK_SET);
  1333.     if (read (handle, buffer, rdsize) == -1) {
  1334.         tprintf(NoRead,argv[1],sys_errlist[errno]);
  1335.         close(handle);
  1336.         free(buffer);
  1337.         return -1;
  1338.     }
  1339.   
  1340.     for (i = rdsize - 1; i > 0; i--) {
  1341.         if (buffer[i] == '\n')
  1342.             line++;
  1343.         if (line == 18)
  1344.             break;
  1345.     }
  1346.     for (; i < rdsize; i++)
  1347.         tputc(buffer[i]);
  1348.   
  1349.     tputc('\n');
  1350.     close(handle);
  1351.     free(buffer);
  1352.     return 0;
  1353. }
  1354. #endif /*ALLCMD*/
  1355.   
  1356. /* No-op command */
  1357. int
  1358. donothing(argc,argv,p)
  1359. int argc;
  1360. char *argv[];
  1361. void *p;
  1362. {
  1363.     return 0;
  1364. }
  1365.  
  1366. /* Pause command */  
  1367. int
  1368. dopause(argc,argv,p)
  1369. int argc;
  1370. char *argv[];
  1371. void *p;
  1372. {
  1373.     int secs;
  1374.  
  1375.     if(argc > 1) {
  1376.         secs = atoi(argv[1]);
  1377.         if (secs > 0) pause(1000L * secs);
  1378.     }
  1379.     return 0;
  1380. }
  1381.  
  1382. #ifdef MAILERROR
  1383. static int SendError = 1;
  1384.   
  1385. int doerror(int argc,char *argv[],void *p) {
  1386.     return setbool(&SendError,"Mail errors",argc,argv);
  1387. }
  1388.   
  1389. /* Mail a system message to the sysop - WG7J */
  1390. void
  1391. mail_error(char *fmt, ...)
  1392. {
  1393.     FILE *wrk,*txt;
  1394.     va_list ap;
  1395.     char *cp;
  1396.     long t,msgid;
  1397.     char fn[128];
  1398.   
  1399.     if(!SendError)
  1400.         return;
  1401.   
  1402.     /* Get current time */
  1403.     time(&t);
  1404.   
  1405.     /* get the message id for this message */
  1406.     msgid = get_msgid();
  1407.   
  1408.     /* Create the smtp work file */
  1409.     sprintf(fn,"%s/%ld.wrk",Mailqdir,msgid);
  1410.     if((wrk = fopen(fn,"w")) == NULL)
  1411.         return;
  1412.   
  1413.      /* Create the smtp text file */
  1414.     sprintf(fn,"%s/%ld.txt",Mailqdir,msgid);
  1415.     if((txt = fopen(fn,"w")) == NULL) {
  1416.         fclose(wrk);
  1417.         return;
  1418.     }
  1419.   
  1420.     /* Fill in the work file */
  1421.     fprintf(wrk,"%s\nMAILER-DAEMON@%s\nsysop@%s",Hostname,Hostname,Hostname);
  1422.     fclose(wrk);
  1423.   
  1424.     /* Fill in the text file headers */
  1425.     fprintf(txt,"%s%s",Hdrs[DATE],ptime(&t));
  1426.     fprintf(txt,"%s<%ld@%s>\n",Hdrs[MSGID],msgid,Hostname);
  1427.     fprintf(txt,"%sMAILER-DAEMON@%s\n",Hdrs[FROM],Hostname);
  1428.     fprintf(txt,"%ssysop@%s\n",Hdrs[TO],Hostname);
  1429.     fprintf(txt,"%sSystem message\n\n",Hdrs[SUBJECT]);
  1430.   
  1431.     /* Print the text body */
  1432.     cp = ctime(&t);
  1433.     fprintf(txt,"On %s",cp);
  1434.     va_start(ap,fmt);
  1435.     vfprintf(txt,fmt,ap);
  1436.     va_end(ap);
  1437.     fputc('\n',txt);
  1438.     fclose(txt);
  1439.   
  1440.     /* Now kick the smtp server */
  1441.     smtptick(NULL);
  1442. }
  1443. #endif /* MAILERROR */
  1444.   
  1445. int
  1446. dosource(argc,argv,p)
  1447. int argc;
  1448. char *argv[];
  1449. void *p;
  1450. {
  1451.     int linenum = 0;
  1452.     char *inbuf,*intmp;
  1453.     FILE *fp;
  1454.   
  1455.     /* Read command source file */
  1456.     if((fp = fopen(argv[1],READ_TEXT)) == NULLFILE){
  1457.         tprintf(NoRead,argv[1],sys_errlist[errno]);
  1458.         return 1;
  1459.     }
  1460.   
  1461.     inbuf = malloc(BUFSIZ);
  1462.     intmp = malloc(BUFSIZ);
  1463.     while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  1464.         strcpy(intmp,inbuf);
  1465.         linenum++;
  1466.         if(Verbose)
  1467.             tputs(intmp);
  1468.         if(cmdparse(Cmds,inbuf,NULL) != 0){
  1469.             tprintf("*** file \"%s\", line %d: %s\n",
  1470.             argv[1],linenum,intmp);
  1471.         }
  1472.     }
  1473.     fclose(fp);
  1474.     free(inbuf);
  1475.     free(intmp);
  1476.     return 0;
  1477. }
  1478.   
  1479. #ifdef TTYLINKSERVER
  1480. /* if unattended mode is set - restrict ax25, telnet and maybe other sessions */
  1481. int
  1482. doattended(argc,argv,p)
  1483. int argc;
  1484. char *argv[];
  1485. void *p;
  1486. {
  1487.     return setbool(&Attended,"Attended flag",argc,argv);
  1488. }
  1489. #endif
  1490.   
  1491. /* if ThirdParty is not set - restrict the mailbox (S)end command to local only */
  1492. int
  1493. dothirdparty(argc,argv,p)
  1494. int argc;
  1495. char *argv[];
  1496. void *p;
  1497. {
  1498.     return setbool(&ThirdParty,"Third-Party mail flag",argc,argv);
  1499. }
  1500.   
  1501. #ifdef ALLCMD
  1502. int
  1503. domdump(argc,argv,p)
  1504. int argc;
  1505. char *argv[];
  1506. void *p;
  1507. {
  1508.     unsigned int i;
  1509.     char *addr,*cp;
  1510.     unsigned int segment,offset;
  1511.     unsigned int len = 8 * 16;      /* default is 8 lines of hex dump */
  1512.   
  1513.     if(argc < 2 || argc > 3) {
  1514.         tputs("Usage:- dump <hex-address | .> [decimal-range] \n");
  1515.         return 0;
  1516.     }
  1517.     if(argv[1][0] == '.')
  1518.         addr = DumpAddr;                /* Use last end address */
  1519.     else {
  1520.         if((cp=strchr(argv[1],':')) != NULL) {
  1521.             /* Interpret segment:offset notation */
  1522.             *cp++ = '\0';
  1523.             segment = (unsigned int) htol(argv[1]);
  1524.             offset = (unsigned int) htol(cp);
  1525.             addr = MK_FP(segment,offset);
  1526.         } else
  1527.             addr = ltop(htol(argv[1]));     /* get address of item being dumped */
  1528.     }
  1529.   
  1530.     if(argc == 3) {
  1531.         len = atoi(argv[2]);
  1532.         len = ((len + 15) >> 4) << 4;   /* round up to modulo 16 */
  1533.     }
  1534.   
  1535.     if(len < 1 || len > 256) {
  1536.         tputs("Invalid dump range. Valid is 1 to 256\n");
  1537.         return 0;
  1538.     }
  1539.     tprintf("            Main Memory Dump Of Location %Fp\n", addr);
  1540.     tputs("Addr (offset)           Hexadecimal                         Ascii\n");
  1541.     tputs("----                    -----------                         -----\n\n");
  1542.   
  1543.     for(i = 0; i < len; i += 16)
  1544.         fmtline(i, (char *)(addr + i), 16);
  1545.     DumpAddr = (char *)(addr + i);          /* update address */
  1546.     return 0;
  1547. }
  1548.   
  1549. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  1550.  * translation, e.g.,
  1551.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  1552.  */
  1553. static void
  1554. fmtline(addr,buf,len)
  1555. int16 addr;
  1556. char *buf;
  1557. int16 len;
  1558. {
  1559.     char line[81];
  1560.     register char *aptr,*cptr;
  1561.     register char c;
  1562.   
  1563.     memset(line,' ',sizeof(line));
  1564.     ctohex(line,(int16)hibyte(addr));
  1565.     ctohex(line+2,(int16)lobyte(addr));
  1566.     aptr = &line[6];
  1567.     cptr = &line[55];
  1568.     while(len-- != 0){
  1569.         c = *buf++;
  1570.         ctohex(aptr,(int16)uchar(c));
  1571.         aptr += 3;
  1572.         c &= 0x7f;
  1573.         if((c > 0x1f) && (c < 0x7f))
  1574.             *cptr++ = c;
  1575.         else
  1576.             *cptr++ = '.';
  1577.     }
  1578.     *cptr++ = '\0';
  1579.     tprintf("%s\n",line);
  1580. }
  1581. /* Convert byte to two ascii-hex characters */
  1582. static void
  1583. ctohex(buf,c)
  1584. register char *buf;
  1585. register int16 c;
  1586. {
  1587.     static char hex[] = "0123456789abcdef";
  1588.   
  1589.     *buf++ = hex[hinibble(c)];
  1590.     *buf = hex[lonibble(c)];
  1591. }
  1592. #endif
  1593.   
  1594. int
  1595. dowrite(argc,argv,p)
  1596. int argc;
  1597. char *argv[];
  1598. void *p;
  1599. {
  1600.     int s;
  1601.     struct mbx *m;
  1602.   
  1603.     if((s = atoi(argv[1])) == 0) { /* must be a name */
  1604. #ifdef MAILBOX
  1605.         /* check the mailbox users */
  1606.         for(m=Mbox;m;m=m->next){
  1607.             if(!stricmp(m->name,argv[1]))
  1608.                 break;
  1609.         }
  1610.         if(!m)
  1611.             return 0;
  1612.         s = m->user;
  1613. #else
  1614.         return 0;
  1615. #endif
  1616.     }
  1617.     usprintf(s,"*** Msg from SYSOP: %s\n",argv[2]);
  1618.     usflush(s);
  1619.   
  1620.     return 0;
  1621. }
  1622.   
  1623. #ifdef MAILBOX
  1624. /* write a message to all nodeshell users
  1625.  * argv[1] is the message.
  1626.  */
  1627. int
  1628. dowriteall(argc,argv,p)
  1629. int argc;
  1630. char *argv[];
  1631. void *p;
  1632. {
  1633.     struct mbx *m;
  1634.   
  1635.     for(m=Mbox;m;m=m->next){
  1636.         if(m->sid & MBX_SID)
  1637.             continue;
  1638.         usprintf(m->user,"*** Msg from SYSOP: %s\n",argv[1]);
  1639.         usflush(m->user);
  1640.     }
  1641.     return 0;
  1642. }
  1643. #endif
  1644.   
  1645.   
  1646. int
  1647. dostatus(argc,argv,p)
  1648. int argc;
  1649. char *argv[];
  1650. void *p;
  1651. {
  1652.     time_t nowtime, elapsedtime, nosseconds;
  1653.     unsigned int days,hrs,mins,secs;
  1654.   
  1655.     nowtime = time(&nowtime);                       /* current time */
  1656.     nosseconds = secclock();                    /* Current NOS lifetime */
  1657.     elapsedtime = nowtime - StartTime;              /* nos elapsed time */
  1658.   
  1659.     tprintf(Nosversion,Version);
  1660.     tputs(Version2);
  1661. /*    tprintf("Tty: %d rows, %d columns\n",Numrows,Numcols);   zkd */
  1662.   
  1663. #ifdef  MSDOS
  1664.     tprintf(NosLoadInfo, _CS, _DS);
  1665. #endif
  1666.     tprintf("\nThe system time is %s", ctime(&nowtime));
  1667.     tprintf("NOS was started on %s\n", ctime(&StartTime));
  1668.     tprintf("Uptime => %s\n",tformat(secclock()));  /*zkd*/
  1669.     if(nosseconds < elapsedtime)
  1670.         tprintf("NOS has lost %lu seconds in missed clock ticks!\n", \
  1671.         elapsedtime - nosseconds);
  1672.     tputc('\n');
  1673. #ifdef TTYLINKSERVER
  1674.     tprintf("The station is currently %sttended.\n", Attended ? "A" : "Una");
  1675. #endif
  1676. #ifdef ALLCMD
  1677.     tputs("The 'Message Of The Day' is ");
  1678.     if(Motd != NULLCHAR)
  1679.         tprintf("\n%s",Motd);
  1680.     else
  1681.         tputs("not set!\n");
  1682. #endif
  1683. #ifdef  __TURBOC__
  1684.     dofstat();              /* print status of open files */
  1685. #endif
  1686.     return 0;
  1687. }
  1688.   
  1689. #ifdef ALLCMD
  1690. int
  1691. domotd(argc,argv,p)
  1692. int argc;
  1693. char *argv[];
  1694. void *p;
  1695. {
  1696.     if(argc > 2) {
  1697.         tputs("Usage: motd \"<your message>\"\n");
  1698.         return 1;
  1699.     }
  1700.   
  1701.     if(argc < 2) {
  1702.         if(Motd != NULLCHAR)
  1703.             tputs(Motd);
  1704.     } else {
  1705.         if(Motd != NULLCHAR){
  1706.             free(Motd);
  1707.             Motd = NULLCHAR;                /* reset the pointer */
  1708.         }
  1709.   
  1710.         if(!strlen(argv[1]))
  1711.             return 0;                       /* clearing the buffer */
  1712.   
  1713.         Motd = mallocw(strlen(argv[1])+5);      /* allow for the EOL char etc */
  1714.         strcpy(Motd, argv[1]);
  1715.         strcat(Motd, "\n");                     /* add the EOL char */
  1716.     }
  1717.     return 0;
  1718. }
  1719. #endif /*ALLCMD*/
  1720.   
  1721. #ifdef  __TURBOC__
  1722. /*
  1723.  * Fstat utility code.
  1724.  * Converted to go into NOS by Kelvin Hill - G1EMM  April 9, 1990
  1725.  */
  1726.   
  1727. extern unsigned char _osmajor;
  1728.   
  1729. static char    *localcopy(char far *);
  1730. static char    *progname(unsigned int);
  1731.   
  1732. #ifdef __TURBOC__
  1733.   
  1734. extern char *Taskers[];
  1735. extern int Mtasker;
  1736.   
  1737. int
  1738. dofstat()
  1739. {
  1740.     union REGS regs;
  1741.     struct SREGS segregs;
  1742.     char far *pfiletab, far * pnext, far * fp;
  1743.     char far *name, file[13], far * plist, far * entry;
  1744.     char ownername[9], ownerext[5];
  1745.     int nfiles, i, j, numhandles, entrylen;
  1746.     unsigned int access, devinfo, progpsp;
  1747.     long length, offset;
  1748.     int heading = 0;
  1749.   
  1750.     regs.h.ah = 0x52;       /* DOS list of lists */
  1751.     intdosx(®s, ®s, &segregs);
  1752.   
  1753.     /* make a pointer to start of master list */
  1754.     plist = (char far *) MK_FP(segregs.es, regs.x.bx);
  1755.   
  1756.     /* pointer to start of file table */
  1757.     pfiletab = (char far *) MK_FP(*(int far *) (plist + 6), *(int far *) (plist + 4));
  1758.   
  1759.     switch (_osmajor) {
  1760.         case 2:
  1761.             entrylen = 40;  /* DOS 2.x */
  1762.             break;
  1763.         case 3:
  1764.             entrylen = 53;  /* DOS 3.x */
  1765.             break;
  1766.         case 4:
  1767.         case 5:                 /* DOS 5.x - like dos 4.x */
  1768.         case 6:                 /* and NOW DOS 6.0 also */
  1769.             entrylen = 59;  /* DOS 4.x - I do not know what is in the
  1770.                  * extra 6 bytes */
  1771.             break;
  1772.         default:
  1773.             tprintf("File table not available under %s\n",Taskers[Mtasker]);
  1774.             return 1;
  1775.     }
  1776.   
  1777.     for (;;) {
  1778.         /* pointer to next file table */
  1779.         pnext = (char far *) MK_FP(*(int far *) (pfiletab + 2), *(int far *) (pfiletab + 0));
  1780.         nfiles = *(int far *) (pfiletab + 4);
  1781. #ifdef DEBUG
  1782.         tprintf("\nFile table at %Fp entries for %d files\n", pfiletab, nfiles);
  1783. #endif
  1784.         for (i = 0; i < nfiles; i++) {
  1785.   
  1786.             /*
  1787.              * cycle through all files, quit when we reach an
  1788.              * unused entry
  1789.              */
  1790.             entry = pfiletab + 6 + (i * entrylen);
  1791.             if (_osmajor >= 3) {
  1792.                 name = entry + 32;
  1793.                 strncpy(file, localcopy(name), 11);
  1794.                 file[11] = '\0';
  1795.                 numhandles = *(int far *) (entry + 0);
  1796.                 access = (int) *(char far *) (entry + 2);
  1797.                 length = *(long far *) (entry + 17);
  1798.                 offset = *(long far *) (entry + 21);
  1799.                 devinfo = *(int far *) (entry + 5);
  1800.                 progpsp = *(int far *) (entry + 49);
  1801.             } else {
  1802.                 name = entry + 4;
  1803.                 strncpy(file, localcopy(name), 11);
  1804.                 file[11] = '\0';
  1805.                 numhandles = (int) *(char far *) (entry + 0);
  1806.                 access = (int) *(char far *) (entry + 1);
  1807.                 length = *(long far *) (entry + 19);
  1808.                 offset = *(long far *) (entry + 36);
  1809.                 devinfo = (int) *(char far *) (entry + 27);
  1810.             }
  1811.             if ((strlen(file) > 0) && (numhandles > 0) && !(devinfo & 0x80)) {
  1812.                 if(!heading) {
  1813.                     tputc('\n');
  1814.                     tputs("                 Table of Open Files.\n");
  1815.                     tputs("                 --------------------\n");
  1816.                     tputs("Name           length   offset hnd acc PSP device type/owner\n");
  1817.                     tputs("----           ------   ------ --- --- --- -----------------\n");
  1818.                     heading++;              /* header now printed */
  1819.                 }
  1820.                 tprintf("%8.8s.%3.3s %8ld %8ld  %2d ",
  1821.                 file, &file[8], length, offset, numhandles);
  1822.                 switch (access) {
  1823.                     case 0:
  1824.                         tputs("r  ");
  1825.                         break;
  1826.                     case 1:
  1827.                         tputs("w  ");
  1828.                         break;
  1829.                     case 2:
  1830.                         tputs("rw ");
  1831.                         break;
  1832.                     default:
  1833.                         tputs("   ");
  1834.                 }
  1835.                 if (_osmajor >= 3)
  1836.                     tprintf("%04X ", progpsp);
  1837.                 else
  1838.                     tputs("---- ");
  1839.                 tprintf("drive %c: ", 'A' + (devinfo & 0x1F));
  1840.                 if (devinfo & 0x8000)
  1841.                     tputs("(network) ");
  1842.                 if (_osmajor >= 3) {
  1843.                     /*
  1844.                      * only DOS 3+ can find out
  1845.                      * the name of the program
  1846.                      */
  1847.                     fnsplit(progname(progpsp), NULL, NULL, ownername, ownerext);
  1848.                     tprintf("   [%s%s]\n", strlwr(ownername), strlwr(ownerext));
  1849.                 } else {
  1850.                     tputc('\n');
  1851.                 }
  1852.             }
  1853.             if (strlen(file) == 0)
  1854.                 return 0;
  1855.         }
  1856.         pfiletab = pnext;
  1857.     }
  1858. }
  1859. #endif /* __TURBOC__ */
  1860.   
  1861. /* Make a copy of a string pointed to by a far pointer */
  1862. static char *
  1863. localcopy(s)
  1864. char far *s;
  1865. {
  1866.     static char localstring[256];
  1867.     char far *p = s;
  1868.     char *l = localstring;
  1869.     int i = 0;
  1870.   
  1871.     while (*p != NULL && i++ < 255) {
  1872.         *l++ = *p++;
  1873.     }
  1874.   
  1875.     *l = '\0';
  1876.   
  1877.     return (localstring);
  1878. }
  1879.   
  1880. /*
  1881.  * Return a near pointer to a character string with the full path name of the
  1882.  * program whose PSP is given in the argument.  If the argument is invalid,
  1883.  * this may return gibberish but I don't know how to tell Offset 0x2C in the
  1884.  * PSP in the segment address of the environment of a program.  Beyond the
  1885.  * last environment string is a null marker, a word count (usually 1), then
  1886.  * the full pathname of the owner of the environment This only works for DOS
  1887.  * 3+
  1888.  */
  1889. static char *
  1890. progname(pid)
  1891. unsigned int pid;
  1892. {
  1893.     unsigned far   *envsegptr;      /* Pointer to seg address of
  1894.                      * environment */
  1895.     char far       *envptr; /* Pointer to pid's environment  */
  1896.     unsigned far   *envsizeptr;     /* Pointer to environment size */
  1897.     unsigned        envsize;/* Size of pid's environment */
  1898.     unsigned        ppid;   /* Parent psp address */
  1899.   
  1900.     /* find the parent process psp at offset 0x16 of the psp */
  1901.     ppid = *(unsigned far *) MK_FP(pid, 0x16);
  1902.   
  1903.     /* find the environment at offset 2Ch of the psp */
  1904.     envsegptr = (unsigned far *) MK_FP(pid, 0x2C);
  1905.     envptr = (char far *) MK_FP(*envsegptr, 0);
  1906.   
  1907.     /*
  1908.      * Make a pointer that contains the size of the environment block.
  1909.      * Must point back one paragraph (to the environments MCB plus three
  1910.      * bytes forward (to the MCB block size field).
  1911.      */
  1912.     envsizeptr = (unsigned far *) MK_FP(*envsegptr - 1, 0x3);
  1913.     envsize = *envsizeptr * 16;     /* x 16 turns it into bytes */
  1914.   
  1915.     while (envsize > 0) {
  1916.         /* search for end of environment block, or NULL */
  1917.         while (--envsize && *envptr++);
  1918.   
  1919.         /*
  1920.          * Now check for another NULL immediately following the first
  1921.          * one located and a word count of 0001 following that.
  1922.          */
  1923.         if (!*envptr && *(unsigned far *) (envptr + 1) == 0x1) {
  1924.             envptr += 3;
  1925.             break;
  1926.         }
  1927.     }
  1928.   
  1929.     if (envsize > 0) {
  1930.         /* Owner name found - return it */
  1931.         return (localcopy(envptr));
  1932.     } else {
  1933.         if (pid == ppid) {
  1934.             /*
  1935.              * command.com doesn't leave it's name around, but if
  1936.              * pid = ppid then we know we have a shell
  1937.              */
  1938.             return ("-shell-");
  1939.         } else {
  1940.             return ("unknown");
  1941.         }
  1942.     }
  1943. }
  1944. #endif /*__TURBOC__*/
  1945.   
  1946. int
  1947. doprompt(argc,argv,p)
  1948. int argc;
  1949. char *argv[];
  1950. void *p;
  1951. {
  1952.     return setbool(&DosPrompt,"prompt",argc,argv);
  1953. }
  1954.   
  1955. /* Command history, see also pc.c - WG7J */
  1956. void logcmd(char *cmd) {
  1957.     struct hist *new;
  1958.     char *cp;
  1959.   
  1960.     if(!Maxhistory)     /* don't keep history */
  1961.         return;
  1962.   
  1963.     /* Get rid of \n; this is also done in cmdparse().
  1964.      * We HAVE to do this here, since the string is NOT null-terminated when
  1965.      * it comes from recv_mbuf()  !!!! rip() makes it nullterminated.
  1966.      */
  1967.     rip(cmd);
  1968.     cp = cmd;
  1969.     while(*cp == ' ' || *cp == '\t')
  1970.         cp++;
  1971.     if(!*cp)     /* Empty command */
  1972.         return;
  1973.   
  1974.     if(Histrysize < Maxhistory) {     /* Add new one */
  1975.         Histrysize++;
  1976.         if(!Histry) {           /* Empty list */
  1977.         /* Initialize circular linked list */
  1978.             Histry = mallocw(sizeof(struct hist));
  1979.             Histry->next = Histry->prev = Histry;
  1980.         } else {
  1981.             new = mallocw(sizeof(struct hist));
  1982.         /* Now link it in */
  1983.             Histry->next->prev = new;
  1984.             new->next = Histry->next;
  1985.             new->prev = Histry;
  1986.             Histry->next = new;
  1987.             Histry = new;
  1988.         }
  1989.     } else {
  1990.     /* Maximum number stored already, use the oldest entry */
  1991.         Histry = Histry->next;
  1992.         free(Histry->cmd);
  1993.     }
  1994.     Histry->cmd = strdup(cp);
  1995. }
  1996.   
  1997. int
  1998. dohistory(int argc,char *argv[],void *p) {
  1999.     struct hist *h;
  2000.     int num;
  2001.   
  2002.     if(argc > 1) {
  2003.         Maxhistory = atoi(argv[1]);
  2004.         return 0;
  2005.     }
  2006.     tprintf("Max recall %d\n",Maxhistory);
  2007.     if((h = Histry) == NULL)
  2008.         return 0;
  2009.     num = 0;
  2010.     do {
  2011.         tprintf("%.2d: %s\n",num++,h->cmd);
  2012.         h = h->prev;
  2013.     } while(h != Histry);
  2014.     return 0;
  2015. }
  2016.   
  2017. #ifdef __BORLANDC__
  2018.   
  2019. /* This adds some additional checks to the fopen()
  2020.  * in the Borland C++ Run Time Library.
  2021.  * It fixes problem with users trying to open system devices like
  2022.  * CON, AUX etc and hang a system.
  2023.  * WG7J, 930205
  2024.  * reworked by N5KNX 8/94 to allow output to printers iff PRINTEROK is defined,
  2025.  * AND the printer can accept output.  It's still risky; JNOS can lockup if
  2026.  * the printer won't accept output.
  2027.  */
  2028. #undef fopen
  2029. FILE _FAR *_Cdecl fopen(const char _FAR *__path, const char _FAR *__mode);
  2030.  
  2031. static char *InvalidName[] = {
  2032.     "NUL",
  2033.     "CON","CON:",
  2034.     "AUX","AUX:",
  2035.     "PRN","PRN:",
  2036.     "LPT1","LPT1:",
  2037.     "LPT2","LPT2:",
  2038.     "LPT3","LPT3:",
  2039.     "COM1","COM1:",
  2040.     "COM2","COM2:",
  2041.     "COM3","COM3:",
  2042.     "COM4","COM4:",
  2043.     "MOUSE$",
  2044.     "CLOCK$",
  2045.     NULLCHAR
  2046. };
  2047.   
  2048. FILE *newfopen (const char *filename, const char *type) {
  2049.     char *cp, *cp1;
  2050.     int i,j;
  2051. #include <bios.h>
  2052.   
  2053.     cp = strrchr(filename, '\\');
  2054.     cp1 = strrchr(filename, '/');
  2055.     if (cp < cp1) cp = cp1;
  2056.     if (cp == NULLCHAR) cp = (char *)filename;
  2057.     else cp++;
  2058.     if ((cp1 = strchr(cp, '.')) == NULLCHAR) j = strlen(cp);
  2059.     else j = (int)(cp1 - cp);
  2060.     if (j==0) return NULL;   /* path is to a dir, or entryname is .XXX, clearly bad */
  2061.  
  2062.     for(i=0;InvalidName[i] != NULLCHAR;i++)
  2063.     if(strnicmp(InvalidName[i],cp, j) == 0) {
  2064.         if (strpbrk(type, "wWaA") == NULLCHAR) return NULL;  /* must be writing */
  2065. #if defined(PRINTEROK)
  2066.         j=-1;
  2067.         if (strnicmp(cp, "prn", 3)==0 ) j=0;
  2068.         else if (strnicmp(cp, "lpt", 3)==0) j=(*(cp+3) - '1');
  2069.         if (j>=0 && j<3 && ((i=_bios_printer(2,j,0)&0xb9) == 0x90)) break;  /* must be selected, no errors, not busy */
  2070. #endif
  2071.         return NULL;
  2072.     }
  2073.  
  2074.     return fopen (filename, type);
  2075. }
  2076. #endif /* __BORLANDC__ */
  2077.   
  2078. #ifdef REPEATSESSION
  2079.   
  2080. #if defined(__TURBOC__) && !defined(__BORLANDC__)
  2081. /* N5KNX: TurboC 2.0 lacks _setcursortype(), which we supply here for dorepeat */
  2082. void _setcursortype(int style)
  2083. {
  2084. /* From TurboC++ conio.h: */
  2085. #define _NOCURSOR      0
  2086. #define _SOLIDCURSOR   1
  2087. #define _NORMALCURSOR  2
  2088.   
  2089. /* Int 0x10 reg cx codes: */
  2090. #define   STD_CURSOR      0x0607
  2091. #define   BLK_CURSOR      0x0006
  2092. #define   NO_CURSOR       0x2607
  2093.   
  2094.     union REGS regs;
  2095.   
  2096.     if (style == _NOCURSOR) regs.x.cx = NO_CURSOR;
  2097.     else if (style == _SOLIDCURSOR) regs.x.cx = BLK_CURSOR;
  2098.     else if (style == _NORMALCURSOR) regs.x.cx = STD_CURSOR;
  2099.     else return;
  2100.     regs.x.ax = 0x0100; /* set cursor */
  2101.     int86(0x10, ®s, ®s);
  2102. }
  2103. #endif
  2104.   
  2105. /* Repeat a command - taken from 930104 KA9Q NOS
  2106.    WA3DSP 1/93
  2107. */
  2108. int
  2109. dorepeat(argc,argv,p)
  2110. int argc;
  2111. char *argv[];
  2112. void *p;
  2113. {
  2114.     int32 interval;
  2115.     int ret;
  2116.     struct session *sp;
  2117.   
  2118.     if(isdigit(argv[1][0])){
  2119.         interval = atol(argv[1]);
  2120.         argc--;
  2121.         argv++;
  2122.     } else {
  2123.         interval = MSPTICK;
  2124.     }
  2125.     if((sp = newsession(argv[2],REPEAT,1)) == NULLSESSION){
  2126.         tputs("Too many sessions\n");
  2127.         return 1;
  2128.     }
  2129.     _setcursortype(_NOCURSOR);
  2130.     while(sp==Current){
  2131.         /*  clrscr(); */
  2132.         /* gotoxy seems to work better - turn cursor off?? */
  2133.         gotoxy(1,1);
  2134.         ret = subcmd(Cmds,argc,argv,p);
  2135.         if(ret != 0 || pause(interval) == -1)
  2136.             break;
  2137.     }
  2138.     _setcursortype(_NORMALCURSOR);
  2139.     freesession(sp);
  2140.     return 0;
  2141. }
  2142. #endif /* REPEATSESSION */
  2143.   
  2144.   
  2145. /* Index given mailbox files */
  2146. int doindex(int argc,char *argv[],void *p) {
  2147.     int i;
  2148.   
  2149.     for(i=1;i<argc;i++) {
  2150.         if(*argv[i] == '*') {
  2151.             UpdateIndex(NULL,1);
  2152.             /* No reason to do others */
  2153.             return 0;
  2154.         } else {
  2155.             dirformat(argv[i]);
  2156.             /* Attempt to lock the mail file! */
  2157.             if(mlock(Mailspool,argv[i])) {
  2158.                 tprintf("Can not lock '%s/%s.txt'!\n",Mailspool,argv[i]);
  2159.                 continue;
  2160.             }
  2161.             if(IndexFile(argv[i],0) != 0)
  2162.                 tprintf("Error writing index file for %s\n",argv[i]);
  2163.             /* Remove the lock */
  2164.             rmlock(Mailspool,argv[i]);
  2165.         }
  2166.     }
  2167.   
  2168.     return 0;
  2169. }
  2170.   
  2171. /* interpret a string "f+b", where f and b are numbers indicating
  2172.  * foreground and background colors to make up the text attribute
  2173.  */
  2174. void GiveColor(char *s,char *attr) {
  2175.     char *cp;
  2176.   
  2177.     if((cp=strchr(s,'+')) != NULL) {
  2178.         *cp++ = '\0';
  2179.         *attr = (char) atoi(s) & 0x0f;  /* Foreground color */
  2180.         *attr += ((char) atoi(cp) & 0x07) << 4;  /* Background, no blinking ! */
  2181.     }
  2182. }
  2183.