home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / OS2COM15.ZIP / OS2COM15.C next >
Text File  |  1990-05-16  |  47KB  |  1,574 lines

  1. /* os2comm.c - a simple os/2 comm program - version 1.5beta
  2. *
  3. * To use this program, type OS2COMM at the OS/2 prompt,
  4. * followed by the port, baud rate, parity, databits, and stopbits,
  5. * and an optional capture file name:
  6. *
  7. *    OS2COMM  COMx:baud,parity,databits,stopbits  capture-filespec
  8. *
  9. * To end this program, press Alt-X.
  10. *
  11. * While a communications session is in progress, data can be transmitted
  12. * from a file by pressing Alt-F or Alt-A.  The program will prompt for the
  13. * filename, the data in the file will be transmitted, then control will be
  14. * returned to the keyboard.  Using Alt-A performs an ASCII upload - replacing
  15. * CRLF pairs with CRs.  Alt-F sends the file without any translation.
  16. *
  17. * This version of OS2Comm has added logic to receive a file using the
  18. * XModem file transfer protocol.  To receive a file using XModem, first
  19. * tell the remote system to begin sending it, then press Alt-R.  OS2Comm
  20. * will prompt you for the receive filespec.  You may optionally specify a
  21. * drive letter and path.
  22. *
  23. * This program will run only in the protected mode of OS/2.
  24. * It will not run under DOS.
  25. *
  26. * The program contains 3 threads:
  27. *
  28. *   1. main() - This thread calls a COM initialization routine, then
  29. *      opens the COM port and creates the next two threads.  After they
  30. *      have been created, it waits for the keytocom() thread to complete,
  31. *      then exits back to OS/2.
  32. *
  33. *   2. keytocom() - This thread reads characters from the keyboard and
  34. *      sends them to the COM device driver.  When a Alt-Z is received
  35. *      from the keyboard, it signals main() to exit.  When Alt-F or Alt-A is
  36. *      received from the keyboard, it prompts for a filename, then sends
  37. *      the data from the file to the COM port.  It also handles the Alt-R
  38. *      XModem protocol for receiving files.
  39. *
  40. *   3. comtodsp() - This thread reads characters from the COM device
  41. *      driver and displays them on the screen.  It also writes data to
  42. *      the optional capture file.
  43. *
  44. * Three semaphores are used in this version of OS2Comm.  The first,
  45. * main_sem, is used to release the main thread when the keytocom thread
  46. * has received an Alt-X from the keyboard.  This allows the program to end
  47. * gracefully.
  48. *
  49. * The second, buf_sem, is used by the ascii upload routine, filetocom,
  50. * which uses the OS/2 DosWriteAsync function to send data to the COM
  51. * device driver.  A semaphore is required by this function to allow the
  52. * program to know when the buffer has been freed.  Using DosWriteAsync for
  53. * this routine allows the file transfer to proceed as fast as possible.
  54. *
  55. * The third semaphore, ctd_sem, is used to control the comtodisp thread.
  56. * Requesting this semaphore causes the comtodisp thread to block waiting
  57. * for it.  Clearing it allows comtodisp to run again.  This method of
  58. * controlling comtodisp is used instead of the OS/2 DosSuspendThread and
  59. * DosResumeThread functions because it allows control over where the
  60. * thread is when it is blocked.  DosSuspendThread will block the thread no
  61. * matter what it is doing at the time.
  62. *
  63. * To compile and link this program, at the OS2 prompt, type:
  64. *
  65. *      set PATH=C:\C\BIN;C:\;C:\OS2
  66. *      set INCLUDE=C:\C\INCLUDE
  67. *      set LIB=C:\C\LIB;C:\OS2
  68. *      set TMP=C:\
  69. *      cl os2comm.c /AS
  70. *
  71. * These settings are dependent on the compiler and version.
  72. *
  73. * This program requires the use of the COM0x.SYS device driver
  74. * in CONFIG.SYS.  Use COM01.SYS for AT class machines.  Use
  75. * COM02.SYS for PS/2 machines.
  76. *
  77. * OS2Comm.c - Copyright 1988 by Jim Gilliland.
  78. */
  79.  
  80. #define   LINT_ARGS
  81. #define   INCL_BASE
  82. #define   INCL_DOSDEVICES
  83. #include <os2.h>
  84. #include <stdio.h>
  85. #include <stdlib.h>
  86. #include <string.h>
  87. #include <conio.h>
  88. #include <ctype.h>
  89. #include <process.h>
  90. #include <malloc.h>
  91. #include <io.h>
  92. #include <fcntl.h>
  93. #include <sys\types.h>
  94. #include <sys\stat.h>
  95. #define   STK_SIZE    2048
  96. #define   MAXDIAL     11
  97.  
  98. typedef struct _TW_ROW
  99.     {
  100.     char *prompt, *text;
  101.     int prow, pcol, trow, tcol, tmax;
  102.     } TW_ROW;
  103.  
  104. static char dialdata[MAXDIAL+1][41] =
  105.             {
  106.             "",
  107.             "ATDT",
  108.             "|",
  109.             "CONNECT",
  110.             "",
  111.             "BUSY",
  112.             "NO ANSWER",
  113.             "NO DIAL TONE",
  114.             "UNSUCCESSFUL",
  115.             "VOICE",
  116.             "ABORT",
  117.             "Time Out"
  118.             };
  119.  
  120. static char dialdataprompt[MAXDIAL+1][21] =
  121.             {
  122.             "Modem Init String",
  123.             "Dial Prefix",
  124.             "Dial Suffix",
  125.             "Connected message 1",
  126.             "Connected message 2",
  127.             "Failed message 1",
  128.             "Failed message 2",
  129.             "Failed message 3",
  130.             "Failed message 4",
  131.             "Failed message 5",
  132.             "Failed message 6",
  133.             ""
  134.             };
  135.  
  136. TW_ROW dialsetup[12] =
  137.     {
  138.     dialdataprompt[0], dialdata[0], 2, 5, 2, 27, 40,
  139.     dialdataprompt[1], dialdata[1], 4, 5, 4, 27, 40,
  140.     dialdataprompt[2], dialdata[2], 6, 5, 6, 27, 40,
  141.     dialdataprompt[3], dialdata[3], 8, 5, 8, 27, 40,
  142.     dialdataprompt[4], dialdata[4], 10, 5, 10, 27, 40,
  143.     dialdataprompt[5], dialdata[5], 12, 5, 12, 27, 40,
  144.     dialdataprompt[6], dialdata[6], 14, 5, 14, 27, 40,
  145.     dialdataprompt[7], dialdata[7], 16, 5, 16, 27, 40,
  146.     dialdataprompt[8], dialdata[8], 18, 5, 18, 27, 40,
  147.     dialdataprompt[9], dialdata[9], 20, 5, 20, 27, 40,
  148.     dialdataprompt[10], dialdata[10], 22, 5, 22, 27, 40,
  149.     NULL, NULL, 0, 0, 0, 0, 0
  150.     };
  151.  
  152. typedef struct _COMDEVICECTRL {
  153.       unsigned int wtime;
  154.       unsigned int rtime;
  155.       unsigned char flags1;
  156.       unsigned char flags2;
  157.       unsigned char flags3;
  158.       unsigned char errchar;
  159.       unsigned char brkchar;
  160.       unsigned char xonchar;
  161.       unsigned char xoffchar;
  162.       } COMDEVICECTRL;
  163.  
  164. typedef struct _COMLINECHAR {
  165.       unsigned char databits;
  166.       unsigned char parity;
  167.       unsigned char stopbits;
  168.       } COMLINECHAR;
  169.  
  170. typedef struct _COMMODEMCTRL{
  171.       unsigned char onmask;
  172.       unsigned char offmask;
  173.       } COMMODEMCTRL;
  174.  
  175.  
  176. void main(int, char**, char**);
  177. int      initcomm(int, char, int, int);
  178. void far keytocom(void);
  179. int      savesetup(void);
  180. int      getsetup(void);
  181. int      gettext(char *, char *, int, int, int, int, int, int, char);
  182. int      window(void *, int, int, int, int, char, char);
  183. int      dial(char *);
  184. int      sendstring(char *);
  185. unsigned chkesc(void);
  186. int      filetocom(char);
  187. int      xmodemr(char *, char);
  188. void far comtodsp(void);
  189. int      parsarg(char*, char*, int*,
  190.                  char*, int*, int*);
  191. void far * tw_open(int,int,int,int,int,int,char,char);
  192. int tw_close(void far *);
  193. unsigned short com, cfile;
  194. unsigned long far main_sem, far buf_sem, far ctd_sem;
  195. unsigned ktcid, ctdid, cflag;
  196.  
  197. char *usage ="\nOS2Comm - usage is:\r\n"
  198. "\n\tOS2Comm COMx:baudrate,parity,"
  199.                 "databits,stopbits"
  200. "\n\twhere:"
  201. "\n\t\t COMx     = COM1, COM2, or COM3"
  202. "\n\t\t baudrate = 300,1200,2400,"
  203.                   "4800,9600, or 19200"
  204. "\n\t\t parity   = N,O,E,M, or S"
  205. "\n\t\t databits = 5,6,7, or 8"
  206. "\n\t\t stopbits = 1 or 2\r\n";
  207.  
  208. void main(argc, argv, envp)
  209. int argc;
  210. char **argv;
  211. char **envp;
  212. {
  213.  char far *ctdstack, far *ktcstack;
  214.  int act, baud, dbits, sbits;
  215.  unsigned int cftype, cfattr;
  216.  unsigned long cfptr;
  217.  char parity, comport[8];
  218.  
  219.  puts("OS2Comm.c version 1.5beta");
  220.  puts("Copyright 1988 by Jim Gilliland");
  221.  
  222.  if (argc < 2 || argc > 3)
  223.     {
  224.      puts(usage);
  225.      exit(1);
  226.     }
  227.  
  228.  if (parsarg(argv[1],comport,&baud,
  229.              &parity,&dbits,&sbits))
  230.     {
  231.      puts(usage);
  232.      exit(1);
  233.     }
  234.  
  235.  /* Open com device driver: */
  236.  if (DosOpen(comport,&com,&act,
  237.              0L,0,0x01,0x0012,0L))
  238.      {
  239.      fprintf(stderr,"\nError opening port");
  240.      exit(1);
  241.      }
  242.  
  243.  /* Initialize com device driver: */
  244.  if (initcomm(baud, parity, dbits, sbits))
  245.     {
  246.     fprintf(stderr,"\nPort setup error");
  247.     exit(1);
  248.     }
  249.  
  250.  /* Open capture file, if specified: */
  251.  if (argc > 2)
  252.    if (DosOpen(argv[2],&cfile,&act,
  253.                0L,0,0x11,0x0022,0L))
  254.      {
  255.      fprintf(stderr,"\nErr: %s\n",argv[2]);
  256.      exit(1);
  257.      }
  258.     else
  259.         {
  260.         cflag = 1;
  261.         DosQHandType(cfile,&cftype,&cfattr);
  262.         if (cftype == 0 && act == 1)
  263.             DosChgFilePtr(cfile,0L,2,&cfptr);
  264.         }
  265.  else cflag = 0;
  266.  
  267.  /* allocate stack for threads: */
  268.  ctdstack = malloc(STK_SIZE);
  269.  ktcstack = malloc(STK_SIZE);
  270.  
  271.  if (ctdstack == NULL || ktcstack == NULL)
  272.     {
  273.     puts ("Unable to allocate stacks");
  274.     exit(2);
  275.     }
  276.  
  277.  /* Create receive and display thread: */
  278.  if (DosCreateThread(comtodsp,&ctdid,
  279.                      ctdstack+STK_SIZE))
  280.     {
  281.     puts("Can't create COM receive thread");
  282.     exit(1);
  283.     }
  284.  
  285.  /* Set semaphore to block main thread: */
  286.  DosSemSet(&main_sem);
  287.  
  288.  /* Create transmit thread: */
  289.  if (DosCreateThread(keytocom,&ktcid,
  290.                      ktcstack+STK_SIZE))
  291.     {
  292.     puts("Can't create COM transmit thread");
  293.     exit(1);
  294.     }
  295.  
  296.  puts("Alt-X will end this program");
  297.  
  298.  /* Set high priority for COM threads */
  299.  DosSetPrty(2,3,1,ctdid); /* time-critical + 1  */
  300.  DosSetPrty(2,3,2,ktcid); /* time-critical + 2  */
  301.  
  302. /* Wait for clear semaphore (see keytocom) */
  303.  DosSemWait(&main_sem,-1L);
  304.  
  305. /* Suspend the other threads before ending */
  306.  DosSuspendThread(ktcid);
  307.  DosSuspendThread(ctdid);
  308.  
  309.  /* Close com driver and capture file: */
  310.  DosClose(com);
  311.  if (cflag==1) DosClose(cfile);
  312.  
  313.  /* Give the DosClose calls time to finish: */
  314.  DosSleep(100L);
  315.  
  316.  DosExit(1,0); /* exit: end all threads */
  317. }
  318. /*******************************************/
  319.  
  320. void far comtodsp()
  321. /* This routine is run as a separate thread */
  322. {
  323.  static char comchar[512];
  324.  unsigned int bytes, readerr, cnt;
  325.  
  326.  while ( -1 )  /* Do forever: */
  327.  {
  328.     DosSemRequest(&ctd_sem,-1L);
  329.     /* read character(s) from COMport: */
  330.     readerr = DosRead(com,comchar,512,&bytes);
  331.  
  332.     if (readerr == 0 && bytes > 0)
  333.        {
  334.         /* Write to screen: */
  335.         VioWrtTTY(comchar,bytes,0);
  336.  
  337.         /* write to capture file: */
  338.         if (cflag == 1)
  339.             DosWrite(cfile,comchar,bytes,&cnt);
  340.        }
  341.     DosSemClear(&ctd_sem);
  342.  }
  343. }
  344. /*******************************************/
  345.  
  346. void far keytocom()
  347. /* This routine is run as a separate thread */
  348. {
  349.  KBDKEYINFO keyinfo;
  350.  unsigned char charcode, scancode, mode, wincolor;
  351.  unsigned int written, ioctlerr, xretcode;
  352.  static char comerr, xname[48], YNresponse[4], number[11];
  353.  void far *twp;
  354.  
  355.  getsetup();
  356.  
  357.  wincolor = 62;
  358.  mode = 'C';
  359.  
  360.  sendstring(dialdata[0]);
  361.  
  362.  while ( -1 )  /* Do forever: */
  363.  {
  364.    /* Get character from keyboard: */
  365.    KbdCharIn (&keyinfo,0,0);
  366.    charcode = keyinfo.chChar;
  367.    scancode = keyinfo.chScan;
  368.  
  369.    /* Alt-X indicates End-Of-Processing: */
  370.    if (charcode == 0x00 && scancode == 0x2D)
  371.       {
  372.       DosSemRequest(&ctd_sem,-1L);
  373.       strcpy(YNresponse,"Yes");
  374.       twp=tw_open(8,10,5,25,10,15,wincolor,1);
  375.       gettext("Exit to OS/2? ",YNresponse,10,15,10,29,3,0,wincolor);
  376.       tw_close(twp);
  377.       DosSemClear(&ctd_sem);
  378.       YNresponse[0] = toupper(YNresponse[0]);
  379.       if (YNresponse[0] == 'Y')
  380.           /* Clear Main semaphore:        */
  381.              DosSemClear(&main_sem);
  382.       continue;
  383.       }
  384.  
  385.    /* Alt-D: get phone number and dial */
  386.    if (charcode == 0x00 && scancode == 0x20)
  387.        {
  388.        DosSemRequest(&ctd_sem,-1L);
  389.        strcpy(number,"");
  390.        twp=tw_open(15,20,5,45,18,25,wincolor,1);
  391.        gettext("Enter phone number: ",number,18,25,18,47,11,0,wincolor);
  392.        tw_close(twp);
  393.        if (strlen(number) == 0)
  394.            {
  395.            DosSemClear(&ctd_sem);
  396.            continue;
  397.            }
  398.        if (dial(number))
  399.            puts("Dial command failed");
  400.        DosSemClear(&ctd_sem);
  401.        continue;
  402.        }
  403.  
  404.    /* Alt-A: get filename and process ASCII file */
  405.    if (charcode == 0x00 && scancode == 0x1E)
  406.       filetocom('a');
  407.  
  408.    /* Alt-F: get filename and process file */
  409.    if (charcode == 0x00 && scancode == 0x21)
  410.       filetocom('f');
  411.  
  412.    /* Alt-S: get setup data */
  413.    if (charcode == 0x00 && scancode == 0x1F)
  414.       window(dialsetup,0,0,25,80,30,121);
  415.  
  416.    /* Alt-P: save setup data */
  417.    if (charcode == 0x00 && scancode == 0x19)
  418.       savesetup();
  419.  
  420.    /* PgDn: get filename and receive XModem file */
  421.    if ((charcode == 0x00 || charcode ==0xE0) && scancode == 0x51)
  422.       {
  423.        DosSemRequest(&ctd_sem,-1L);
  424.        strcpy(xname,"");
  425.        twp=tw_open(9,10,11,60,18,5,wincolor,1);
  426.  
  427.        VioWrtCharStrAtt("X - XModem  -   Checksum",24,10,20,&wincolor,0);
  428.        VioWrtCharStrAtt("C - XModem  -   CRC     ",24,11,20,&wincolor,0);
  429.        VioWrtCharStrAtt("F - XModemG -   CRC     ",24,12,20,&wincolor,0);
  430.        VioWrtCharStrAtt("Y - YModem batch  - CRC ",24,13,20,&wincolor,0);
  431.        VioWrtCharStrAtt("G - YModemG batch - CRC ",24,14,20,&wincolor,0);
  432.  
  433.        gettext("Protocol type? (X,C,F,Y,G): ",&mode,16,15,16,44,1,0,wincolor);
  434.        mode = toupper(mode);
  435.        if (mode != 'X' && mode != 'C' && mode != 'F' &&
  436.            mode != 'Y' && mode != 'G')
  437.            {
  438.            DosSemClear(&ctd_sem);
  439.            tw_close(twp);
  440.            continue;
  441.            }
  442.        if (mode == 'Y' || mode == 'G')
  443.            gettext("Enter receive pathname: ",xname,17,15,18,20,48,0,wincolor);
  444.        else
  445.            gettext("Enter receive filename: ",xname,17,15,18,20,48,0,wincolor);
  446.        tw_close(twp);
  447.        if (strlen(xname) == 0)
  448.            {
  449.            DosSemClear(&ctd_sem);
  450.            continue;
  451.            }
  452.        do  {
  453.            xretcode = xmodemr(xname,mode);
  454.            }
  455.            while (xretcode == 2);
  456.  
  457.        if (xretcode)
  458.            puts("Transfer failed");
  459.        DosSemClear(&ctd_sem);
  460.        continue;
  461.       }
  462.  
  463.    if ((charcode == 0x00 || charcode == 0xE0) && scancode != 0x00)
  464.       continue; /* skip Alt-keys & F-Keys */
  465.  
  466.    /* Write character(s) to com port: */
  467.    DosWrite(com,&charcode,1,&written);
  468.  
  469.    if (written == 0)
  470.       {
  471.        DosDevIOCtl(&comerr,NULL,0x64,01,com);
  472.        printf("\r\nCOM Driver reports error %u\r\n", comerr);
  473.       }
  474.  }
  475. }
  476.  
  477. int sendstring(string)
  478. char *string;
  479. {
  480.     register char *c;
  481.     char sendchar;
  482.     int ctrlflag = 0;
  483.     int written;
  484.     for (c=string; *c; c++)
  485.         {
  486.         if (ctrlflag == 1)
  487.             {
  488.             sendchar = *c & 0x1F;
  489.             ctrlflag = 0;
  490.             }
  491.         else
  492.             {
  493.             switch (*c)
  494.                 {
  495.                 case '^':
  496.                     ctrlflag = 1;
  497.                     sendchar = NULL;
  498.                     break;
  499.                 case '~':
  500.                     DosSleep(500L);
  501.                     sendchar = NULL;
  502.                     break;
  503.                 case '|':
  504.                     sendchar = '\r';
  505.                     break;
  506.                 case '`':
  507.                     sendchar = ' ';
  508.                     break;
  509.                 default:
  510.                     sendchar = *c;
  511.                 }
  512.             }
  513.         if (sendchar)
  514.             DosWrite(com,&sendchar,1,&written);
  515.         }
  516. }
  517.  
  518. int dial(number)
  519. /* This routine dials until it connects */
  520. char number[];
  521.  
  522. {
  523.     unsigned rsub[MAXDIAL+1];
  524.     int bytes, written, retcode;
  525.     int i, timecount;
  526.     char comchar;
  527.     char comstring[20];
  528.     unsigned int callnumber = 1;
  529.  
  530.     static COMDEVICECTRL olddcb, newdcb;
  531.  
  532.     /* get current settings: */
  533.     DosDevIOCtl((char *)&olddcb,NULL,0x73,01,com);
  534.  
  535.     /* Set com device processing parameters:  */
  536.     newdcb.wtime = 10; /* .1sec transmit timeout */
  537.     newdcb.rtime = 10; /* .1sec receive  timeout */
  538.     newdcb.flags1 = 0x01;  /* enable DTR */
  539.     newdcb.flags2 = 0x40;  /* enable RTS, disable XON/XOFF */
  540.     newdcb.flags3 = 0x02;  /* recv timeout mode  */
  541.     newdcb.errchar = olddcb.errchar;
  542.     newdcb.brkchar = olddcb.brkchar;
  543.     newdcb.xonchar = olddcb.xonchar;
  544.     newdcb.xoffchar = olddcb.xoffchar;
  545.     DosDevIOCtl(NULL,(char *)&newdcb,0x53,01,com);
  546.  
  547.     printf("\n");
  548.     retcode = 0;
  549.  
  550.     while (-1)
  551.         {
  552.         for (bytes = 1; bytes == 1; ) /* wait for quiet */
  553.              DosRead(com,&comchar,1,&bytes);
  554.  
  555.         DosSleep(250L); /* Wait 1 quarter second to hang up phone */
  556.  
  557.         if (chkesc())  /* check keyboard for ESC character */
  558.            {
  559.             fprintf(stderr,"\r\nDial command aborted.\r\n");
  560.             retcode=1;
  561.             break;
  562.            }
  563.  
  564.         sendstring(dialdata[1]);
  565.         sendstring(number);
  566.         sendstring(dialdata[2]);
  567.  
  568.         timecount = 0;
  569.  
  570.         for ( i = 0; i < MAXDIAL+1; )
  571.               rsub[i++] = 0;
  572.  
  573.         while (-1)
  574.             {
  575.             if (chkesc())  /* check keyboard for ESC character */
  576.                {
  577.                 fprintf(stderr,"\r\nDial command aborted.\r\n");
  578.                 retcode = 1;
  579.                 break;
  580.                }
  581.  
  582.             DosRead(com,&comchar,1,&bytes);
  583.             if (bytes == 0)
  584.                 {
  585.                 if (timecount++ > 200)
  586.                     {
  587.                     i = MAXDIAL;
  588.                     break;
  589.                     }
  590.                 else
  591.                     continue;
  592.                 }
  593.  
  594.             for (i=3; i < MAXDIAL; i++ )
  595.                 {
  596.                 if (comchar == dialdata[i][rsub[i]])
  597.                     {
  598.                     rsub[i]++;
  599.                     if (dialdata[i][rsub[i]] == NULL)
  600.                         break;
  601.                     }
  602.                 else
  603.                     rsub[i] = 0;
  604.                 }
  605.  
  606.             if (i < MAXDIAL)
  607.                 break;
  608.             }
  609.  
  610.         if (retcode == 0)
  611.             printf("\rResult %u: %s                 \r",
  612.                       callnumber++,dialdata[i]);
  613.         else
  614.             break;
  615.  
  616.         if (i == 3 || i == 4)   /* 3 and 4 are success codes */
  617.             {
  618.             DosBeep(880,100);
  619.             DosBeep(660,100);
  620.             break;
  621.             }
  622.         }
  623.     DosDevIOCtl(NULL,(char *)&olddcb,0x53,01,com);
  624.     printf("\n");
  625.     return retcode;
  626. }
  627.  
  628. savesetup()
  629. {
  630.     FILE *parm;
  631.     static char parmname[64];
  632.     int i;
  633.  
  634.     strcpy(parmname,"os2comm.prm");
  635.     parm = fopen(parmname,"w+");
  636.     fwrite(dialdata,1,sizeof(dialdata),parm);
  637.     fclose(parm);
  638. }
  639.  
  640. getsetup()
  641. {
  642.     FILE *parm;
  643.     static char parmname[64];
  644.     int i, j;
  645.  
  646.     strcpy(parmname,"os2comm.prm");
  647.     parm = fopen(parmname,"r");
  648.     fread(dialdata,1,sizeof(dialdata),parm);
  649.     fclose(parm);
  650. }
  651.  
  652. int filetocom(type)
  653. /* this routine transmits an ASCII file to the remote system */
  654. char type;
  655. {
  656.  static char buffer[64], work[64];
  657.  register char *cptr;
  658.  unsigned written, writerr, bytes, inhandle, inoflag;
  659.  static char infile[48];
  660.  void far *twp;
  661.  
  662.     DosSemRequest(&ctd_sem,-1L);
  663.     strcpy(infile,"");
  664.     twp=tw_open(15,0,5,80,18,5,62,1);
  665.     gettext("Enter file name: ",infile,18,5,18,23,48,0,62);
  666.     tw_close(twp);
  667.     if (strlen(infile) == 0)
  668.        {
  669.        DosSemClear(&ctd_sem);
  670.        return 0;
  671.        }
  672.     if (type == 'a')
  673.         inoflag = O_RDONLY | O_TEXT;
  674.     else
  675.         inoflag = O_RDONLY | O_BINARY;
  676.     if ((inhandle=open(infile,inoflag)) == -1)
  677.        {
  678.        fprintf(stderr,"\nOpen error: %s\r\n",infile);
  679.        DosSemClear(&ctd_sem);
  680.        return 1;
  681.        }
  682.  
  683.     DosSemClear(&ctd_sem);
  684.     /* Initialize write semaphore: */
  685.     DosSemClear(&buf_sem);
  686.  
  687.     while ( -1 )   /* Do forever: */
  688.     {
  689.       bytes=read(inhandle,work,64);
  690.       if (bytes == 0)  /* end of file ? */
  691.          {
  692.          close(inhandle); /* close file */
  693.          DosSemWait(&buf_sem, -1L);
  694.          return 0;
  695.          }
  696.  
  697.       /* Translate newline chars to carriage returns: */
  698.       if (type == 'a')
  699.          for ( cptr=work ; cptr < work+bytes ; cptr++ )
  700.                 if (*cptr == '\n') *cptr = '\r';
  701.  
  702.       /* Wait for last write to complete: */
  703.       DosSemWait(&buf_sem, -1L);
  704.  
  705.       strncpy(buffer,work,bytes); /* copy to buffer */
  706.  
  707.       if (chkesc())  /* check keyboard for ESC character */
  708.          {
  709.           fprintf(stderr,"\r\nText upload aborted.\r\n");
  710.           return 1;
  711.          }
  712.  
  713.       DosSemSet(&buf_sem);
  714.       DosWriteAsync(com,&buf_sem,&writerr,
  715.                     buffer,bytes,&written);
  716.  
  717.     }
  718. }
  719.  
  720. int gettext(prompt,text,prow,pcol,trow,tcol,max,mode,tcolor)
  721.  
  722. char prompt[], text[];
  723. int prow, pcol, trow, tcol, max, mode;
  724. char tcolor;
  725.  
  726. /* mode 0 - one entry only
  727.    mode 1 - one of a group of entries
  728.    mode 2 - display and return without accepting any input
  729. */
  730.  
  731. {
  732.         KBDKEYINFO keyinfo;
  733.         VIOCURSORINFO curhold, curinfo;
  734.         register unsigned char keystroke, scancode;
  735.         register int p, i;
  736.         int len, retcode;
  737.         unsigned char insert;
  738.         char blankcell[2];
  739.  
  740.         text[max] = '\0'; /* force string length to be max or less */
  741.  
  742.         VioGetCurType(&curhold,0);
  743.         curinfo.cEnd = curhold.cEnd;
  744.         curinfo.cx   = curhold.cx;
  745.         curinfo.attr = curhold.attr;
  746.         VioWrtCharStr(prompt,strlen(prompt),prow,pcol,0);
  747.         p = 0;
  748.         insert = 0x00;
  749.         blankcell[0] = ' ';
  750.         blankcell[1] = tcolor;
  751.  
  752.         while( -1 )
  753.         {
  754.             VioSetCurPos(trow,tcol+p,0);
  755.             len = strlen(text);
  756.  
  757.             VioWrtCharStrAtt(text,len,trow,tcol,&tcolor,0);
  758.             VioWrtNCell(blankcell,max-len,trow,tcol+len,0);
  759.  
  760.             if (mode == 2)
  761.                 return 0;
  762.  
  763.             if (KbdCharIn(&keyinfo,0,0))
  764.                 continue;
  765.             keystroke = keyinfo.chChar;
  766.             scancode  = keyinfo.chScan;
  767.  
  768.             if  (keystroke == 0x00 || keystroke == 0xE0)
  769.                 if (scancode == 0x4b && p > 0)
  770.                     {
  771.                     p--;
  772.                     continue;
  773.                     }
  774.                 else if ((scancode == 0x4d) && (p < len) && (p < max))
  775.                     {
  776.                     p++;
  777.                     continue;
  778.                     }
  779.                 else if (scancode == 0x47)
  780.                     {
  781.                     p=0;
  782.                     continue;
  783.                     }
  784.                 else if (scancode == 0x4f)
  785.                     {
  786.                     p=((len < max)? len : max);
  787.                     continue;
  788.                     }
  789.                 else if (scancode == 0x52)
  790.                     {
  791.                     insert ^= 0x01;
  792.                     if (insert)
  793.                         curinfo.yStart = curhold.yStart / 2;
  794.                     else
  795.                         curinfo.yStart = curhold.yStart;
  796.                     VioSetCurType(&curinfo,0);
  797.                     continue;
  798.                     }
  799.                 else if (scancode == 0x53 && p < len)
  800.                     {
  801.                     for (i=p; i<len+1; i++)
  802.                         text[i] = text[i+1];
  803.                     continue;
  804.                     }
  805.                 else if (scancode == 0x75 && p < len)
  806.                     {
  807.                     text[p] = '\0';
  808.                     continue;
  809.                     }
  810.                 else if (scancode == 0x48 && mode == 1)
  811.                          {
  812.                          retcode = -1;
  813.                          break;
  814.                          }
  815.                 else if (scancode == 0x50 && mode == 1)
  816.                          {
  817.                          retcode = +1;
  818.                          break;
  819.                          }
  820.                 else continue;
  821.  
  822.             if  (keystroke == '\r')
  823.                 {
  824.                 retcode = 0;
  825.                 break;
  826.                 }
  827.  
  828.             if  (keystroke == 0x1b)
  829.                 if (mode == 0)
  830.                     if (len == 0)
  831.                         {
  832.                         retcode = 0x1b;
  833.                         break;
  834.                         }
  835.                     else
  836.                         {
  837.                         p=0;
  838.                         text[p] = '\0';
  839.                         }
  840.                 else
  841.                     {
  842.                     retcode = 0x1b;
  843.                     break;
  844.                     }
  845.  
  846.             if  ((keystroke == '\b') && (p > 0))
  847.                 {
  848.                 p--;
  849.                 for (i=p; i<len+1; i++)
  850.                     text[i] = text[i+1];
  851.                 }
  852.             else
  853.             if  (isprint(keystroke))
  854.                 if (insert)
  855.                     {
  856.                     if (len < max)
  857.                         {
  858.                         for (i=len+1; i>=p; i--)
  859.                             text[i+1] = text[i];
  860.                         text[p++] = keystroke;
  861.                         }
  862.                     }
  863.                 else
  864.                     if (p < max)
  865.                         {
  866.                         text[p++] = keystroke;
  867.                         if  (p > len)
  868.                             text[p] = '\0';
  869.                         }
  870.         }
  871.         if (len > 0)   /* eliminate trailing blanks */
  872.             for (i=len-1; (text[i] == ' ') && (i >= 0); i--)
  873.                 text[i] = '\0';
  874.         VioSetCurType(&curhold,0);
  875.         return retcode;
  876. }
  877.  
  878. unsigned chkesc()
  879. /* this function checks the keyboard for the Escape character */
  880. {
  881.       KBDKEYINFO keyinfo;
  882.       while ( -1 )
  883.         {
  884.          if (KbdCharIn(&keyinfo,1,0))
  885.               return 0;   /* return if keyboard error */
  886.          if ((keyinfo.fbStatus & 0xC0) == 0)
  887.               return 0;   /* return if no key pressed */
  888.          if (((keyinfo.fbStatus & 0x40) != 0) &&
  889.               keyinfo.chChar == 0x1B)
  890.              {
  891.               KbdFlushBuffer(0);
  892.               return 1;   /* if escape was pressed  */
  893.              }
  894.         }
  895. }
  896.  
  897. int waitforquiet()
  898. {
  899.         static COMDEVICECTRL dcb;
  900.         unsigned char dummy, oldflags3;
  901.         unsigned int oldrtime, bytes;
  902.  
  903.         DosDevIOCtl((char *)&dcb,NULL,0x73,01,com);
  904.         oldflags3 = dcb.flags3;
  905.         oldrtime  = dcb.rtime;
  906.  
  907.         dcb.flags3 &= 0xF9; /* turn off both rtime bits */
  908.         dcb.flags3 |= 0x04; /* turn on "wait" rtime bit */
  909.         dcb.rtime = 10;     /* .1 second time out */
  910.         DosDevIOCtl(NULL,(char *)&dcb,0x53,01,com);
  911.  
  912.         /* Read chars until no more available */
  913.         for (bytes = 1; bytes == 1; )
  914.              DosRead(com,&dummy,1,&bytes);
  915.  
  916.         dcb.flags3 = oldflags3;
  917.         dcb.rtime = oldrtime;
  918.         DosDevIOCtl(NULL,(char *)&dcb,0x53,01,com);
  919. }
  920.  
  921. #define  NAK  "\x15"
  922. #define  ACK  "\x06"
  923. #define  SOH   0x01
  924. #define  STX   0x02
  925. #define  CAN   0x18
  926. #define  EOT   0x04
  927. #define  BS    0x08
  928.  
  929. int xmodemr(xname,mode)
  930. char *xname;
  931. char mode;
  932. /* this function processes the XModem file receive */
  933.  
  934. {
  935.     register unsigned int crc, count, c;
  936.     register unsigned char *cbp, chksum;
  937.     unsigned char chksum_in, fileopenflag;
  938.     unsigned int crc_in;
  939.     unsigned int fact, ferr, writ, bytes, blksize,
  940.                  checksize, retcode, nak, ioctlerr;
  941.     unsigned long int totsofar;
  942.     unsigned long int filelength_in;
  943.     unsigned short fhand;
  944.     unsigned char ident, expected, comerr, initnak;
  945.  
  946.     static unsigned char filename_in[96];
  947.     static unsigned char filename[160];
  948.     static unsigned char pathname[64];
  949.     static struct {
  950.         unsigned char packet;
  951.         unsigned char xpacket;
  952.         unsigned char data[1030];
  953.         } combuff;
  954.  
  955.     static COMDEVICECTRL olddcb, newdcb;
  956.  
  957.     static COMLINECHAR oldlc, newlc;
  958.  
  959.     if (mode != 'Y' && mode != 'G')
  960.         {
  961.         strcpy(filename,xname);
  962.         ferr=DosOpen(filename,&fhand,&fact,0L,0,0x12,0x0022,0L);
  963.         if (ferr)
  964.            {
  965.            printf("\r\n\nError Opening file: %s\r\n", filename);
  966.            return 1;
  967.            }
  968.         fileopenflag = 1;
  969.         }
  970.     else
  971.         {
  972.         fileopenflag = 0;
  973.         strcpy(pathname,xname);
  974.         if (*(pathname+strlen(pathname)-1) != '\\')
  975.             strcat(pathname,"\\");
  976.         }
  977.  
  978.     if (mode == NULL || mode == 'X')
  979.         {
  980.         initnak = 0x15;
  981.         checksize = 1;
  982.         }
  983.     else if (mode == 'Y' || mode == 'C')
  984.         {
  985.         initnak = 'C';
  986.         checksize = 2;
  987.         }
  988.     else if (mode == 'G' || mode == 'F')
  989.         {
  990.         initnak = 'G';
  991.         checksize = 2;
  992.         }
  993.     else
  994.         {
  995.         initnak = 0x15;
  996.         checksize = 1;
  997.         }
  998.  
  999.     /* get current settings: */
  1000.     DosDevIOCtl((char *)&olddcb,NULL,0x73,01,com);
  1001.     DosDevIOCtl((char *)&oldlc,NULL,0x62,01,com);
  1002.  
  1003.     /* Set com device processing parameters:  */
  1004.     newdcb.wtime = 10; /* .1sec transmit timeout */
  1005.     newdcb.rtime = 300; /* 3sec receive  timeout */
  1006.     newdcb.flags1 = 0x01;  /* enable DTR */
  1007.     newdcb.flags2 = 0x40;  /* enable RTS, disable XON/XOFF */
  1008.     newdcb.flags3 = 0x02;  /* recv timeout mode  */
  1009.     newdcb.errchar = olddcb.errchar;
  1010.     newdcb.brkchar = olddcb.brkchar;
  1011.     newdcb.xonchar = olddcb.xonchar;
  1012.     newdcb.xoffchar = olddcb.xoffchar;
  1013.     DosDevIOCtl(NULL,(char *)&newdcb,0x53,01,com);
  1014.  
  1015.     /* Set databits, stopbits, parity: */
  1016.     newlc.parity = 0;
  1017.     newlc.stopbits = 0;
  1018.     newlc.databits = 8;
  1019.     DosDevIOCtl(NULL,(char *)&newlc,0x42,01,com);
  1020.  
  1021.     /* Make sure line is quiet before starting: */
  1022.     waitforquiet();
  1023.  
  1024.     printf("\r\n");
  1025.     expected = 1;
  1026.     nak = 0;
  1027.     totsofar = 0;
  1028.     filelength_in = 0;
  1029.     retcode = 0;
  1030.  
  1031.     DosWrite(com,&initnak,1,&writ);
  1032.  
  1033.     while ( -1 )
  1034.     {
  1035.         if (chkesc()) /* check keyboard for ESC character */
  1036.            {
  1037.             printf("\rDownload aborted.             \r\n");
  1038.             waitforquiet();
  1039.             DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1040.             retcode = 1;
  1041.             break;
  1042.            }
  1043.  
  1044.         /* Set com device processing parameters:  */
  1045.         newdcb.rtime = 300; /* 3sec receive  timeout */
  1046.         DosDevIOCtl(NULL,(char *)&newdcb,0x53,01,com);
  1047.  
  1048.         if (nak == 3 && totsofar == 0)
  1049.             {
  1050.             initnak = 0x15;
  1051.             checksize = 1;
  1052.             }
  1053.  
  1054.         if (nak == 8)
  1055.            {
  1056.             printf("\rError: timed out or too many errors  \r\n");
  1057.             waitforquiet();
  1058.             DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1059.             retcode = 1;
  1060.             break;
  1061.            }
  1062.  
  1063.         /* Read lead character; should be SOH, STX, CAN, or EOT: */
  1064.         DosRead(com,&ident,1,&bytes);
  1065.  
  1066.         /* Send NAKs until first packet is started: */
  1067.         if (bytes == 0)
  1068.            {
  1069.             DosWrite(com,&initnak,1,&writ);
  1070.             nak++;
  1071.             continue;
  1072.            }
  1073.  
  1074.         if (ident != SOH && ident != EOT &&
  1075.             ident != STX && ident != CAN)
  1076.             continue;
  1077.  
  1078.         if (ident == EOT) /* EOT=End Of Transmission */
  1079.            {
  1080.             printf("\r\nReceived EOT\r\n");
  1081.             waitforquiet();
  1082.             DosWrite(com,ACK,1,&writ);
  1083.             if (mode == 'Y' || mode == 'G')
  1084.                 retcode = 2;
  1085.             else
  1086.                 retcode = 0;
  1087.             break;
  1088.            }
  1089.  
  1090.         if (ident == CAN) /* CAN=Cancel XModem process */
  1091.            {
  1092.             printf("\rReceived CAN                         \r\n");
  1093.             waitforquiet();
  1094.             retcode = 1;
  1095.             break;
  1096.            }
  1097.  
  1098.         /* if not EOT and not CAN, then receive the rest of the packet: */
  1099.  
  1100.         if (ident == STX)
  1101.             blksize = 1024;
  1102.         else
  1103.             blksize = 128;
  1104.  
  1105.         /* Set com device processing parameters:  */
  1106.         newdcb.rtime = 100; /* 1sec receive  timeout */
  1107.         DosDevIOCtl(NULL,(char *)&newdcb,0x53,01,com);
  1108.  
  1109.         DosRead(com,(char *)&combuff,2+blksize+checksize,&bytes);
  1110.  
  1111.         if ((bytes != 2+blksize+checksize) ||
  1112.            ((combuff.packet & combuff.xpacket) != 0x00))
  1113.            {
  1114.             printf("\rPacket Error: bytes %i, packet %x, xpacket %x\r\n",
  1115.                                     bytes, combuff.packet, combuff.xpacket);
  1116.             if (mode == 'G' || mode == 'F')
  1117.                 {
  1118.                 printf("\rDownload aborted.             \r\n");
  1119.                 DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1120.                 retcode = 1;
  1121.                 break;
  1122.                 }
  1123.             waitforquiet();
  1124.             DosWrite(com,NAK,1,&writ);
  1125.             nak++;
  1126.             continue;
  1127.            }
  1128.  
  1129.         if (checksize == 1)
  1130.             {
  1131.             chksum = 0;
  1132.             /* Compute checksum: */
  1133.             for (cbp = combuff.data ; cbp < combuff.data+blksize ; cbp++)
  1134.                 chksum += *cbp;
  1135.  
  1136.             chksum_in = *(combuff.data+blksize);
  1137.  
  1138.             if (chksum != chksum_in)
  1139.                {
  1140.                 printf("\rChecksum error: received %#2.2x, computed %#2.2x\r\n",
  1141.                                           chksum_in,       chksum);
  1142.                 if (mode == 'G' || mode == 'F')
  1143.                     {
  1144.                     printf("\rDownload aborted.             \r\n");
  1145.                     DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1146.                     retcode = 1;
  1147.                     break;
  1148.                     }
  1149.                 waitforquiet();
  1150.                 DosWrite(com,NAK,1,&writ);
  1151.                 nak++;
  1152.                 continue;
  1153.                }
  1154.             }
  1155.         else
  1156.             {
  1157.             crc_in = (((unsigned int) *(combuff.data+blksize)) << 8)
  1158.                     + *(combuff.data+blksize+1);
  1159.             crc = 0;
  1160.             /* Compute cyclic redundancy check: */
  1161.             for (cbp = combuff.data ; cbp < combuff.data+blksize+2 ; cbp++)
  1162.                 {
  1163.                 c = *cbp;
  1164.                 for (count=8; count>0; count--)
  1165.                     {
  1166.                     if (crc & 0x8000)
  1167.                         {
  1168.                         crc <<= 1;
  1169.                         crc += (((c<<=1) & 0x0100)  !=  0);
  1170.                         crc ^= 0x1021;
  1171.                         }
  1172.                     else
  1173.                         {
  1174.                         crc <<= 1;
  1175.                         crc += (((c<<=1) & 0x0100)  !=  0);
  1176.                         }
  1177.                     }
  1178.                 }
  1179.  
  1180.             if (crc != 0)
  1181.                {
  1182.                 printf("\rCRC error: received %#4.4x, computed %#4.4x\r\n",
  1183.                                               crc_in,      crc);
  1184.                 if (mode == 'G' || mode == 'F')
  1185.                     {
  1186.                     printf("\rDownload aborted.             \r\n");
  1187.                     DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1188.                     retcode = 1;
  1189.                     break;
  1190.                     }
  1191.                 waitforquiet();
  1192.                 DosWrite(com,NAK,1,&writ);
  1193.                 nak++;
  1194.                 continue;
  1195.                }
  1196.             }
  1197.  
  1198.         if ((combuff.packet != expected) && (combuff.packet != expected-1))
  1199.            {
  1200.             printf("\rSequence failure: expected %u, received %u\r\n",
  1201.                                         expected,    combuff.packet);
  1202.             waitforquiet();
  1203.             DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1204.             retcode = 1;
  1205.             break;
  1206.            }
  1207.         else if (combuff.packet == expected-1)
  1208.              /* either this is the Ymodem zero packet, or */
  1209.              /* we've already received this packet, so ignore */
  1210.            {
  1211.             if (mode != 'G' && mode != 'F')
  1212.                 DosWrite(com,ACK,1,&writ);
  1213.             nak = 0;
  1214.             if (combuff.packet == 0 && totsofar == 0)
  1215.                 {
  1216.                 if (strlen(combuff.data) > 0)
  1217.                     printf("\rFilename header: %s\r\n", combuff.data);
  1218.                 if (mode == 'Y' || mode == 'G')
  1219.                     {
  1220.                     if (strlen(combuff.data) == 0)
  1221.                         {
  1222.                         printf("\rEnd of Batch\r\n");
  1223.                         retcode = 0;
  1224.                         break;
  1225.                         }
  1226.                     strcpy(filename,pathname);
  1227.                     strcat(filename,combuff.data);
  1228.                     strlwr(filename);
  1229.                     while ((cbp=strchr(filename,'/')) != NULL)
  1230.                         *cbp = '\\';
  1231.                     ferr=DosOpen(filename,&fhand,&fact,0L,0,0x12,0x0022,0L);
  1232.                     if (ferr)
  1233.                        {
  1234.                        printf("\r\n\nError Opening file: %s\r\n", filename);
  1235.                        waitforquiet();
  1236.                        DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1237.                        retcode = 1;
  1238.                        break;
  1239.                        }
  1240.                     else
  1241.                        fileopenflag = 1;
  1242.                     }
  1243.                 cbp = combuff.data+strlen(combuff.data)+1;
  1244.                 filelength_in = strtol(cbp,NULL,10);
  1245.                 printf("\rFile length:    %lu\r\n", filelength_in);
  1246.                 }
  1247.             continue;
  1248.            }
  1249.         else
  1250.            {
  1251.              /* good packet, write it to disk, increment bytecount */
  1252.             if (totsofar == 0)
  1253.                 {
  1254.                 if (checksize == 1)
  1255.                     printf("\rChecksum protocol in use\r\n");
  1256.                 else
  1257.                     printf("\rCRC protocol in use\r\n");
  1258.                 }
  1259.             totsofar += blksize;
  1260.             printf("\rBytes received: %lu\r", totsofar);
  1261.             if (mode != 'G' && mode != 'F')
  1262.                 DosWrite(com,ACK,1,&writ);
  1263.             if (fileopenflag == 1)
  1264.                 ferr=DosWrite(fhand,combuff.data,blksize,&writ);
  1265.             else
  1266.                {
  1267.                 printf("\r\nProtocol error: No file specified\r\n");
  1268.                 waitforquiet();
  1269.                 DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1270.                 retcode = 1;
  1271.                 break;
  1272.                }
  1273.  
  1274.             if (ferr || writ < blksize)
  1275.                {
  1276.                 printf("\r\nFile write error: %u, %u bytes written\r\n",
  1277.                                             ferr, writ);
  1278.                 waitforquiet();
  1279.                 DosWrite(com,"\x18\x18\x18\x08\x08\x08",6,&writ);
  1280.                 retcode = 1;
  1281.                 break;
  1282.                }
  1283.             expected++;
  1284.             nak = 0;
  1285.             continue;
  1286.            }
  1287.     }
  1288.  
  1289.     if (fileopenflag == 1)
  1290.         if (filelength_in > 0 && totsofar > filelength_in)
  1291.             {
  1292.             DosNewSize(fhand,filelength_in);
  1293.             printf("\r%s received: %lu bytes           \r\n",
  1294.                          filename, filelength_in);
  1295.             }
  1296.         DosClose(fhand);
  1297.     if (retcode == 2)
  1298.         printf("\r%s received successfully.           \r\n", filename);
  1299.     if (retcode == 0)
  1300.         {
  1301.         if (mode == 'Y' || mode == 'G')
  1302.             printf("\rBatch received successfully         \r\n");
  1303.         else
  1304.             printf("\r%s received successfully.           \r\n", filename);
  1305.         }
  1306.  
  1307.     ioctlerr=DosDevIOCtl(NULL,(char *)&olddcb,0x53,01,com);
  1308.     if (ioctlerr) printf("\r\nDevIOCtl 53h Error: %x\r\n",ioctlerr);
  1309.     ioctlerr=DosDevIOCtl(NULL,(char *)&oldlc,0x42,01,com);
  1310.     if (ioctlerr) printf("\r\nDevIOCtl 42h Error: %x\r\n",ioctlerr);
  1311.     return retcode;
  1312. }
  1313. /*******************************************/
  1314.  
  1315. int window(win_data,top,left,height,width,color,tcolor)
  1316.  
  1317. TW_ROW win_data[];
  1318. int top,left,height,width;
  1319. char color, tcolor;
  1320.  
  1321. {
  1322.     void far *twp;
  1323.     register int i, keycode;
  1324.     int imax;
  1325.  
  1326.     twp=tw_open(top,left,height,width,0,0,color,1);
  1327.  
  1328.     for (i=0; win_data[i].prompt != NULL; i++)
  1329.         gettext(win_data[i].prompt, win_data[i].text,
  1330.                 win_data[i].prow, win_data[i].pcol,
  1331.                 win_data[i].trow, win_data[i].tcol,
  1332.                 win_data[i].tmax, 2, tcolor);
  1333.  
  1334.     imax = i-1;
  1335.     i = 0;
  1336.  
  1337.     while (-1)
  1338.         {
  1339.         keycode = gettext(win_data[i].prompt, win_data[i].text,
  1340.                           win_data[i].prow, win_data[i].pcol,
  1341.                           win_data[i].trow, win_data[i].tcol,
  1342.                           win_data[i].tmax, 1, tcolor);
  1343.  
  1344.         if (keycode == -1 && i > 0)
  1345.             i--;
  1346.  
  1347.         if ((keycode == +1 || keycode == 0) && i < imax)
  1348.             i++;
  1349.  
  1350.         if (keycode == 0x1b)
  1351.             break;
  1352.         }
  1353.  
  1354.     tw_close(twp);
  1355. }
  1356.  
  1357.  
  1358. typedef struct _TW
  1359.     {
  1360.     int top, left, height, width, currow, curcol;
  1361.     char restore; /* first character of video-hold buffer */
  1362.     } TW;
  1363.  
  1364. void far *tw_open(top,left,height,width,currow,curcol,color,border)
  1365.  
  1366. int top, left, height, width, currow, curcol;
  1367. char color, border;
  1368.  
  1369. {
  1370.     char cell[2];
  1371.     int i, j;
  1372.     char far *ibuff;
  1373.     TW far *twp;
  1374.     SEL seg;
  1375.     DosAllocSeg(2*height*width + sizeof(TW), &seg, 0);
  1376.     twp = MAKEP(seg,0);
  1377.     twp->top = top;
  1378.     twp->left = left;
  1379.     twp->height = height;
  1380.     twp->width = width;
  1381.  
  1382.     VioGetCurPos(&(twp->currow),&(twp->curcol),0);
  1383.  
  1384.     cell[0] = ' ';
  1385.     cell[1] = color;
  1386.     for (i=0 ; i < height ; i++)
  1387.         {
  1388.         j = width*2;
  1389.         ibuff = &(twp->restore) + i*j;
  1390.         VioReadCellStr(ibuff, &j, top+i, left, 0);
  1391.         if (border)
  1392.             {
  1393.             if (i == 0)
  1394.                 {
  1395.                 cell[0] = 201;
  1396.                 VioWrtNCell(cell, 1, top+i, left, 0);
  1397.                 cell[0] = 187;
  1398.                 VioWrtNCell(cell, 1, top+i, left+width-1, 0);
  1399.                 cell[0] = 205;
  1400.                 VioWrtNCell(cell, width-2, top+i, left+1, 0);
  1401.                 }
  1402.             else if (i == height-1)
  1403.                 {
  1404.                 cell[0] = 200;
  1405.                 VioWrtNCell(cell, 1, top+i, left, 0);
  1406.                 cell[0] = 188;
  1407.                 VioWrtNCell(cell, 1, top+i, left+width-1, 0);
  1408.                 cell[0] = 205;
  1409.                 VioWrtNCell(cell, width-2, top+i, left+1, 0);
  1410.                 }
  1411.             else
  1412.                 {
  1413.                 cell[0] = 186;
  1414.                 VioWrtNCell(cell, 1, top+i, left, 0);
  1415.                 cell[0] = 186;
  1416.                 VioWrtNCell(cell, 1, top+i, left+width-1, 0);
  1417.                 cell[0] = 32;
  1418.                 VioWrtNCell(cell, width-2, top+i, left+1, 0);
  1419.                 }
  1420.             }
  1421.         else
  1422.             {
  1423.             cell[0] = 32;
  1424.             VioWrtNCell(cell, width, top+i, left, 0);
  1425.             }
  1426.         }
  1427.  
  1428.     VioSetCurPos(currow,curcol,0);
  1429.     return twp;
  1430.  
  1431. }
  1432.  
  1433. tw_close(twp)
  1434.  
  1435. TW far *twp;
  1436.  
  1437. {
  1438.     int i, j;
  1439.     char far *ibuff;
  1440.     j = (twp->width)*2;
  1441.     for (i=0 ; i < (twp->height) ; i++)
  1442.         {
  1443.         ibuff = &(twp->restore) + i*j;
  1444.         VioWrtCellStr(ibuff, j, (twp->top)+i, (twp->left), 0);
  1445.         }
  1446.     VioSetCurPos(twp->currow,twp->curcol,0);
  1447.  
  1448.     DosFreeSeg(SELECTOROF(twp));
  1449. }
  1450.  
  1451. int initcomm(baud,parity,dbits,sbits)
  1452. char parity;
  1453. int baud,dbits,sbits;
  1454.    /* this routine used by main thread */
  1455. {
  1456. static COMLINECHAR linechar;
  1457.  
  1458. static COMMODEMCTRL modemctrl;
  1459.  
  1460. static COMDEVICECTRL dcb;
  1461.  
  1462. int comerr,act;
  1463.  
  1464.  /* Set bitrate: */
  1465.  if (DosDevIOCtl(NULL,(char *)&baud,
  1466.                      0x41,01,com))
  1467.      {
  1468.      fprintf(stderr,"\nBitrate error");
  1469.      return(1);
  1470.      }
  1471.  
  1472.  /* Set databits, stopbits, parity: */
  1473.  if (parity == 'N') linechar.parity = 0;
  1474.  if (parity == 'O') linechar.parity = 1;
  1475.  if (parity == 'E') linechar.parity = 2;
  1476.  if (parity == 'M') linechar.parity = 3;
  1477.  if (parity == 'S') linechar.parity = 4;
  1478.  if (sbits == 2) linechar.stopbits = 2;
  1479.  if (sbits == 1) linechar.stopbits = 0;
  1480.  linechar.databits = dbits;
  1481.  if (DosDevIOCtl(NULL,(char *)&linechar,
  1482.                      0x42,01,com))
  1483.      {
  1484.      puts("Line characteristics error");
  1485.      return(1);
  1486.      }
  1487.  
  1488.  /* Set modem control signals: */
  1489.  modemctrl.onmask = 0x03;  /* DTR & RTS on */
  1490.  modemctrl.offmask = 0xff; /* nothing off */
  1491.  if (DosDevIOCtl((char *)&comerr,
  1492.        (char *)&modemctrl,0x46,01,com))
  1493.      {
  1494.      puts("Modem control error");
  1495.      return(1);
  1496.      }
  1497.  
  1498.  /* Set com device processing parameters:  */
  1499.  dcb.wtime = 100; /* 1sec transmit timeout */
  1500.  dcb.rtime = 100; /* 1sec receive  timeout */
  1501.  dcb.flags1 = 0x01;  /* enable DTR,        */
  1502.  dcb.flags2 = 0x40;  /* enable RTS, disable XON/XOFF  */
  1503.  dcb.flags3 = 0x04;  /* recv timeout mode  */
  1504.  dcb.errchar = 0x00; /* no error translate */
  1505.  dcb.brkchar = 0x00; /* no break translate */
  1506.  dcb.xonchar = 0x11;  /* standard XON  */
  1507.  dcb.xoffchar = 0x13; /* standard XOFF */
  1508.  if (DosDevIOCtl(NULL,(char *)&dcb,
  1509.                        0x53,01,com))
  1510.      {
  1511.      puts("Device control block error");
  1512.      return(1);
  1513.      }
  1514.  
  1515.  return(0);
  1516. }
  1517.  
  1518. int parsarg(arg,port,baud,parity,dbits,sbits)
  1519. char *arg,*port;
  1520. char *parity;
  1521. int *baud,*dbits,*sbits;
  1522.     /* this routine used by main thread */
  1523. {
  1524.   register unsigned int strptr;
  1525.   char strhold[8];
  1526.   strupr(arg);   /* cvt to uppercase */
  1527.  
  1528.   /* Parse cmdline for COM port: */
  1529.   if ((strptr=strcspn(arg,":")) == 0)
  1530.                                   return(1);
  1531.   if (strptr > 8) return(1);
  1532.   strncpy(port,arg,strptr);
  1533.   *(port+strptr) = '\0';
  1534.   arg = arg+strptr+1;
  1535.  
  1536.   /* Parse for cmdline baudrate: */
  1537.   if ((strptr=strcspn(arg,",")) == 0)
  1538.                                   return(2);
  1539.   strncpy(strhold,arg,strptr);
  1540.   *(strhold+strptr) = '\0';
  1541.   *baud = atoi(strhold);
  1542.   if (*baud != 300 &&  *baud != 1200 &&
  1543.       *baud != 2400 && *baud != 4800 &&
  1544.       *baud != 9600 && *baud != 19200)
  1545.                                   return(2);
  1546.   arg = arg+strptr+1;
  1547.  
  1548.   /* Parse cmdline for parity: */
  1549.   if ((strptr = strcspn(arg,",")) == 0)
  1550.                                   return(3);
  1551.   *parity = *(arg+strptr-1);
  1552.   if (*parity != 'N' && *parity != 'O' &&
  1553.       *parity != 'E' && *parity != 'M' &&
  1554.       *parity != 'S')             return(3);
  1555.   arg = arg+strptr+1;
  1556.  
  1557.   /* Parse cmdline for databits: */
  1558.   if ((strptr = strcspn(arg,",")) == 0)
  1559.                                   return(4);
  1560.   *dbits = *(arg+strptr-1) - '0';
  1561.   if (*dbits != 5 &&   *dbits != 6 &&
  1562.       *dbits != 7 &&   *dbits != 8)
  1563.       return(4);
  1564.   arg = arg+strptr+1;
  1565.  
  1566.   /* Parse for stopbit value: */
  1567.   if ((strptr = strcspn(arg,",")) == 0)
  1568.                                   return(5);
  1569.   *sbits = *(arg+strptr-1) - '0';
  1570.   if (*sbits != 1 && *sbits != 2) return(5);
  1571.  
  1572.   return(0);
  1573. }
  1574.