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