home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / program / c / bts314b4 / bt314src / emsi.c next >
C/C++ Source or Header  |  1994-09-17  |  60KB  |  2,644 lines

  1. /*
  2.  * emsi.c
  3.  *
  4.  * EMSI implementation
  5.  *
  6.  * This implementation written by Steven Green (2:255/355) for the
  7.  * Atari ST version of BinkleyTerm.
  8.  *
  9.  * The original EMSI specifications were designed by Chris Irwin and
  10.  * Joaquim H. Homrighausen.
  11.  *
  12.  * This module is based on the information given in:
  13.  *    EMSC-0001; Electronic Mail Standards Document #001; May 3, 1991
  14.  *    (and later republished as FSC-0056)
  15.  *
  16.  * This file replaces:
  17.  *    recvsync.c sendsync.c b_whack.c
  18.  *
  19.  *
  20.  * Revision history:
  21.  *    17Jul91 : SWG : Started
  22.  *
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28. #include <stdlib.h>
  29. #ifdef __TOS__
  30. #include <ext.h>
  31. #else
  32. #include <sys\types.h>
  33. #include <sys\stat.h>
  34. #endif
  35. #include <errno.h>
  36. #include <time.h>
  37.  
  38. #include "bink.h"
  39. #include "msgs.h"
  40. #include "emsi.h"
  41. #include "com.h"
  42. #include "sbuf.h"
  43. #include "zmodem.h"
  44. #include "wazoo.h"
  45. /* #include "version.h" */
  46. #include "password.h"
  47. #include "session.h"
  48. #include "defines.h"
  49. #include "sched.h"
  50. #include "nodeproc.h"
  51.  
  52. BOOLEAN cantdo_EMSI = FALSE;            /* Local EMSI disable for this session */
  53.  
  54. /*
  55.  * define the packet strings
  56.  */
  57.  
  58. #define EMSI_IDLEN 14
  59.  
  60. char *emsi_pkt[] = {
  61.     "**EMSI_INQ",
  62.     "**EMSI_REQ",
  63.     "**EMSI_CLI",
  64.     "**EMSI_HBT",
  65.     "**EMSI_DAT",
  66.     "**EMSI_ACK",
  67.     "**EMSI_NAK",
  68.     NULL
  69. };
  70.  
  71. #define EMSI_INQ 0
  72. #define EMSI_REQ 1
  73. #define EMSI_CLI 2
  74. #define EMSI_HBT 3
  75. #define EMSI_DAT 4
  76. #define EMSI_ACK 5
  77. #define EMSI_NAK 6
  78.  
  79. #define MAX_DATLEN 4096            /* Maximum size of EMSI_DAT packet */
  80.  
  81.  
  82. /*
  83.  * Check incomming character for completion of EMSI packet name
  84.  *
  85.  * Return:
  86.  *    -1 : no completion
  87.  *    0..5 : EMSI_type
  88.  *
  89.  * buf must be at least EMSI_IDLEN+1 bytes and the 1st element initialised
  90.  * to 0 before first call.
  91.  *
  92.  * This could be simplified by making it modal, i.e.:
  93.  *    if(c == '*')
  94.  *      c = modem_in
  95.  *      if(c == '*')
  96.  *        read 8 bytes
  97.  *        compare to emsi_packet sequences
  98.  *        read 4 byte CRC
  99.  *
  100.  * However this may cause the calling routine to miss characters particularly
  101.  * if any external mailer strings have '**' in them, etc...
  102.  */
  103.  
  104. static int check_emsi(char c, char *buf)
  105. {
  106.     char *s;
  107.     size_t l;
  108.     char **id;
  109.     int n;
  110.  
  111.     /* Add character to end of buffer */
  112.  
  113.     s = buf;
  114.     while(*s)
  115.         s++;
  116.     *s++ = c & 0x7f;
  117.     *s = 0;
  118.  
  119.     /* Compare to Packet ID's */
  120.  
  121.     l = strlen(buf);
  122.     if(l == EMSI_IDLEN)        /* Enough for full ID name + crc16 or len16 */
  123.     {
  124.         id = emsi_pkt;
  125.         n = 0;
  126.         while(*id)
  127.         {
  128.             if(strncmp(*id, buf, 10) == 0)
  129.             {
  130.                 UWORD crc;
  131.                 UWORD val;
  132.  
  133.                 buf[0] = 0;        /* Clear buffer to restart next time */
  134.  
  135.                 if(sscanf(&buf[10], "%04x", &val) != 1)    /* read hex-value */
  136.                     return -1;
  137.  
  138.                 if(n != EMSI_DAT)
  139.                 {
  140.                     crc = crc_block( buf + 2, 8 );
  141.                     if(crc != val)
  142.                     {
  143.                         status_line("+%s %s (CRC=%04x, VAL=%04x)", msgtxt[M_CRC_MSG], buf+2, crc, val);
  144.  
  145.                         return -1;
  146.                     }
  147.                     else
  148.                         return n;
  149.                 }
  150.                 else
  151.                     return n;
  152.  
  153.             }
  154.             n++;
  155.             id++;
  156.         }
  157.         /* should never get here... */
  158.         buf[0] = 0;
  159.         return -1;
  160.     }
  161.  
  162.     /*
  163.      * We get here if we have less than 14 characters or it doesn't match
  164.      * any of the packet types
  165.      *
  166.      * Shift buffer along to 1st possible match
  167.      *
  168.      * This probably doesn't need to be this complex, but I want to make
  169.      * it handle all cases, e.g.
  170.      *     ***EMSI_REQ      : must ignore the 1st * instead of resetting at the 3rd
  171.      *     **EMS**EMSI_REQ  : Must not reset at the 2nd group of '*'.
  172.      *
  173.      * In fact we could probably assume that all sequences start at the
  174.      * start of a line (except for the double EMSI_INQ sent during initialisation
  175.      */
  176.  
  177.     l = strlen(buf);
  178.     if(l <= 10)            /* Any bigger than 10 and we are into the <crc16> and must have already matched */
  179.     {
  180.         s = buf;
  181.         while(l)
  182.         {
  183.             id = emsi_pkt;
  184.             while(*id)
  185.             {
  186.                 if(strncmp(*id, s, l) == 0)
  187.                 {
  188.                     if(s != buf)
  189.                         strcpy(buf, s);
  190.                     return -1;
  191.                 }
  192.                 id++;
  193.             }
  194.             l--;
  195.             s++;
  196.         }
  197.         buf[0] = 0;        /* No matches */
  198.     }
  199.  
  200.  
  201.     return -1;
  202. }
  203.  
  204. static char hex[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
  205.  
  206. static int put_hex(UWORD val)
  207. {
  208.  
  209.     SENDBYTE(hex[(val >> 12) & 0xf]);
  210.     SENDBYTE(hex[(val >>  8) & 0xf]);
  211.     SENDBYTE(hex[(val >>  4) & 0xf]);
  212.     SENDBYTE(hex[ val         & 0xf]);
  213.  
  214.     return 0;
  215. }
  216.  
  217. static int byte_to_hex(int c)
  218. {
  219.     c = toupper(c);
  220.     c -= '0';
  221.     if (c > 9)
  222.         c -= ('A' - '9' - 1);
  223.     return c;
  224. }
  225.  
  226. static int send_string(char *s)
  227. {
  228.     while(*s)
  229.         SENDBYTE(*s++);
  230.     return 0;
  231. }
  232.  
  233. static int send_emsi(int type, BOOLEAN cr)
  234. {
  235.     char *s = emsi_pkt[type];
  236.     UWORD crc;
  237.  
  238.     send_string(s);
  239.  
  240.     if(type != EMSI_DAT)
  241.     {
  242.         crc = 0;
  243.         s += 2;        /* Skip over "**" */
  244.         while(*s)
  245.             crc = xcrc(crc, (unsigned)*s++);
  246.  
  247.         put_hex(crc);
  248.         if(cr)
  249.             SENDBYTE('\r');
  250.     }
  251.     SENDBYTE(XON);
  252.     return 0;
  253. }
  254.  
  255. /*
  256.  * Initiate call and return type of session unless its EMSI in which
  257.  * case it goes ahead and does it!
  258.  */
  259.  
  260.  
  261. /*
  262.   State table for TxEmsi: This is the 1st table I've ever written
  263.  
  264.   state|function     Conditions                Actions                  next
  265.  /-----+------------+------------------------+--------------------------+------\
  266.  | TS0 | WhackInit    |                         | Start 10 second timer    |       |
  267.  |       |            |                         | Init Line buffer         | TS1  |
  268.  +-----+------------+------------------------+--------------------------+------+
  269.  | TS1 | WhackCR    | 1. Timer expired         | Nobody Home                | exit |
  270.  |       |            +------------------------+--------------------------+------+
  271.  |       |            | 2. Lost carrier         | Lost Carrier             | exit |
  272.  |       |            +------------------------+--------------------------+------+
  273.  |       |            | 3. Something received  | Someone home             | TS2  |
  274.  |       |            +------------------------+--------------------------+------+
  275.  |       |            | 4. Nothing received     | Send <CR>, wait 1 sec    | TS1  |
  276.  |       |------------+------------------------+--------------------------+------+
  277.  |(TS2)| RxInit     |                         | Init Line buffer         |       |
  278.  |       |            |                         | Start 10 second timer    | TS3  |
  279.  |       |------------+------------------------+--------------------------+------+
  280.  |(TS3)| RxIntro    | 1. Timer expired         | Nobody Home                | exit |
  281.  |       |            +------------------------+--------------------------+------+
  282.  |       |            | 2. Lost carrier         | Lost Carrier             | exit |
  283.  |       |            +------------------------+--------------------------+------+
  284.  |       |            | 3. EMSI_REQ recieved     | Send EMSI_INQ twice        |       |
  285.  |       |            |                         | select EMSI                | exit |
  286.  |       |            +------------------------+--------------------------+------+
  287.  |       |            | 3. <CR> received         | Show intro                | TS4  |
  288.  |       |            +------------------------+--------------------------+------+
  289.  |       |            | 4. printable char rx     | Put it in buffer         | TS3  |
  290.  +-----+------------+------------------------+--------------------------+------+
  291.  | TS4 | InitTxEmsi |                         | Prepare 3 sec Sync timer |       |
  292.  |       |            |                         | Prepare .5 sec NAK timer |       |
  293.  |       |            |                         | Init NAK count            |       |
  294.  |       |            |                         | Init Line buffer         |       |
  295.  |       |            |                         | Start 60 sec master tmr    | TS5  |
  296.  |       |------------+------------------------+--------------------------+------+
  297.  |(TS5)| SendSync    | 1. 60 seconds elapsed  |                            |       |
  298.  |       |            |     or no carrier         | no response                | exit |
  299.  |       |            +------------------------+--------------------------+------+
  300.  |       |            | 2. 3 sec timer elapsed | Send EMSI_INQ twice        |       |
  301.  |       |            |     or never started     | Send YOOHOO TSYNC CR     | TS6  |
  302.  |       |            +------------------------+--------------------------+------+
  303.  |       |            | 3. EMSI_REQ received     | Send EMSI_INQ twice        |       |
  304.  |       |            |                         | Select EMSI                | exit |
  305.  |       |            +------------------------+--------------------------+------+
  306.  |       |            | 4. Otherwise...         |                            | TS6  |
  307.  |       |------------+------------------------+--------------------------+------+
  308.  |(TS6)| WaitResp    | 1. Nothing received     | need response            | TS5  |
  309.  |       |            +------------------------+--------------------------+------+
  310.  |       |            | 2. ENQ received         | Wazoo selected            | exit |
  311.  |       |            +------------------------+--------------------------+------+
  312.  |       |            | 3. 'C' or NAK received | Maybe FTS-0001            | TS7  |
  313.  |       |            +------------------------+--------------------------+------+
  314.  |       |            | 4. CR                  | Init Line buffer&NAK cnt | TS5  |
  315.  |       |            +------------------------+--------------------------+------+
  316.  |       |            | 5. Other character     | Init NAK /into buffer    | TS5  |
  317.  |       |------------+------------------------+--------------------------+------+
  318.  |(TS7)| NAKtmr     | 1. Timer expired         | NAK count++                | TS8  |
  319.  |       |            +------------------------+--------------------------+------+
  320.  |       |            | 2. Timer not expired     | Zero NAK count            |       |
  321.  |       |            |                         | Start .5 sec NAK timer    | TS5  |
  322.  |       |------------+------------------------+--------------------------+------+
  323.  |(TS8)| NAKcount    | 1. Count >= 2          | Select FTS-0001            | exit |
  324.  |       |            +------------------------+--------------------------+------+
  325.  |       |            | 2. count < 2             | continue                 | TS5  |
  326.  +-----+------------+------------------------+--------------------------+------+
  327.  
  328.  
  329.  I can't help feeling that this would be a lot cleaner just as a single function
  330.  As these state diagrams when you look at them are really going back to the
  331.  days of Spaghetti Basic!  In fact I've cut it down to just 2 states!
  332.  
  333. */
  334.  
  335. #define INTRO_LEN 180        /* Maximum size of Intro/banner */
  336.  
  337. /*
  338.  * Data structure used by TxEmsiInit
  339.  */
  340.  
  341. typedef struct {
  342.     int result;
  343. } TSARGS;
  344.  
  345.  
  346. #define TS0     0
  347. #define TSexit    0
  348. #define TS1     2
  349. #define TS4        3
  350.  
  351. /*
  352.  /-----+------------+------------------------+--------------------------+------\
  353.  | TS0 | WhackInit    |                         | Start 10 second timer    |       |
  354.  |       |            |                         | Init Line buffer         | TS1  |
  355.  +-----+------------+------------------------+--------------------------+------+
  356. */
  357.  
  358. static int cdecl TSWhackInit(TSARGS *args, int start_state)
  359. {
  360.     if ( start_state )
  361.     {
  362.     }
  363.     
  364.     args->result = SESSION_FAIL;        /* Default to failure */
  365.     cantdo_EMSI = check_noemsi(&called_addr, (char**)NULL);
  366.  
  367.     return TS1;
  368. }
  369.  
  370. static int cdecl TSExit(TSARGS *args, int cur_state)
  371. {
  372.     if ( cur_state )
  373.     {
  374.     }
  375.     
  376.     return args->result;
  377. }
  378.  
  379. /*
  380.  * Check for abort or timeout
  381.  */
  382.  
  383. static int check_abort(long timer, char *msg)
  384. {
  385.     if(KEYPRESS())
  386.     {
  387.         status_line(msgtxt[M_KBD_MSG]);
  388.  
  389.         hang_up();
  390.         READKB();            /* Eat character */
  391.         return -1;
  392.     }
  393.     if(!CARRIER)
  394.     {
  395.         status_line(msgtxt[M_NO_CARRIER]);
  396.         return -1;
  397.     }
  398.     if(timer && timeup(timer))
  399.     {
  400.         if(msg)
  401.             status_line(msg);
  402.         return -1;
  403.     }
  404.     return 0;
  405. }
  406.  
  407. /*
  408.  +-----+------------+------------------------+--------------------------+------+
  409.  | TS1 | WhackCR    | 1. Timer expired         | Nobody Home                | exit |
  410.  |       |            +------------------------+--------------------------+------+
  411.  |       |            | 2. Lost carrier         | Lost Carrier             | exit |
  412.  |       |            +------------------------+--------------------------+------+
  413.  |       |            | 3. Something received  | Someone home             | TS2  |
  414.  |       |            +------------------------+--------------------------+------+
  415.  |       |            | 4. Nothing received     | Send <CR>, wait 1 sec    | TS1  |
  416.  |       +------------+------------------------+--------------------------+------+
  417.  |(TS2)| RxInit     |                         | Init Line buffer         |       |
  418.  |       |            |                         | Start 10 second timer    | TS3  |
  419.  |       +------------+------------------------+--------------------------+------+
  420.  |(TS3)| RxIntro    | 1. Timer expired         | Nobody Home                | exit |
  421.  |       |            +------------------------+--------------------------+------+
  422.  |       |            | 2. Lost carrier         | Lost Carrier             | exit |
  423.  |       |            +------------------------+--------------------------+------+
  424.  |       |            | 3. EMSI_REQ recieved     | Send EMSI_INQ twice        |       |
  425.  |       |            |                         | select EMSI                | exit |
  426.  |       |            +------------------------+--------------------------+------+
  427.  |       |            | 3. <CR> received         | Show intro                | TS4  |
  428.  |       |            +------------------------+--------------------------+------+
  429.  |       |            | 4. printable char rx     | Put it in buffer         | TS3  |
  430.  +-----+------------+------------------------+--------------------------+------+
  431. */
  432.  
  433. static int cdecl TSWhackCR(TSARGS *args)
  434. {
  435.     long sectimer = 0L;
  436.     long bigtimer;
  437.     char c = '\r';
  438.     int pos;
  439.     char buffer[INTRO_LEN];
  440.     char emsibuf[EMSI_IDLEN+1];
  441.  
  442.     /*
  443.      * Send <CR> once per second until anything is received
  444.      * or until carrier lost/timeout/keyboard escape
  445.      */
  446.  
  447.     pos = 0;
  448.     emsibuf[0] = '\0';
  449.     bigtimer = timerset(3000);            /* Up to 30 seconds */
  450.  
  451.     for(;;)
  452.     {
  453.         if(check_abort(bigtimer, msgtxt[M_NOBODY_HOME]))
  454.         {
  455.             args->result = SESSION_FAIL;
  456.             return TSexit;
  457.         }
  458.         else if(!CHAR_AVAIL())
  459.         {
  460.             if(!sectimer || timeup(sectimer))
  461.             {
  462.                 SENDBYTE(c);
  463.                 c ^= ' ' ^ '\r';    /* Alternate space/CR */
  464.                 sectimer = timerset(100);
  465.             }
  466.             else
  467.                 time_release();
  468.         }
  469.         else
  470.         {
  471.  
  472.             /*
  473.              * Input line and treat it as either a banner or an EMSI_REQ
  474.              */
  475.  
  476.             unsigned char c = MODEM_IN();
  477.  
  478.             if(c == '\r')    /* CR = end of banner/intro */
  479.             {
  480.                 if(pos)
  481.                 {
  482.                     buffer[pos] = '\0';    /* Make sure null terminated */
  483.                     if(un_attended && fullscreen)
  484.                     {
  485.                         clear_filetransfer ();
  486.                         sb_move (filewin, 1, 2);
  487.                         sb_puts (filewin, buffer);
  488.                         sb_show ();
  489.                         status_line ("*%s%s", msgtxt[M_INTRO], buffer);
  490.                     }
  491.                     else
  492.                     {
  493.                         set_xy (NULL);
  494.                         scr_printf(msgtxt[M_INTRO]);
  495.                         scr_printf(buffer);
  496.                     }
  497.  
  498.                     SENDBYTE ('\013');        /* ('♪'); Try to stop output on an Opus */
  499.  
  500.                     return TS4;        /* Get on with next section */
  501.                 }
  502.             }
  503.             else
  504.             {
  505.                 if( (c >= ' ') && (pos < (INTRO_LEN-2)) )
  506.                     buffer[pos++] = c;
  507.  
  508.                 /* Check it against EMSI_REQ */
  509.  
  510.                 if(!cantdo_EMSI && check_emsi(c, emsibuf) == EMSI_REQ)
  511.                 {
  512.                     if(un_attended && fullscreen)
  513.                         clear_filetransfer ();
  514.                     send_emsi(EMSI_INQ, TRUE);
  515.                     args->result = SESSION_EMSI;
  516.                     return TSexit;
  517.                 }
  518.             }
  519.         }
  520.     }
  521. }
  522.  
  523. /*
  524.  
  525.  +-----+------------+------------------------+--------------------------+------+
  526.  | TS4 | InitTxEmsi |                         | Prepare 3 sec Sync timer |       |
  527.  |       |            |                         | Prepare .5 sec NAK timer |       |
  528.  |       |            |                         | Init NAK count            |       |
  529.  |       |            |                         | Init Line buffer         |       |
  530.  |       |            |                         | Start 60 sec master tmr    | TS5  |
  531.  |       |------------+------------------------+--------------------------+------+
  532.  |(TS5)| SendSync    | 1. 60 seconds elapsed  |                            |       |
  533.  |       |            |     or no carrier         | no response                | exit |
  534.  |       |            +------------------------+--------------------------+------+
  535.  |       |            | 2. 3 sec timer elapsed | Send EMSI_INQ twice        |       |
  536.  |       |            |     or never started     | Send YOOHOO TSYNC CR     | TS6  |
  537.  |       |            +------------------------+--------------------------+------+
  538.  |       |            | 3. EMSI_REQ received     | Send EMSI_INQ twice        |       |
  539.  |       |            |                         | Select EMSI                | exit |
  540.  |       |            +------------------------+--------------------------+------+
  541.  |       |            | 4. Otherwise...         |                            | TS6  |
  542.  |       |------------+------------------------+--------------------------+------+
  543.  |(TS6)| WaitResp    | 1. Nothing received     | need response            | TS5  |
  544.  |       |            +------------------------+--------------------------+------+
  545.  |       |            | 2. ENQ received         | Wazoo selected            | exit |
  546.  |       |            +------------------------+--------------------------+------+
  547.  |       |            | 3. 'C' or NAK received | Maybe FTS-0001            | TS7  |
  548.  |       |            +------------------------+--------------------------+------+
  549.  |       |            | 4. CR                  | Init Line buffer&NAK cnt | TS5  |
  550.  |       |            +------------------------+--------------------------+------+
  551.  |       |            | 5. Other character     | Init NAK /into buffer    | TS5  |
  552.  |       |------------+------------------------+--------------------------+------+
  553.  |(TS7)| NAKtmr     | 1. Timer expired         | NAK count++                | TS8  |
  554.  |       |            +------------------------+--------------------------+------+
  555.  |       |            | 2. Timer not expired     | Zero NAK count            |       |
  556.  |       |            |                         | Start .5 sec NAK timer    | TS5  |
  557.  |       |------------+------------------------+--------------------------+------+
  558.  |(TS8)| NAKcount    | 1. Count >= 2          | Select FTS-0001            | exit |
  559.  |       |            +------------------------+--------------------------+------+
  560.  |       |            | 2. count < 2             | continue                 | TS5  |
  561.  +-----+------------+------------------------+--------------------------+------+
  562.  
  563. */
  564.  
  565. static int cdecl TSInitTxEMSI(TSARGS *args)
  566. {
  567.     long bigtimer;
  568.     long naktimer = 0L;
  569.     long synctimer = 0L;
  570.     int nakcount = 0;
  571.     char emsibuf[EMSI_IDLEN+1];
  572.  
  573.     bigtimer = timerset(6000);        /* Up to 1 minute */
  574.     emsibuf[0] = '\0';
  575.  
  576.     for(;;)
  577.     {
  578.         /*
  579.          * Check for:
  580.          *    keyboard abort
  581.          *    timeout
  582.          *    Carrier loss
  583.          */
  584.         if(check_abort(bigtimer, NULL))
  585.         {
  586.             args->result = SESSION_FAIL;
  587.             return TSexit;
  588.         }
  589.  
  590.         /*
  591.          * Send handshake start stuff every 3 seconds...
  592.          */
  593.  
  594.         if(!synctimer || timeup(synctimer))
  595.         {
  596.             if(!cantdo_EMSI)
  597.             {
  598.                 send_emsi(EMSI_INQ, FALSE);
  599.                 send_emsi(EMSI_INQ, FALSE);
  600.             }
  601.             if(!no_WaZOO && !no_WaZOO_Session)
  602.                 SENDBYTE(YOOHOO);
  603.             SENDBYTE(TSYNC);
  604.             if(!cantdo_EMSI)
  605.                 SENDBYTE('\r');
  606.  
  607.             synctimer = timerset(300);
  608.         }
  609.  
  610.  
  611.         if(CHAR_AVAIL())
  612.         {
  613.             char c = PEEKBYTE();
  614.  
  615.             /*
  616.              * We must fiddle about like this because FTS-0001 expects
  617.              * the NAK or 'C' to still be available
  618.              *
  619.              * It would be easier to implement a unget function
  620.              */
  621.  
  622.             switch(c)
  623.             {
  624.             /* Check for Wazoo */
  625.  
  626.             case ENQ:
  627.                 c = MODEM_IN();
  628.                 if(!no_WaZOO && !no_WaZOO_Session)
  629.                 {
  630.                     args->result = SESSION_WAZOO;
  631.                     return TSexit;
  632.                 }
  633.                 goto bad_char;
  634.  
  635.             case 'C':
  636.             case NAK:
  637.                 if(!naktimer || !timeup(naktimer))
  638.                 {
  639.                     naktimer = timerset(50);
  640.                     nakcount = MODEM_IN();
  641.                     nakcount = 0;
  642.                 }
  643.                 else
  644.                 {
  645.                     nakcount++;
  646.                     if(nakcount >= 2)
  647.                     {
  648.                         args->result = SESSION_FTSC;
  649.                         return TSexit;
  650.                     }
  651.                 }
  652.                 break;
  653.  
  654.             default:
  655.             bad_char:
  656.             /* Check it against EMSI_REQ */
  657.                 c = MODEM_IN();
  658.                 if(!cantdo_EMSI && check_emsi(c, emsibuf) == EMSI_REQ)
  659.                 {
  660.                     send_emsi(EMSI_INQ, TRUE);
  661.                     args->result = SESSION_EMSI;
  662.                     return TSexit;
  663.                 }
  664.                 if(naktimer)
  665.                     naktimer = timerset(50);
  666.                 break;
  667.  
  668.             }
  669.         }
  670.  
  671.  
  672.     }
  673.  
  674.     /* return TSexit; */
  675. }
  676.  
  677. /*
  678.  * State machine table
  679.  */
  680.  
  681. static STATES States_TxEmsiInit[] = {
  682.   {    "TSWhackInit",    ( void *)TSWhackInit        },
  683.   {    "TSExit",        ( void *)TSExit            },
  684.   {    "TSWhackCR",    ( void *)TSWhackCR        },
  685.   {    "TSInitTxEMSI",    ( void *)TSInitTxEMSI    }
  686. };
  687.  
  688. int TxEmsiInit(void)
  689. {
  690.     TSARGS args;
  691.  
  692.     return state_machine(States_TxEmsiInit, &args, TS1);
  693. }
  694.  
  695. /*-----------------------------------------------------------------
  696.  * Receiver intialisation
  697.  */
  698.  
  699. /*
  700.  State Machine:
  701.  
  702.  /-----+----------+--------------------------------+--------------------+-----\
  703.  | RS0 | IdleWait | 1. 5 seconds elapsed           | Take initiative    | RS1 |
  704.  |       |          +--------------------------------+--------------------+-----+
  705.  |       |          | 2. No carrier or keypress       | Abort                | exit|
  706.  |       |          +--------------------------------+--------------------+-----+
  707.  |       |          | 3. YOOHOO or TSYNC peeked       | Get on with it!    | RS2 |
  708.  |       |          +--------------------------------+--------------------+-----+
  709.  |       |          | 4. CR, LF, Space, Esc           | Something's there    | RS1 |
  710.  |       |          +--------------------------------+--------------------+-----+
  711.  |       |          | 5. EMSI sequence?               | Get on with it     | RS2 |
  712.  |       |          +--------------------------------+--------------------+-----+
  713.  |       |          | 6. Any other character...       | Eat it             | RS0 |
  714.  +-----+----------+--------------------------------+--------------------+-----+
  715.  | RS1 | SendIntro| 1. Error sending /carrier drop | Abort                | exit|
  716.  |       |  and      +--------------------------------+--------------------+-----+
  717.  |       | EMSI_REQ | 2. Sent OK                       |                    | RS2 |
  718.  +-----+----------+--------------------------------+--------------------+-----+
  719.  | RS2 | RxInit   |                                | Init ext-mail        | RS3 |
  720.  |       |          |                                | Start 20sec time    |      |
  721.  |       |          |                                | Init 10 sec time    |      |
  722.  +-----+----------+--------------------------------+--------------------+-----+
  723.  | RS3 | SendSync | 1. Error sending / no carrier  | Abort                | exit|
  724.  |       |          +--------------------------------+--------------------+-----+
  725.  |       |          | 2. Sent OK                       |                    | RS4 |
  726.  +-----+----------+--------------------------------+--------------------+-----+
  727.  | RS4 | WaitSync | 1. Carrier lost/keypress       | Abort                | exit|
  728.  |       |          +--------------------------------+--------------------+-----+
  729.  |       |          | 2. YOOHOO received               | Do WaZOO            | exit|
  730.  |       |          +--------------------------------+--------------------+-----+
  731.  |       |          | 3. TSYNC rx + timer not running| Start 10 sec timer | RS4 |
  732.  |       |          +--------------------------------+--------------------+-----+
  733.  |       |          | 4. CR received                   | resend sync        | RS3 |
  734.  |       |          +--------------------------------+--------------------+-----+
  735.  |       |          | 5. Esc received                | BBS                | exit|
  736.  |       |          +--------------------------------+--------------------+-----+
  737.  |       |          | 6. EMSI_INQ received           | EMSI                | exit|
  738.  |       |          +--------------------------------+--------------------+-----+
  739.  |       |          | 7. 10 second timer               | FSC001             | exit|
  740.  |       |          +--------------------------------+--------------------+-----+
  741.  |       |          | 8. 20 second timer               | BBS                | exit|
  742.  +-----+----------+--------------------------------+--------------------+-----+
  743.  
  744. */
  745.  
  746. typedef struct {
  747.     int result;
  748. } RSARGS;
  749.  
  750. #define RS0        0
  751. #define RSexit    0
  752. #define RS1        2
  753. #define RS2        3
  754.  
  755. static int cdecl RSExit(RSARGS *args)
  756. {
  757.     return args->result;
  758. }
  759.  
  760. /*
  761.  * RS0:
  762.  *
  763.  * For a short while see if there are any shortcut characters
  764.  */
  765.  
  766. static int cdecl RSIdleWait(RSARGS *args)
  767. {
  768.     long idletimer;
  769.     char emsibuf[EMSI_IDLEN+1];
  770.  
  771.     emsibuf[0] = '\0';
  772.     idletimer = timerset(50);        /* Up to 5 seconds.. cut down to .5 seconds! */
  773.     for(;;)
  774.     {
  775.         if(check_abort(0L, NULL))        /* No carrier or keypress */
  776.         {
  777.             args->result = SESSION_FAIL;
  778.             return TSexit;
  779.         }
  780.         if(timeup(idletimer))
  781.             return RS1;
  782.         if(CHAR_AVAIL())
  783.         {
  784.             char c = PEEKBYTE();
  785.  
  786.             switch(c)
  787.             {
  788.             case TSYNC:        /* Bypass intro... */
  789.             case YOOHOO:
  790.                 return RS2;
  791.             case CR:        /* Signs of life */
  792.             case LF:    /* Line feed! */
  793.             case ' ':
  794.             case ESC:
  795.             case ENQ:
  796.                 return RS1;
  797.             default:
  798.                 c = MODEM_IN();        /* Eat the character */
  799.  
  800.                 /* And see if its EMSI_REQ */
  801.  
  802.                 if(!cantdo_EMSI && check_emsi(c, emsibuf) == EMSI_INQ)
  803.                 {
  804.                     args->result = SESSION_EMSI;
  805.                     return RSexit;
  806.                 }
  807.             }
  808.         }
  809.     }
  810.  
  811.     /* return RSexit; */
  812. }
  813.  
  814. /*
  815.  * RS1: Send Intro and banners and things
  816.  */
  817.  
  818. static int cdecl RSSendBanner(RSARGS *args)
  819. {
  820.     char buff[128];
  821.  
  822.     if(!cantdo_EMSI)
  823.         send_emsi(EMSI_REQ, TRUE);
  824.  
  825.     /* intro = "\r\r* Address %s Using %s\r\n" */
  826.  
  827.     sprintf(buff, msgtxt[M_ADDRESS], Full_Addr_Str(&alias[0].ad), ANNOUNCE);
  828.  
  829.     if(!SendBanner(buff))
  830.     {
  831.     fail:
  832.         args->result = SESSION_FAIL;
  833.         return RSexit;
  834.     }
  835.  
  836.     /* Banner, e.g. the BBS name */
  837.  
  838.     if(BBSbanner && strlen(BBSbanner))
  839.     {
  840.         SENDBYTE('\r');
  841.         SENDBYTE('\n');
  842.         if(!SendBanner(BBSbanner))
  843.             goto fail;
  844.         SENDBYTE('\r');
  845.         SENDBYTE('\n');
  846.     }
  847.  
  848.     /* The welcome file */
  849.  
  850.     if(!mail_only)
  851.         if(!SendBanner(BBSwelcome))
  852.             goto fail;
  853.  
  854.     return RS2;
  855. }
  856.  
  857. /*
  858.  * RS2:
  859.  *
  860.  *    Init Sync timers
  861.  *    Send Sync line
  862.  *    Wait for sync line
  863.  */
  864.  
  865. static int cdecl RSSendSync(RSARGS *args)
  866. {
  867.     int k;
  868.     BOOLEAN needbanner = TRUE;
  869.     char *ExtMailScan[16];
  870.     char emsibuf[EMSI_IDLEN+1];
  871.     long bigtimer;
  872.     long synctimer = 0L;
  873.  
  874.     /* Init external mail strings */
  875.  
  876.     for(k = 0; k < num_ext_mail; k++)
  877.         ExtMailScan[k] = ext_mail_string[k];
  878.     emsibuf[0] = '\0';
  879.     bigtimer = timerset((long)BBStimeout);            /* 20 seconds timeout */
  880.  
  881.     for(;;)
  882.     {
  883.         /* Send synchronisation string (press esc for BBS) */
  884.  
  885.         if(needbanner)
  886.         {
  887.             char *c;
  888.  
  889.             if(mail_only)
  890.                 c = noBBS;
  891.             else
  892.                 c = BBSesc;
  893.  
  894.             if(!SendBanner(c))
  895.             {
  896.                 args->result = SESSION_FAIL;
  897.                 return RSexit;
  898.             }
  899.             needbanner = FALSE;
  900.         }
  901.  
  902.         if(check_abort(0L, NULL))            /* No carrier or keyboard escape */
  903.         {
  904.             args->result = SESSION_FAIL;
  905.             return RSexit;
  906.         }
  907.  
  908.         if(CHAR_AVAIL())
  909.         {
  910.             unsigned char c = MODEM_IN();
  911.  
  912.             switch(c)
  913.             {
  914.             case YOOHOO:
  915.                 if(!no_WaZOO)
  916.                 {
  917.                     CLEAR_OUTBOUND();    /* Stop any outgoing banner */
  918.                     args->result = SESSION_WAZOO;
  919.                     return RSexit;
  920.                 }
  921.                 break;
  922.  
  923.             case TSYNC:
  924.                 CLEAR_OUTBOUND();
  925.                 if(no_WaZOO)
  926.                 {
  927.                     args->result = SESSION_FTSC;
  928.                     return RSexit;
  929.                 }
  930.                 else
  931.                 {
  932.                     if(!synctimer)
  933.                     {
  934.                         synctimer = timerset(1000);            /* 10 seconds */
  935.                         bigtimer = timerset((long)BBStimeout);    /* Reset sync timer */
  936.                     }
  937.                 }
  938.                 break;
  939.  
  940.             case CR:
  941.                 needbanner = TRUE;
  942.                 break;
  943.  
  944.             case ESC:
  945.                 if(!mail_only)
  946.                 {
  947.                     args->result = SESSION_BBS;
  948.                     return RSexit;
  949.                 }
  950.                 break;
  951.  
  952.             default:
  953.  
  954.                 /* Check for EMSI */
  955.  
  956.                 if(!cantdo_EMSI && check_emsi(c, emsibuf) == EMSI_INQ)
  957.                 {
  958.                     args->result = SESSION_EMSI;
  959.                     return RSexit;
  960.                 }
  961.  
  962.                 /* Check for external mailer */
  963.  
  964.                 c &= 0x7f;
  965.                 for(k = 0; k < num_ext_mail; k++)
  966.                 {
  967.                     if(c != *(ExtMailScan[k]++) )
  968.                         ExtMailScan[k] = ext_mail_string[k];
  969.                     else if(!*ExtMailScan[k])
  970.                     {
  971.                         args->result = SESSION_EXTERN+k;
  972.                         return RSexit;
  973.                     }
  974.                 }
  975.  
  976.                 break;
  977.             }
  978.         }
  979.         else    /* !CHAR_AVAIL() */
  980.         {
  981.             if(synctimer && timeup(synctimer))
  982.             {
  983.                 args->result = SESSION_FTSC;
  984.                 return RSexit;
  985.             }
  986.  
  987.             if(timeup(bigtimer))
  988.             {
  989.                 if(mail_only)
  990.                     args->result = SESSION_FAIL;
  991.                 else
  992.                     args->result = SESSION_BBS;
  993.                 return RSexit;
  994.             }
  995.         }
  996.     }
  997. }
  998.  
  999.  
  1000. static STATES States_RxEmsiInit[] = {
  1001.     { "RSIdleWait",     ( void *)RSIdleWait    },
  1002.     { "RSExit",            ( void *)RSExit            },
  1003.     { "RSSendBanner",    ( void *)RSSendBanner    },
  1004.     { "RSSendSync",    ( void *)RSSendSync        }
  1005. };
  1006.  
  1007.  
  1008. int RxEmsiInit(void)
  1009. {
  1010.     TSARGS args;
  1011.  
  1012.     cantdo_EMSI = check_noemsi(NULL, (char**)NULL);
  1013.     return state_machine(States_RxEmsiInit, &args, RS0);
  1014. }
  1015.  
  1016. /*------------------------------------------------------------
  1017.  * Send EMSI_DAT packet
  1018.  */
  1019.  
  1020. EMSI_CAPABILITY emsi_capability;        /* Capability we can do */
  1021. EMSI_CAPABILITY emsi_remote_capability;    /* What the other guy can do */
  1022. EMSI_CAPABILITY emsi_protocol;            /* What we are doing */
  1023. EMSI_CALL_OPTIONS emsi_options;
  1024. long ourTrx;                            /* Session Identification */
  1025.  
  1026. static void initTrx(void)
  1027. {
  1028.     time_t thetime;
  1029.     
  1030. #if 0
  1031.     struct tm *tim;
  1032.     
  1033.     time(&thetime);
  1034.     tim = gmtime(&thetime);
  1035.     ourTrx = mktime(tim);
  1036. #else
  1037.     time(&thetime);
  1038.     ourTrx = thetime;
  1039. #endif
  1040. }
  1041.  
  1042. /* add character to buffer with escaping */
  1043.  
  1044. static char *add_char(char c, char *s)
  1045. {
  1046.     while(*s)
  1047.         s++;        /* Get to end of string */
  1048.     if( (c == '\\') || (c == '}') || (c == ']'))
  1049.     {
  1050.         *s++ = c;
  1051.         *s++ = c;
  1052.     }
  1053.     else if(isprint(c))
  1054.         *s++ = c;
  1055.     else
  1056.     {
  1057.         *s++ = '\\';
  1058.         *s++ = hex[(c >> 4) & 0xf];
  1059.         *s++ = hex[ c        & 0xf];
  1060.     }
  1061.     *s = 0;
  1062.     return s;
  1063. }
  1064.  
  1065. /* add's character without any escaping */
  1066.  
  1067. static char *add_field(char c, char *s)
  1068. {
  1069.     while(*s)
  1070.         s++;
  1071.     *s++ = c;
  1072.     *s = 0;
  1073.     return s;
  1074. }
  1075.  
  1076. /* Add string to buffer with escaping */
  1077.  
  1078. static char *add_str(char *str, char *s)
  1079. {
  1080.     while(*str)
  1081.         s = add_char(*str++, s);
  1082.     return s;
  1083. }
  1084.  
  1085. static int TxEMSI_DAT(BOOLEAN sender)
  1086. {
  1087.     int i;
  1088.     size_t length;
  1089.     UWORD crc;
  1090.     int tries;
  1091.     long t1, t2;
  1092.     char emsibuf[EMSI_IDLEN+1];
  1093.     char *buffer;
  1094.     char *ptr;
  1095.  
  1096.     /* Create the Data */
  1097.  
  1098.     buffer = malloc(MAX_DATLEN);
  1099.     if(!buffer)
  1100.     {
  1101.         status_line(msgtxt[M_EMSI_NOMEM]);
  1102.         return EMSI_ABORT;
  1103.     }
  1104.  
  1105.     ptr = buffer;
  1106.     strcpy(buffer, "**EMSI_DAT0000{EMSI}");        /* DAT+len+Fingerprint */
  1107.  
  1108.     /* System addresses... assumed goes first */
  1109.  
  1110.     ptr = add_field('{', ptr);
  1111.     make_assumed(&remote_addr);        /* Work out assumed */
  1112.     ptr = add_str(Full_Addr_Str(&alias[assumed].ad), ptr);
  1113.     for(i = 0; i < num_addrs; i++)
  1114.     {
  1115.         if(i != assumed)
  1116.         {
  1117.             ptr = add_char(' ', ptr);
  1118.             ptr = add_str(Full_Addr_Str(&alias[i].ad), ptr);
  1119.         }
  1120.     }
  1121.     ptr = add_field('}', ptr);
  1122.  
  1123.     /* Password */
  1124.  
  1125.     ptr = add_field('{', ptr);
  1126. #ifdef NORXPASSWORD
  1127.     if(sender)
  1128. #endif
  1129.         if (n_getpassword(&remote_addr))
  1130.             ptr = add_str(remote_password, ptr);
  1131.     ptr = add_field('}', ptr);
  1132.  
  1133.     /* Link codes */
  1134.  
  1135.     ptr = add_field('{', ptr);
  1136.     ptr = add_str("8N1", ptr);
  1137.     if(sender)
  1138.     {
  1139.         add_str(",PUA", ptr);        /* Pick up all mail */
  1140.     }
  1141.     else
  1142.     {
  1143.         /* Disable FREQ's */
  1144.         
  1145.         if( !(matrix_mask & TAKE_REQ) ||
  1146. #if 0
  1147.             (sender && !check_reqonus(&remote_addr)) ||
  1148. #endif
  1149.             (DEFAULT.rq_OKFile == NULL))
  1150.                 ptr = add_str(",HRQ", ptr);
  1151.     }
  1152.     
  1153.     ptr = add_field('}', ptr);
  1154.  
  1155.     /* Compatibility codes */
  1156.  
  1157.     ptr = add_field('{', ptr);
  1158.  
  1159.     /* Work out what we can do first */
  1160.  
  1161.     emsi_capability = 0;
  1162.     if ((janus_baud >= cur_baud) || (janus_OK))
  1163.         emsi_capability |= EMSI_P_JAN;
  1164.     if(!no_zapzed)
  1165.         emsi_capability |= EMSI_P_ZAP;
  1166.     emsi_capability |= EMSI_P_ZMO;        /* Minimum spec of ZedZip */
  1167.  
  1168.     /* We can't do Kermit or DZA */
  1169.  
  1170.     /* MSDOS filenames, arcmail, other compression */
  1171.  
  1172.     emsi_capability |= EMSI_P_FNC | EMSI_P_ARC | EMSI_P_XMA;
  1173.  
  1174.     /* NRQ? */
  1175.  
  1176.     if( (DEFAULT.rq_OKFile == NULL) ||
  1177.         (sender && !check_reqonus(&remote_addr, (char**)NULL)) ||
  1178.         (!sender && check_norequest(&remote_addr, (char**)NULL)) ||
  1179.          no_requests
  1180.         )
  1181.             emsi_capability |= EMSI_P_NRQ;
  1182.  
  1183.     if(sender)        /* Send everything we can do */
  1184.     {
  1185.         if(emsi_capability & EMSI_P_JAN)
  1186.             ptr = add_str("JAN,", ptr);
  1187.         if(emsi_capability & EMSI_P_ZAP)
  1188.             ptr = add_str("ZAP,", ptr);
  1189.         ptr = add_str("ZMO,", ptr);
  1190.     }
  1191.     else            /* Pick best protocol */
  1192.     {
  1193.         if(emsi_capability & emsi_remote_capability & EMSI_P_JAN)
  1194.         {
  1195.             ptr = add_str("JAN,", ptr);
  1196.             emsi_protocol = EMSI_P_JAN;
  1197.         }
  1198.         else if(emsi_capability & emsi_remote_capability & EMSI_P_ZAP)
  1199.         {
  1200.             ptr = add_str("ZAP,", ptr);
  1201.             emsi_protocol = EMSI_P_ZAP;
  1202.         }
  1203.         else
  1204.         {
  1205.             ptr = add_str("ZMO,", ptr);
  1206.             emsi_protocol = EMSI_P_ZMO;
  1207.         }
  1208.     }
  1209.  
  1210.     if(emsi_capability & EMSI_P_NRQ)
  1211.         ptr = add_str("NRQ,", ptr);
  1212.         
  1213.     ptr = add_str("ARC,XMA,FNC", ptr);
  1214.     ptr = add_field('}', ptr);
  1215.  
  1216.     /* mailer_product_code */
  1217.  
  1218.     ptr = add_field('{', ptr);
  1219.     sprintf(ptr, "%02x", isBINKST);
  1220.     ptr = add_field('}', ptr);
  1221.  
  1222.     /* mailer_name */
  1223.  
  1224.     ptr = add_field('{', ptr);
  1225.     ptr = add_str(MAILER_NAME, ptr);
  1226.     ptr = add_field('}', ptr);
  1227.  
  1228.     /* mailer_version */
  1229.  
  1230.     ptr = add_field('{', ptr);
  1231.     ptr = add_str(MAILER_VER, ptr);
  1232.     ptr = add_field('}', ptr);
  1233.  
  1234.     /* mailer_serial */
  1235.  
  1236.     ptr = add_field('{', ptr);
  1237.     ptr = add_str(MAILER_SER, ptr);
  1238.     ptr = add_field('}', ptr);
  1239.  
  1240.     /* Do the IDENT fields */
  1241.  
  1242.     ptr = add_field('{', ptr);
  1243.     ptr = add_str("IDENT", ptr);
  1244.     ptr = add_field('}', ptr);
  1245.  
  1246.     ptr = add_field('{', ptr);
  1247.     {
  1248.         /* Find ourself in the nodelist */
  1249.  
  1250.         BOOLEAN inlist = nodefind(&alias[assumed].ad, FALSE);
  1251.  
  1252.         /* System name */
  1253.  
  1254.         ptr = add_field('[', ptr);
  1255.         if(NL_System)
  1256.             ptr = add_str(NL_System, ptr);
  1257.         else
  1258.         if(inlist)
  1259.             ptr = add_str(newnodedes.SystemName, ptr);
  1260.         else
  1261.             ptr = add_str(system_name, ptr);
  1262.         ptr = add_field(']', ptr);
  1263.  
  1264.         /* City */
  1265.  
  1266.         ptr = add_field('[', ptr);
  1267.         if(NL_City)
  1268.             ptr = add_str(NL_City, ptr);
  1269.         else
  1270.         if(inlist)
  1271.             ptr = add_str(newnodedes.MiscInfo, ptr);
  1272.         ptr = add_field(']', ptr);
  1273.  
  1274.         /* Operator Name */
  1275.  
  1276.         ptr = add_field('[', ptr);
  1277.         ptr = add_str(sysop, ptr);
  1278.         ptr = add_field(']', ptr);
  1279.  
  1280.         /* Phone number */
  1281.  
  1282.         ptr = add_field('[', ptr);
  1283.         if(NL_Phone)
  1284.             ptr = add_str(NL_Phone, ptr);
  1285.         else
  1286.         if(inlist)
  1287.             ptr = add_str(newnodedes.PhoneNumber, ptr);
  1288.         else
  1289.             ptr = add_str("-Unpublished", ptr);
  1290.         ptr = add_field(']', ptr);
  1291.  
  1292.         /* baud-rate */
  1293.  
  1294.         ptr = add_field('[', ptr);
  1295.         if(NL_Baud)
  1296.             ptr = add_str(NL_Baud, ptr);
  1297.         else
  1298.         if(inlist)
  1299.             sprintf(ptr, "%lu", (unsigned long) newnodedes.BaudRate * 300);
  1300.         else
  1301.             sprintf(ptr, "%lu", (unsigned long) max_baud.rate_value);
  1302.         ptr = add_field(']', ptr);
  1303.  
  1304.         /* flags */
  1305.  
  1306.         ptr = add_field('[', ptr);
  1307.         if(NL_Flags)
  1308.             ptr = add_str(NL_Flags, ptr);
  1309.         else
  1310.         {
  1311.             ptr = add_str("XB", ptr);
  1312.             if(inlist)
  1313.             {
  1314.                 if(newnodedes.NodeFlags & B_CM)
  1315.                     ptr = add_str(",CM", ptr);
  1316.                 if(newnodedes.ModemType & M_HST)
  1317.                     ptr = add_str(",HST", ptr);
  1318.                 if(newnodedes.ModemType & M_PEP)
  1319.                     ptr = add_str(",PEP", ptr);
  1320.             }
  1321.             if(mail_only)
  1322.                 ptr = add_str("MO", ptr);
  1323.         }
  1324.         ptr = add_field(']', ptr);
  1325.     }
  1326.     ptr = add_field('}', ptr);
  1327.  
  1328.     /* Do the TRX# fields */
  1329.  
  1330.     ptr = add_field('{', ptr);
  1331.     ptr = add_str("TRX#", ptr);
  1332.     ptr = add_field('}', ptr);
  1333.  
  1334.     ptr = add_field('{', ptr);
  1335.       ptr = add_field('[', ptr);
  1336.           sprintf(ptr, "%08lx", (long)ourTrx);
  1337.       ptr = add_field(']', ptr);
  1338.     ptr = add_field('}', ptr);
  1339.  
  1340.  
  1341.     length = strlen(buffer) - 14;        /* Length of packet [not **EMSI_DATllll] */
  1342.     buffer[10] = hex[(length >> 12) & 0xf];
  1343.     buffer[11] = hex[(length >>  8) & 0xf];
  1344.     buffer[12] = hex[(length >>  4) & 0xf];
  1345.     buffer[13] = hex[ length        & 0xf];
  1346.     length += 14;
  1347.  
  1348.     /*
  1349.      * Calculate CRC
  1350.      */
  1351.  
  1352.     crc = crc_block(&buffer[2], length-2);
  1353.  
  1354. #ifdef DEBUG
  1355.     {
  1356.         FILE *fp;
  1357.         fp = fopen("EMSI_DAT.TX", "wb");
  1358.         if(fp)
  1359.         {
  1360.             fwrite(buffer, length, 1, fp);
  1361.             fclose(fp);
  1362.         }
  1363.     }
  1364. #endif
  1365.  
  1366.     /*---------*
  1367.      | State 1 |
  1368.      ----------*/
  1369.  
  1370.     tries = 0;
  1371.     t1 = timerset(6000);
  1372.     emsibuf[0] = '\0';
  1373.  
  1374.     for(;;)
  1375.     {
  1376.         /*---------*
  1377.          | State 2 |
  1378.          ----------*/
  1379.  
  1380.         SENDCHARS(buffer, length, TRUE);        /* Transmit EMSI_DAT */
  1381.         CLEAR_INBOUND();
  1382.         put_hex(crc);
  1383.         SENDBYTE('\r');
  1384.  
  1385.         tries++;
  1386.  
  1387.         if(tries > 6)
  1388.         {
  1389.             free(buffer);
  1390.             return EMSI_ABORT;
  1391.         }
  1392.  
  1393.         /*---------*
  1394.          | State 3 |
  1395.          ----------*/
  1396.  
  1397.         t2 = timerset(2000);
  1398.  
  1399.         /*---------*
  1400.          | State 4 |
  1401.          ----------*/
  1402.  
  1403.         for(;;)
  1404.         {
  1405.             if(check_abort(t1, NULL))
  1406.             {
  1407.                 free(buffer);
  1408.                 return EMSI_ABORT;
  1409.             }
  1410.             if(timeup(t2))
  1411.                 break;
  1412.             if(CHAR_AVAIL())
  1413.             {
  1414.                 unsigned char c = MODEM_IN();
  1415.                 int pkt;
  1416.  
  1417.                 pkt = check_emsi(c, emsibuf);
  1418.                 if(pkt == EMSI_ACK)
  1419.                 {
  1420.                     free(buffer);
  1421.                     return EMSI_SUCCESS;
  1422.                 }
  1423.                 if((pkt >= 0) && (pkt != EMSI_REQ))
  1424.                     break;
  1425.             }
  1426.         }
  1427.     }
  1428. }
  1429.  
  1430. /*------------------------------------------------------------
  1431.  * Receive EMSI_DAT packet
  1432.  *
  1433.  * I'm going to do this just as one function instead of a state machine
  1434.  *
  1435.  *
  1436.  * Extract a field from the data
  1437.  *
  1438.  * Similar to strtok() but understands escape sequences \ab \\ }} and ]]
  1439.  *
  1440.  * The first time it is called you should pass the buffer address
  1441.  * future calls may pass NULL to continmue with next field
  1442.  *
  1443.  * fields are {...} and [...]
  1444.  * double }} and ]] are converted to single characters
  1445.  *
  1446.  * Note the actual data buffer is altered by having nulls put in
  1447.  *
  1448.  * returns NULL if any error.
  1449.  */
  1450.  
  1451. static char *last_field = NULL;
  1452.  
  1453. static char *get_field(char *dat)
  1454. {
  1455.     char sep;
  1456.     char *s, *s1;
  1457.  
  1458.     if(dat == NULL)
  1459.         dat = last_field;
  1460.  
  1461.     if(dat == NULL)
  1462.         return NULL;
  1463.  
  1464.     sep = *dat++;
  1465.     if(sep == '{')
  1466.         sep = '}';
  1467.     else if(sep == '[')
  1468.         sep = ']';
  1469.     else
  1470.         return NULL;
  1471.  
  1472.     s = s1 = dat;
  1473.     while(*s)
  1474.     {
  1475.         unsigned char c = *s++;
  1476.  
  1477.         if(c == sep)
  1478.         {
  1479.             if(*s == sep)    /* Double end brace */
  1480.                 s++;
  1481.             else            /* Single end brace marks end */
  1482.             {
  1483.                 *s1 = 0;
  1484.                 last_field = s;
  1485.                 return dat;
  1486.             }
  1487.         }
  1488.         else if( (c == '\\') && (sep == '}') && (*s != '}'))    /* hex escape */
  1489.         {
  1490.             int n;
  1491.  
  1492.             c = *s++;
  1493.             n = byte_to_hex(c);
  1494.             if(!(n & ~15))
  1495.             {
  1496.                 c = n;
  1497.                 n = byte_to_hex(*s);
  1498.                 if(!(n & ~15))            /* If 2nd digit is not hex?? */
  1499.                 {
  1500.                     s++;
  1501.                     c = (c << 4) | n;
  1502.                 }
  1503.             }
  1504.         }
  1505.         *s1++ = c;
  1506.     }
  1507.     return NULL;
  1508. }
  1509.  
  1510. /*
  1511.  * Add an address to the list of remote addresses
  1512.  */
  1513.  
  1514. static int add_remotead(ADDR *ad)
  1515. {
  1516.     ADDR_LIST *ads;
  1517.     ADDR_LIST *newad;
  1518.     
  1519.     ads = &remote_ads;    /* This should be empty, but we'll go to the end anyway! */
  1520.     while(ads->next)
  1521.         ads = ads->next;
  1522.  
  1523.     newad = malloc(sizeof(ADDR_LIST));
  1524.     if(newad)
  1525.     {
  1526.         newad->ad = *ad;    /* Structure copy */
  1527.         newad->next = NULL;
  1528.         ads->next = newad;
  1529.         ads = newad;
  1530.     }
  1531.     else
  1532.     {
  1533.         status_line(msgtxt[M_EMSI_NOMEM]);
  1534.         return EMSI_ABORT;
  1535.     }
  1536.     return EMSI_SUCCESS;
  1537. }
  1538.  
  1539. static void show_akas(void)
  1540. {
  1541.     ADDR_LIST *ads;
  1542.     #define AKA_BUFLEN 76
  1543.     char buffer[AKA_BUFLEN];
  1544.     size_t bufpos = 0;
  1545.  
  1546.     /* Process each address */
  1547.  
  1548.     ads = remote_ads.next;
  1549.     if(ads)                        /* Skip 1st address */
  1550.         ads = ads->next;
  1551.         
  1552.     while(ads)
  1553.     {
  1554.         char *s = Full_Addr_Str(&ads->ad);
  1555.         size_t len = strlen(s);
  1556.         
  1557.         if((len + bufpos + 1) >= AKA_BUFLEN)
  1558.         {
  1559.             status_line(buffer);
  1560.             bufpos = 0;
  1561.         }
  1562.         if(bufpos == 0)
  1563.         {
  1564.             strcpy(buffer, "*Aka:");
  1565.             bufpos = strlen(buffer);
  1566.         }
  1567.         buffer[bufpos++] = ' ';            /* Space between entries */
  1568.         strcpy(buffer+bufpos, s);        /* Potential Bug... if s is long */
  1569.         bufpos += len;
  1570.  
  1571.         ads = ads->next;
  1572.     }
  1573.     if(bufpos != 0)
  1574.         status_line(buffer);
  1575. }
  1576.  
  1577. /*
  1578.  * Process the incoming EMSI_DAT packet
  1579.  */
  1580.  
  1581.  
  1582. static int process_dat(unsigned char *dat, BOOLEAN sender)
  1583. {
  1584.     char *s, *s1, *s2, *s3, *offset;
  1585.     ADDR ad;
  1586.     int n, time_offset;
  1587.     int ret = EMSI_SUCCESS;
  1588.     BOOLEAN first = TRUE;    
  1589.  
  1590.     /* fingerprint */
  1591.  
  1592.     s = get_field(dat);        /* Finger print */
  1593.     if(!s || stricmp(s, "EMSI"))
  1594.         return EMSI_ABORT;
  1595.  
  1596.     /* Addresses */
  1597.  
  1598.     s = get_field(NULL);
  1599.     if(!s)
  1600.         return EMSI_ABORT;
  1601.  
  1602.     n = 0;
  1603.     s = strtok(s, " ");
  1604.     while(s)
  1605.     {
  1606.  
  1607.         if(find_address(s, &ad))
  1608.         {
  1609.             if(fullscreen)
  1610.             {
  1611.                 if(n && (n < 6))    /* Display AKA's (not 1st address) */
  1612.                 {
  1613.                     if(n == 1)        /* Clear Window on 1st pass */
  1614.                         sb_fill(holdwin, ' ', colors.hold);
  1615.  
  1616.                     sb_move(holdwin, n, 1);
  1617.                     sb_puts(holdwin, Pretty_Addr_Str(&ad));
  1618.                 }
  1619.                 n++;
  1620.             }
  1621.  
  1622. #ifdef DEBUG
  1623.             if(debugging_log)
  1624.                 status_line(">Address: %s", Pretty_Addr_Str(&ad));
  1625. #endif
  1626.  
  1627.             if(first)
  1628.             {
  1629.                 first = FALSE;
  1630.                 remote_addr = ad;                /* Make 1st address the remote_addr */
  1631.                 status_line(msgtxt[M_REMOTE_ADDRESS], Pretty_Addr_Str(&ad));
  1632.             }
  1633.  
  1634.             if(add_remotead(&ad) != EMSI_SUCCESS)
  1635.                 return EMSI_ABORT;
  1636.         }
  1637.  
  1638.         s = strtok(NULL, " ");
  1639.     }
  1640.     sb_show();
  1641.     show_akas();
  1642.  
  1643.     /* Password */
  1644.  
  1645.     s = get_field(NULL);
  1646.     if(!s)
  1647.         return EMSI_ABORT;
  1648.  
  1649.     if(sender && !s[0])
  1650.     {
  1651.         if(n_getpassword(&remote_addr))
  1652.             status_line(msgtxt[M_PASSWORD_OVERRIDE]);
  1653.     }
  1654.     else
  1655.     if(n_password(&remote_addr, s, TRUE))        /* Only receiver checks password */
  1656.     {
  1657.         if(sender)
  1658.             status_line(msgtxt[M_PASSWORD_OVERRIDE]);
  1659.         else
  1660.             ret = EMSI_ABORT;    /* Or do the hangup here? */
  1661.     }
  1662.     if(remote_password)
  1663.         session_password = strdup(remote_password);
  1664.     else
  1665.         session_password = NULL;
  1666.  
  1667.     /* Link codes */
  1668.  
  1669.     s = get_field(NULL);
  1670.     if(!s)
  1671.         return EMSI_ABORT;
  1672.     emsi_options = PUA;    /* Default to all addresses */
  1673.     s = strtok(s, ",");
  1674.     while(s)
  1675.     {
  1676.         if(!stricmp(s, "PUA"))
  1677.             emsi_options = PUA;
  1678.         else if(!stricmp(s, "PUP"))
  1679.             emsi_options = PUP;
  1680.         else if(!stricmp(s, "NPU"))
  1681.             emsi_options = NPU;
  1682.         else if(!stricmp(s, "HAT"))
  1683.             emsi_remote_capability |= EMSI_O_HAT;
  1684.         else if(!stricmp(s, "HXT"))
  1685.             emsi_remote_capability |= EMSI_O_HXT;
  1686.         else if(!stricmp(s, "HRQ"))
  1687.             emsi_remote_capability |= EMSI_O_HRQ;
  1688.  
  1689.         s = strtok(NULL, ",");
  1690.     }
  1691.  
  1692.     /* Ignore this for time being
  1693.      *    We should be looking for:
  1694.      *        PUA/PUP/NPU if we are receiver
  1695.      *        HAT/HXT/HRQ if we are sender
  1696.      */
  1697.  
  1698.     /* Compatibility */
  1699.  
  1700.     s = get_field(NULL);
  1701.     s = strtok(s, ",");
  1702.     while(s)
  1703.     {
  1704.         if(!stricmp(s, "DZA"))
  1705.             emsi_remote_capability |= EMSI_P_DZA;
  1706.         if(!stricmp(s, "ZAP"))
  1707.             emsi_remote_capability |= EMSI_P_ZAP;
  1708.         if(!stricmp(s, "ZMO"))
  1709.             emsi_remote_capability |= EMSI_P_ZMO;
  1710.         if(!stricmp(s, "JAN"))
  1711.             emsi_remote_capability |= EMSI_P_JAN;
  1712.         if(!stricmp(s, "KER"))
  1713.             emsi_remote_capability |= EMSI_P_KER;
  1714.         /* Also check for NCP/NRQ/ARC/XMA/FNC */
  1715.         if(!stricmp(s, "NRQ"))
  1716.             emsi_remote_capability |= EMSI_P_NRQ;
  1717.  
  1718.         s = strtok(NULL, ",");
  1719.     }
  1720.     if(sender)
  1721.         emsi_protocol = emsi_remote_capability & emsi_capability &
  1722.             (EMSI_P_DZA | EMSI_P_ZAP | EMSI_P_ZMO | EMSI_P_JAN | EMSI_P_KER);
  1723.  
  1724.     /* Mailer code */
  1725.  
  1726.     s = get_field(NULL);        /* Code */
  1727.     s1 = get_field(NULL);        /* Name */
  1728.     s2 = get_field(NULL);        /* Version */
  1729.     s3 = get_field(NULL);        /* Revision */
  1730.     status_line ("%s %s %s/%s (%s)", msgtxt[M_REMOTE_USES], s1, s2, s3, s);
  1731.  
  1732.     /* Extra fields */
  1733.  
  1734.     s = get_field(NULL);
  1735.     while(s)
  1736.     {
  1737.         /* 1st field is identifier */
  1738.  
  1739.         if(!stricmp(s, "IDENT"))
  1740.         {
  1741.             char *last_tok;
  1742.             s = get_field(NULL);    /* Identifier */
  1743.             last_tok = last_field;
  1744.  
  1745.             /* Parse IDENT */
  1746.  
  1747.             s = get_field(s);
  1748.             if(s && *s)
  1749.                 status_line(msgtxt[M_EMSI_SYSTEM], s);    /* System name */
  1750.             s = get_field(NULL);
  1751.             if(s && *s)
  1752.                 status_line(msgtxt[M_EMSI_LOCATION], s);
  1753.             s = get_field(NULL);
  1754.             if(s && *s)
  1755.                 status_line(msgtxt[M_EMSI_SYSOP], s);
  1756.             s = get_field(NULL);
  1757.             if(s && *s)
  1758.                 status_line(msgtxt[M_EMSI_PHONE], s);
  1759.             s = get_field(NULL);
  1760.             if(s && *s)
  1761.                 status_line(msgtxt[M_EMSI_BAUD], s);
  1762.             s = get_field(NULL);
  1763.             if(s && *s)
  1764.                 status_line(msgtxt[M_EMSI_FLAGS], s);
  1765.  
  1766.             last_field = last_tok;
  1767.         }
  1768.         else
  1769.         if(!stricmp(s, "TRX#"))
  1770.         {
  1771.             char *last_tok;
  1772.             struct tm thetime;    /* Complete structure */
  1773.             time_t newtime;
  1774.  
  1775.             s = get_field(NULL);
  1776.             last_tok = last_field;
  1777.  
  1778.             s = get_field(s);                /* Number is enclosed in [] */
  1779.             status_line(":Tranx: %s / %08lx", s, (long)ourTrx);
  1780.  
  1781.             /* convert s to time_t */
  1782.                 
  1783.             if(sscanf(s, "%08lx", &newtime) == 1)
  1784.             {
  1785.                 union {
  1786.                     DOSTIME dos;
  1787.                     long tos;
  1788.                 } tostime;
  1789.                 
  1790.                 memcpy(&thetime, localtime(&newtime), sizeof(thetime));
  1791.                 
  1792.                 status_line("#Remote's time is %s", asctime(&thetime));
  1793.  
  1794.                 if(tranx_list && find_ad_strlist(tranx_list, &remote_addr, &offset))
  1795.                 {
  1796.                     if (offset)
  1797.                     {    
  1798.                         time_offset = (int) (3600L * atol (offset));
  1799.                         
  1800.                         /*
  1801.                         ** if time_offset is 0 then don't display
  1802.                         ** corrected time
  1803.                         */
  1804.                         
  1805.                         if (time_offset)                        
  1806.                         {
  1807.                             newtime += time_offset;
  1808.                             memcpy(&thetime, localtime(&newtime), sizeof(thetime));
  1809.                             status_line("#Corrected time is %s", asctime(&thetime));
  1810.                         }
  1811.                     }
  1812.                         
  1813.                     status_line(":Updating our clock to %s", asctime(&thetime));        
  1814.             
  1815.                     tostime.dos.time = ((thetime.tm_sec + 1) >> 1)
  1816.                                       + (thetime.tm_min      << 5)
  1817.                                       + (thetime.tm_hour     << 11);
  1818.                     tostime.dos.date = ( thetime.tm_mday            )
  1819.                                      + ((thetime.tm_mon + 1 )  <<  5)
  1820.                                      + ((thetime.tm_year - 80) <<  9);
  1821.                     Settime(tostime.tos);    /* TOS time/date */
  1822.                     Tsettime(tostime.dos.time); /* DOS time      */
  1823.                     Tsetdate(tostime.dos.date); /* DOS date      */
  1824.                 }
  1825.             }
  1826.             else
  1827.                 status_line(":Tranx: couldn't convert %s to time", s);
  1828.             
  1829.             last_field = last_tok;
  1830.         }
  1831.         else
  1832.         if(!stricmp(s, "MOH#"))
  1833.         {
  1834.             char *last_tok;
  1835.             
  1836.             s = get_field(NULL);
  1837.             last_tok = last_field;
  1838.  
  1839.             s = get_field(s);                /* Number is enclosed in [] */
  1840.             status_line(":MailOnHold: %lu bytes", strtoul(s, NULL, 16));
  1841.             
  1842.             last_field = last_tok;
  1843.         }
  1844.         else
  1845.         {
  1846. #ifdef DEBUG
  1847.             status_line("#EMSI: Extra field : %s", s);
  1848. #endif
  1849.             s = get_field(NULL);
  1850. #ifdef DEBUG
  1851.             status_line("#EMSI: Field Data : %s", s);
  1852. #endif
  1853.         }
  1854.         s = get_field(NULL);
  1855.     }
  1856.  
  1857.     return ret;
  1858. }
  1859.  
  1860. /*
  1861.  * Read the actual packet and its crc
  1862.  *
  1863.  * return 0: EMSI_SUCCESS : OK
  1864.  *         -1: EMSI_ABORT   : abort (no carrier or keyboard escape)
  1865.  *         -2: EMSI_RETRY   : Timeout or CRC error
  1866.  *
  1867.  * emsibuf excludes the **, i.e. it is "EMSI_DAT<len16>"
  1868.  */
  1869.  
  1870. static int read_emsi_dat(char *emsibuf, BOOLEAN sender)
  1871. {
  1872.     unsigned char *dat;
  1873.     int length;
  1874.     char *ptr;
  1875.     int count;
  1876.     UWORD crc;
  1877.     UWORD check;
  1878.  
  1879.     /* Get the packet length */
  1880.  
  1881.     if(sscanf(&emsibuf[8], "%04x", &length) != 1)    /* read hex-value */
  1882.         return EMSI_RETRY;
  1883. #ifdef DEBUG
  1884.     if(debugging_log)
  1885.         status_line(">EMSI_DAT <len16> = %04x", length);
  1886. #endif
  1887.     if(length > 4096)        /* Assume >4K is silly */
  1888.         return EMSI_RETRY;
  1889.  
  1890.     dat = malloc((size_t)length);
  1891.     if(!dat)    /* Out of memory! */
  1892.     {
  1893.         status_line(msgtxt[M_EMSI_NOMEM]);
  1894.         return EMSI_ABORT;
  1895.     }
  1896.  
  1897.     /*
  1898.      * Initialise the CRC:
  1899.      * The specs aren't very clear on this, but I'll assume
  1900.      * for now that it includes all of "EMSI_DAT<len16><data>"
  1901.      *
  1902.      * Also is the length and crc apply to the data before or after
  1903.      * escaping 8 bit data?  I will assume it applies to the binary data
  1904.      */
  1905.  
  1906.     crc = crc_block(emsibuf, 8+4);    /* EMSI_DAT <len16> */
  1907.  
  1908.     /* Read in all the data */
  1909.  
  1910.     count = length;
  1911.     ptr = dat;
  1912.     while(count--)
  1913.     {
  1914.         int c;
  1915.  
  1916.         if(check_abort(0L, NULL))    /* Abort if no carrier or keypress */
  1917.         {
  1918.             free(dat);
  1919.             return EMSI_ABORT;
  1920.         }
  1921.         c = Z_GetByte(100);            /* Wait up to 10 seconds */
  1922.         if(c < 0)
  1923.         {
  1924.             free(dat);
  1925.             return EMSI_RETRY;
  1926.         }
  1927.  
  1928.         crc = xcrc(crc, c);
  1929.         *ptr++ = c;
  1930.     }
  1931.  
  1932.     /* Get the checksum */
  1933.  
  1934.     count = 4;
  1935.     check = 0;
  1936.     while(count--)
  1937.     {
  1938.         int c = Z_GetByte(100);
  1939.         if(c < 0)
  1940.         {
  1941.             free(dat);
  1942.             return EMSI_RETRY;
  1943.         }
  1944.         c = byte_to_hex(c);
  1945.         if(c & ~0xf)
  1946.         {
  1947.             free(dat);
  1948.             return EMSI_RETRY;
  1949.         }
  1950.         check = (check << 4) | c;
  1951.     }
  1952.  
  1953. #ifdef DEBUG
  1954.     /* Dump the data into a file for perusal */
  1955.     {
  1956.         FILE *fp = fopen("EMSI_DAT.RX", "wb");
  1957.         if(fp)
  1958.         {
  1959.             fwrite(dat, (size_t)length, 1, fp);
  1960.             fclose(fp);
  1961.         }
  1962.     }
  1963. #endif
  1964.  
  1965.     if(check != crc)
  1966.     {
  1967.         status_line("+%s %s (crc=%04x, check=%04x)", msgtxt[M_CRC_MSG], emsibuf, crc, check);
  1968.         free(dat);
  1969.         return EMSI_RETRY;
  1970.     }
  1971.  
  1972.     /*
  1973.      * Acknowledge it
  1974.      */
  1975.  
  1976.     send_emsi(EMSI_ACK, TRUE);
  1977.     send_emsi(EMSI_ACK, TRUE);
  1978.  
  1979.     /*
  1980.      * Process it
  1981.      */
  1982.  
  1983.     if(process_dat(dat, sender) < 0)
  1984.     {
  1985.         free(dat);
  1986.         return EMSI_ABORT;
  1987.     }
  1988.  
  1989.     free(dat);
  1990.     return EMSI_SUCCESS;
  1991. }
  1992.  
  1993.  
  1994. static int RxEMSI_DAT(BOOLEAN sender)
  1995. {
  1996.     char emsibuf[EMSI_IDLEN+1];
  1997.     int tries;
  1998.     long t1;
  1999.     long t2;
  2000.  
  2001.     /*---------*
  2002.      | State 1 |
  2003.      *---------*/
  2004.  
  2005.     tries = 0;
  2006.     t1 = timerset(2000);    /* 20 seconds */
  2007.     t2 = timerset(6000);    /* 60 second timer */
  2008.     emsibuf[0] = '\0';
  2009.  
  2010.     for(;;)
  2011.     {
  2012.         /*---------*
  2013.          | State 2 |
  2014.          *---------*/
  2015.  
  2016.         tries++;
  2017.         if(tries > 6)
  2018.             return -1;            /* Terminate and report failure */
  2019.         if(!sender)
  2020.             send_emsi(EMSI_REQ, TRUE);
  2021.         else if(tries > 1)
  2022.             send_emsi(EMSI_NAK, TRUE);
  2023.  
  2024.         /*---------*
  2025.          | State 3 |
  2026.          *---------*/
  2027.  
  2028.         t1 = timerset(2000);
  2029.  
  2030.         /*---------*
  2031.          | State 4 |
  2032.          *---------*/
  2033.  
  2034.         for(;;)
  2035.         {
  2036.             if(check_abort(t2, NULL))        /* If Timer2 expired, terminate */
  2037.                 return -1;
  2038.             if(timeup(t1))                    /* If timer1 expired goto state 2 */
  2039.                 break;
  2040.             if(CHAR_AVAIL())
  2041.             {
  2042.                 unsigned char c = MODEM_IN();
  2043.                 int pkt;
  2044.  
  2045.                 pkt = check_emsi(c, emsibuf);
  2046.  
  2047.                 if(pkt == EMSI_HBT)            /* Heartbeat */
  2048.                     t1 = timerset(2000);
  2049.                 else if(pkt == EMSI_DAT)    /* Data packet */
  2050.                 {
  2051.                     int val = read_emsi_dat(&emsibuf[2], sender);
  2052.                     if(val == EMSI_SUCCESS)
  2053.                         return EMSI_SUCCESS;
  2054.                     else if(val == EMSI_ABORT)
  2055.                         return EMSI_ABORT;
  2056.                     else
  2057.                         break;            /* Goto step 2 */
  2058.                 }
  2059.             }
  2060.         }
  2061.     }
  2062. }
  2063.  
  2064.  
  2065. /*--------------------------------------------------------------------------*/
  2066. /* Send files for one address                                                */
  2067. /*     returns TRUE (1) for good xfer, FALSE (0) for bad                        */
  2068. /*--------------------------------------------------------------------------*/
  2069.  
  2070. static int fsent;
  2071.  
  2072. /*
  2073.  * EMSI_callback () -- send requested file using WaZOO method.
  2074.  *
  2075.  */
  2076.  
  2077. static int EMSI_callback (char *reqs)
  2078. {
  2079. #ifdef DEBUG
  2080.     if(debugging_log)
  2081.         status_line(">EMSI_callback(%s)", reqs);
  2082. #endif
  2083.    return (Send_Zmodem (reqs, NULL, fsent++, DO_WAZOO));
  2084. }
  2085.  
  2086. static int send_to_address(ADDR *ad)
  2087. {
  2088.     char fname[80];
  2089.     char s[80];
  2090.     char *HoldName;
  2091.     struct stat buf;
  2092.  
  2093.     char *extptr;
  2094.  
  2095.     /* Ignore unknown domains */
  2096.  
  2097. /* #ifdef DEBUG
  2098.     if(debugging_log) */
  2099.         status_line("#Checking mail for %s", Pretty_Addr_Str(ad));
  2100. /* #endif */
  2101.  
  2102.     if(!isKnownDomain(ad))
  2103.         return TRUE;
  2104.  
  2105.     /* Check the password for every aka */
  2106.  
  2107.     if(session_password)
  2108.     {
  2109.         char *nf = CurrentNetFiles;    /* remember the inbound directory we are in! */
  2110.         BOOLEAN flag = n_password(ad, session_password, FALSE);
  2111.         CurrentNetFiles = nf;        /* Restore inbound folder */
  2112.  
  2113.         if(flag)
  2114.         {
  2115. #ifdef DEBUG
  2116.             if(debugging_log)
  2117.                 status_line(">No session password defined for address %s",
  2118.                     Pretty_Addr_Str(ad));
  2119. #endif
  2120.             return TRUE;    /* return but don't abort! */
  2121.         }
  2122.     }
  2123.     status_line(msgtxt[M_SENDING_FOR], Pretty_Addr_Str(ad));
  2124.  
  2125.     if (flag_file (TEST_AND_SET, ad, 1))
  2126.         goto done_send;
  2127.  
  2128.     HoldName = HoldAreaNameMunge(ad);
  2129.  
  2130.     /*--------------------------------------------------------------------*/
  2131.     /* Send all waiting ?UT files (mail packets)                         */
  2132.     /*--------------------------------------------------------------------*/
  2133.  
  2134.     extptr = "ODCH";
  2135.     while(*extptr)
  2136.     {
  2137.         char ch = *extptr++;
  2138.         
  2139.         if (caller && (ch == 'H') && !check_holdonus(ad, (char**)NULL))
  2140.             continue;
  2141.  
  2142.         /*
  2143.          * 2D style OUT uncompressed packets
  2144.          */
  2145.         
  2146.         sprintf (fname,
  2147.                 "%s%s.%cUT",
  2148.                 HoldName, Hex_Addr_Str (ad), ch);
  2149.  
  2150.         if (!stat (fname, &buf))
  2151.         {
  2152.  
  2153.             /*--- Build a dummy PKT file name */
  2154.  
  2155.             invent_pkt_name (s);
  2156.  
  2157.             /*--- Tell ZModem to handle this as a SEND AS then DELETE */
  2158.  
  2159.             status_line (msgtxt[M_PACKET_MSG]);
  2160.  
  2161.             if (!Send_Zmodem (fname, s, fsent++, DO_WAZOO))
  2162.             {
  2163.                 net_problems = 1;
  2164.                 flag_file (CLEAR_FLAG, ad, 1);
  2165. #ifdef DEBUG
  2166.                 if(debugging_log)
  2167.                     status_line(">Error sending packet %s", fname);
  2168. #endif
  2169.                 return FALSE;
  2170.             }
  2171.             CLEAR_IOERR ();
  2172.             unlink (fname);
  2173.         }
  2174.  
  2175. #ifdef IOS
  2176.         /*
  2177.          * New 4D style OPT Uncompressed packets
  2178.          */
  2179.              
  2180.         sprintf(fname, "%s%s.%cPT", HoldName, Addr36(ad), ch);
  2181.         if(!stat(fname, &buf))
  2182.         {
  2183.             invent_pkt_name(s);
  2184.             status_line(msgtxt[M_PACKET_MSG]);
  2185.  
  2186.             if(!Send_Zmodem(fname, s, fsent++, DO_WAZOO))
  2187.             {
  2188.             ios_error:
  2189.                 net_problems = 1;
  2190.                 flag_file(CLEAR_FLAG, ad, 1);
  2191. #ifdef DEBUG
  2192.                 if(debugging_log)
  2193.                     status_line(">Error sending IOS packet %s", fname);
  2194. #endif
  2195.                 return FALSE;
  2196.             }
  2197.             CLEAR_IOERR();
  2198.             unlink(fname);
  2199.         }
  2200.  
  2201.         /*
  2202.          * 4D style OAT, compressed mail
  2203.          */
  2204.              
  2205.         if(!(emsi_remote_capability & EMSI_O_HXT))    /* Other end accepts compressed mail! */
  2206.         {
  2207.             sprintf(fname, "%s%s.%cAT", HoldName, Addr36(ad), ch);
  2208.             if(!stat(fname, &buf))
  2209.             {
  2210.                 make_dummy_arcmail(s, &alias[assumed].ad, ad);
  2211.                 status_line(msgtxt[M_PACKET_MSG]);
  2212.  
  2213.                 if(!Send_Zmodem(fname, s, fsent++, DO_WAZOO))
  2214.                     goto ios_error;
  2215.                 CLEAR_IOERR();
  2216.                 unlink(fname);
  2217.             }
  2218.         }
  2219. #endif
  2220.  
  2221.  
  2222.     }         /* for */
  2223.  
  2224.     /*--------------------------------------------------------------------*/
  2225.     /* Send files listed in ?LO files (attached files)                      */
  2226.     /*--------------------------------------------------------------------*/
  2227.  
  2228.     if(!(emsi_remote_capability & EMSI_O_HXT))    /* Doesnt want compressed mail */
  2229.     {
  2230.         if(!do_FLOfile("FDCH", EMSI_callback, ad))
  2231.         {
  2232.         flo_error:
  2233.             flag_file (CLEAR_FLAG, ad, 1);
  2234. #ifdef DEBUG
  2235.             if(debugging_log)
  2236.                 status_line(">Error processing FLOfiles", fname);
  2237. #endif
  2238.             return FALSE;
  2239.         }
  2240.  
  2241. #ifdef IOS
  2242.         if(!do_FLOfile("DHOC", EMSI_callback, ad))
  2243.             goto flo_error;
  2244. #endif    
  2245.  
  2246.     }
  2247.  
  2248.     /*--------------------------------------------------------------------*/
  2249.     /* Send our File requests to other system                              */
  2250.     /*--------------------------------------------------------------------*/
  2251.  
  2252. /* #ifndef NEW */ /* TRYREQ    26.08.1990 */
  2253.     if (requests_ok)
  2254. /* #endif */
  2255.     {
  2256.         sprintf (fname, request_template, HoldName, Hex_Addr_Str(ad));
  2257.         if (!stat (fname, &buf))
  2258.         {
  2259.             if(emsi_remote_capability & (EMSI_P_NRQ | EMSI_O_HRQ))
  2260.                 status_line (msgtxt[M_FREQ_DECLINED]);
  2261.             else
  2262.             {
  2263.                 status_line (msgtxt[M_OUT_REQUESTS]);
  2264.                 ++made_request;
  2265.                 if (Send_Zmodem (fname, NULL, fsent++, DO_WAZOO))
  2266.                     unlink (fname);
  2267.             }
  2268.         }
  2269. #ifdef IOS
  2270.         extptr = "DHOC";
  2271.         while(*extptr)
  2272.         {
  2273.             char c = *extptr++;
  2274.             if (caller && (c == 'H') && !check_holdonus(ad, (char**)NULL))
  2275.                 continue;
  2276.             sprintf(fname, "%s%s.%cRT", HoldName, Addr36(ad), c);
  2277.             if(!stat(fname, &buf))
  2278.             {
  2279.                 if(emsi_remote_capability & (EMSI_P_NRQ | EMSI_O_HRQ))
  2280.                     status_line (msgtxt[M_FREQ_DECLINED]);
  2281.                 else
  2282.                 {
  2283.                     status_line (msgtxt[M_OUT_REQUESTS]);
  2284.                     ++made_request;
  2285.                     sprintf (s, request_template, HoldName, Hex_Addr_Str(ad));
  2286.                     if (Send_Zmodem (fname, s, fsent++, DO_WAZOO))
  2287.                         unlink (fname);
  2288.                 }
  2289.             }            
  2290.         }
  2291. #endif
  2292.     }
  2293.  
  2294.     flag_file (CLEAR_FLAG, ad, 1);
  2295.  
  2296. done_send:
  2297.  
  2298.     bad_call(ad, BAD_REMOVE);        /* Clear $$ files */
  2299.  
  2300.     return TRUE;
  2301.  
  2302. }                                                 /* WaZOO */
  2303.  
  2304. /*---------------------------------------------
  2305.  * Send files for all addresses using send_to_address
  2306.  *
  2307.  * Loop through all addresses and set called_addr
  2308.  */
  2309.  
  2310. static void send_all_files(BOOLEAN sender)
  2311. {
  2312.     ADDR_LIST *ads;
  2313.  
  2314.     /* Intialise */
  2315.  
  2316.     fsent = 0;
  2317.  
  2318.     if ( sender )
  2319.     {
  2320.     }
  2321.     
  2322.     if(emsi_remote_capability & EMSI_O_HAT)
  2323.     {
  2324.         status_line("#Remote asked to Hold All Traffic");
  2325.         bad_call(&remote_addr, BAD_STOPCALL);
  2326.     }
  2327.     else
  2328.     if(emsi_options != NPU)
  2329.     {
  2330.         if(emsi_options & PUP)        /* Only send to primary address */
  2331.         {
  2332.             if(!send_to_address(&remote_addr))
  2333.                 return;
  2334.         }
  2335.         else    /* Assume PUA */
  2336.         {
  2337.  
  2338.             /* Process each address */
  2339.  
  2340.             ads = remote_ads.next;    /* This should be empty, but we'll go to the end anyway! */
  2341.             while(ads)
  2342.             {
  2343.                 if(!send_to_address(&ads->ad))    /* Send the mail */
  2344.                     return;                        /* Abort if error */
  2345.                 ads = ads->next;
  2346.             }
  2347.  
  2348.         }
  2349.  
  2350.         /*
  2351.          * respond_to_file_requests acts on all addresses so do it here
  2352.          *
  2353.          * If receiver then files are to be sent with main batch
  2354.          * otherwise they are sent as a seperate phase later
  2355.          */
  2356.  
  2357.         if(!caller)
  2358.             fsent = respond_to_file_requests (fsent, EMSI_callback);
  2359.  
  2360.         /* Finish off */
  2361.  
  2362.         if (!fsent)
  2363.             status_line (msgtxt[M_NOTHING_TO_SEND], Pretty_Addr_Str(&remote_addr));
  2364.     }
  2365.  
  2366.     status_line(msgtxt[M_EMSI_FILES], fsent);
  2367.  
  2368.     Send_Zmodem (NULL, NULL, fsent ? END_BATCH : NOTHING_TO_DO, DO_WAZOO);
  2369. #if 0
  2370.     Send_Zmodem (NULL, NULL, NOTHING_TO_DO, DO_WAZOO);
  2371.     Send_Zmodem (NULL, NULL, (fsent ? END_BATCH : NOTHING_TO_DO), DO_WAZOO);
  2372.     Send_Zmodem (NULL, NULL, ((fsent) ? END_BATCH : EMPTY_BATCH), DO_WAZOO);
  2373. #endif
  2374.  
  2375.     sent_mail = 1;
  2376. }
  2377.  
  2378. /*------------------------------------------------------------------
  2379.  * Do an EMSI session
  2380.  */
  2381.  
  2382. /* this mostly copied from b_wazoo.c and modified */
  2383.  
  2384. static int EMSI_session(BOOLEAN sender)
  2385. {
  2386.     int stat;
  2387.     /* int i = 0; */
  2388.     char j[100];
  2389.     char k[100];
  2390.     int error = EMSI_SUCCESS;
  2391.  
  2392.    /*--------------------------------------------------------------------*/
  2393.    /* Initialize WaZOO                                                     */
  2394.    /*--------------------------------------------------------------------*/
  2395.    stat =
  2396.       made_request =
  2397.       got_arcmail =
  2398.       got_packet = 0;
  2399.  
  2400.    Netmail_Session = 1;
  2401.  
  2402.    isOriginator = sender;
  2403.  
  2404.    if (sender &&
  2405.       ((remote_addr.Zone != called_addr.Zone) ||
  2406.        (remote_addr.Net != called_addr.Net) ||
  2407.        (remote_addr.Node != called_addr.Node) ||
  2408.        (remote_addr.Point != called_addr.Point) ||
  2409.        (remote_addr.Domain != called_addr.Domain)))
  2410.     {
  2411.         /* 
  2412.          * Do NOT say this message if the node is a host
  2413.          * or a region-Node
  2414.          */
  2415.  
  2416.         if ((called_addr.Node != 0) && (called_addr.Net >= 100))
  2417.         {
  2418.             sprintf (k, "%s", Pretty_Addr_Str (&remote_addr));
  2419.             sprintf (j, msgtxt[M_CALLED], Pretty_Addr_Str (&called_addr), k);
  2420.             status_line (j);
  2421.         }
  2422.         add_remotead(&called_addr);
  2423.     }
  2424.     else
  2425.         called_addr = remote_addr;
  2426.  
  2427.     if (!CARRIER)
  2428.     {
  2429.         error = EMSI_ABORT;
  2430.         goto endemsi;
  2431.     }
  2432.  
  2433.     /* Make sure we have the correct inbound area for the remote */
  2434.  
  2435.     nodefind(&remote_addr, FALSE);
  2436.  
  2437.     /* Set up Wazoo compatible compatibilities */
  2438.  
  2439.     if(emsi_remote_capability & (EMSI_P_NRQ | EMSI_O_HRQ))    /* Can we do File requests? */
  2440.         remote_capabilities = 0;
  2441.     else
  2442.         remote_capabilities = WZ_FREQ;
  2443.  
  2444.    /* Try Janus first */
  2445.     if (emsi_protocol & EMSI_P_JAN)
  2446.     {
  2447.         status_line ("%s Janus", msgtxt[M_EMSI_METHOD]);
  2448.         remote_capabilities |= DOES_IANUS;
  2449.         Janus ();
  2450.         goto endemsi;
  2451.     }
  2452.  
  2453.     /* See if we can both do ZEDZAP */
  2454.  
  2455.     if (emsi_protocol & EMSI_P_ZAP)
  2456.     {
  2457.         status_line ("%s ZedZap", msgtxt[M_EMSI_METHOD]);
  2458.         remote_capabilities |= ZED_ZAPPER;
  2459.     }
  2460.     else if (emsi_protocol & EMSI_P_ZMO)
  2461.     {
  2462.         status_line ("%s ZedZip", msgtxt[M_EMSI_METHOD]);
  2463.         remote_capabilities |= ZED_ZIPPER;
  2464.     }
  2465.     else
  2466.     {
  2467.         status_line("%s %s", msgtxt[M_EMSI_METHOD], msgtxt[M_NONE]);
  2468.         error = EMSI_ABORT;
  2469.         goto endemsi;
  2470.     }
  2471.  
  2472.     /* ZMODEMBLOCKLEN  07/16/90 07:43pm */
  2473.     blklen = 0;
  2474.  
  2475.     /*--------------------------------------------------------------------*/
  2476.     /* ORIGINATOR: send/receive/send                                      */
  2477.     /*--------------------------------------------------------------------*/
  2478.  
  2479.     if (sender)
  2480.     {
  2481.  
  2482.         send_all_files(sender);
  2483. #ifdef DEBUG
  2484.         if(debugging_log)
  2485.             status_line(">Finished SEND phase");
  2486. #endif
  2487.         if (!CARRIER)
  2488.             goto endemsi;
  2489.         if(!get_Zmodem (CurrentNetFiles, NULL))
  2490.             goto endemsi;
  2491. #ifdef DEBUG
  2492.         if(debugging_log)
  2493.             status_line(">Finished RECEIVE phase");
  2494. #endif
  2495.         if (!CARRIER)
  2496.             goto endemsi;
  2497.  
  2498.         if(check_reqonus(&remote_addr, (char**)NULL))
  2499.             stat = respond_to_file_requests (0, WaZOO_callback);    /* was (i, WaZOO_callback) */
  2500.  
  2501.         if (stat)
  2502.             Send_Zmodem (NULL, NULL, ((stat) ? END_BATCH : NOTHING_TO_DO), DO_WAZOO);
  2503.         mail_finished = 1;
  2504.     }
  2505.  
  2506.    /*--------------------------------------------------------------------*/
  2507.    /* CALLED SYSTEM: receive/send/receive                                 */
  2508.    /*--------------------------------------------------------------------*/
  2509.     else
  2510.     {
  2511.         if (!get_Zmodem (CurrentNetFiles, NULL))
  2512.             goto endemsi;
  2513. #ifdef DEBUG
  2514.         if(debugging_log)
  2515.             status_line(">Finished RECEIVE phase");
  2516. #endif
  2517.         if (!CARRIER)
  2518.             goto endemsi;
  2519.         send_all_files(sender);
  2520. #ifdef DEBUG
  2521.         if(debugging_log)
  2522.             status_line(">Finished SEND phase");
  2523. #endif
  2524.         if (!CARRIER || !made_request)
  2525.             goto endemsi;
  2526.         get_Zmodem (CurrentNetFiles, NULL);
  2527.     }
  2528.  
  2529. endemsi:
  2530.     status_line (msgtxt[M_EMSI_END]);
  2531.  
  2532.     if(session_password)
  2533.     {
  2534.         free(session_password);
  2535.         session_password = NULL;
  2536.     }
  2537.  
  2538.     return error;
  2539. }
  2540.  
  2541. /*
  2542.  * Do session
  2543.  */
  2544.  
  2545. int EMSI_sender(void)
  2546. {
  2547.     if (un_attended && fullscreen)
  2548.     {
  2549.         sb_move (filewin, 2, 2);
  2550.         sb_puts (filewin, "EMSI");
  2551.         sb_show ();
  2552.     }
  2553.     else
  2554.         set_xy ("EMSI ");
  2555.  
  2556.     emsi_capability = emsi_remote_capability = emsi_protocol = 0;
  2557.  
  2558.     initTrx();
  2559.  
  2560.     if(TxEMSI_DAT(TRUE))
  2561.         return 0;
  2562.  
  2563.     if (un_attended && fullscreen)
  2564.     {
  2565.         sb_puts (filewin, "/Tx");
  2566.         sb_show ();
  2567.     }
  2568.     else
  2569.         set_xy ("EMSI/Tx");
  2570.  
  2571.     if(RxEMSI_DAT(TRUE))
  2572.         return 0;
  2573.  
  2574.     if (un_attended && fullscreen)
  2575.     {
  2576.         sb_puts (filewin, "/Rx");
  2577.         sb_show ();
  2578.     }
  2579.     else
  2580.         set_xy ("EMSI/Rx");
  2581.  
  2582.     EMSI_session(TRUE);
  2583.  
  2584.     return 0;
  2585. }
  2586.  
  2587. /*
  2588.  * Do Receiver session
  2589.  */
  2590.  
  2591. int EMSI_receiver(void)
  2592. {
  2593.     if (un_attended && fullscreen)
  2594.     {
  2595.         sb_move (filewin, 2, 2);
  2596.         sb_puts (filewin, "EMSI");
  2597.         sb_show ();
  2598.     }
  2599.     else
  2600.         set_xy ("EMSI ");
  2601.  
  2602.     emsi_capability = emsi_remote_capability = emsi_protocol = 0;
  2603.  
  2604.     initTrx();
  2605.  
  2606.     if(RxEMSI_DAT(FALSE))
  2607.         return 0;
  2608.  
  2609.     if (un_attended && fullscreen)
  2610.     {
  2611.         sb_puts (filewin, "/Rx");
  2612.         sb_show ();
  2613.     }
  2614.     else
  2615.         set_xy ("EMSI/Rx");
  2616.  
  2617.     if(TxEMSI_DAT(FALSE))
  2618.         return 0;
  2619.  
  2620.     if (un_attended && fullscreen)
  2621.     {
  2622.         sb_puts (filewin, "/Tx");
  2623.         sb_show ();
  2624.     }
  2625.     else
  2626.         set_xy ("EMSI Rx/Tx");
  2627.  
  2628.  
  2629.     last_type (1, &remote_addr);
  2630.     ++hist.mail_calls;
  2631.     if (un_attended && fullscreen)
  2632.     {
  2633.         sb_move (historywin, HIST_MAIL_ROW, HIST_COL);
  2634.         sprintf (junk, "%d/%d/%d",
  2635.                 hist.bbs_calls, hist.mail_calls, hist.extmails);
  2636.         sb_puts (historywin, junk);
  2637.     }
  2638.  
  2639.     EMSI_session(FALSE);
  2640.  
  2641.     return 0;
  2642. }
  2643.  
  2644.