home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / Mac⁄gnuucp 6.14 / source / sysdep.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-21  |  22.6 KB  |  1,125 lines  |  [TEXT/KAHL]

  1. /*
  2.  * @(#)sysdep.mac 1.2 87/09/23    Copyright 1987 Free Software Foundation, Inc.
  3.  *
  4.  * Copying and use of this program are controlled by the terms of the
  5.  * GNU Emacs General Public License.
  6.  */
  7.  
  8. #ifndef lint
  9. char sysdep_version[] = "@(#)sysdep.mac gnuucp Version Fort Pond Research-6.14";
  10. #endif
  11.  
  12. /*
  13.  * Created 22 September 1987 by John Gilmore, 
  14.  * using code from sun!seismo!psc!jsl (John Labovitz).
  15.  * His comments:
  16.  
  17.     1. Logging cleanup.  It makes it somewhat easier to make the
  18.        right time and date for whatever OS you're using.  I made it
  19.        more modular.
  20.     2. Changes in the login routine to let it be more like real Unix
  21.        systems.  I made a special routine that reads a line from the
  22.        input port, and *then* checks it, instead of only checking each
  23.        character as it comes in.  Also, it handles ^D, which my Unix
  24.        systems uses to make sure there's a prompt.  Doesn't handle break.
  25.  
  26. This needs some more work on the Mac side, like letting the user abort
  27. uuslave.  Right now you have to reset the machine!
  28.  
  29. Hope this is useful.  I'm really interesting in running this thing, although
  30. I'm not quite sure how I'm going to configure it (like how to read mail on
  31. the Mac).  But soon I'll be "potomac!sly!jsl".  What I might do is actually
  32. run this as a server on a PC, connected to the Unix machine via RS232, then
  33. write a program on the Mac that can access the PC via Appletalk (aon the
  34. MacBridge card) and get the mail.  That way, any of our 30 macs can get mail
  35. without being connected to Unix... Dreams.
  36.  
  37.  */
  38.  
  39. #include "includes.h"
  40. #include <pascal.h>
  41. #include "uucp.h"
  42. #include <Devices.h>
  43. #include <Serial.h>
  44. #include <Errors.h>
  45. #include <LoMem.h>
  46. #include <Desk.h>
  47. #include <Devices.h>
  48.  
  49. #define    CONTROL    "gnuucp.ctl"
  50.  
  51. long total_data_processed = 0;
  52.  
  53. int abort_key_pressed(void);
  54. void HandleEvent (EventRecord *, int);
  55. int gnuucp_cleaned_up = 0;
  56.  
  57.  
  58. /*
  59.  * Exported variables
  60.  */
  61. char     sysdep_control[] = CONTROL;
  62.  
  63. /*
  64.  * Open the serial line for an incoming call.
  65.  * Argument of NULL or empty string means stdin.
  66.  * FIXME, baud rate should be settable here?
  67.  */
  68.  
  69. char inbuf[SER_BUF_SIZE];
  70. char outbuf[SER_BUF_SIZE];
  71.  
  72. Boolean GNUPortOpen = FALSE;
  73. int inRefNum;
  74. unsigned char *inRefName;
  75. int outRefNum;
  76. unsigned char *outRefName;
  77.  
  78. void dtr_state(Boolean);
  79.  
  80. void drop_dtr_for (int amt);
  81.  
  82. int
  83. openline(ttynam, baud)
  84.     char    *ttynam;
  85.     int    baud;
  86. {
  87.     int baud_set;
  88.     int compos;
  89.     int err;
  90.     SerShk SerFlags;
  91.     compos = strcmp(".B", ttynam);
  92.     if (compos == -1) 
  93.         {
  94.             inRefNum = binRefNum;
  95.             inRefName = "\p.Bin";
  96.             outRefNum = boutRefNum;
  97.             outRefName = "\p.Bout";
  98.             }
  99.         else
  100.         {
  101.             compos = strcmp(".A", ttynam);
  102.             if (compos == -1)
  103.                 {
  104.                     inRefNum = ainRefNum;
  105.                     inRefName = "\p.Ain";
  106.                     outRefNum = aoutRefNum;
  107.                     outRefName = "\p.Aout";
  108.                     }
  109.             else
  110.                 {
  111.                     logit("Unknown port.", ttynam);
  112.                     sigint(0);
  113.                     }
  114.             }
  115.     switch (baud)
  116.         {
  117.             case 300:
  118.                 baud_set = baud300;
  119.                 break;
  120.             case 1200:
  121.                 baud_set = baud1200;
  122.                 break;
  123.             case 2400:
  124.                 baud_set = baud2400;
  125.                 break;
  126.             case 3600:
  127.                 baud_set = baud3600;
  128.                 break;
  129.             case 4800:
  130.                 baud_set = baud4800;
  131.                 break;
  132.             case 7200:
  133.                 baud_set = baud7200;
  134.                 break;
  135.             case 9600:
  136.                 baud_set = baud9600;
  137.                 break;
  138.             case 19200:
  139.                 baud_set = baud19200;
  140.                 break;
  141.             case 57600:
  142.                 baud_set = baud57600;
  143.                 break;
  144.             default:
  145.                 return(EOF);
  146.                 break;
  147.                 }
  148.     if (OpenDriver(inRefName, (short *)&inRefNum) != noErr)
  149.         return(EOF);
  150.     if (OpenDriver(outRefName, (short *)&outRefNum) != noErr)
  151.         return(EOF);
  152.     GNUPortOpen = TRUE;
  153.     SerReset(inRefNum, baud_set+data8+stop10);
  154.     SerReset(outRefNum, baud_set+data8+stop10);
  155.     SerSetBuf(inRefNum, inbuf, SER_BUF_SIZE);
  156.     SerSetBuf(outRefNum, outbuf, SER_BUF_SIZE);
  157.     SerFlags.fXOn = 0;
  158.     SerFlags.fCTS = 0;
  159.     SerFlags.xOn = 0; 
  160.     SerFlags.xOff = 0;
  161.     SerFlags.errs = 0;
  162.     SerFlags.evts = 0;
  163.     SerFlags.fInX = 0;
  164.     SerFlags.fDTR = 0;
  165.     SerHShake(inRefNum, &SerFlags);
  166.     SerHShake(outRefNum, &SerFlags);    
  167.     dtr_state(TRUE);
  168.     gnuucp_cleaned_up = 0;
  169.     gnusleep(1); /* Let the line settle */ 
  170.     return(0);
  171. }
  172.  
  173. /*
  174.  * Open the serial line for an outgoing call.
  175.  */
  176. int
  177. openout(p)
  178.     struct port *p;
  179.     {
  180.     int tty;
  181.     tty = openline(p->devname, p->baud);
  182.     return(tty);
  183. }
  184.  
  185. int
  186. openin(p)
  187.     struct port *p;
  188.     {
  189.     int tty;
  190.     char *ttynam;
  191.     char *modemname;
  192.     int baud;
  193.     ttynam = p->devname;
  194.     modemname = p->modemname;
  195.     baud = p->baud;
  196.     tty = openline(ttynam, baud);
  197.     if (strcmp(modemname, "none") != 0)
  198.         {
  199.             xwrite(/* 0, */"+++", 3);
  200.             gnusleep(4);
  201.             xwrite(/* 0, */"ats0=2\r", 7);
  202.             }
  203.     return(tty);
  204. }
  205. /*
  206.  * Basement level I/O routines
  207.  *
  208.  * xwrite() writes a character string to the serial port
  209.  * xgetc() returns a character from the serial port, or an EOF for timeout.
  210.  * sigint() restores the state of the serial port on exit.
  211.  * hangup() hangs up the serial port (e.g. drop DTR).
  212.  */
  213.  
  214. void
  215. sigint(val)
  216. int val;
  217. {
  218.     exit(1);
  219.     }
  220.  
  221. xwrite(/* dummy, */ buf, ctr)
  222. /* int dummy; */
  223. char *buf;
  224. int ctr;
  225. {
  226.     long count;
  227.     
  228.     count = ctr;
  229.     
  230.     HandleEvents();
  231.     if (FSWrite(outRefNum, &count, buf) != noErr)
  232.         return(EOF);
  233.     total_data_processed += ctr;
  234.     return((int)count);
  235. }
  236.  
  237. long xgetc_buf_pos = 0;
  238. long xgetc_buf_count = 0;
  239. unsigned char xgetc_buf[SER_BUF_SIZE];
  240.  
  241. int xgetc_fill_buff()
  242. {
  243.     long count;
  244.     SerGetBuf(inRefNum, &count);
  245.     if (count > SER_BUF_SIZE) count = SER_BUF_SIZE;
  246.     if (FSRead(inRefNum, &count, xgetc_buf) != noErr)
  247.         return(0);
  248.     else
  249.         xgetc_buf_count = count;
  250.         xgetc_buf_pos = 0;
  251.         return(count);
  252.     }
  253.     
  254. xgetc()
  255. {
  256.     long count;
  257.     long i;
  258.     if (xgetc_buf_count > 0) 
  259.         {
  260.             unsigned char data;
  261.             data = xgetc_buf[xgetc_buf_pos];
  262.             total_data_processed++;
  263.             xgetc_buf_pos++;
  264.             xgetc_buf_count--;
  265.             return(data & 0xFF);
  266.                }
  267.     i = TickCount() + (ByteTimeout * 60L);
  268.     count = 0;
  269.     while ((TickCount() < i) && xgetc_buf_count <= 0) 
  270.     {
  271.         HandleEvents();
  272.         xgetc_fill_buff();
  273.         if (xgetc_buf_count > 0) break;
  274.         gnusleep(1);
  275.         }
  276.     if (xgetc_buf_count > 0) 
  277.         {
  278.             unsigned char data;
  279.             data = xgetc_buf[xgetc_buf_pos];
  280.             total_data_processed++;
  281.             xgetc_buf_pos++;
  282.             xgetc_buf_count--;
  283.             return(data & 0xFF);
  284.                }
  285.          else
  286.            return(EOF);
  287.     }
  288.  
  289. void
  290. send_break ()
  291. {
  292.     SerSetBrk(outRefNum);
  293.     gnusleep(1);
  294.     SerClrBrk(outRefNum);
  295.     }
  296.     
  297. /*
  298.  * hangup(): hang up the 'fone.
  299.  */
  300. int
  301. hangup(p)
  302. struct port *p;
  303. {
  304.  
  305.     char *modemname;
  306.     modemname = p ->modemname;
  307.     if (GNUPortOpen == TRUE);
  308.         {
  309.             drop_dtr_for (1);
  310.             }
  311.     if (strcmp(modemname, "none") != 0)
  312.         {
  313.             xlat_str(DialPostfix);
  314.             // xwrite(/* (int)NULL, */"+++", 3);
  315.             // gnusleep(3);
  316.             // xwrite(/* (int)NULL, */"ATH\r", 4);
  317.             // gnusleep(1);
  318.             // xwrite(/* (int)NULL, */"ats0=0\r", 7);
  319.             }
  320.     if (GNUPortOpen == TRUE);
  321.         {
  322.             CloseDriver(inRefNum);
  323.             CloseDriver(outRefNum);
  324.             GNUPortOpen = FALSE;
  325.             }
  326.     gnuucp_cleaned_up = 1;
  327.     }
  328.         
  329.  
  330.  
  331. /*
  332.  * Create a temporary file name for receiving a file into.
  333.  * "name" is the name we will actually eventually want to use for the file.
  334.  * We currently ignore it, but some OS's that can't move files around
  335.  * easily might want to e.g. put the temp file into the same directory
  336.  * that this file is going into.
  337.  *
  338.  * FIXME:
  339.  * This interface should be able to return a "possible" filename, and
  340.  * be re-called if the name is already in use, to get another.
  341.  * This avoids checking here whether the name is good -- saving system calls.
  342.  */
  343. #define MAXTRIES 20
  344. char *
  345. temp_filename(name)
  346.     register char *name;
  347. {
  348.     static char tname[NAMESIZE];
  349.     int i;
  350.     FILE *fd;
  351.     i = 0;
  352.     if (ourpid == 0)
  353.         ourpid = getpid();
  354.     while (TRUE)
  355.         {
  356.             i++;
  357.             (void) sprintf(tname, "TM.u%d", rand());
  358.             if (access(tname, 0) != 0)
  359.                 break;
  360.             if (i == MAXTRIES) 
  361.                 {
  362.                     printf("can't generate unique file name\n");
  363.                     exit(EXIT_ERR);
  364.                     }
  365.     }
  366.     DEBUG(7, "Using temp file %s\n", tname);
  367.     return tname;
  368. }
  369.  
  370.  
  371. /*
  372.  * Transform a filename from a uucp packet (in Unix format) into a local
  373.  * filename that will work in the local file system.
  374.  *
  375.  * This is a real hack; it puts all the files into one big directory.
  376.  * Everything.  Yuk.
  377.  */
  378. char *
  379. munge_filename(name)
  380.     register char *name;
  381. {
  382.     register char *p;
  383.     static char buffer[NAMESIZE+SLOP];
  384.     int len, hostlen;
  385.     int i, j;
  386.     Boolean found_dot = FALSE;
  387.     DEBUG(7, "Munge_filename  input: %s\n", name);
  388.  
  389.     for (p = name + strlen(name); p != name && *(p-1) != '/'; p--) ;
  390.     len = strlen(p);
  391.     for (i = 0, j = 0; i < len; i++, j++)
  392.         {
  393.             if (name[i] == '.') found_dot = TRUE;
  394.             if ((isupper(name[i]) != 0) && (found_dot == TRUE))
  395.                 {
  396.                     buffer[j] = '_';
  397.                     j++;
  398.                     }
  399.             buffer[j] = name[i];
  400.             }
  401.     buffer[j] = '\0';
  402.     DEBUG(7, "Munge_filename output: %s\n", buffer);
  403.     return buffer;
  404. }
  405.  
  406. char *
  407. unmunge_filename(name)
  408.     register char *name;
  409. {
  410.     register char *p;
  411.     static char unbuffer[NAMESIZE+SLOP];
  412.     int len, hostlen;
  413.     int i, j;
  414.     Boolean found_dot = FALSE;
  415.     DEBUG(7, "Unmunge_filename  input: %s\n", name);
  416.  
  417.     for (p = name + strlen(name); p != name && *(p-1) != '/'; p--) ;
  418.     len = strlen(p);
  419.     for (i = 0, j = 0; i < len; i++, j++)
  420.         {
  421.             if (name[i] == '.') found_dot = TRUE;
  422.             if ((name[i] == '_') && (found_dot == TRUE))
  423.                 {
  424.                     i++;
  425.                     unbuffer[j] = toupper(name[i]);
  426.                     }
  427.             unbuffer[j] = name[i];
  428.             }
  429.     unbuffer[j] = '\0';
  430.     DEBUG(7, "Unmunge_filename output: %s\n", unbuffer);
  431.     return unbuffer;
  432. }
  433. /*
  434.  * Uucp work queue scan.
  435.  *
  436.  * gotsome = work_scan(hostname, type);
  437.  * workfile = work_next();
  438.  * void work_done();
  439.  */
  440.  
  441. /*
  442.  * Local variables of the work queue scanner -- not visible to outsiders
  443.  *
  444.  * Workhost and worktype are always null-terminated; keeping their lengths
  445.  * is just a performance hack.  Workprefix is NOT null terminated; various
  446.  * people copy things after it and use the whole string.  Workprefix is
  447.  * exactly workplen long; to append something, strcpy(workprefix+workplen, ...)
  448.  */
  449. #define MAX_TYPE    10
  450. static struct DIR    *workdir = (struct DIR *)NULL;
  451. static struct dirent    *workfile;
  452. static char    workhost[MAX_HOST+1];
  453. static int    workhlen;
  454. static char    worktype[MAX_TYPE+1];
  455. static int    worktlen;
  456. static char    workfirst = 0;
  457. /* FIXME, at the moment this can be local to work_scan() */
  458. static char    workprefix[MAX_TYPE+1+MAX_HOST+1+MAX_TYPE+1+MAX_HOST+6+SLOP];
  459.         /*       D        . hoptoad  / D        . hoptoad  N1234\0 */
  460. static int    workplen;
  461.  
  462.  
  463. void
  464. work_done()
  465. {
  466.     if (workdir)
  467.         closedir(workdir);
  468.     workdir = (struct DIR *) NULL;
  469.     workfile = (struct dirent *) NULL;
  470.     workfirst = 0;
  471. }
  472.  
  473. char *
  474. index(str, ch)
  475. char *str;
  476. char ch;
  477. {
  478.     strchr(str, ch);
  479.     }
  480.     
  481. int
  482. work_scan(host, type)
  483.     char *host;
  484.     char *type;
  485. {
  486.     char *p;
  487.  
  488.     if (!host)
  489.         host = "";
  490.  
  491.     /* If called twice in a row, don't thrash the disk again */
  492.     /* if (strcmp(workhost, host) == SAME &&
  493.         strcmp(worktype, type) == SAME && workfile)
  494.         return 1; */
  495.  
  496.     if (workdir) work_done();        /* Clean up prev call */
  497.  
  498.     workfirst = 1;                /* Initialize for work_next */
  499.     strcpy(workhost, munge_filename(host));
  500.     workhlen = strlen(workhost);
  501.     if (workhlen > sizeof (workhost) -1) 
  502.         {
  503.             printf("WORK_SCAN SIZE RESTRICTION", "workhlen > sizeof(workhost) - 1");
  504.             exit(1);
  505.             }
  506.     if (workhlen > 30) workhlen = 30;        /* Unix uucp limit */
  507.     strcpy(worktype, type);
  508.     worktlen = strlen(worktype);
  509.     if (worktlen > sizeof (worktype) -1) 
  510.         {
  511.             printf("WORK_SCAN SIZE RESTRICTION", "worktlen > sizeof(worktype) - 1");
  512.             exit(1);
  513.             }
  514.     /* Figure out which subdirectory this class of files is in. */
  515.     /* FIXME: doesn't handle "all D. files" since D.myname is separate. */
  516.     sprintf(workprefix, "%s.%s", worktype, workhost);
  517.     /* p = munge_filename(workprefix);
  518.     strcpy(workprefix, p); */
  519.     p = index(workprefix, ':');
  520.     if (p)
  521.         workplen = 1 + p - workprefix;    /* Prefix ends after '/' */
  522.     else
  523.         workplen = 0;        /* No / in munged; hence no dir */
  524.     workprefix[workplen] = '\0';
  525.     DEBUG(7, "Work prefix is =%s=\n", workprefix);
  526.  
  527.     strcpy(workprefix+workplen, ".");
  528.     workdir = opendir(workprefix);    /* Open whatever directory */
  529.     if (workdir == NULL) {
  530.         DEBUG(0, "Can't open queue directory %s\n", workprefix);
  531.         return 0;            /* No work */
  532.     }
  533.  
  534.     return work_look();
  535. }
  536.  
  537.  
  538. static int
  539. work_look()
  540. {
  541.     int len;
  542.     closedir(workdir);
  543.     opendir(workprefix);
  544.     for (;;) {
  545.         workfile = readdir(workdir);
  546.         if (workfile == NULL) {
  547.             DEBUG(7, "work_look readdir null\n", 0);
  548.             work_done();
  549.             return 0;        /* No work */
  550.         }
  551.         DEBUG(7, "work_look readdir %s\n", workfile->d_name);
  552.  
  553.         /* Is it the right type? */
  554.         if (strncmpic(workfile->d_name, worktype, worktlen) == SAME
  555.             && workfile->d_name[worktlen] == '.') {
  556.             /* see if it matches the hostname */
  557.             len = strlen(workfile->d_name);
  558.             /*         "C"        "." "hoptoad" "Xnnnn" */
  559.             if (workhlen == 0 || 
  560.                 (len == worktlen + 1 + workhlen + 5 &&
  561.                  !strncmp(workhost, workfile->d_name+2, workhlen))
  562.                ) {
  563.                 /* Found an entry! */
  564.                 /* FIXME, check grade letter! */
  565.                 DEBUG(7, "work_look found it!\n", 0);
  566.                 return 1;    /* Found work */
  567.             }
  568.         }
  569.     }
  570.     /* NOTREACHED */
  571. }
  572.  
  573.  
  574. char *
  575. work_next()
  576. {
  577.  
  578.     if (!workfirst) {
  579.         if (!workfile || !work_look())
  580.             return (char *)NULL;
  581.     }
  582.     workfirst = 0;
  583.     return unmunge_filename(workfile->d_name);
  584. }
  585.  
  586. /*
  587.  * Routine to return a string that gives the current date and time, and
  588.  * identifies the current process, if on a multiprocess system.
  589.  */
  590. char *
  591. time_and_pid()
  592. {
  593.     unsigned long clock;
  594.     struct tm *tm;
  595.     static int ourpid = 0;
  596.     static char format[] = "%d/%d-%d:%02d:%02d-%d";
  597.     static char outbuf[sizeof(format)];
  598.  
  599.     (void) time(&clock);
  600.     tm = localtime(&clock);
  601.     if (ourpid == 0)
  602.         ourpid = getpid();
  603.     sprintf(outbuf, format,
  604.         tm->tm_mon+1, tm->tm_mday,
  605.         tm->tm_hour, tm->tm_min, tm->tm_sec,
  606.         ourpid);
  607.     return outbuf;
  608. }
  609.  
  610. int
  611. chdir(ndir)
  612. char *ndir;
  613. {
  614.     WDPBRec    pb;
  615.     int err = 0;
  616.     int vol;
  617.     vol = 0;
  618.     CtoPstr(ndir);
  619.     pb.ioCompletion = 0;
  620.     pb.ioNamePtr = (StringPtr)ndir;
  621.     pb.ioVRefNum = 0;
  622.     pb.ioWDDirID = 0;
  623.     /* err = PBHSetVol(&pb,0); */
  624.     PtoCstr((unsigned char *)ndir);
  625.     return(err);
  626.     }
  627.  
  628. #ifdef IGNORED
  629. int
  630. execlp (pgm, arg1, arg2)
  631. char *pgm;
  632. char *arg1;
  633. int arg2;
  634. {
  635.     printf("Going to exec", pgm);
  636.     }
  637. #endif
  638.  
  639. HFileParam Opendir;
  640. char file_name[256];
  641.  
  642. struct DIR*
  643. opendir(path)
  644. char *path;
  645. {
  646.     char tmp_str[256];
  647.     WDPBRec    pb;
  648.     int err = 0;
  649.     int vol;
  650.     vol = 0;
  651.     strcpy(tmp_str, Spool);
  652.     CtoPstr(tmp_str);
  653.     pb.ioCompletion = 0;
  654.     pb.ioNamePtr = (StringPtr)tmp_str;
  655.     pb.ioVRefNum = 0;
  656.     pb.ioWDDirID = 0;
  657.     err = PBOpenWD(&pb,0);
  658.     if (err != noErr)
  659.         return((struct DIR *)0);
  660.     Opendir.ioCompletion = 0;
  661.     Opendir.ioNamePtr = (StringPtr)&file_name;
  662.     Opendir.ioVRefNum = pb.ioVRefNum;
  663.     Opendir.ioFDirIndex = 0;
  664.     Opendir.ioDirID = 0;
  665.     return((struct DIR *)&Opendir);
  666.     }
  667.  
  668. int closedir(dir)
  669. struct DIR *dir;
  670. {
  671.     WDPBRec pb;
  672.     int err;
  673.     pb.ioCompletion = 0;
  674.     pb.ioVRefNum = Opendir.ioVRefNum;
  675.     err = PBCloseWD(&pb, 0);
  676.     return(err);
  677.     }
  678.     
  679. struct dirent current_file;
  680.  
  681. struct dirent*
  682. readdir(dir)
  683. struct DIR *dir;
  684. {
  685.     int err;
  686.     Opendir.ioCompletion = 0;
  687.     Opendir.ioNamePtr = (StringPtr)&file_name;
  688.     Opendir.ioDirID = 0;
  689.     Opendir.ioFDirIndex++;
  690.     err = PBHGetFInfo((HParmBlkPtr)&Opendir, 0);
  691.     if (err != noErr)
  692.         return((struct dirent *)0);
  693.     current_file.d_name = (char *)Opendir.ioNamePtr;
  694.     PtoCstr((unsigned char *)current_file.d_name);
  695.     return(¤t_file);
  696.     }
  697.  
  698. #ifdef IGNORED
  699. char *strtok(in, look_for)
  700.     char *in;
  701.     char *look_for;
  702.     {
  703.         static char *saved;
  704.         char *tmp, *tmp1;
  705.         if (in != NULL)
  706.             {
  707.                 saved = in;
  708.                 }
  709.         tmp = strpbrk(saved, look_for);
  710.         tmp1 = saved;
  711.         saved = tmp + strspn(tmp, look_for);
  712.         *tmp = '\0';
  713.         return(tmp1);
  714.         }
  715. #endif
  716.  
  717. int strncmpic (s1, s2, n)
  718. register char *s1;
  719. register char *s2;
  720. int n;
  721. {
  722.     register int i;
  723.     
  724.     for (i = 0; i < n; i++)
  725.         {
  726.             if (toupper(s1[i]) != toupper(s2[i]))
  727.                 {
  728.                     return(1);
  729.                     }
  730.         }
  731.     return(0);
  732.     }
  733.     
  734. void
  735. bzero(ptr, bytes)
  736. char *ptr;
  737. unsigned bytes;
  738. {
  739.     memset(ptr, 0, bytes);
  740.     }
  741.  
  742. void
  743. bcopy(to, from, count)
  744. char *to, *from;
  745. int count;
  746. {
  747.     memcpy(from, to, count);
  748.     }
  749.  
  750. #ifdef IGNORED
  751. int system(exe)
  752.     char *exe;
  753.     {
  754.         printf("SYSTEM NOT IMPLEMENTED", exe);
  755.         exit(1);
  756.         }
  757. #endif
  758.         
  759. int
  760. access(file, code)
  761.     char *file;
  762.     int code;
  763.     {
  764.         FILE *exists;
  765.         exists = fopen(file, "r");
  766.         if (exists != 0) 
  767.             {
  768.                 fclose(exists);
  769.                 return(0);
  770.                 }
  771.             else
  772.                 {
  773.                     if (errno == bdNamErr)
  774.                             return(0);
  775.                         else
  776.                             return(1);
  777.                     }
  778.                 }
  779.  
  780.     
  781. /* get a random number for names and other stuff */
  782. random()
  783. {
  784.     int it;
  785.     long tmp;
  786.  
  787.     it = time((unsigned long *)&tmp);
  788.     it &= 0xff;
  789.     return (it);
  790. }
  791.  
  792. /* return the index of c in st. The first char is at 0 */
  793. mindex(st, c)
  794. char c, *st;
  795.  
  796. {
  797.     int i;
  798.  
  799.     for (i = 0; st[i] != '\0'; i++) {
  800.     if (st[i] == c)
  801.         return (i);
  802.     }
  803.     return (-1);
  804. }
  805.  
  806. void
  807. gnuucp_cleanup()
  808.     {
  809.         /* hanup the phone This is abnormal so always do the hayes thing */
  810.         if (!gnuucp_cleaned_up)
  811.             {
  812.              if (GNUPortOpen == TRUE)
  813.                 {
  814.                     drop_dtr_for (1);
  815.                 }
  816.                 gnusleep(1);
  817.                 xwrite(/* (int)NULL, */"+++", 3);
  818.                 gnusleep(3);
  819.                 xwrite(/* (int)NULL, */"ATH\r", 4);
  820.                 xwrite(/* (int)NULL, */"+++", 3);
  821.                 gnusleep(1);
  822.                 xwrite(/* (int)NULL, */"ats0=0\r", 7);
  823.             if (GNUPortOpen == TRUE)
  824.                 {
  825.                     CloseDriver(inRefNum);
  826.                     CloseDriver(outRefNum);
  827.                     GNUPortOpen = FALSE;
  828.                 }
  829.             gnuucp_cleaned_up = 1;
  830.         }
  831.     }
  832.  
  833. long eventcounter = 0;
  834. #define EVENTMAX 30
  835.  
  836. void ProcessEvent (void);
  837.  
  838. /* swallow key events looking for Command-. */
  839. void HandleEvents()
  840.     {
  841.         EventRecord event;
  842.         int mine;
  843.         if (eventcounter <= 0)
  844.             {
  845.                 if (abort_key_pressed() == 1) sigint(0);
  846.                 if (WNEIsImplemented())
  847.                 {
  848.                     mine = WaitNextEvent( everyEvent, &event, 0L, 0L);
  849.                        }
  850.                    else
  851.                 {
  852.                     mine = GetNextEvent(everyEvent, &event);
  853.                     }
  854.             HandleEvent(&event, mine);
  855.             eventcounter = EVENTMAX;
  856.             }
  857.             else
  858.                 eventcounter--;
  859.             }
  860.  
  861.  
  862. char *currtime()
  863. {
  864.     static char timebuffer[26];
  865.     register char *tp;
  866.     unsigned long Time;
  867.     char Year[10];
  868.     DateTimeRec MacTimeRec;
  869.     register Intl1Hndl myHndl;
  870.     register int i;    
  871.         GetDateTime(&Time);
  872.         Secs2Date(Time,&MacTimeRec);
  873.     
  874.         myHndl = (Intl1Hndl)IUGetIntl(1);
  875.         tp = timebuffer;
  876.     
  877.         for (i=1; i<4; i++)
  878.             *tp++ = (*myHndl)->days[MacTimeRec.dayOfWeek-1][i]; /* make day of week */
  879.         *tp++ = ',';
  880.         *tp++ = ' ';
  881.         sprintf(tp,"%02d ",MacTimeRec.day); /* now put in day of month */
  882.         tp += 3;
  883.         for (i=1; i<4; i++)
  884.             *tp++ = (*myHndl)->months[MacTimeRec.month-1][i]; /* make month */
  885.         *tp++ = ' ';
  886.         Year[0] = '\0';
  887.         sprintf(Year, "%d", MacTimeRec.year);
  888.         /* Prepare for new century, i used to start at 2 */
  889.         for (i=0; i<4; i++)
  890.             *tp++ = Year[i]; /* make year */
  891.         *tp++ = ' ';
  892.         sprintf(tp,"%02d:%02d:%02d\n",MacTimeRec.hour,MacTimeRec.minute,MacTimeRec.second);
  893.         return(timebuffer);
  894.         }
  895.  
  896. void
  897. gnusleep (time)
  898. unsigned time;
  899. {
  900.     long start_t;
  901.     long curr_t;
  902.     EventRecord theEvent;
  903.     int mine;
  904.     start_t = clock() / CLOCKS_PER_SEC;
  905.     for (curr_t = start_t; 
  906.          curr_t - start_t < time;
  907.          curr_t = clock() / CLOCKS_PER_SEC)
  908.         {
  909.             if (WNEIsImplemented())
  910.                 {
  911.                     mine = WaitNextEvent( everyEvent, &theEvent, 
  912.                        (time - (curr_t - start_t)) * CLOCKS_PER_SEC, 0L);
  913.                        HandleEvent(&theEvent, mine);
  914.                        }
  915.                    else
  916.                     {
  917.                         long finalTime;
  918.                         Delay(CLOCKS_PER_SEC*time, &finalTime);
  919.                         }
  920.                }
  921.     }
  922.  
  923. extern int interrupted;
  924. int abort_key_pressed ()
  925. {
  926.     if (interrupted) 
  927.         {
  928.             interrupted = 0;
  929.             logit("Aborting Mac/gnuucp", "Goodbye");
  930.             return(1);
  931.             }
  932.     return(0);
  933.     }
  934.  
  935. #define hiword(x)        (((short *) &(x))[0])
  936. #define loword(x)        (((short *) &(x))[1])
  937. extern MenuHandle appleMenu;
  938.  
  939. void HandleEvent(event, mine)
  940. EventRecord *event;
  941. int mine;
  942. {
  943.     int key;
  944.     WindowPeek wp;
  945.     long choice;
  946.     Str255 buf;
  947.     
  948.         /*  check for an event  */
  949.         
  950.     SEvtEnb = false;
  951.     SystemTask();
  952.     if (mine != 0) {
  953.         if (!SystemEvent(event))
  954.             goto doEvent;
  955.     }
  956.     else if (event->what == nullEvent) {
  957.         if (FrontWindow() == 0)
  958.             InitCursor();
  959.     }
  960.     return;
  961.     
  962.         /*  handle event  */
  963.  
  964. doEvent:
  965.     if (event->what == mouseDown) {
  966.         switch (FindWindow(event->where, (WindowPtr *)&wp)) {
  967.             case inMenuBar:
  968.                 InitCursor();
  969.                 choice = MenuSelect(event->where);
  970.                 goto doMenu;
  971.             case inSysWindow:
  972.                 SystemClick(event, (WindowPtr)wp);
  973.                 break;
  974.         }
  975.     }
  976.     return;
  977.  
  978.         /*  handle menu choice  */
  979.  
  980. doMenu:    
  981.     switch (hiword(choice)) {
  982.         case 1:        /*  Apple  */
  983.             GetItem(appleMenu, loword(choice), buf);
  984.             OpenDeskAcc(buf);
  985.             break;
  986.         case 2:        /*  File  */
  987.             console_options.pause_atexit = 0;
  988.             exit(0);
  989.             /* no return */
  990.         case 3:        /*  Edit  */
  991.             SystemEdit(loword(choice) - 1);
  992.             break;
  993.     }
  994.     HiliteMenu(0);
  995. }
  996.  
  997.                                     /** Define trap numbers **/
  998. #ifndef _Unimplemented
  999. #define _Unimplemented    0xA89F            /* Unimplemented trap                */
  1000. #endif
  1001.  
  1002. #ifndef _WaitNextEvent
  1003. #define _WaitNextEvent    0xA860            /* WaitNextEvent trap                */
  1004. #endif
  1005.  
  1006. #ifndef _OSDispatch
  1007. #define _OSDispatch        0xA88F            /* Temporary MF memory calls        */
  1008. #endif
  1009.  
  1010. /******************************************************************************
  1011.  TrapAvailable
  1012.  
  1013.      Check whether a certain trap exists on this machine. For pre-Mac II
  1014.      machines, trap numbers only go up to 0x1FF.
  1015.  ******************************************************************************/
  1016.  
  1017. Boolean        TrapAvailable(
  1018.     short            trapNum,            /* The trap number to check            */
  1019.     short            tType)                /* OS or Toolbox trap                */
  1020. {
  1021.     SysEnvRec        theWorld;
  1022.     
  1023.     SysEnvirons(1, &theWorld);
  1024.     
  1025.     if ( (tType == ToolTrap)  &&                        /* Toolbox trap        */
  1026.          ((theWorld.machineType < envMachUnknown)  ||    /* 64K ROM machine    */
  1027.          ((theWorld.machineType > envMachUnknown)  &&    /* …512KE, Plus, or    */
  1028.          (theWorld.machineType < envMacII))) ) {        /* …SE                */
  1029.          
  1030.         trapNum &= 0x3FF;                /* Traps numbers are 10 bits long    */
  1031.         
  1032.         if (trapNum > 0x1FF) {            /* Traps only go up to 0x1FF on        */
  1033.             return(false);                /*   these machines                    */
  1034.         }
  1035.     }
  1036.     
  1037.         /* Compare the address of this trap with that of the    */
  1038.         /* unimplemented trap                                    */
  1039.  
  1040.     return( NGetTrapAddress(trapNum, tType)  !=
  1041.             GetTrapAddress(_Unimplemented) );
  1042. }
  1043.  
  1044.  
  1045. /******************************************************************************
  1046.  WNEIsImplemented
  1047.  
  1048.      Check whether the WaitNextEvent is implemented or not
  1049.  ******************************************************************************/
  1050.  
  1051. Boolean        WNEIsImplemented()
  1052. {
  1053.     SysEnvRec    theWorld;                /* System environment                */
  1054.     
  1055.     SysEnvirons(1, &theWorld);            /* Check environment                */
  1056.     
  1057.     if (theWorld.machineType < 0)         /* Old ROMs, definitely not present    */
  1058.         return(FALSE);
  1059.         
  1060.     else                                /* Check for WNE trap                */
  1061.         return(TrapAvailable(_WaitNextEvent, ToolTrap));
  1062. }
  1063.  
  1064. #define NARGS        25
  1065.  
  1066. char *argv[NARGS+1];
  1067.  
  1068. int
  1069. parse(s, t, argvv)
  1070. register char *s, *t;
  1071. char **argvv[];
  1072. {
  1073.     int c, quote = 0, argc = 0;
  1074.         
  1075.     while (c = *s++) {
  1076.         if (c == ' ')
  1077.             continue;
  1078.         if (argc < NARGS)
  1079.             argv[argc++] = t;
  1080.         do {
  1081.             if (c == '\\' && *s)
  1082.                 c = *s++;
  1083.             else if (c == '"' || c == '\'') {
  1084.                 if (!quote) {
  1085.                     quote = c;
  1086.                     continue;
  1087.                 }
  1088.                 if (c == quote) {
  1089.                     quote = 0;
  1090.                     continue;
  1091.                 }
  1092.             }
  1093.             *t++ = c;
  1094.         } while (*s && ((c = *s++) != ' ' || quote));
  1095.         *t++ = 0;
  1096.     }
  1097.     *argvv = argv;
  1098.     return(argc);
  1099. }
  1100.  
  1101.  
  1102. void
  1103. dtr_state (on_or_off)
  1104. Boolean on_or_off;
  1105. {
  1106.     int ControlCode;
  1107.     CntrlParam ParamPtr;
  1108.     if (on_or_off == TRUE) 
  1109.         ControlCode = 17; /* Turn it on */
  1110.     else
  1111.         ControlCode = 18; /* Trun it off */
  1112.     ParamPtr.csCode = ControlCode;
  1113.     Control(outRefNum, ControlCode, &ParamPtr);    
  1114.     }
  1115.  
  1116. void drop_dtr_for (amt)
  1117. int amt;
  1118. {
  1119.     dtr_state(FALSE);
  1120.     gnusleep(amt);
  1121.     dtr_state(TRUE);
  1122.     }
  1123.  
  1124.  
  1125.