home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / comm / bbs / s342q08.lha / modem.c < prev    next >
C/C++ Source or Header  |  1994-10-11  |  45KB  |  1,905 lines

  1. /*
  2. *       modem.c
  3. *
  4. * modem code for Citadel bulletin board system
  5. * NB: this code is rather machine-dependent:  it will typically
  6. * need some twiddling for each new installation.
  7. *       82Nov05 CrT
  8. *
  9. * now this file is mostly for upper layer modem handling and the protocols,
  10. * so it may need no fiddling.
  11. *       88May07 HAW
  12. */
  13. /*
  14. *       history
  15. *
  16. * 85Nov09 HAW  Warning bell before timeout.
  17. * 85Oct27 HAW  Cermetek support eliminated.
  18. * 85Oct18 HAW  2400 support.
  19. * 85Sep15 HAW  Put limit in ringSysop().
  20. * 85Aug17 HAW  Update for gotCarrier().
  21. * 85Jul05 HAW  Insert fix code (Brian Riley) for 1200 network.
  22. * 85Jun11 HAW  Fix readFile to recognize loss of carrier.
  23. * 85May27 HAW  Code for networking time out.
  24. * 85May06 HAW  Code for daily timeout.
  25. * 85Mar07 HAW  Stick in Sperry PC mods for MSDOS.
  26. * 85Feb22 HAW  Upload/download implemented.
  27. * 85Feb20 HAW  IMPERVIOUS flag implemented.
  28. * 85Feb17 HAW  Baud change functions installed.
  29. * 85Feb09 HAW and Sr.  Chat bug analyzed by Sr.
  30. * 85Jan16 JLS  fastIn modified for CR being first character from modem.
  31. * 85Jan04 HAW  Code added but not tested for new WC functions.
  32. * 84Sep12 HAW  Continue massacre of portability -- bye, pMIReady.
  33. * 84Aug30 HAW  Wheeee!!  MS-DOS time!!
  34. * 84Aug22 HAW  Compilation directive for 8085 chips inserted.
  35. * 84Jul08 JLS & HAW ReadFile() fixed for the 255 rollover.
  36. * 84Jul03 JLS & HAW All references to putCh changed to putChar.
  37. * 84Jun23 HAW & JLS Local unused variables zapped.
  38. * 84Mar07 HAW  Upgrade to BDS 1.50a begun.
  39. * 83Mar01 CrT  FastIn() ignores LFs etc -- CRLF folks won't be trapped.
  40. * 83Feb25 CrT  Possible fix for backspace-in-message-entry problem.
  41. * 83Feb18 CrT  fastIn() upload mode cutting in on people.  Fixed.
  42. * 82Dec16 dvm  modemInit revised for FDC-1, with kludge for use with
  43. *   Big Board development system
  44. * 82Dec06 CrT  2.00 release.
  45. * 82Nov15 CrT  readfile() & sendfile() borrowed from TelEdit.c
  46. * 82Nov05 CrT  Individual history file established
  47. */
  48. #include "ctdl.h"
  49. void DumpToFile(int LastReceived, int BufSize, CRC_TYPE tc, CRC_TYPE oc);
  50. /*
  51. *       Contents
  52. *
  53. * BBSCharReady()    returns true if user input is ready
  54. * ClearWX()   finishes a WXMODEM transmission
  55. * CommonPacket()    reads a block
  56. * CommonWrite()   writes a block to wherever
  57. * FlowControl()   flow control handler for WXMODEM
  58. * GenTrInit()   general init for individual protocols
  59. * getMod()    bottom-level modem-input filter
  60. * iChar()     top-level user-input function
  61. * initTransfers()   initial data buffers of protocols
  62. * interact()    chat mode
  63. * JumpStart()   gets protocol reception going
  64. * MIReady()   check MS-DOS interrupt for data
  65. * modIn()     returns a user char
  66. * modemInit()   top-level initialize-all-modem-stuff
  67. * oChar()     top-level user-output function
  68. * Reception()   receive data via protocol
  69. * recWX()     receive data via WXMODEM
  70. * recWXchar()   receive a WXMODEM char, stripped of DLE
  71. * recXYmodem()    receive data via X or Y MODEM
  72. * ringSysop()   signal chat-mode request
  73. * SendCmnBlk()    sends a WX/X/Y/MODEM block
  74. * sendWCChar()    send file with WC-protocol handshaking
  75. * sendWXchar()    send a char for WXMODEM
  76. * sendWXModem()   send data with WXMODEM protocol
  77. * sendYMChar()    send file with YMODEM protocol
  78. * SummonSysop()   rings bell for ^T
  79. * SurreptitiousChar() process a console character in MODEM
  80. * Transmission()    handles protocol transmission
  81. * WXResponses()   handles NAK/ACK XON/XOFF for WXMODEM
  82. * XYBlock()   common routine for X & Y modem
  83. * XYClear()   finished X or Y MODEM transmission
  84. * YMHdr()     YMODEM BATCH header handler
  85. */
  86. void ReActivate_Window(void);  /* allow window to be activated */
  87. char justLostCarrier = FALSE;   /* Modem <==> rooms connection  */
  88. char newCarrier = FALSE;   /* Just got carrier  */
  89. char onConsole;     /* Who's in control?!?  */
  90. int  outPut = NORMAL;
  91. char modStat;     /* Whether modem had carrier LAST time  */
  92. /* you checked. */
  93. char CallSysop = FALSE;   /* Call sysop on user logout  */
  94. char whichIO = CONSOLE;   /* CONSOLE or MODEM */
  95. #ifdef NEED_VISIBLE
  96. char visibleMode;   /* make non-printables visible? */
  97. #endif
  98. static char captureOn = FALSE;
  99. static FILE *cptFile;
  100. char haveCarrier;   /* set if DCD == TRUE */
  101. char textDownload = FALSE;  /* read host files, TRUE => ASCII */
  102. char echo;      /* Either NEITHER, CALLER, or BOTH  */
  103. char echoChar;      /* What to echo with if echo == NEITHER */
  104. int  TransProtocol;   /* Transfer protocol value  */
  105. int  upDay;     /* Day system was brought up  */
  106. char nextDay;     /* Come down tomorrow rather than today?*/
  107. int  timeCrash;
  108. char anyEcho = TRUE;
  109. char warned;
  110. long netBytes;
  111. char ChatMode;
  112. char NoConsoleBanner;   /* defaults to FALSE */
  113. long TempBytes;
  114. char ConOnly = FALSE;
  115. static char PB = 0;
  116. /* Block transfer variables */
  117. TransferBlock Twindow[4];
  118. #define blk Twindow[0]
  119. int  CurWindow,   /* For sequence #, init to 1 */
  120. TrBlock,    /* For block #, init to 1 */
  121. StartWindow,  /* First block of current Twindow, init = 1 */
  122. TrCount,    /* Byte accumulator counter, init to 0 */
  123. LastSent,   /* Last seq block sent to receiver, regardless of ACK */
  124. CurYBufSize,  /* Size of current YMODEM block to send */
  125. GlobalHeader; /* Starting char of transfer (YMODEM) */
  126. char DoCRC,   /* True if doing CRC */
  127. DLinkError, /* For conveying errors during WXMODEM */
  128. TrError,    /* True only on fatal error */
  129. DLEsignal;    /* True only when an WXMODEM read involved a DLE */
  130. AN_UNSIGNED *DataBuf;
  131. int      TrCksm;  /* Checksum variable for transmissions */
  132. static char *msg[] =
  133.   {
  134.   "NO ERROR",
  135.   "BAD DLE",
  136.   "EARLY SYN",
  137.   "DATA TIMEOUT",
  138.   "BAD CRC",
  139.   "BAD CHECKSUM",
  140.   "BAD SECTOR COMPLEMENT",
  141.   "SYNCH ERROR",
  142.   "WRITE ERROR",
  143.   "CARRIER LOSS"
  144.  
  145.   };
  146. #define WindowFull()    IsSent(0) && IsSent(1) && IsSent(2) && IsSent(3)
  147. #define WindowEmpty()   IsDone(0) && IsDone(1) && IsDone(2) && IsDone(3)
  148. #define IsDone(x) (IsAcked(x) || NotUsed(x))
  149. #define IsSent(x) (Twindow[x].status == SENT)
  150. #define IsAcked(x)  (Twindow[x].status == ACKED)
  151. #define NotUsed(x)  (Twindow[x].status == NOT_USED)
  152. /*
  153. * This table presupposes that XMODEM is defined as 1, YMODEM as 2, WXMODEM
  154. * as 3.  Used only by CommonPacket().
  155. */
  156. static int time_table[] =
  157.   {
  158.   0, 1, 4, 15
  159.  
  160.   };
  161. long ByteCount;
  162. extern MessageBuffer   msgBuf;  /* Message buffer */
  163. extern CONFIG    cfg;   /* Configuration variables  */
  164. extern logBuffer logBuf;  /* Log buffer of a person */
  165. extern aRoom  roomBuf;  /* Room buffer  */
  166. extern FILE *upfd;
  167. extern char loggedIn; /* Is we logged in? */
  168. extern char prevChar; /* previous char  */
  169. extern char outFlag;  /* output flag  */
  170. extern char ExitToMsdos;  /* Kill program flag  */
  171. extern int  exitValue;
  172. /* net stuff vars should go here */
  173. extern char inNet;
  174. extern FILE *netLog;
  175. extern FILE *strollfd;
  176. /* bloooooop! */
  177. extern int  acount;
  178. extern char netDebug;
  179. #define AUDIT 9000
  180. extern char audit[AUDIT];
  181. extern PROTO_TABLE  Table[];
  182. /*
  183. * BBSCharReady()
  184. *
  185. * This returns TRUE if char is available from user.
  186. * NB: user may be on modem, or may be sysop in CONSOLE mode.
  187. */
  188. char BBSCharReady()
  189.   {
  190.   return (char) (PB || ((haveCarrier && whichIO == MODEM) && MIReady()) ||
  191.   (whichIO == CONSOLE  &&   KBReady()));
  192.  
  193.   }
  194. #ifdef WXMODEM_AVAILABLE
  195. /*
  196. * ClearWX()
  197. *
  198. * This finishes a WXMODEM transmission.
  199. */
  200. int ClearWX()
  201.   {
  202.   int rover, BlockRover, TempSent, SendEOT;
  203.   if (!gotCarrier())
  204.   return CARR_LOSS;
  205.   outMod(EOT);  /* Forces us to wait until output buffer is flushed */
  206.   while (!WindowEmpty())
  207.     {
  208.     WXResponses();
  209.     for (BlockRover = (LastSent + 1) % 4, TempSent = LastSent, SendEOT=0;
  210.     BlockRover != LastSent; BlockRover = (BlockRover + 1) % 4)
  211.       {
  212.       if (Twindow[BlockRover].status != SECTOR_READY) break;
  213.       SendEOT++;
  214.       SendCmnBlk(WXMDM, Twindow + BlockRover, sendWXchar, SECTSIZE);
  215.       Twindow[BlockRover].status = SENT;
  216.       TempSent = BlockRover;
  217.  
  218.       }
  219.     LastSent = TempSent;
  220.     if (!gotCarrier())
  221.     return CARR_LOSS;
  222.     if (SendEOT) outMod(EOT);
  223.  
  224.     }
  225.   for (rover = 1; rover < MAX_WX_ERRORS; rover++)
  226.     {
  227.     if (!gotCarrier())
  228.     return CARR_LOSS;
  229.     if (receive(3) != ACK) outMod(EOT);
  230.     else return TRAN_SUCCESS;
  231.  
  232.     }
  233.   return TRAN_FAILURE;
  234.  
  235.   }
  236. #endif
  237. /*
  238. * CommonPacket()
  239. *
  240. * This reads a block of data (XMDM, YMDM, WXMDM).
  241. */
  242. int CommonPacket(char type, int size, int (*recFn)(int t), int *Sector)
  243.   {
  244.   int  comp, cksm, i, c, hi, lo, time;
  245.   CRC_TYPE crc;
  246.   #ifdef NEED_NET_DEBUG_ERRORS
  247.   CRC_TYPE oc;
  248.   #endif
  249.   /*
  250.   * Format:
  251.   *
  252.   * <SOH | STX><Sec#><w Sec#><size bytes of data><checksum or CRC>
  253.   *
  254.   * SOH | STX has already been received by the caller.  type is used for
  255.   * protocol specific problems, as follows.
  256.   *
  257.   * WXMDM:
  258.   * 1. When SYN is detected without DLEsignal == TRUE, this indicates a bad
  259.   *    packet problem, so that must be checked.
  260.   */
  261.   time = time_table[type];
  262.   *Sector = (*recFn)(time);   /* Get Sector # */
  263.   #ifdef WXMODEM_AVAILABLE
  264.   if (type == WXMDM && *Sector == SYN && !DLEsignal) return EARLY_SYN;
  265.   #endif
  266.   comp = (*recFn)(time);  /* Get Sector #'s complement */
  267.   #ifdef WXMODEM_AVAILABLE
  268.   if (type == WXMDM && comp == SYN && !DLEsignal) return EARLY_SYN;
  269.   #endif
  270.   for (i = cksm = 0; i < size; i++)
  271.     {
  272.     /* Get data block */
  273.     if ((c = (*recFn)(time)) == ERROR)
  274.       {
  275.       if (!gotCarrier())
  276.       return CARR_LOSS;
  277.       if (cfg.BoolFlags.debug)splitF(netLog, "TIMEOUT on byte %d\n", i);
  278.       return DATA_TIMEOUT;
  279.  
  280.       }
  281.     #ifdef WXMODEM_AVAILABLE
  282.     if (  type == WXMDM &&
  283.     c == SYN && !DLEsignal  )
  284.       {
  285.       return EARLY_SYN;
  286.  
  287.       }
  288.     #endif
  289.     DataBuf[i] = c;
  290.     cksm = (c + cksm) & 0xFF;
  291.     if (!gotCarrier()) return CARR_LOSS;
  292.  
  293.     }
  294.   hi = (*recFn)(time);  /* Get cksm or hi byte of CRC */
  295.   if (DoCRC)
  296.     {
  297.     lo = (*recFn)(time);    /* Get lo byte of CRC */
  298.     crc = (hi << 8) + lo;
  299.     if (*Sector + comp == 0xff) /* Validations... */
  300.     if (crc != calcrc(DataBuf, size))
  301.       {
  302.       #ifdef NEED_NET_DEBUG_ERRORS
  303.       splitF(netLog, "CRC error: we calc %x, they sent %x\n", oc=calcrc(DataBuf, size), crc);
  304.       DumpToFile(*Sector, size, crc, oc);
  305.       #endif
  306.       return BAD_CRC;
  307.  
  308.       }
  309.  
  310.     }
  311.   else
  312.     {
  313.     if (hi != cksm)
  314.     return BAD_CKSM;
  315.  
  316.     }
  317.   if (*Sector + comp != 0xFF)
  318.     {
  319.     /* Check this to make sure, too */
  320.     #ifdef NEED_NET_DEBUG_ERRORS
  321.     if (inNet != NON_NET && netDebug)
  322.     splitF(netLog, "BT: %x %x\n", *Sector, comp);
  323.     printf("\nBT: %x %x\n", *Sector, comp);
  324.     #endif
  325.     return BAD_SEC_COMP;
  326.  
  327.     }
  328.   return NO_ERROR;
  329.  
  330.   }
  331. /*
  332. * CommonWrite()
  333. *
  334. * This function writes a block of data to wherever.
  335. */
  336. int CommonWrite(int (*WriteFn)(int c), int size)
  337.   {
  338.   int i;
  339.   for (i = 0; i < size; i++)
  340.   if ((*WriteFn)(DataBuf[i]) == ERROR)
  341.   return WRITE_ERROR;
  342.   return NO_ERROR;
  343.  
  344.   }
  345. #ifdef WXMODEM_AVAILABLE
  346. /*
  347. * FlowControl()
  348. *
  349. * This function handles XON/XOFF for WXMODEM.
  350. */
  351. void FlowControl()
  352.   {
  353.   int val;
  354.   startTimer(WORK_TIMER);
  355.   do
  356.   val = receive(1); /* Use receive in this instance */
  357.   while (val != XON && chkTimeSince(WORK_TIMER) < 10);
  358.  
  359.   }
  360. #endif
  361. /*
  362. * GenTrInit()
  363. *
  364. * General protocol initializations.
  365. */
  366. void GenTrInit()
  367.   {
  368.   int i;
  369.   for (i = 0; i < 4; i++) Twindow[i].status = NOT_USED;
  370.   CurWindow  = TrBlock   = StartWindow = 1;
  371.   TrCount    = LastSent  = TrCksm = 0;
  372.   DLinkError = DLEsignal = FALSE;
  373.   TrError    = TRAN_SUCCESS;
  374.   DoCRC = TRUE;
  375.  
  376.   }
  377. /*
  378. * iChar()
  379. *
  380. * This is the top-level user-input function -- this is the function the rest
  381. * of Citadel uses to obtain user input.
  382. */
  383. char iChar()
  384.   {
  385.   char  c;
  386.   extern AN_UNSIGNED crtColumn; /* current position on screen */
  387.   if (justLostCarrier)   return 0;    /* ugly patch   */
  388.   c = cfg.filter[modIn() & 0x7f];
  389.   /* AUDIT CODE */
  390.   audit[acount] = c;
  391.   acount = (acount + 1) % AUDIT;
  392.   switch (echo)
  393.     {
  394.     case BOTH:
  395.     if (haveCarrier)
  396.       {
  397.       if (c == '\n')
  398.         {
  399.         if (!HalfDup) doCR();
  400.  
  401.         }
  402.       else
  403.       if (!HalfDup) outMod(c);
  404.  
  405.       }
  406.     mputChar(c);  /* Let putChar decide if it should go on console */
  407.     crtColumn += (c == '\b') ? -1 : 1;
  408.     break;
  409.     case CALLER:
  410.     if (whichIO == MODEM)
  411.       {
  412.       if (c == '\n')
  413.         {
  414.         if (!HalfDup) doCR();
  415.  
  416.         }
  417.       else
  418.         {
  419.         if (!HalfDup) outMod(c);
  420.  
  421.         }
  422.  
  423.       }
  424.     else
  425.       {
  426.       mputChar(c);
  427.  
  428.       }
  429.     crtColumn += (c == '\b') ? -1 : 1;
  430.     break;
  431.     case NEITHER:
  432.     if (echoChar != '\0')
  433.       {
  434.       if (whichIO == MODEM)
  435.         {
  436.         if (c == '\n') doCR();
  437.         else if (c <= ' ') outMod(c);
  438.         else  outMod(echoChar);
  439.  
  440.         }
  441.       else
  442.         {
  443.         if (c == '\n') doCR();
  444.         else if (c <= ' ') mputChar(c);
  445.         else  mputChar(echoChar);
  446.  
  447.         }
  448.       crtColumn += (c == '\b') ? -1 : 1;
  449.  
  450.       }
  451.     break;
  452.  
  453.     }
  454.   return(c);
  455.  
  456.   }
  457. /*
  458. * initTransfers()
  459. *
  460. * This initializes data buffers for protocol transfers.
  461. */
  462. void initTransfers()
  463.   {
  464.   int i;
  465.   for (i = 1; i < 4; i++)
  466.     {
  467.     Twindow[i].buf = GetDynamic(SECTSIZE);
  468.  
  469.     }
  470.   DataBuf = blk.buf = GetDynamic(YM_BLOCK_SIZE);
  471.  
  472.   }
  473. /*
  474. * interact()
  475. *
  476. * Here we try to chat with the users.  Or at least the modem.
  477. */
  478. void interact(char ask)
  479.   {
  480.   char CallerDumb;
  481.   char last = 0;
  482.   int  c = 0;
  483.   extern char *APPEND_TEXT;
  484.   ChatMode = TRUE;
  485.   printf("\nDirect modem-interaction mode\n");
  486.   if (ask)
  487.     {
  488.     ConOnly = TRUE;
  489.     CallerDumb = getYesNo("DUMBCL");
  490.     ConOnly = FALSE;
  491.     if (!gotCarrier()) EnableModem(FALSE);
  492.  
  493.     }
  494.   else
  495.     {
  496.     CallerDumb = FALSE;
  497.  
  498.     }
  499.   printf("<ESC> to exit\n");
  500.   /* incredibly ugly code.  Rethink sometime: */
  501.   while (c != SPECIAL )
  502.     {
  503.     c = 0;
  504.     BufferingOn();
  505.     if (MIReady())
  506.       {
  507.       c = inp() & 0x7f;
  508.       if( c == '\0')c = SPECIAL;
  509.       if (c == SPECIAL && !ask) c = 0;
  510.       if (c != '\r') c = cfg.filter[c];
  511.       if (c != '\r')
  512.         {
  513.         if (CallerDumb && c != ESC && c != 0)   outMod(c);
  514.         if (c != 0) interOut(c);
  515.  
  516.         }
  517.       else
  518.         {
  519.         interOut('\n');
  520.         if (CallerDumb)
  521.           {
  522.           outMod('\r');
  523.           outMod('\n');
  524.  
  525.           }
  526.  
  527.         }
  528.  
  529.       }
  530.     else if (KBReady())
  531.       {
  532.       BufferingOff();
  533.       if ((c = getCh()) == '\r') c = '\n';
  534.       if (c == CPT_SIGNAL)
  535.         {
  536.         /* capture input? */
  537.         captureOn = !captureOn;
  538.         if (captureOn)
  539.           {
  540.           if ((cptFile = safeopen("chat.txt", APPEND_TEXT)) == NULL)
  541.             {
  542.             printf("\nCOULDN'T OPEN/APPEND TO CHAT.TXT!\n");
  543.             captureOn = FALSE;
  544.  
  545.             }
  546.           else
  547.             {
  548.             printf("\nAppending to CHAT.TXT\n");
  549.             mPrintf(
  550.             "\n WARNING from Citadel: This chat is now being recorded.\n ");
  551.  
  552.             }
  553.  
  554.           }
  555.         else
  556.           {
  557.           fclose(cptFile);
  558.           printf("\nCapture finished\n");
  559.           mPrintf(
  560.           " \nMessage from Citadel: Chat no longer being captured.\n ");
  561.  
  562.           }
  563.  
  564.         }
  565.       else if (c == 5 || ChatEat(c))
  566.         {
  567.         ChatGrab(TRUE);
  568.  
  569.         }
  570.       else if (c == 6 || ChatSend(c))
  571.         {
  572.         ChatGrab(FALSE);
  573.  
  574.         }
  575.       else if (c != NEWLINE)
  576.         {
  577.         if (CallerDumb)  interOut(c);
  578.         if (c != ESC && c != '\\')   outMod(c);
  579.         else
  580.           {
  581.           if (last == '\\')
  582.             {
  583.             outMod(c);
  584.             c = 0;
  585.  
  586.             }
  587.  
  588.           }
  589.         last = c;
  590.  
  591.         }
  592.       else
  593.         {
  594.         outMod('\r');
  595.         if (CallerDumb)
  596.           {
  597.           interOut('\n');
  598.           outMod('\n');
  599.  
  600.           }
  601.  
  602.         }
  603.  
  604.       }
  605.     else
  606.       {
  607.       BufferingOff();
  608.       BeNice(CHAT_NICE);
  609.       DoTimeouts();
  610.  
  611.       }
  612.  
  613.     }
  614.   if (captureOn)
  615.     {
  616.     captureOn = FALSE;
  617.     fclose(cptFile);
  618.  
  619.     }
  620.   if (!gotCarrier() && whichIO == CONSOLE)
  621.   DisableModem(FALSE);
  622.   ChatMode = FALSE;
  623.   BufferingOff();
  624.  
  625.   }
  626. /*
  627. * ChatGrab()
  628. *
  629. * This function implements downloading from Chat.
  630. */
  631. void ChatGrab(char Up)
  632.   {
  633.   SListBase CSelects =
  634.     {
  635.     NULL, FindSelect, NULL, NoFree, NULL
  636.  
  637.     };
  638.   char *Protocols[] =
  639.     {
  640.     TERM "Xmodem",
  641.     #ifdef WXMODEM_AVAILABLE
  642.     TERM "Wxmodem",
  643.     #endif
  644.     TERM "Ymodem",
  645.     /* these are the external protocols */
  646.     " ", " ", " ", " ", " ",
  647.     " ", " ", " ", " ", " ",
  648.     " ", " ", " ", " ", " ",
  649.     ""
  650.  
  651.     };
  652.   char  letter[2];
  653.   int   protocol;
  654.   label roomName;
  655.   if (roomBuf.rbflags.ISDIR != 1)
  656.     {
  657.     printf("\nSorry this is not a directory room.\nNew room? ");
  658.     ConOnly = TRUE;
  659.     getNormStr("", roomName, NAMESIZE, 0);
  660.     ConOnly = FALSE;
  661.     if (strLen(roomName) == 0) return;
  662.     gotoRoom(roomName, 'R');
  663.     if (roomBuf.rbflags.ISDIR != 1)
  664.       {
  665.       printf("\nNor is this is a directory room.\n");
  666.       return;
  667.  
  668.       }
  669.  
  670.     }
  671.   printf((Up) ? "Grabbing file from other system (into %s)\n" :
  672.   "Sending file to other system (from %s)\n", roomBuf.rbname);
  673.   ConOnly = TRUE;
  674.   AddExternProtocolOptions(Protocols, Up);
  675.   printf("\nProtocol: ");
  676.   CmdMenuList(Protocols, &CSelects, NULL, letter, FALSE, FALSE);
  677.   switch (letter[0])
  678.     {
  679.     #ifdef WXMODEM_AVAILABLE
  680.     case 'X':
  681.     case 'W':
  682.     case 'Y':
  683.     protocol    = (letter[0] == 'W') ? WXMDM :
  684.     (letter[0] == 'X') ? XMDM : YMDM;
  685.     break;
  686.     #else
  687.     case 'X':
  688.     case 'Y':
  689.     protocol    = (letter[0] == 'X') ? XMDM : YMDM;
  690.     break;
  691.     #endif
  692.     default:
  693.     if ((protocol = FindProtocolCode(letter[0], Up)) == -1)
  694.       {
  695.       ConOnly = FALSE;
  696.       /* KillList(&CSelects); */
  697.       return ;
  698.  
  699.       }
  700.  
  701.     }
  702.   if (Up) upLoad(protocol,NULL,FALSE);
  703.   else    TranFiles(protocol, "");
  704.   ConOnly = FALSE;
  705.   /* KillList(&CSelects); */
  706.   printf("\nBack in Chat.\n");
  707.  
  708.   }
  709. /*
  710. * interOut()
  711. *
  712. * This function actually implements chat capture and general interact()
  713. * output.
  714. */
  715. void interOut(char c)
  716.   {
  717.   mputChar(c);
  718.   if (captureOn)
  719.   fputc(c, cptFile);
  720.  
  721.   }
  722. /*
  723. * JumpStart()
  724. *
  725. * Generic jump start for Reception.
  726. */
  727. char JumpStart(int tries, int timeout, int Starter, int t1, int t2,
  728. char (*Method)(int (*wrt)(int c)), int (*WriteFn)(int c))
  729.   {
  730.   int StartTries;
  731.   for (StartTries = 0; StartTries < tries; StartTries++)
  732.     {
  733.     if (!gotCarrier())
  734.       {
  735.       #ifdef NEED_NET_DEBUG_ERRORS
  736.       if (inNet != NON_NET)
  737.       splitF(netLog, "RecError: JS Carr Loss\n");
  738.       #endif
  739.       return CARR_LOSS;
  740.  
  741.       }
  742.     outMod(Starter);
  743.     GlobalHeader = receive(timeout);
  744.     if (GlobalHeader == t1 || GlobalHeader == t2)
  745.       {
  746.       return (*Method)(WriteFn);
  747.  
  748.       }
  749.     if (GlobalHeader == CAN)
  750.       {
  751.       #ifdef NEED_NET_DEBUG_ERRORS
  752.       if (inNet != NON_NET)
  753.       splitF(netLog, "RecError: JS JS received CAN\n");
  754.       #endif
  755.       return CANCEL;
  756.  
  757.       }
  758.     if (GlobalHeader == EOT)
  759.       {
  760.       outMod(ACK);
  761.       return TRAN_SUCCESS;  /* zero length data */
  762.  
  763.       }
  764.  
  765.     }
  766.   return NO_LUCK;
  767.  
  768.   }
  769. /*
  770. * ModemSetup()
  771. *
  772. * This function will set up modem handling variables.
  773. */
  774. char ModemSetup(char ShouldBeCarrier)
  775.   {
  776.   haveCarrier = modStat = gotCarrier();
  777.   if (ShouldBeCarrier && !haveCarrier) return FALSE;
  778.   if (!ShouldBeCarrier && haveCarrier)
  779.     {
  780.     HangUp(TRUE);
  781.     haveCarrier = modStat = gotCarrier();
  782.  
  783.     }
  784.   return TRUE;
  785.  
  786.   }
  787. /**
  788. * modIn()
  789. *
  790. * toplevel modem-input function.
  791. *
  792. * If DCD status has changed since the last access, reports carrier present or
  793. * absent and sets flags as appropriate.  In case of a carrier loss, waits 20
  794. * ticks and rechecks carrier to make sure it was not a temporary glitch.
  795. * If carrier is newly received, returns newCarrier = TRUE;  if carrier lost
  796. * returns 0.  If carrier is present and state has not changed, gets a
  797. * character if present and returns it.  If a character is typed at the console,
  798. * checks to see if it is keyboard interrupt character.  If so, prints
  799. * short-form console menu and awaits next keyboard character.
  800. *
  801. * Globals modified:    carrierDetect   modStat    haveCarrier
  802. *     justLostCarrier whichIO   ExitToMsDos
  803. *     visibleMode
  804. * Returns:  modem or console input character,
  805. *   or above special values
  806. **/
  807. #define MAX_TIME  210l  /* Time out is 210 seconds  */
  808. AN_UNSIGNED modIn()
  809.   {
  810.   AN_UNSIGNED logVal = 0;
  811.   AN_UNSIGNED c;
  812.   char *whatRate;
  813.   char signal = FALSE;
  814.   if (PB)
  815.     {
  816.     c = PB;
  817.     PB = 0;
  818.     return c;
  819.  
  820.     }
  821.   if (!onLine() && CallSysop)SummonSysop();
  822.   startTimer(WORK_TIMER);
  823.   while (TRUE)
  824.     {
  825.     if ((whichIO==MODEM) && (c=gotCarrier()) != modStat)
  826.       {
  827.       /* carrier changed   */
  828.       if (c)
  829.         {
  830.         /* carrier present   */
  831.         if (Find_baud(&whatRate))
  832.           {
  833.           printf("Carr-detect (%s)\n", whatRate);
  834.           warned      = FALSE;
  835.           haveCarrier = TRUE;
  836.           modStat     = c;
  837.           newCarrier  = TRUE;
  838.           justLostCarrier = FALSE;
  839.           logMessage(BAUD, whatRate, FALSE);
  840.           ScrNewUser();
  841.  
  842.           }
  843.         else
  844.         HangUp(TRUE);
  845.         return(0);
  846.  
  847.         }
  848.       else
  849.         {
  850.         pause(100);   /* confirm it's not a glitch */
  851.         if (!gotCarrier())
  852.           {
  853.           /* check again */
  854.           printf("Carr-loss\n");
  855.           logMessage(CARRLOSS, "", logVal);
  856.           HangUp(TRUE);
  857.           modStat = haveCarrier = FALSE;
  858.           justLostCarrier = TRUE;
  859.           startTimer(NEXT_ANYNET);  /* start anytime net timer */
  860.           return(0);
  861.  
  862.           }
  863.  
  864.         }
  865.  
  866.       }
  867.     if (MIReady())
  868.       {
  869.       if (haveCarrier)
  870.         {
  871.         c = inp() & 0x7f;
  872.         if (whichIO == MODEM)   return c;
  873.  
  874.         }
  875.  
  876.       }
  877.     if (KBReady())
  878.       {
  879.       c = getCh();
  880.       if (whichIO == CONSOLE) return(c);
  881.       else
  882.         {
  883.         if (!SurreptitiousChar(c))
  884.         return 0;
  885.  
  886.         }
  887.  
  888.       }
  889.     if (DoTimeouts()) return 0;
  890.     /* check for no input.  (Short-circuit evaluation, remember!) */
  891.     if ((whichIO==MODEM  &&  haveCarrier  &&
  892.     chkTimeSince(WORK_TIMER) >= MAX_TIME) ||
  893.     (whichIO == CONSOLE && cfg.ConTimeOut != 0 &&
  894.     chkTimeSince(WORK_TIMER) >= cfg.ConTimeOut))
  895.       {
  896.       mPrintf("Sleeping? Call again :-)");
  897.       logVal = 't';
  898.       if (whichIO == MODEM)
  899.       HangUp(FALSE);
  900.       else
  901.         {
  902.         logMessage(CARRLOSS, "", logVal);
  903.         justLostCarrier = TRUE;
  904.         onConsole = FALSE;
  905.         return 0;
  906.  
  907.         }
  908.  
  909.       }
  910.     else if ((whichIO == MODEM &&
  911.     haveCarrier &&
  912.     chkTimeSince(WORK_TIMER) == MAX_TIME - 10) ||
  913.     (whichIO == CONSOLE && cfg.ConTimeOut != 0 &&
  914.     chkTimeSince(WORK_TIMER) == cfg.ConTimeOut - 10))
  915.       {
  916.       if (!signal)
  917.       oChar(BELL);
  918.       signal = TRUE;
  919.  
  920.       }
  921.     BeNice((haveCarrier || onConsole) ? INUSE_PAUSE : IDLE_PAUSE);
  922.  
  923.     }
  924.  
  925.   }
  926. /*
  927. * SurreptitiousChar()
  928. *
  929. * This function will process a console character when the system is in modem
  930. * mode.
  931. */
  932. int SurreptitiousChar(char c)
  933.   {
  934.   switch (toUpper(c))
  935.     {
  936.     case CON_NEXT:    /* ^T */
  937.     if (onLine())
  938.       {
  939.       CallSysop = !CallSysop;
  940.       printf("\nSysop call toggle is %s\n", CallSysop ? "ON" : "OFF");
  941.       ScrNewUser();
  942.       break;
  943.  
  944.       }
  945.     /* yes, don't break here! */
  946.     case SPECIAL:   /* ESC */
  947.     printf("CONSOLE mode\n ");
  948.     whichIO = CONSOLE;
  949.     if (!gotCarrier())
  950.       {
  951.       DisableModem(FALSE);
  952.       logMessage(BAUD, "", FALSE);
  953.  
  954.       }
  955.     setUp(FALSE);
  956.     if (!gotCarrier())
  957.       {
  958.       ScrNewUser();
  959.       if (!NoConsoleBanner)
  960.       newCarrier = TRUE;
  961.  
  962.       }
  963.     warned = FALSE;
  964.     return FALSE;
  965.     case 1:     /* ^A */
  966.     ForceAnytime();
  967.     break;
  968.     case 5:     /* ^E */
  969.     anyEcho = !anyEcho;
  970.     ScrNewUser();
  971.     break;
  972.     case CNTRLD:
  973.     cfg.BoolFlags.debug  = !cfg.BoolFlags.debug;
  974.     break;
  975.     case CNTRLZ:
  976.     cfg.BoolFlags.noChat = !cfg.BoolFlags.noChat;
  977.     ScrNewUser();
  978.     break;
  979.  
  980.     }
  981.   return TRUE;
  982.  
  983.   }
  984. /*
  985. * oChar()
  986. *
  987. * This function is the top-level user-output routine.  It sends to modem port
  988. * and console, does conversion to upper-case etc as necessary in "debug" mode,
  989. * converts control chars to uppercase letters
  990. * Globals modified: prevChar
  991. */
  992. int delay_factor= -1;
  993. void oChar(char c)
  994.   {
  995.   prevChar = c;     /* for end-of-paragraph code    */
  996.   if (outFlag != OUTOK &&   /* s(kip) mode  */
  997.   outFlag != IMPERVIOUS)
  998.   return;
  999.   if( !onConsole && logBuf.lbdelay > 0 && delay_factor == -1)
  1000.     {
  1001.     delay_factor = ( 256 - logBuf.lbdelay );
  1002.     };
  1003.  
  1004.   if (c == NEWLINE)   c = ' ';  /* doCR() handles real newlines */
  1005.   /* show on console  */
  1006.   if (outPut == DISK)
  1007.   putc(c, upfd);
  1008.   else
  1009.     {
  1010.     if (haveCarrier && !ConOnly)
  1011.     (*Table[TransProtocol].method)(c);
  1012.     if (TransProtocol == ASCII)
  1013.       {
  1014.       mputChar(c);
  1015.       if (!onConsole && logBuf.lbdelay > 0 )
  1016.          {
  1017.          if( delay_factor-- < 1 )
  1018.            {
  1019.            delay_factor = ( 256 - logBuf.lbdelay );
  1020.            MilliSecPause(3);
  1021.            };
  1022.          };
  1023.  
  1024.       }
  1025.  
  1026.     }
  1027.   crtColumn += (c == '\b') ? -1 : 1;
  1028.  
  1029.   }
  1030. /*
  1031. * PushBack()
  1032. */
  1033. void PushBack(char c)
  1034.   {
  1035.   PB = c;
  1036.  
  1037.   }
  1038. /*
  1039. * Reception()
  1040. *
  1041. * This function reads data, trying to use specified protocol.  Note: This only
  1042. * handles XMODEM, WXMODEM, and YMODEM.  Due to the multiple authors of these
  1043. * protocols, this code is a mess.  I do da best I can, wid da leetle brain
  1044. * giben me.
  1045. */
  1046. char Reception(int protocol, int (*WriteFn)(int c))
  1047.   {
  1048.   char RetVal;
  1049.   if (!gotCarrier())
  1050.   return CARR_LOSS;
  1051.   GenTrInit();
  1052.   #ifdef WXMODEM_AVAILABLE
  1053.   /* From P. Boswell's WXMODEM doc */
  1054.   if (protocol == WXMDM)
  1055.     {
  1056.     if ((RetVal = JumpStart(3, 3, 'W', SYN, SYN, recWX, WriteFn))
  1057.     != NO_LUCK)
  1058.     return RetVal;
  1059.     if ((RetVal = JumpStart(3, 3, 'C', SOH, SOH, recXYmodem, WriteFn))
  1060.     != NO_LUCK)
  1061.     return RetVal;
  1062.     DoCRC = FALSE;
  1063.     if ((RetVal = JumpStart(4, 3, NAK, SOH, SOH, recXYmodem, WriteFn))
  1064.     != NO_LUCK)
  1065.     return RetVal;
  1066.  
  1067.     }
  1068.   /* From Ward's XMODEM.DOC -- 10 seconds between start tries */
  1069.   else
  1070.   #endif
  1071.   if (protocol == XMDM)
  1072.     {
  1073.     if ((RetVal = JumpStart((inNet != NON_NET) ? 2 : 4, 10, 'C', SOH,
  1074.     SOH, recXYmodem, WriteFn)) != NO_LUCK)
  1075.     return RetVal;
  1076.     DoCRC = FALSE;
  1077.     if ((RetVal = JumpStart(6, 10, NAK, SOH, SOH, recXYmodem, WriteFn))
  1078.     != NO_LUCK)
  1079.     return RetVal;
  1080.  
  1081.     }
  1082.   /* Extrapolated from C. Forsberg's doc and WC's doc. */
  1083.   else if (protocol == YMDM)
  1084.   if ((RetVal = JumpStart(10, 10, 'C', SOH, STX, recXYmodem, WriteFn))
  1085.   != NO_LUCK)
  1086.   return RetVal;
  1087.   return NO_START;
  1088.  
  1089.   }
  1090. #ifdef WXMODEM_AVAILABLE
  1091. /*
  1092. * recWX()
  1093. *
  1094. * This function receives data via WXMODEM.
  1095. */
  1096. char recWX(int (*WriteFn)(int c))
  1097.   {
  1098.   int CurChar,
  1099.   LastChar, /* Confirm that SOH follows a SYN */
  1100.   lastReceived = 0,
  1101.   Sector,
  1102.   SectorResult,
  1103.   LastError = NO_ERROR,
  1104.   LastNak = -1;
  1105.   /*
  1106.   * Assume that the startup part of the protocol has completed, which would
  1107.   * be indicated by a SYN -- already received by us.
  1108.   */
  1109.   CurChar = SYN;
  1110.   do
  1111.     {
  1112.     DLinkError = NO_ERROR;
  1113.     if (inNet == NON_NET) printf("Awaiting block %d\r", lastReceived +1);
  1114.     /*
  1115.     * Get starting SOH, discarding leading SYN and other characters.
  1116.     */
  1117.     do
  1118.       {
  1119.       LastChar = CurChar;
  1120.       CurChar = recWXchar(15);
  1121.  
  1122.       }
  1123.     while (!(CurChar == SOH && LastChar == SYN) && CurChar != EOT &&
  1124.     gotCarrier());
  1125.     if (CurChar != EOT)
  1126.       {
  1127.       SectorResult = CommonPacket(WXMDM, 128, recWXchar, &Sector);
  1128.       if (SectorResult == NO_ERROR)
  1129.         {
  1130.         if (Sector == (lastReceived + 1) % 256)
  1131.           {
  1132.           SectorResult = CommonWrite(WriteFn, SECTSIZE);
  1133.           lastReceived = Sector;
  1134.  
  1135.           }
  1136.         sendWXchar(ACK);
  1137.         sendWXchar(Sector & 3);
  1138.  
  1139.         }
  1140.       if (SectorResult != NO_ERROR)
  1141.         {
  1142.         /*
  1143.         * See Section 6.4.4 of the WXMODEM doc.
  1144.         */
  1145.         /*      if (!inNet) printf("Error: %s\n", msg[SectorResult]); */
  1146.         #ifdef NEED_NET_DEBUG_ERRORS
  1147.         splitF(netLog, "Error: %s\n", msg[SectorResult]);
  1148.         #endif
  1149.         if (SectorResult == CARR_LOSS)
  1150.           {
  1151.           return TRAN_FAILURE;
  1152.  
  1153.           }
  1154.         if (SectorResult == WRITE_ERROR)
  1155.           {
  1156.           sendWXchar(CAN);    /* Cancel transfer - fatal error */
  1157.           sendWXchar(CAN);
  1158.           sendWXchar(CAN);
  1159.           return TRAN_FAILURE;
  1160.  
  1161.           }
  1162.         if (LastError == NO_ERROR || Sector == LastNak)
  1163.           {
  1164.           sendWXchar(NAK);
  1165.           sendWXchar(Sector & 3);
  1166.           LastError = SectorResult;
  1167.           LastNak = Sector;
  1168.  
  1169.           }
  1170.  
  1171.         }
  1172.       else if (lastReceived == Sector)
  1173.         {
  1174.         LastError = NO_ERROR;   /* Clear signal */
  1175.         LastNak   = -1;
  1176.  
  1177.         }
  1178.  
  1179.       }
  1180.  
  1181.     }
  1182.   while (CurChar != EOT);
  1183.   sendWXchar(ACK);    /* Ack the EOT, indicates end of file */
  1184.   return TRAN_SUCCESS;
  1185.  
  1186.   }
  1187. /*
  1188. * recWXchar()
  1189. *
  1190. * This function reads a character, strips any leading DLE.
  1191. */
  1192. int recWXchar(int ErrorTime)
  1193.   {
  1194.   int result;
  1195.   if ((result = receive(ErrorTime)) == ERROR)
  1196.   return ERROR;
  1197.   if (result == DLE)
  1198.     {
  1199.     DLEsignal = TRUE;
  1200.     if ((result = receive(ErrorTime)) == ERROR)
  1201.     return ERROR;
  1202.     result ^= 64;
  1203.     switch (result)
  1204.       {
  1205.       case DLE:
  1206.       case SYN:
  1207.       case XON:
  1208.       case XOFF: break;
  1209.       default:
  1210.       DLinkError = BAD_DLE;
  1211.       result  = ERROR;
  1212.       break;
  1213.  
  1214.       }
  1215.  
  1216.     }
  1217.   else DLEsignal = FALSE;
  1218.   return result;
  1219.  
  1220.   }
  1221. #endif
  1222. /*
  1223. * recXYmodem()
  1224. *
  1225. * This function receives data via YMODEM SINGLE.
  1226. *      (May also work with XMODEM...)
  1227. * Note: algorithm modified to ACK the transmitter before trying
  1228. * to write to disk (or wherever).  This should up performance, but
  1229. * at the expense code complexity.
  1230. */
  1231. char recXYmodem(int (*WriteFn)(int c))  /* Supports YMODEM SINGLE mode only */
  1232.   {
  1233.   char AbortTransmission = FALSE, WriteError = FALSE;
  1234.   int  SectorResult,    /* Result of packet read */
  1235.   Sector,   /* Sector # received */
  1236.   LastReceived = 0, /* Last sector received */
  1237.   TotalErrors = 0,  /* Total errors for this transmission */
  1238.   CurrentErrors = 0,  /* Total errors for block */
  1239.   SOH_val,    /* SOH indicates 128, STX 1024 */
  1240.   BufSize;    /* In conjunction with SOH_val */
  1241.   /*
  1242.   * Assume that the initial SOH or STX has been received.  An initial EOT
  1243.   * should also be handled by the startup function.
  1244.   */
  1245.   SOH_val = GlobalHeader; /* Set by startup function, is global */
  1246.   do
  1247.     {
  1248.     BufSize = (SOH_val == SOH) ? SECTSIZE : YM_BLOCK_SIZE;
  1249.     SectorResult = CommonPacket(YMDM, BufSize, receive, &Sector);
  1250.     if (WriteError) SectorResult = WRITE_ERROR;
  1251.     if (SectorResult == NO_ERROR)
  1252.       {
  1253.       if ((Sector == (LastReceived + 1) % 256) ||
  1254.       Sector == LastReceived)
  1255.       outMod(ACK);
  1256.       if (Sector == (LastReceived + 1) % 256)
  1257.         {
  1258.         WriteError = (CommonWrite(WriteFn, BufSize) == WRITE_ERROR);
  1259.         LastReceived++;
  1260.         if (inNet == NON_NET)
  1261.         printf("Block %d received (try %d, %d total errors)\r",
  1262.         LastReceived,
  1263.         CurrentErrors,
  1264.         TotalErrors);
  1265.  
  1266.         }
  1267.       else if (Sector != LastReceived)
  1268.       SectorResult = SYNCH_ERROR;
  1269.  
  1270.       }
  1271.     if (SectorResult != NO_ERROR)
  1272.       {
  1273.       TotalErrors++;
  1274.       splitF(netLog, "Error on sector %d: %s (%d)\n", LastReceived+1,msg[SectorResult],CurrentErrors+1);
  1275.       switch (SectorResult)
  1276.         {
  1277.         case SYNCH_ERROR:
  1278.         case WRITE_ERROR:
  1279.         outMod(CAN);
  1280.         outMod(CAN);
  1281.         outMod(CAN);    /* Fatal error -- cancel transmission */
  1282.         case CARR_LOSS: /* Don't bother with CANs here */
  1283.         AbortTransmission = TRUE;
  1284.         splitF(netLog, "\nAborting reception due to %s error\n",
  1285.         msg[SectorResult]);
  1286.         break;
  1287.         default:  /* Some normal problem */
  1288.         outMod(NAK);
  1289.         if (CurrentErrors++ >= 9)
  1290.           {
  1291.           AbortTransmission = TRUE;
  1292.           splitF(netLog,
  1293.           "Aborting reception due to 10 consecutive errors\n");
  1294.  
  1295.           }
  1296.  
  1297.         }
  1298.  
  1299.       }
  1300.     else
  1301.       {
  1302.       CurrentErrors = 0;
  1303.  
  1304.       }
  1305.     if (!AbortTransmission)
  1306.       {
  1307.       do
  1308.       SOH_val = receive(10);
  1309.       while (SOH_val != EOT && SOH_val != SOH && SOH_val != CAN &&
  1310.       SOH_val != STX && gotCarrier());
  1311.  
  1312.       }
  1313.  
  1314.     }
  1315.   while (SOH_val != EOT && !AbortTransmission && SOH_val != CAN);
  1316.   if (AbortTransmission)
  1317.   splitF(netLog, "Leaving recXY loop due to AT\n");
  1318.   if (!AbortTransmission && SOH_val != CAN )
  1319.     {
  1320.     outMod(ACK);    /* Ack the EOT, indicates end of file */
  1321.     return TRAN_SUCCESS;
  1322.  
  1323.     }
  1324.   else return TRAN_FAILURE;
  1325.  
  1326.   }
  1327. /*
  1328. * ringSysop()
  1329. *
  1330. * This function signals a chat mode request.  Exits on input from modem or
  1331. * keyboard.
  1332. */
  1333. #define RING_LIMIT 6
  1334. void ReActivate_Window(void);
  1335. void ringSysop()
  1336.   {
  1337.   char answered;
  1338.   int  i, ring;
  1339.   ReActivate_Window();
  1340.   mPrintf("\n Ringing sysop.\n ");
  1341.   answered = FALSE;
  1342.   for (ring = 0; ring < RING_LIMIT && !answered && gotCarrier(); ring++)
  1343.     {
  1344.     for (i=0; !BBSCharReady() && !KBReady(); i = ++i % 7)
  1345.       {
  1346.       /* play shave-and-a-haircut/two bits... as best we can: */
  1347.       oChar(BELL);
  1348.       pause(cfg.shave[i]);
  1349.       if (i == 6) ring++;
  1350.  
  1351.       }
  1352.     if (BBSCharReady() || KBReady()) answered = TRUE;
  1353.  
  1354.     }
  1355.   if (KBReady())
  1356.     {
  1357.     getCh();
  1358.     whichIO = CONSOLE;
  1359.     interact(TRUE);
  1360.     whichIO = MODEM;
  1361.  
  1362.     }
  1363.   else if (ring >= RING_LIMIT)
  1364.     {
  1365.     cfg.BoolFlags.noChat = TRUE;
  1366.     mPrintf("\n Sorry, Sysop not around...\n ");
  1367.  
  1368.     }
  1369.   else modIn();
  1370.  
  1371.   }
  1372. /*
  1373. * SendCmnBlk()
  1374. *
  1375. * This function sends a WX/X/Y Modem block.
  1376. */
  1377. void SendCmnBlk(char type, TransferBlock *block,char (*SendFn)(int c), int size)
  1378.   {
  1379.   int rover;
  1380.   #ifndef NEED_NET_DEBUG_ERRORS
  1381.   if (inNet == NON_NET)
  1382.   printf("Sending block %d\r", block->ThisBlock);
  1383.   #else
  1384.   splitF(netLog, "Sending block %d, type %d, size %d\n", block->ThisBlock, type, size);
  1385.   #endif
  1386.   #ifdef WXMODEM_AVAILABLE
  1387.   if (type == WXMDM)
  1388.     {
  1389.     /* Thrust out some SYNs first */
  1390.     fastMod(SYN);
  1391.     fastMod(SYN);
  1392.  
  1393.     }
  1394.   else
  1395.   #endif
  1396.   BufferingOn();
  1397.   (*SendFn)((size == SECTSIZE) ? SOH : STX);
  1398.   (*SendFn)(block->ThisBlock & 0xFF);
  1399.   (*SendFn)(~(block->ThisBlock & 0xff));
  1400.   for (rover = 0; rover < size; rover++)
  1401.     {
  1402.     (*SendFn)(block->buf[rover]);
  1403.     #ifdef WXMODEM_AVAILABLE
  1404.     if (type == WXMDM) WXResponses();
  1405.     #endif
  1406.     if (!gotCarrier())
  1407.       {
  1408.       TrError = CARR_LOSS;
  1409.       if (cfg.BoolFlags.debug) splitF(netLog, "SendCmnBlk lost carrier\n");
  1410.       BufferingOff();
  1411.       return ;
  1412.  
  1413.       }
  1414.  
  1415.     }
  1416.   /*
  1417.   * Handle CRC/Checksum stuff.
  1418.   */
  1419.   if (DoCRC)
  1420.     {
  1421.     (*SendFn)(((block->ThisCRC & 0xff00) >> 8));
  1422.  
  1423.     }
  1424.   (*SendFn)(block->ThisCRC & 0xff);
  1425.   BufferingOff();
  1426.  
  1427.   }
  1428. /*
  1429. * sendWCChar()
  1430. *
  1431. * This function sends a file using Ward Christensen's protocol.
  1432. * (i.e., compatable with xModem, modem7, modem2, YAM, ... )
  1433. */
  1434. int sendWCChar(int c)
  1435.   {
  1436.   if (TrError != TRAN_SUCCESS)
  1437.   return FALSE;
  1438.   blk.buf[TrCount++] = c;
  1439.   TrCksm = (TrCksm + c) & 0xFF;
  1440.   if (TrCount != SECTSIZE)
  1441.   return TRUE;
  1442.   blk.ThisBlock = TrBlock;
  1443.   blk.ThisCRC   = (DoCRC) ? calcrc(blk.buf, SECTSIZE) : TrCksm;
  1444.   return (XYBlock(XMDM, SECTSIZE));
  1445.  
  1446.   }
  1447. #ifdef WXMODEM_AVAILABLE
  1448. /*
  1449. * sendWXchar()
  1450. *
  1451. * This function sends a char via WXMODEM with appropriate leaders, etc.
  1452. */
  1453. char sendWXchar(int data)
  1454.   {
  1455.   data &= 0xff;
  1456.   switch (data)
  1457.     {
  1458.     case DLE:
  1459.     case SYN:
  1460.     case XON:
  1461.     case XOFF:
  1462.     fastMod(DLE);
  1463.     fastMod(data ^ 64);
  1464.     break;
  1465.     default:
  1466.     fastMod(data);
  1467.     break;
  1468.  
  1469.     }
  1470.   return 0;
  1471.  
  1472.   }
  1473. /*
  1474. * sendWXModem()
  1475. *
  1476. * This function sends a character using WXMODEM protocol.
  1477. */
  1478. int sendWXModem(int c)
  1479.   {
  1480.   int BlockRover, TempSent, LoopCount;
  1481.   /*
  1482.   * First, check for terminal failure.
  1483.   */
  1484.   if (TrError != TRAN_SUCCESS) return FALSE;
  1485.   /*
  1486.   * Process current character.
  1487.   */
  1488.   Twindow[CurWindow].buf[TrCount] = c;
  1489.   /*
  1490.   * Block is full, so clean up details in preparation for transmission.
  1491.   */
  1492.   if (++TrCount == SECTSIZE)
  1493.     {
  1494.     Twindow[CurWindow].ThisBlock = TrBlock;
  1495.     Twindow[CurWindow].ThisCRC = calcrc(Twindow[CurWindow].buf, SECTSIZE);
  1496.     Twindow[CurWindow].status = SECTOR_READY;   /* Set to go */
  1497.     /* TrBlock = (TrBlock + 1) % 256; line below should work -- see SendCmnBlk */
  1498.     TrBlock++;
  1499.     CurWindow = (CurWindow + 1) % 4;
  1500.     TrCount = 0;
  1501.  
  1502.     }
  1503.   /*
  1504.   * Check for responses from receiver.
  1505.   */
  1506.   WXResponses();
  1507.   /*
  1508.   * Now we need to send outstanding blocks.
  1509.   */
  1510.   for (    BlockRover = (LastSent + 1) % 4, TempSent = LastSent;
  1511.   BlockRover != LastSent; BlockRover = (BlockRover + 1) % 4)
  1512.     {
  1513.     if (Twindow[BlockRover].status != SECTOR_READY) break;
  1514.     SendCmnBlk(WXMDM, Twindow + BlockRover, sendWXchar, SECTSIZE);
  1515.     Twindow[BlockRover].status = SENT;
  1516.     TempSent = BlockRover;
  1517.     if (!gotCarrier())
  1518.       {
  1519.       break;
  1520.  
  1521.       }
  1522.  
  1523.     }
  1524.   LastSent = TempSent;
  1525.   /*
  1526.   * Now we need to check to see if the Twindow is "full"
  1527.   */
  1528.   for (LoopCount = 0; gotCarrier() && WindowFull() &&
  1529.   LoopCount < MAX_WX_ERRORS;
  1530.   LoopCount++)
  1531.     {
  1532.     startTimer(WORK_TIMER);
  1533.     do
  1534.     WXResponses();
  1535.     while (chkTimeSince(WORK_TIMER) < 10 && WindowFull());
  1536.     if (WindowFull())
  1537.     SendCmnBlk(WXMDM, Twindow + LastSent, sendWXchar, SECTSIZE);
  1538.  
  1539.     }
  1540.   /*
  1541.   * If the Twindow is still full at this point, then we've suffered some
  1542.   * sort of fatal error, and it's time to bomb out.
  1543.   */
  1544.   if (WindowFull() || !gotCarrier())
  1545.     {
  1546.     TrError = TRAN_FAILURE;
  1547.     return FALSE;
  1548.  
  1549.     }
  1550.   return TRUE;
  1551.  
  1552.   }
  1553. #endif
  1554. /*
  1555. * sendYMChar()
  1556. *
  1557. * This function sends a character using YMODEM protocol.
  1558. */
  1559. int sendYMChar(int c)
  1560.   {
  1561.   if (TrError != TRAN_SUCCESS)
  1562.   return FALSE;
  1563.   blk.buf[TrCount++] = c;
  1564.   if (TrCount != CurYBufSize)
  1565.   return TRUE;
  1566.   return SendYBlk();
  1567.  
  1568.   }
  1569. /*
  1570. * SendYBlk()
  1571. *
  1572. * This function sends a YMODEM block.
  1573. */
  1574. int SendYBlk()
  1575.   {
  1576.   blk.ThisBlock = TrBlock;
  1577.   blk.ThisCRC   = calcrc(blk.buf, CurYBufSize);
  1578.   return XYBlock(YMDM, CurYBufSize);
  1579.  
  1580.   }
  1581. /*
  1582. * SummonSysop()
  1583. *
  1584. * This function rings the sysop for ^T.
  1585. */
  1586. void SummonSysop()
  1587.   {
  1588.   int i;
  1589.   CallSysop = FALSE;
  1590.   DisableModem(FALSE);
  1591.   ReActivate_Window();  /* allow window to be activated and to the front */
  1592.   printf("SYSOP: System available!  Hit space!\n");
  1593.   for (i = 0; i < 12 && !KBReady(); i++)
  1594.     {
  1595.     onConsole = TRUE;
  1596.     printf("%c", BELL);
  1597.     onConsole = FALSE;
  1598.     startTimer(WORK_TIMER);
  1599.     while (!KBReady() && chkTimeSince(WORK_TIMER) < 10l)
  1600.     ;
  1601.  
  1602.     }
  1603.   if (KBReady())
  1604.     {
  1605.     getCh();
  1606.     printf("CONSOLE mode\n ");
  1607.     whichIO = CONSOLE;
  1608.     setUp(FALSE);
  1609.     ScrNewUser();
  1610.     warned  = FALSE;
  1611.     logMessage(BAUD, "", FALSE);
  1612.  
  1613.     }
  1614.   else
  1615.     {
  1616.     printf("No answer.  System back on MODEM.\n");
  1617.     EnableModem(FALSE);
  1618.  
  1619.     }
  1620.   givePrompt();
  1621.  
  1622.   }
  1623. /*
  1624. * Transmission()
  1625. *
  1626. * Starts protocols up.
  1627. * Note: This only handles XMODEM, WXMODEM, and YMODEM.
  1628. */
  1629. char Transmission(int protocol, char mode)  /* Transmission handler */
  1630.   {
  1631.   int Errors, m;
  1632.   if (!gotCarrier() && protocol != ASCII)
  1633.     {
  1634.     #ifdef NEED_NET_DEBUG_ERRORS
  1635.     if (inNet != NON_NET)
  1636.     splitF(netLog, "Error: Transmission() got carrier loss\n");
  1637.     #endif
  1638.     return CARR_LOSS;
  1639.  
  1640.     }
  1641.   if (protocol == ASCII) return TRAN_SUCCESS;
  1642.   if (mode == STARTUP)
  1643.     {
  1644.     GenTrInit();
  1645.     ByteCount = 0l;
  1646.     for (Errors = 0; Errors < ERRORMAX; Errors++)
  1647.       {
  1648.       m = receive(MINUTE);
  1649.       switch (m)
  1650.         {
  1651.         case CAN:
  1652.         if (cfg.BoolFlags.debug) splitF(netLog, "Transmission() CANned\n");
  1653.         return CANCEL;
  1654.         case ERROR:
  1655.         if (cfg.BoolFlags.debug) splitF(netLog, "Transmission() did not start\n");
  1656.         return NO_START;
  1657.         case NAK:
  1658.         TransProtocol = XMDM;
  1659.         DoCRC = FALSE;
  1660.         if (cfg.BoolFlags.debug)splitF(netLog, "XMODEM Transmission\n");
  1661.         return TRAN_SUCCESS;
  1662.         #ifdef WXMODEM_AVAILABLE
  1663.         case 'W':
  1664.         if (protocol == WXMDM)
  1665.           {
  1666.           TransProtocol = WXMDM;
  1667.           if (cfg.BoolFlags.debug)splitF(netLog, "WXMODEM Transmission\n");
  1668.           return TRAN_SUCCESS;
  1669.  
  1670.           }
  1671.         break;
  1672.         #endif
  1673.         case 'C':
  1674.         if (protocol == YMDM)
  1675.           {
  1676.           if (cfg.BoolFlags.debug) splitF(netLog, "YMODEM Transmission\n");
  1677.           /* Kludge for floopy performance */
  1678.           CurYBufSize = 1024;
  1679.           TransProtocol = YMDM;
  1680.           return TRAN_SUCCESS;
  1681.  
  1682.           }
  1683.         TransProtocol = XMDM;
  1684.         if (cfg.BoolFlags.debug) splitF(netLog, "XMODEM-CRC Transmission\n");
  1685.         return TRAN_SUCCESS;
  1686.         default:
  1687.         if (cfg.BoolFlags.debug) splitF(netLog, "TrStart: -%c (0x%x)-\n", m, m);
  1688.  
  1689.         }
  1690.  
  1691.       }
  1692.     if (cfg.BoolFlags.debug) splitF(netLog, "returning NO_START on loop exit.\n");
  1693.     return NO_START;    /* If we make it out of the loop, error */
  1694.  
  1695.     }
  1696.   else
  1697.     {
  1698.     if (inNet == NON_NET) printf("\n");
  1699.     if (TrError != TRAN_SUCCESS)
  1700.       {
  1701.       if (cfg.BoolFlags.debug) splitF(netLog, "TranFin found TrError was bad immediately\n");
  1702.       return TrError;
  1703.  
  1704.       }
  1705.     if (TransProtocol == YMDM && TrCount < SECTSIZE)
  1706.     CurYBufSize = SECTSIZE;
  1707.     while (TrCount != 0)
  1708.       {
  1709.       (*Table[TransProtocol].method)(' ');
  1710.  
  1711.       }
  1712.     if (TrError != TRAN_SUCCESS)
  1713.       {
  1714.       if (cfg.BoolFlags.debug) splitF(netLog, "TranFin found TrError after buffer fill\n");
  1715.       return TrError;
  1716.  
  1717.       }
  1718.     if (Table[TransProtocol].CleanUp != NULL)
  1719.       {
  1720.       return (char) (*Table[TransProtocol].CleanUp)();
  1721.  
  1722.       }
  1723.     TransProtocol = ASCII;  /* Return to normal */
  1724.     return TRAN_SUCCESS;
  1725.  
  1726.     }
  1727.   }
  1728. #ifdef WXMODEM_AVAILABLE
  1729. /*
  1730. * WXResponses()
  1731. *
  1732. * Handles ACK/NAK and XON/XOFF for WXMODEM.
  1733. */
  1734. void WXResponses()
  1735.   {
  1736.   int rover, sig, old, SeqReceived;
  1737.   if (MIReady())
  1738.     {
  1739.     sig = recWXchar(1);
  1740.     switch (sig)
  1741.       {
  1742.       case XOFF:
  1743.       FlowControl();
  1744.       break;
  1745.       case ACK:
  1746.       case NAK:
  1747.       SeqReceived = recWXchar(5) & 0x03;
  1748.       if (sig == ACK)
  1749.         {
  1750.         rover = StartWindow;
  1751.         do
  1752.           {
  1753.           Twindow[rover].status = ACKED;
  1754.           old = rover;
  1755.           rover = (rover + 1) % 4;
  1756.  
  1757.           }
  1758.         while (old != SeqReceived);
  1759.         StartWindow = rover;    /* First block of Twindow */
  1760.  
  1761.         }
  1762.       else
  1763.         {
  1764.         /* NAK */
  1765.         LastSent = (SeqReceived == 0) ? 3 : (SeqReceived - 1);
  1766.         rover = SeqReceived;
  1767.         do
  1768.           {
  1769.           Twindow[rover].status = SECTOR_READY;
  1770.           rover = (rover + 1) % 4;
  1771.  
  1772.           }
  1773.         while (rover != CurWindow);
  1774.  
  1775.         }
  1776.       break;
  1777.  
  1778.       }
  1779.  
  1780.     }
  1781.  
  1782.   }
  1783. #endif
  1784. /*
  1785. * XYBlock()
  1786. *
  1787. * This function handles common work of XMODEM and YMODEM.
  1788. */
  1789. char XYBlock(int mode, int size)
  1790.   {
  1791.   int i, m;
  1792.   #ifdef NEED_NET_DEBUG
  1793.   splitF(netLog, "In XYBlock\n");
  1794.   #endif
  1795.   ByteCount += size;
  1796.   for (i = 0; i < ERRORMAX; i++)
  1797.     {
  1798.     SendCmnBlk(mode, &blk, outMod, size);
  1799.     while (MIReady()) inp();  /* clear line */
  1800.     m = receive(10);  /* wait 10 seconds for return ACK/NAK */
  1801.     if (m == ACK || m == CAN || !gotCarrier()) break;
  1802.     #ifdef NEED_NET_DEBUG_ERRORS
  1803.     if (inNet != NON_NET)
  1804.     splitF(netLog, "Tr Resend (m=%c [%x])\n", m, m);
  1805.     #endif
  1806.  
  1807.     }
  1808.   TrCksm  = TrCount = 0;
  1809.   TrBlock++;
  1810.   if (m == ACK)
  1811.     {
  1812.     #ifdef NEED_NET_DEBUG_ERRORS
  1813.     if (inNet != NON_NET)
  1814.     splitF(netLog, "Ack on block\n");
  1815.     #endif
  1816.     return TRUE;
  1817.  
  1818.     }
  1819.   TrError = TRAN_FAILURE;
  1820.   if (inNet == NON_NET) printf("Aborting\n ");
  1821.   else splitF(netLog, "XYBlock aborting (%s)\n", (gotCarrier()) ? "10 NAKs" :
  1822.   "carrier loss");
  1823.   return FALSE;
  1824.  
  1825.   }
  1826. /*
  1827. * XYClear()
  1828. *
  1829. * This function finishes XMODEM and YMODEM transmission.
  1830. */
  1831. int XYClear()
  1832.   {
  1833.   int i, m;
  1834.   for (i = 0; gotCarrier() && i < ERRORMAX; i++)
  1835.     {
  1836.     #ifdef NEED_NET_DEBUG
  1837.     splitF(netLog, "Sending EOT\n");
  1838.     #endif
  1839.     outMod(EOT);
  1840.     if ((m = receive(10)) == ACK)
  1841.     return TRAN_SUCCESS;
  1842.     if (m == CAN)
  1843.     return TRAN_FAILURE;
  1844.  
  1845.     }
  1846.   return TRAN_FAILURE;
  1847.  
  1848.   }
  1849. /*
  1850. * YMHdr()
  1851. *
  1852. * This function sends the header for a YMODEM BATCH transmission.
  1853. */
  1854. int YMHdr(long fileSize, char *filename)
  1855.   {
  1856.   extern int (*ITLFunc)(int c);
  1857.   TrBlock    = 0; /* One a kludge, two a kludge, three a kludge .. */
  1858.   ITLFunc = sendYMChar;
  1859.   mTrPrintf("%s", filename);
  1860.   mTrPrintf("%ld", fileSize);
  1861.   if (TrCount < 128)
  1862.   CurYBufSize = 128;
  1863.   if (TrCount != 128)
  1864.   for (; TrCount != 0 && sendYMChar(0); )
  1865.   ;
  1866.   else
  1867.   SendYBlk();
  1868.   if (TrError != TRAN_SUCCESS) return FALSE;
  1869.   if (strLen(filename) != 0)
  1870.   Transmission(YMDM, STARTUP);  /* now restart protocol *sigh* */
  1871.   return TrError == TRAN_SUCCESS;
  1872.  
  1873.   }
  1874. #ifdef NEED_NET_DEBUG_ERRORS
  1875. void DumpToFile(int LastReceived, int BufSize, CRC_TYPE tc, CRC_TYPE oc)
  1876.   {
  1877.   int i, j;
  1878.   FILE *fd;
  1879.   extern NetBuffer netBuf;
  1880.   if (strCmpU(netBuf.netName, "Images") == 0)
  1881.     {
  1882.     if ((fd = fopen("badsector", "a")) != NULL)
  1883.       {
  1884.       fprintf(fd, "Error on sector %d.  Their crc is %x, our's %x. Contents:\n", LastReceived, tc, oc);
  1885.       for (i = 0; i < BufSize; i += 16)
  1886.         {
  1887.         fprintf(fd, "%2x:", i);
  1888.         for (j = i; j < i + 16; j++)
  1889.         fprintf(fd, " %02x", DataBuf[j]);
  1890.         fprintf(fd, "   ");
  1891.         for (j = i; j < i + 16; j++)
  1892.         fprintf(fd, "%c", isprint(DataBuf[j]) ? DataBuf[j] : '.');
  1893.         fprintf(fd, "\n");
  1894.  
  1895.         }
  1896.       fprintf(fd, "\n");
  1897.       fclose(fd);
  1898.  
  1899.       }
  1900.  
  1901.     }
  1902.  
  1903.   }
  1904. #endif
  1905.