home *** CD-ROM | disk | FTP | other *** search
/ Boot Disc 8 / boot-disc-1997-04.iso / PDA_Soft / Psion / comms / p3nfs / nfsc / nfsc.c < prev    next >
C/C++ Source or Header  |  1996-05-26  |  39KB  |  1,310 lines

  1. /*
  2.  * In this file lines end with CR/LF, as our psion C-compiler lives in the 
  3.  * DOS-WORLD
  4.  * Copyright GNU Public License
  5.  */
  6.  
  7. #include <plib.h>                                 /* NFS Client V3.10 N.N */
  8. #include <p_serial.h>
  9. #include <wlib.h>
  10. #include <hwif.h>
  11. #include "nfsc.h"
  12.  
  13. #define TXT_TYPE  H_DTEXT_ALIGN_CENTRE
  14.  
  15. /*======================================================== NFSC set ===*/
  16. #define NR_OF_DEVICES 5  /* do not change, configure over menu */
  17.  
  18. #ifdef HAVE_NFSSUPPORT
  19. static char *dev_name[]={"LOC::M:", "LOC::A:", "LOC::B:", "LOC::C:", "ROM::"};
  20. #endif
  21. static char welcome[]= "Welcome to Nfsc 4.3b";
  22.  
  23. struct settings set = {
  24.     {P_BAUD_9600,P_BAUD_9600,P_DATA_8,0,P_IGN_CTS,0x11,0x13,0,0},
  25.     {0,0,P_SRDTR_ON},                /* modem sense, DTR assert */
  26.     {1,1,1,1,1},                              /* all devices active */
  27.     FLAGS_SHOW_STATS | FLAGS_SMALL_STATWIN | FLAGS_NFSD_NEW | FLAGS_JUMPSCROLL,
  28.     WS_FONT_BASE+4,                /* Roman 8 Point, s3 see bel. */
  29.     XY_YMODEM1K
  30. };
  31.  
  32.  
  33.  
  34. TEXT *EnvironmentName="NFSC_v32";
  35.  
  36. /*========================================================== menu's used ===*/
  37. static H_MENU_DATA mdata[]= {
  38. #ifdef HAVE_NFSSUPPORT
  39.     "Nfsc", 4,
  40. #else
  41.     "Nfsc", 2,
  42. #endif
  43.     "Serial Line", 7,
  44. #ifdef HAVE_TERMEMU
  45.     "Emulator",6,
  46. #endif
  47. #ifdef HAVE_XYMODEM
  48.     "XYmodem",3,
  49. #endif
  50.     NULL
  51. };
  52.  
  53. static TEXT * cmds[]= {
  54.     /* nfsc */
  55.         "aAbout...",
  56. #ifdef HAVE_NFSSUPPORT
  57.         "dDevices...",
  58.     "nNfsd support...",
  59. #endif
  60.         "xExit",
  61.     /* Serial Line */
  62.         "pParameters...",
  63.         "hHandshaking...",
  64.         "HExpert settings...",
  65.         "tToggle stats",
  66.         "cClear stats",
  67.     "uUpdate stats...",
  68.     "bSend a break",
  69. #ifdef HAVE_TERMEMU
  70.     /* Emulator */
  71.         "rReset",
  72.     "zZoom: bigger",
  73.     "ZZoom: smaller",
  74.     "fFont...",
  75.     "FFn Keys...",
  76.     "sSettings...",
  77. #endif
  78. #ifdef HAVE_XYMODEM
  79.     /* XYmodem */
  80.     "CConfigure...",
  81.     "SSend file...",
  82.     "RReceive file...",
  83. #endif
  84.         NULL
  85. };
  86.  
  87. TEXT **        _cmds=cmds;
  88. H_MENU_DATA *  _mdata=mdata;
  89.  
  90.  
  91. /*===================================================== global variables ===*/
  92. ULONG  stats_read, stats_write;    /* Read / write statistics */
  93.  
  94. P_RECT hisrect;            /* Rectangle for nfscmd history scrolling */
  95. INT    stat_y,modem_x,io_x;    /* Y pos for stat printing (font descent),etc*/
  96. UBYTE  charwidth,charheight,    /* Character data */
  97.        ascent, rows, cols;
  98. WORD   screenx,screeny,        /* Character width */
  99.        t_w, t_h;        /* terminal width & height in pixels */
  100. BYTE   clkwin;
  101. BYTE   debug = 0;
  102. BYTE   isnfsd = 0;        /* used for sending a resize event *gulp* */
  103.  
  104. extern UWORD _UseFullScreen;    /* use full s3a or only s3 screen */
  105. char   buf[256], buf2[256];    /* serial read buffers, not on stack  */
  106. char   rfilename[256];        /* last filename read */
  107. VOID   *rfile = 0;        /* last read filehandle */
  108. LONG   roff = 0;        /* last read offset */
  109. INT    hgc;            /* handle to graphics context */
  110. UINT   main_win;        /* main window ID */
  111. VOID   *serial = 0;        /* handle serial port */
  112. LOCAL_D VOID *timH;        /* handle timer */
  113. LOCAL_D ULONG timint = 20;    /* poll interval in 100msec units */
  114. WORD   zero=0,one=1;        /* constants to interact with serial port */
  115. TEXT   mfb[40];            /* message formatting buffer; */
  116. UBYTE  pctrl = 0xff;        /* store last pctrl */
  117. UBYTE  protocol;        /* nfsd protocol none=0,old=1,new=2
  118.                                  * new = 0x80 as escape character for nfs cmd,
  119.                  * old = no terminal capability
  120.                  * none = only terminal
  121.                  */
  122. UBYTE  sch;            /* Serial character */
  123. WORD   ttystat;            /* We need it global */
  124. UBYTE  is_rtscts;
  125.  
  126.  
  127. #ifdef HAVE_TERMEMU
  128.  
  129. struct fkey *fk;
  130. static char logfile[129]   = "\015\\opd\\nfsc.log";
  131. static char fnkeyname[129] = "\017\\opd\\fnkeys.nfs";
  132. char   cur_appl;        /* cursor keys in application mode */
  133. BYTE   fnkey = 0;
  134. void  *logfd = 0;
  135.  
  136. #include "cnv.h"        /* charset conversion */
  137.  
  138. #endif
  139.  
  140. static char c_handshaking[] = "Handshaking";
  141. static char c_ignore[]      = "Ignore";
  142. static char c_load[]        = "Load";
  143. static char c_save[]        = "Save";
  144. static char c_cfgserial[]   = "configure serial";
  145. static char c_dtr[]         = "change DTR";
  146. static char c_query[]       = "query modem";
  147.  
  148. /*========================================================= AddToHistory ===*/
  149. void AddToHistory (char ch) {
  150.   static char idle;
  151.   P_POINT o;
  152.   int i = hisrect.tl.x;
  153.  
  154.   if(! ( set.flags & FLAGS_SHOW_STATS) )
  155.     return;
  156.  
  157.   if (!ch)        /* a heart beat indicator */
  158.     {
  159.       idle++;
  160.       if (idle != 2)    /* Will wrap after 256 ticks. But that is o.k. */
  161.         return;
  162.       /* seen two heatbeats in a row. Print a '.' as idle indicator */
  163.       ch = '.';        
  164.     }
  165.   else 
  166.     idle = 0;
  167.  
  168.   gPrintText(hisrect.br.x-charwidth, stat_y, &ch, 1);
  169.   o.y = 0;
  170.   o.x = -charwidth;            
  171.   hisrect.tl.x += charwidth;
  172.   wScrollRect(main_win, &hisrect, &o);    /* scroll one character leftward */
  173.   hisrect.tl.x = hisrect.br.x - charwidth;
  174.   gClrRect(&hisrect, G_TRMODE_CLR);    /* clear space for next character */
  175.   hisrect.tl.x = i;
  176. }
  177.  
  178. void Check (INT val,TEXT *msg)
  179. {
  180.   if (!val) return;
  181.   p_atos(&mfb[0],"Failed to %s",msg);
  182.   if (!p_notifyerr(val,&mfb[0],"Abort",c_ignore,0))
  183.     p_exit(0);
  184. }
  185.  
  186. void UpdateModem()
  187. {
  188.   if(serial == 0 || !(set.flags & FLAGS_SHOW_STATS) )
  189.     return;
  190.  
  191.   Check(p_iow(serial, P_FCTRL, set.pctrl), c_query);
  192.   if (set.pctrl[0] == pctrl)
  193.     return;
  194.   
  195.   pctrl = set.pctrl[0];
  196.   
  197.   p_atos(mfb, "%s %s %s", 
  198.          (pctrl & P_SRCTRL_CTS) ? "CTS" : "cts",
  199.          (pctrl & P_SRCTRL_DSR) ? "DSR" : "dsr",
  200.          (pctrl & P_SRCTRL_DCD) ? "DCD" : "dcd");
  201.   set.pctrl[1] = 0x00;     /* in case we did set it here */
  202.   gPrintText(modem_x, stat_y, mfb, p_slen(mfb));
  203. }
  204.  
  205.  
  206. /*===============  Check, if write would block, i.e. flow control is on === */
  207. void
  208. serial_write(char *p, int n)
  209. {
  210.   int ret;
  211.  
  212.   if(!(set.tty.hand & P_IGN_CTS))
  213.     {
  214.       Check(p_iow(serial, P_FCTRL, set.pctrl), c_query);
  215.       while(!(set.pctrl[0] & P_SRCTRL_CTS))
  216.     {
  217.       H_DI_TEXT  line1={buf+  0,TXT_TYPE}, 
  218.              line2={buf+ 50,TXT_TYPE};
  219.  
  220.       uZTStoBCS (line1.str, "Hardware flowcontrol specified,");
  221.       uZTStoBCS (line2.str, "but modem line CTS is not set");
  222.       if (   uOpenDialog ("WARNING!")
  223.           || uAddDialogItem (H_DIALOG_TEXT, NULL, &line1)
  224.           || uAddDialogItem (H_DIALOG_TEXT, NULL, &line2)
  225.           || (uAddButtonList ("Exit",   'x',
  226.                   c_ignore, 'i',
  227.                   "Retry",  W_KEY_RETURN, NULL))
  228.           || (ret = uRunDialog()) <= 0)
  229.           continue;
  230.       if(ret == 'x')
  231.         p_exit(0);
  232.       if(ret == 'i')
  233.         {
  234.           Sw_Serial(OFF);
  235.           set.tty.hand |= P_IGN_CTS;
  236.           p_waitstat (&ttystat);
  237.           if ((ret=p_iow(serial,P_FSET,&set.tty)) != 0) p_panic (ret);
  238.           Sw_Serial(ON);
  239.           break;
  240.         }
  241.       Check(p_iow(serial, P_FCTRL, set.pctrl), c_query);
  242.     }
  243.     }
  244.   p_write (serial, p, n);
  245.   stats_write += n;
  246. }
  247.  
  248. /*============================================================ ShowStats ===*/
  249. void ShowStats (void) {
  250.  
  251.   if(! ( set.flags & FLAGS_SHOW_STATS) )
  252.     return;
  253.  
  254.   p_atos (mfb, "I/O:%07Lu/%07Lu", stats_read, stats_write);
  255.   gPrintText(io_x, stat_y, mfb, p_slen(mfb));
  256. }
  257.  
  258. /*=============================================================== Resize ===*/
  259. /* Compute every position & redraw everything */
  260. void Resize (void)
  261. {
  262.     W_WINDATA    wd;
  263.     WORD    havestat;
  264.     P_RECT    pr;
  265.     G_FONT_INFO fi;
  266.     G_GC    gc;
  267.     int        ret, l1, l2;
  268.  
  269.     /*----------------------------------- draw screen with status window ---*/
  270.  
  271.     if(clkwin)
  272.       {
  273.     if (_UseFullScreen) /* S3a */
  274.       {
  275.         if(clkwin == 2)
  276.           havestat = W_STATUS_WINDOW_BIG;
  277.         else
  278.           havestat = W_STATUS_WINDOW_SMALL;
  279.         wInquireStatusWindow (havestat, &wd.extent);
  280.         wd.extent.tl.x = wd.extent.tl.y = 0;
  281.         wd.extent.width = screenx - wd.extent.width;
  282.         wd.extent.height = screeny;
  283.       }
  284.     else
  285.       wsScreenExt (&wd.extent);   /* Much easier */
  286.       }
  287.     else
  288.       {
  289.     wd.extent.tl.x = wd.extent.tl.y = 0;
  290.     wd.extent.width = screenx;
  291.     wd.extent.height = screeny;
  292.       }
  293.  
  294.     wSetWindow (main_win, W_WIN_EXTENT, &wd);
  295.  
  296.     if ((ret=wCheckPoint()) != 0) p_exit (ret);
  297.  
  298.     pr.tl.x = pr.tl.y = 0;
  299.     pr.br.x = wd.extent.width;
  300.     pr.br.y = wd.extent.height;
  301.     gClrRect(&pr, G_TRMODE_CLR);
  302.  
  303.     if(clkwin)
  304.       {
  305.     if(_UseFullScreen)
  306.           wStatusWindow(havestat);
  307.     else
  308.           wsEnable();
  309.       }
  310.     else
  311.       wsDisable();
  312.  
  313.     /*-------------------------------------------------------- Change GC ---*/
  314.     gc.style = G_STY_MONO;
  315.     gc.font = WS_FONT_BASE + set.font;
  316.     gSetGC(hgc, G_GC_MASK_STYLE|G_GC_MASK_FONT, &gc);
  317.  
  318.     /*----------------- compute layout of the graphics items: ---*/
  319.     gFontInfo(gc.font, G_STY_MONO, &fi);
  320.  
  321.     charwidth  = fi.max_width;
  322.     charheight = fi.height;
  323.     ascent     = fi.ascent;
  324.     t_w           = wd.extent.width;
  325.     t_h        = screeny;
  326.  
  327.     if ( set.flags & FLAGS_SHOW_STATS )
  328.       {
  329.         t_h -= charheight;
  330.  
  331.     l1  = gTextWidth(gc.font, G_STY_MONO, "I/O:9999999/9999999", 19);
  332.     l2  = gTextWidth(gc.font, G_STY_MONO, "CTS DSR DCD", 11);
  333.  
  334.     stat_y = screeny - fi.descent;
  335.     io_x = 0;
  336.  
  337.     hisrect.tl.x = l1+1;
  338.     hisrect.tl.y = screeny - charheight;
  339.     hisrect.br.x = t_w - l2;
  340.     hisrect.br.y = screeny;
  341.  
  342.     modem_x = hisrect.br.x;
  343.  
  344.     /*
  345.     gDrawLine(0, t_y, t_w, t_y);
  346.     */
  347.  
  348.     ShowStats();
  349.     pctrl = 0xff;
  350.     UpdateModem();
  351.       }
  352.  
  353.     rows = t_h / charheight; t_h = charheight * rows;
  354.     cols = t_w / charwidth;  t_w = charwidth * cols;
  355.     if(isnfsd)
  356.       {
  357.     /* Resize event ... */
  358.         buf2[0] = 0; buf2[1] = rows; buf2[2] = cols;
  359.     P_WRITE(serial, buf2, 3);
  360.       }
  361.  
  362. #ifdef HAVE_TERMEMU
  363.     Reset();
  364.       
  365.     LoadFnKey(fnkeyname, 0);
  366.  
  367.     p_atos (mfb, "rows: %d, cols: %d", rows, cols);
  368.     wInfoMsgCorner(mfb, W_CORNER_BOTTOM_RIGHT);
  369. #endif
  370. }
  371.  
  372. /*=========================================== screen/menu initialization ===*/
  373. void ScreenInitialize (void) {
  374.  
  375.     INT        len;
  376.     G_GC    gc;
  377.  
  378.     /*-------------------------------------------------- initialize HWIF ---*/
  379.     _UseFullScreen = TRUE;    /* Set this to False for testing S3 */
  380.     hCrackCommandLine();
  381.     uCommonInit();
  382.     uEscape (FALSE);
  383.  
  384.     /*----------------------------------- read set from environment ---*/
  385.     /* p_delenv (EnvironmentName);/* */
  386.     len = p_getenviron (EnvironmentName, p_slen(EnvironmentName), buf);
  387.     if (len==sizeof(set))
  388.       p_bcpy (&set, buf, sizeof(set));
  389.     else
  390.       {
  391.         if(!_UseFullScreen)
  392.       set.font = 0; /* S3 font for the first time */
  393.       }
  394.     clkwin   = (set.flags >> 2) & 0x3;
  395.     protocol = (set.flags >> 4) & 0x3;
  396.  
  397.     /*--------------------------------------------- set process priority ---*/
  398.     p_setpri (p_getpid(), E_MAX_PRIORITY);
  399.     if (_UseFullScreen) wSetPriorityControl (FALSE);            /* S3a only */
  400.  
  401.     /*----------------------------------------------------- first resize ---*/
  402.     main_win = uFindMainWid();
  403.     if(_UseFullScreen)
  404.       {
  405.     screenx = 480; screeny = 160;
  406.       }
  407.     else
  408.       {
  409.         screenx = 240; screeny = 80;
  410.       }
  411.  
  412.     gc.textmode = G_TRMODE_REPL; /* Default ist _SET */
  413.     hgc = gCreateGC(main_win, G_GC_MASK_TEXTMODE, &gc);
  414.  
  415.     Resize();
  416. }
  417.  
  418. /*======================================== Cancel / Reenable serial input ==*/
  419. void Sw_Serial(char on)
  420. {
  421.   if(on)
  422.     {
  423.       one=1;
  424.       p_ioa (serial, P_FREAD, &ttystat, &sch, &one);
  425.     }
  426.   else
  427.     {
  428.       p_iow (serial, P_FCANCEL);
  429.     }
  430. }
  431.  
  432. /*=============================================================== DoExit ===*/
  433. void DoExit()
  434. {
  435.   int ret;
  436.  
  437.   set.flags &= ~0x3c;    /* Delete bits for clkwin & protocol */
  438.   set.flags |= (clkwin << 2) | (protocol << 4);
  439.   ret = p_setenviron(EnvironmentName, p_slen(EnvironmentName),
  440.                      &set, sizeof(set));
  441.   uErrorValue(ret);
  442.   p_exit(0);
  443. }
  444.  
  445. #ifdef HAVE_TERMEMU
  446. /*=============================================================== iso2cp ===*/
  447. unsigned char
  448. iso2cp(unsigned char ch)            /* Called only with ch > 127 */
  449. {
  450.   if(set.flags & FLAGS_NOCHARCONV)
  451.     return ch;
  452.   else
  453.     return tbl_iso2cp[ch-128];
  454. }
  455. #endif
  456.  
  457. /*=================================================== ExecuteMenuCommand ===*/
  458. void ParseKey (UWORD key, UBYTE modifier) {
  459.  
  460.     INT    ret;
  461.  
  462.     /*--------------------------------------------------- system event ---*/
  463.     if (key == 0x404)
  464.       {
  465.         wGetCommand((UBYTE *)buf);
  466.     if(*buf == 'X')
  467.       DoExit();
  468.     return;
  469.       }
  470.     if (key & 0x400)    /* Some other system  event */
  471.       return;
  472.     /*------------------------------------------- Function keys -----------*/
  473. #ifdef HAVE_TERMEMU
  474.     if(fnkey)    /* Define or delete it */
  475.       {
  476.     if(fnkey == 'd')
  477.       {
  478.         H_DI_TEXT  l1={buf+  0, TXT_TYPE}, 
  479.                l2={buf+ 50, TXT_TYPE},
  480.                l3={buf+100, TXT_TYPE},
  481.                l4={buf+150, TXT_TYPE};
  482.         H_DI_EDIT  l5={buf+150, 100}; 
  483.  
  484.         fnkey = 0;
  485.         uZTStoBCS(l1.str, "Type in the characters to be sent.");
  486.         uZTStoBCS(l2.str, "Use \\<nnn> for nonprintable (e.g. \\027=ESC)");
  487.         uZTStoBCS(l3.str, "and \\s<nn> for delay (e.g. \\s99=9.9 seconds)");
  488.         uZTStoBCS(l4.str, "");
  489.         if (   uOpenDialog ("Defining the function key")
  490.         || uAddDialogItem (H_DIALOG_TEXT, NULL, &l1)
  491.         || uAddDialogItem (H_DIALOG_TEXT, NULL, &l2)
  492.         || uAddDialogItem (H_DIALOG_TEXT, NULL, &l3)
  493.         || uAddDialogItem (H_DIALOG_TEXT, NULL, &l4)
  494.         || uAddDialogItem (H_DIALOG_EDIT, NULL, &l5))
  495.             return;
  496.         if(uRunDialog() > 0)
  497.           AddFnKey(key, modifier, l5.str);
  498.       }
  499.     if(fnkey == 'r')
  500.       {
  501.         struct fkey **fp, *f;
  502.  
  503.         for(fp = &fk, f = fk; *fp; f = *fp)
  504.           if(f->key == key && f->modifier == modifier)
  505.         {
  506.           *fp = f->next;
  507.           p_free(f);
  508.           wInfoMsgCorner("FnKey deleted", W_CORNER_BOTTOM_RIGHT);
  509.         }
  510.           else
  511.         fp = &f->next;
  512.       }
  513.         fnkey = 0;
  514.     return;
  515.       }
  516.  
  517.     {        /* Was the key a function key ? */
  518.       struct fkey *f;
  519.  
  520.       for(f = fk; f; f = f->next)
  521.     if(f->key == key && f->modifier == modifier)
  522.       {
  523.         SendFnKey(f);
  524.         return;
  525.       }
  526.     }
  527. #endif
  528.  
  529.     /*------------------------------------------- clock window ------------*/
  530.     if (key == W_KEY_MENU && modifier == W_CTRL_MODIFIER)
  531.       {
  532.     if(--clkwin < 0)
  533.           clkwin = _UseFullScreen ? 2 : 1;
  534.     Resize();
  535.         return;
  536.       }
  537.  
  538.     /*------------------------------------- send key to the serial line ---*/
  539.     if (!(key & W_SPECIAL_KEY) && (key!=W_KEY_MENU))
  540.       {
  541. #ifdef HAVE_TERMEMU
  542.     if(key >= 256 && key <= 259) /* Arrow key */
  543.       {
  544.             char mb[3];
  545.  
  546.         mb[0] = 0x1b;
  547.         mb[1] = cur_appl ? 'O' : '[';
  548.         mb[2] = 'A' + (key - 256);
  549.         P_WRITE(serial, mb, 3); 
  550.       }
  551.     else
  552.       {
  553.         key = key & 0xff;
  554.         if(key > 127 && !(set.flags & FLAGS_NOCHARCONV))
  555.           key = tbl_cp2iso[key-128];
  556.         P_WRITE(serial, (char *)&key, 1);         /* BigEndian!!! */
  557.       }
  558. #endif
  559.     return; /* terminal */
  560.       }
  561.  
  562.     /*------------------------- strip Psion modifier and get menu option ---*/
  563.     key &= ~W_SPECIAL_KEY;
  564.     if((key==W_KEY_MENU) && ((key=uPresentMenus()) <= 0))
  565.       return;
  566.     if (modifier & W_SHIFT_MODIFIER)
  567.       key -= 0x20;
  568.  
  569.     /*---------------------------------------- switch on command request ---*/
  570.     switch (key) {
  571.  
  572.         case 'a': { /*-------------------------------------------- About ---*/
  573.             H_DI_TEXT  line1={buf+  0,TXT_TYPE}, 
  574.                    line2={buf+ 50,TXT_TYPE},
  575.                line3={buf+100,TXT_TYPE},
  576.                line4={buf+150,TXT_TYPE},
  577.                line5={buf+200,TXT_TYPE};
  578.  
  579.             uZTStoBCS (line1.str, "N.N, Rudolf König,");
  580.             uZTStoBCS (line2.str, "Michael Schröder, Jürgen Weigert");
  581.             uZTStoBCS (line3.str, "╕ 1995, 1996");
  582.             uZTStoBCS (line4.str, "jnweiger / rfkoenig@immd4.uni-erlangen.de");
  583.             uZTStoBCS (line5.str, "Distributed under GNU Copyleft (Version 2)");
  584.  
  585.             if (   uOpenDialog ("About NFSC v4.3b")
  586.                 || uAddDialogItem (H_DIALOG_TEXT, NULL, &line1)
  587.                 || uAddDialogItem (H_DIALOG_TEXT, NULL, &line2)
  588.                 || uAddDialogItem (H_DIALOG_TEXT, NULL, &line3)
  589.                 || uAddDialogItem (H_DIALOG_TEXT, NULL, &line4)
  590.                 || uAddDialogItem (H_DIALOG_TEXT, NULL, &line5)
  591.                 || (_UseFullScreen && uAddButtonList ("", W_KEY_RETURN, NULL)) /* S3 doesn't fit */
  592.                 || uRunDialog() <= 0)
  593.                 return;
  594.  
  595.             return;
  596.         }
  597.  
  598.         case 'p': { /*--------------------------------------------- Port ---*/
  599.             UWORD  baud     = set.tty.tbaud;
  600.             UWORD  databits = (set.tty.frame & P_DATA_FRM) + 1;
  601.             UWORD  stopbits = (set.tty.frame & P_TWOSTOP) ? 2 : 1;
  602.             UWORD  parity   = (set.tty.frame & P_PARITY) ? 
  603.                     set.tty.parity + 1 : 0x01 /*none*/;
  604.             UWORD  ignore   = (set.tty.flags & P_IGNORE_PARITY) ? 1 : 2;
  605.  
  606.             if (   uOpenDialog ("Port")
  607.                 || uAddChoiceList ("Baud rate", &baud, "50","75","110","134",
  608.                 "150","300","600","1200","1800","2000","2400",
  609.                 "3600","4800","7200","9600", 
  610.                 _UseFullScreen ? "19200" : NULL, NULL)
  611.                 || uAddChoiceList ("Data bits",&databits,"5","6","7","8",NULL)
  612.                 || uAddChoiceList ("Stop bits", &stopbits, "1", "2", NULL)
  613.                 || uAddChoiceList ("Parity",&parity,"none","even","odd",NULL)
  614.                 || uAddChoiceList ("Ignore parity", &ignore,"yes","no", NULL)
  615.                 || uRunDialog() <= 0)
  616.                 return;
  617.  
  618.             set.tty.tbaud  = set.tty.rbaud = baud;
  619.             set.tty.frame  = databits - 1;
  620.             set.tty.frame |= (stopbits == 2) ? P_TWOSTOP : 0x00;
  621.             set.tty.frame |= (parity > 1 /*none*/) ? P_PARITY  : 0x00;
  622.             set.tty.parity = parity - 1;
  623.             set.tty.flags  = (ignore == 1) ? P_IGNORE_PARITY : 0x00;
  624.  
  625.         Sw_Serial(OFF);        /* otherwise panic with P_FSET! */
  626.             p_waitstat (&ttystat);
  627.  
  628.             if ((ret=p_iow(serial,P_FSET,&set.tty)) != 0) p_panic (ret);
  629.  
  630.         Sw_Serial(ON);
  631.  
  632.             return;
  633.         }
  634.  
  635.         case 'h': { /*-------------------------------------- Handshaking ---*/
  636.             UWORD  flow;
  637.  
  638.         if(set.tty.hand & P_SEND_XOFF) /* Software flow control */
  639.           flow = 1;
  640.         else if(set.tty.hand & P_IGN_CTS)
  641.           flow = 3;
  642.         else
  643.           flow = 2;            /* Hw flow control */
  644.  
  645.             if (   uOpenDialog(c_handshaking)
  646.                 || uAddChoiceList("Flowcontrol:",&flow,
  647.                           "Software","Hardware","None", NULL)
  648.                 || uRunDialog() <= 0)
  649.                 return;
  650.  
  651.         if(flow == 1)
  652.           set.tty.hand = P_SEND_XOFF | P_IGN_CTS;
  653.         else if(flow == 2)
  654.           set.tty.hand = 0;
  655.         else
  656.           set.tty.hand = P_IGN_CTS;
  657.         set.pctrl[1] = set.pctrl[2] == P_SRDTR_ON;
  658.  
  659.         Sw_Serial(OFF);        /* otherwise panic with P_FSET! */
  660.             p_waitstat (&ttystat);
  661.  
  662.             Check(p_iow(serial,P_FSET,&set.tty), c_cfgserial);
  663.             Check(p_iow(serial,P_FCTRL,&set.pctrl), c_dtr);
  664.         set.pctrl[1] = 0x00;    /* or ModemUpdate will do it again */
  665.  
  666.         Sw_Serial(ON);
  667.             return;
  668.       }
  669.         case 'H': { /*------------------------------- Expert Handshaking ---*/
  670.             UWORD  xon_xoff = set.tty.hand & P_SEND_XOFF ? 2 : 1;
  671.             UWORD  rts_cts  = set.tty.hand & P_IGN_CTS   ? 2 : 1;
  672.             UWORD  dsr_dtr  = set.tty.hand & P_OBEY_DSR  ? 2 : 1;
  673.             UWORD  dcd      = set.tty.hand & P_OBEY_DCD  ? 2 : 1;
  674.             UWORD  dtr      = set.pctrl[2] == P_SRDTR_ON ? 2 : 1;
  675.  
  676.             if (   uOpenDialog (c_handshaking)
  677.                 || uAddChoiceList ("Send Xon/Xoff",  &xon_xoff, "Off","On",NULL)
  678.                 || uAddChoiceList ("Ignore RTS/CTS", &rts_cts,  "Off","On",NULL)
  679.                 || uAddChoiceList ("Obey DSR/DTR",   &dsr_dtr,  "Off","On",NULL)
  680.                 || uAddChoiceList ("Obey DCD",       &dcd,      "Off","On",NULL)
  681.                 || uAddChoiceList ("Assert DTR",     &dtr,      "Off","On",NULL)
  682.                 || uRunDialog() <= 0)
  683.                 return;
  684.  
  685.             set.tty.hand  = 0x00;       /* default is ZERO for RTS/CTS */
  686.             set.tty.hand |= (xon_xoff == 2) ? P_SEND_XOFF|P_OBEY_XOFF : 0;
  687.             set.tty.hand |= (rts_cts  == 2) ? P_IGN_CTS   : 0x00;
  688.             set.tty.hand |= (dsr_dtr  == 2) ? P_OBEY_DSR  : 0x00;
  689.             set.tty.hand |= (dcd      == 2) ? P_OBEY_DCD  : 0x00;
  690.         set.pctrl[2] = 0x00;
  691.         set.pctrl[2] |= (dtr      == 2) ? P_SRDTR_ON  : P_SRDTR_OFF;
  692.         set.pctrl[1] = set.pctrl[2];
  693.  
  694.         Sw_Serial(OFF);        /* otherwise panic with P_FSET! */
  695.             p_waitstat (&ttystat);
  696.  
  697.             Check(p_iow(serial,P_FSET,&set.tty), c_cfgserial);
  698.             Check(p_iow(serial,P_FCTRL,&set.pctrl), c_dtr);
  699.         set.pctrl[1] = 0x00;    /* or ModemUpdate will do it again */
  700.  
  701.         Sw_Serial(ON);
  702.             return;
  703.         }
  704. #ifdef HAVE_NFSSUPPORT
  705.         case 'd': { /*------------------------------------------ Devices ---*/
  706.             UWORD dev[5];
  707.             INT   i;
  708.  
  709.             if(uOpenDialog ("Devices"))
  710.           return;
  711.             for(i=0; i<NR_OF_DEVICES; i++)
  712.           {
  713.         dev[i] = set.devices[i] + 1;
  714.         if(uAddChoiceList(dev_name[i], &dev[i], "Off", "On", NULL))
  715.           return;
  716.           }
  717.             if(uRunDialog() <= 0)
  718.           return;
  719.             for(i=0; i<NR_OF_DEVICES; i++)
  720.           set.devices[i] = dev[i] - 1;
  721.             return;
  722.         }
  723.         case 'n': { /*---------------------------------------- Nfsd support */
  724.             UWORD  prt = protocol+1;
  725.  
  726.             if (   uOpenDialog ("Protocol")
  727.                 || uAddChoiceList("Support:",&prt,
  728.            "Terminal only", "Old p3nfsd", "Terminal + New p3nfsd", NULL)
  729.                 || uRunDialog() <= 0)
  730.                 return;
  731.  
  732.         protocol = prt-1;
  733.             return;
  734.         }
  735. #endif
  736.  
  737.         case 27:    /* Psion-Esc */
  738.         case 'x':   /*--------------------------------------------- Exit ---*/
  739.         DoExit();
  740.  
  741.         case 't':   /*-------------------------------- Statistics:Toggle ---*/
  742.         if ( set.flags & FLAGS_SHOW_STATS )
  743.           set.flags &= ~FLAGS_SHOW_STATS;
  744.         else
  745.           set.flags |= FLAGS_SHOW_STATS;
  746.         Resize();
  747.             return;
  748.         
  749.         case 'c':   /*--------------------------------- Statistics:Clear ---*/
  750.         stats_read = stats_write = 0;
  751.         ShowStats();
  752.         return;
  753.  
  754.     case 'u': {  /*------------------------------------------- Update ---*/
  755.       /* dialog to change update frequency: timint */
  756.       H_DI_NUMBER num;
  757.  
  758.       num.value= (LONG *)&timint;
  759.       num.low = 5;
  760.       num.high = 1000;
  761.       if (uOpenDialog("Update frequency") ||
  762.           uAddDialogItem(H_DIALOG_NUMBER, "10ths of secs", &num) ||
  763.           uRunDialog() <= 0)
  764.         return;
  765.       return;
  766.     }
  767.     case 'b': {  /*-------------------------------------- Send a break --*/
  768.       /* We can send a break of 10/50sec = 200msec at most. Should be
  769.          at least 250msec, but it could be better than nothing */
  770.           P_SRCHAR  tty;
  771.       unsigned char z = 0, i;
  772.  
  773.       Sw_Serial(OFF);
  774.       p_iow (serial, P_FFLUSH);
  775.       p_waitstat (&ttystat);
  776.  
  777.       tty = set.tty;
  778.       tty.tbaud = tty.rbaud = P_BAUD_50;
  779.       tty.frame = P_DATA_8 | P_PARITY;         /* This means 200ms */
  780.       tty.parity = P_PAR_EVEN;
  781.       tty.hand = P_IGN_CTS;
  782.       Check(p_iow(serial, P_FSET, &tty), c_cfgserial);
  783.       for(i = 0; i < 6; i++)            /* little over 1 sec */
  784.         P_WRITE(serial, (char *)&z, 1);
  785.  
  786.       Check(p_iow(serial,P_FSET,&set.tty), c_cfgserial);
  787.       set.pctrl[1] = 0x00;    /* or ModemUpdate will do it again */
  788.       p_iow (serial, P_FFLUSH);
  789.  
  790.       Sw_Serial(ON);
  791.       return;
  792.     }
  793.  
  794. #ifdef HAVE_TERMEMU
  795.     case 'r':    /*--------------------------------------- Reset term --*/
  796.       Resize();
  797.       return;
  798.  
  799.     case 'z':    /*------------------------------------- Zoom bigger ---*/
  800.         if(!_UseFullScreen)
  801.           return;
  802.         if(set.font == 12)
  803.           set.font = 4;
  804.         else
  805.           set.font++;
  806.         Resize();
  807.         return;
  808.     case 'Z':    /*------------------------------------- Zoom smaller ---*/
  809.         if(!_UseFullScreen)
  810.           return;
  811.         if(set.font == 4)
  812.           set.font = 12;
  813.         else
  814.           set.font--;
  815.         Resize();
  816.         return;
  817.     
  818.     case 'f': {  /*------------------------------------ Choose font ---*/
  819.             UWORD  font = set.font > 7 ? 2 : 1;
  820.             UWORD  size = set.font - (font == 1 ? 3 : 7);
  821.  
  822.             if (   uOpenDialog ("Font & size")
  823.                 || uAddChoiceList ("Font", &font, "Roman", "Swiss", NULL)
  824.                 || uAddChoiceList ("Size", &size, "8", "11", "13", "16", NULL)
  825.                 || uRunDialog() <= 0)
  826.                 return;
  827.  
  828.         font = (font == 1 ? 3 : 7) + size;
  829.         if ( font != set.font )
  830.           {
  831.         set.font = font;
  832.         Resize();
  833.           }
  834.         return;
  835.       }
  836.     case 'F': {  /*--------------------------------------- Fn keys ---*/
  837.  
  838.         char title[] = "Function keys";
  839.         if (uOpenDialog (title)
  840.         || (uAddButtonList ("Define", 'd', "Remove", 'r',
  841.                     c_save,   's', c_load,   'l', NULL))
  842.         || (ret = uRunDialog()) <= 0)
  843.             return;
  844.           
  845.         if(ret == 'd' || ret == 'r')
  846.           {
  847.         wInfoMsgCorner("Type the function key",W_CORNER_BOTTOM_RIGHT);
  848.         fnkey = ret;
  849.           }
  850.         if(ret == 's' || ret == 'l')
  851.           {
  852.         H_DI_TEXT  line1={buf+  0,TXT_TYPE}, 
  853.                line2={buf+ 50,TXT_TYPE};
  854.         H_DI_FSEL  line3={ fnkeyname, 0 };
  855.                 
  856.         if(ret=='s')
  857.           line3.flags |= H_FILE_NEW_EDITOR;
  858.         uZTStoBCS (line1.str, "nfsc is autoloading \\opd\\fnkeys.nfs");
  859.         uZTStoBCS (line2.str, "");
  860.  
  861.         if (   uOpenDialog (title)
  862.             || uAddDialogItem (H_DIALOG_TEXT, NULL, &line1)
  863.             || uAddDialogItem (H_DIALOG_TEXT, NULL, &line2)
  864.             || uAddDialogItem (H_DIALOG_FSEL, 
  865.                                ret=='s' ? c_load : c_save, &line3)
  866.             || uRunDialog() <= 0)
  867.             return;
  868.         if(ret == 's')
  869.           SaveFnKey(fnkeyname);
  870.         else
  871.           LoadFnKey(fnkeyname, 1);
  872.           }
  873.         return;
  874.       }
  875.     case 's': {  /*------------------------------ Settings ---*/
  876.             UWORD  cnv = (set.flags & FLAGS_NOCHARCONV) ? 2 : 1;
  877.             UWORD  jsc = (set.flags & FLAGS_JUMPSCROLL) ? 1 : 2;
  878.             UWORD  log = logfd ? 1 : 2;
  879.         UWORD  db  = debug ? 1 : 2;
  880.  
  881.             if (   uOpenDialog ("Terminal emulator settings")
  882.                 || uAddChoiceList ("ISO8859-1 to IBM850", &cnv,"On","Off",NULL)
  883.                 || uAddChoiceList ("Enable jumpscroll",   &jsc,"On","Off",NULL)
  884.                 || uAddChoiceList ("Debugging",           &db, "On","Off",NULL)
  885.                 || uAddChoiceList ("Log terminal output", &log,"Yes","No",NULL)
  886.                 || uRunDialog() <= 0)
  887.                 return;
  888.  
  889.         if(cnv == 1)
  890.           set.flags &= ~FLAGS_NOCHARCONV;
  891.         else
  892.           set.flags |= FLAGS_NOCHARCONV;
  893.  
  894.         if(jsc == 1)
  895.           set.flags |= FLAGS_JUMPSCROLL;
  896.         else
  897.           set.flags &= ~FLAGS_JUMPSCROLL;
  898.  
  899.         debug = 2 - db;
  900.  
  901.         log = 2 - log;
  902.  
  903.         if((logfd && !log) || (!logfd && log)) /* Changed */
  904.           {
  905.             if(!log)
  906.           {
  907.             p_close(logfd);
  908.             logfd = 0;
  909.             wInfoMsgCorner("Logging terminated", W_CORNER_BOTTOM_RIGHT);
  910.           }
  911.         else
  912.           {
  913.             extern char cant_open_the_file[];
  914.             H_DI_FSEL  line3={ logfile, H_FILE_NEW_EDITOR };
  915.  
  916.             logfile[*logfile+1] = 0;
  917.  
  918.             if (   uOpenDialog ("Logging")
  919.             || uAddDialogItem (H_DIALOG_FSEL, "Logfile:", &line3)
  920.             || uRunDialog() <= 0)
  921.               return;
  922.  
  923.             if(p_open(&logfd,logfile+1,P_FSTREAM|P_FREPLACE|P_FUPDATE))
  924.               wInfoMsgCorner(cant_open_the_file, W_CORNER_BOTTOM_RIGHT);
  925.             else
  926.               wInfoMsgCorner("Logging started", W_CORNER_BOTTOM_RIGHT);
  927.           }
  928.           }
  929.         return;
  930.       }
  931. #endif /* HAVE_TERMEMU */
  932.  
  933. #ifdef HAVE_XYMODEM
  934.     case 'C':  /*------------------------------------------ XYmodem ----*/
  935.     case 'S':
  936.     case 'R':  /*------------------------------------------ XYmodem ----*/
  937.       /* XYmodem commands are only allowed in terminal-only mode */
  938.       if(protocol != 0)
  939.         {
  940.         H_DI_TEXT  line1={buf+  0,TXT_TYPE}, 
  941.                line2={buf+ 50,TXT_TYPE};
  942.         int ret;
  943.  
  944.         uZTStoBCS (line1.str, "Sorry, XYmodem commands are only");
  945.         uZTStoBCS (line2.str, "allowed in the \"Terminal only\" mode");
  946.  
  947.         if (   uOpenDialog ("XYmodem commands:")
  948.             || uAddDialogItem (H_DIALOG_TEXT, NULL, &line1)
  949.             || uAddDialogItem (H_DIALOG_TEXT, NULL, &line2)
  950.             || (uAddButtonList ("",  W_KEY_RETURN, NULL))
  951.             || (ret = uRunDialog()) <= 0)
  952.             return;
  953.         return;
  954.         }
  955.       DoXYmodem(key);
  956.       return;
  957. #endif
  958.     }
  959. }
  960.  
  961.  
  962. #ifdef HAVE_NFSSUPPORT
  963. /*============================================================== Respond ===*/
  964. VOID Respond(int rc) {
  965.  
  966.   if(protocol == 1)
  967.     {
  968.       P_WRITE (serial, (char *)&rc, 1); /* Big Endian!!! */
  969.     }
  970.   else
  971.     {
  972.       char ret[2];
  973.  
  974.       ret[0] = PREFIX;
  975.       ret[1] = rc;
  976.       P_WRITE (serial, ret, 2);
  977.     }
  978. }
  979.  
  980. /*=============================================================== DoWork ===*/
  981. VOID DoWork (void) {
  982.  
  983.     struct  { LONG offset; UINT len; UBYTE req; } *parms;
  984.     void    *file;
  985.     char    *str;
  986.     INT     rc, to_read;
  987.     LONG    offset;
  988.     P_INFO  p_info;
  989.     UWORD   crc, crc2;
  990.     WORD    len;
  991.  
  992.     /*-------------------------------------------------- read length&data ---*/
  993.  
  994.     len = sch;
  995.     if(protocol == 2)    /* We are reading the length here for the new proto */
  996.       {
  997.     len = 0;
  998.     P_READ (serial, &len, 1);    /* Big Endian!! */
  999.       }
  1000.     P_READ (serial, buf, len);
  1001.  
  1002.     /*------------------ last (few) bytes contain request type and parms ---*/
  1003.     parms = (void *) (buf + len - sizeof(*parms));
  1004.  
  1005.  
  1006.     /*---------------- string is PASCAL string with C string termination ---*/
  1007.     str = buf+1;
  1008.  
  1009.     /*---------------------------------- piggyback statd code onto gattr ---*/
  1010.     if (parms->req == 0x0C) {
  1011.         AddToHistory ('f');
  1012.     Respond(0);
  1013.     }
  1014.  
  1015.     /*------------------------------------ last byte in frame is request ---*/
  1016.     switch (parms->req) {
  1017.  
  1018.     case 0x01: /*------------------------------------------------- creat ---*/
  1019.         rc = p_open (&file, str, P_FSTREAM|P_FREPLACE|P_FUPDATE);
  1020.         AddToHistory ((rc == 0) ? 'c' : 'C');
  1021.     if(!rc)
  1022.       p_close (file);
  1023.     Respond(rc);
  1024.         return;
  1025.  
  1026.     case 0x02: /*------------------------------------------------- gattr ---*/
  1027.         rc = p_finfo (str, &p_info);
  1028.         AddToHistory ((rc == 0) ? 'g' : 'G');
  1029.         Respond(rc);
  1030.         if (rc) return;
  1031.  
  1032.         if (p_info.status & P_FADIR) {
  1033.     case 0x0C: /* statd */
  1034.             /* damned filesystem without linkcount :( */
  1035.             p_info.version = 0;
  1036.             p_scat (str, "\\");
  1037.             p_open (&file, str, P_FDIR);
  1038.             while(p_iow (file, P_FREAD, buf, (P_INFO*)buf2) != E_FILE_EOF)
  1039.               if(((P_INFO *)buf2)->status & P_FADIR)
  1040.             p_info.version++;
  1041.             p_close (file);
  1042.         }
  1043.         P_WRITE (serial, (char *)&p_info, 12);
  1044.         return;
  1045.  
  1046.     case 0x03: /*--------------------------------------------------- mkd ---*/
  1047.         AddToHistory ('m');
  1048.         Respond(p_mkdir(str));
  1049.         return;
  1050.  
  1051.     case 0x04: /*-------------------------------------------------- read ---*/
  1052.         /* Only close the read fd after the last file chunk was read */
  1053.         offset = parms->offset;
  1054.         len = parms->len;
  1055.     rc = 0;
  1056.  
  1057.     if(*rfilename == 0 || p_scmp(rfilename, str))
  1058.       {
  1059.         if(*rfilename)
  1060.           {
  1061.             p_close(rfile);
  1062.         *rfilename = 0;
  1063.           }
  1064.         rc = p_open (&rfile,str,P_FOPEN|P_FSTREAM|P_FRANDOM|P_FSHARE);
  1065.         if(!rc)
  1066.           {
  1067.         p_scpy(rfilename, str);
  1068.         roff = 0;
  1069.           }
  1070.       }
  1071.  
  1072.         if(rc == 0) rc = p_finfo (str, &p_info);
  1073.         if(offset > p_info.size) offset = p_info.size;
  1074.         if(offset + len > p_info.size) len = p_info.size - offset;
  1075.  
  1076.         if(rc == 0 && roff != offset)
  1077.       rc = p_seek (rfile, P_FABS, &offset);
  1078.     AddToHistory ((rc == 0) ? 'r' : 'R');
  1079.     Respond(rc);
  1080.         if(rc)
  1081.       return;
  1082.  
  1083.     roff = offset;
  1084.  
  1085.         P_WRITE (serial, (char *)&p_info, 12);
  1086.     crc = 0;
  1087.         while(len > 0) {
  1088.             to_read = (len > sizeof(buf)) ? sizeof(buf) : len;
  1089.             to_read = p_read (rfile, buf, to_read);
  1090.         len  -= to_read;
  1091.         roff += to_read;
  1092.  
  1093.         if(protocol > 1)
  1094.           p_crc(&crc, (UBYTE *)buf, (UINT)to_read);
  1095.             P_WRITE (serial, buf, to_read);
  1096.         }
  1097.     if(protocol > 1)
  1098.       P_WRITE (serial, (char *)&crc, 2);
  1099.  
  1100.     if(roff == p_info.size)
  1101.       {
  1102.         p_close (rfile);
  1103.         *rfilename = 0;
  1104.       }
  1105.         return;
  1106.  
  1107.     case 0x05: /*-------------------------------------------------- rdir ---*/
  1108.         AddToHistory ('l');
  1109.         Respond(0);
  1110.         p_open (&file, str, P_FDIR);
  1111.         while (p_iow (file, P_FREAD, buf, NULL) != E_FILE_EOF)
  1112.             P_WRITE (serial, buf, p_slen(buf)+1);
  1113.         p_close (file);
  1114.         P_WRITE(serial, (char *)&zero, 1);
  1115.         return;
  1116.  
  1117.     case 0x06: /*-------------------------------------------------- remv ---*/
  1118.         AddToHistory ('d');
  1119.         Respond(p_delete(str));
  1120.         return;
  1121.  
  1122.     case 0x07: /*-------------------------------------------------- renm ---*/
  1123.         AddToHistory ('n');
  1124.         len = ((unsigned char *)(&parms->len))[1];
  1125.         P_READ (serial, buf2, len);
  1126.         buf2[len]=0;
  1127.         rc = p_rename (str, buf2+1);
  1128.         Respond(rc);
  1129.         return;
  1130.  
  1131.     case 0x08: /*--------------------------------------------------- rmd ---*/
  1132.         AddToHistory ('z');
  1133.         Respond(p_delete(str));
  1134.         return;
  1135.  
  1136.     case 0x09: /*------------------------------------------------- sattr ---*/
  1137.         AddToHistory ('s');
  1138.         Respond(p_sfstat (str, parms->len,/*attr*/ 0x0F2F));
  1139.         return;
  1140.  
  1141.     case 0x0A: /*------------------------------------------------- write ---*/
  1142.         offset = parms->offset;
  1143.         len    = parms->len;
  1144.  
  1145.         rc = p_open (&file, str, P_FOPEN | P_FSTREAM | P_FUPDATE | P_FRANDOM);
  1146.         if(rc == 0 && offset > 0)
  1147.       rc = p_seek (file, P_FABS, &offset);
  1148.  
  1149.     crc = 0;
  1150.         while (len) {
  1151.             to_read = (len > sizeof(buf)) ? sizeof(buf) : len;
  1152.             P_READ(serial, buf, to_read);
  1153.         if(protocol > 1)
  1154.           p_crc(&crc, (UBYTE *)buf, (UINT)to_read);
  1155.         if(rc == 0)
  1156.               rc = p_write (file, buf, to_read);
  1157.             len -= to_read;
  1158.         }
  1159.         p_close (file);
  1160.  
  1161.     if(protocol > 1)
  1162.       {
  1163.         P_READ (serial, &crc2, 2);
  1164.         if(crc != crc2)
  1165.           {
  1166.         AddToHistory ('?');
  1167.         if(rc == 0)
  1168.           rc = 1;
  1169.           }
  1170.       }
  1171.  
  1172.         Respond(rc);
  1173.         AddToHistory ((rc == 0) ? 'w' : 'W');
  1174.         return;
  1175.  
  1176.     case 0x0B: /*-------------------------------------------------- getd ---*/
  1177.         AddToHistory ('>');
  1178.         Respond(0);
  1179.         for(len=0; len<NR_OF_DEVICES; len++)
  1180.       {
  1181.         if(set.devices[len] && p_dinfo(dev_name[len], (P_DINFO *)buf) == 0)
  1182.           {
  1183.         P_WRITE (serial, dev_name[len], p_slen(dev_name[len])+1);
  1184.         P_WRITE (serial, buf, 14);
  1185.           }
  1186.       }
  1187.         P_WRITE (serial, (char *)&zero, 1);
  1188.         return;
  1189.  
  1190. #ifdef HAVE_TERMEMU
  1191.     case 0x0D: /*------------------------------------------------- ttydata -*/
  1192.     if(protocol == 2)
  1193.       {
  1194.         AddToHistory ('+');
  1195.         TtyEmu((UBYTE *)str, *(UBYTE *)buf);     /* No return this time */
  1196.         if(isnfsd == 0)
  1197.           {
  1198.             isnfsd = 1;
  1199.         buf2[0] = 0;                         /* Resize event ... */
  1200.         buf2[1] = rows;
  1201.         buf2[2] = cols;
  1202.         P_WRITE(serial, buf2, 3);
  1203.           }
  1204.       }
  1205.     else
  1206.       {
  1207.         AddToHistory ('X');
  1208.         Respond(1);
  1209.       }
  1210.     return;
  1211. #endif
  1212.  
  1213.     default:   /*----------------------------------------------- default ---*/
  1214.         AddToHistory ('X');
  1215.         Respond(1);
  1216.         return;
  1217.     }
  1218. }
  1219. #endif /* HAVE_NFSSUPPORT */
  1220.  
  1221. #define QueueTimer(when) p_ioa4(timH,P_FRELATIVE,&timstat,&when)
  1222.  
  1223. /*================================================================= main ===*/
  1224. void main (void) {
  1225.  
  1226.     WORD       keystat, timstat;
  1227.     WMSG_KEY   key;
  1228.     char      *str;
  1229.  
  1230.     /*------------------------------------------- program initialization ---*/
  1231.     stats_read = stats_write = 0;
  1232.     ScreenInitialize ();
  1233.     for(str = welcome; *str; str++)
  1234.       AddToHistory(*str);
  1235.  
  1236.     /*------------------------------------------------- open serial port ---*/
  1237.     Check(p_open(&serial,"TTY:A",-1), "open TTY:A");
  1238.     Check(p_iow(serial,P_FSET,&set.tty), "init serial line");
  1239.     one=1; p_ioa (serial, P_FREAD, &ttystat, &sch, &one);
  1240.  
  1241.     if (set.flags & FLAGS_SHOW_STATS)
  1242.       UpdateModem();
  1243.  
  1244.     Check(p_open(&timH,"TIM:",-1), "open timer");
  1245.     QueueTimer(timint);
  1246.     uGetKeyA (&keystat, &key);
  1247.  
  1248.     /*-------------------------------------------------------- main loop ---*/
  1249.     for (;;) {
  1250.  
  1251.         /*--------------------------------- wait for something to happen ---*/
  1252.         p_iowait();
  1253.  
  1254.         /*------------------------------------------- was a key pressed? ---*/
  1255.         if (keystat != E_FILE_PENDING) {
  1256.             ParseKey (key.keycode, key.modifiers);
  1257.             uGetKeyA (&keystat, &key);
  1258.             continue;
  1259.         }
  1260.  
  1261.  
  1262.         /*------------------------------ did the serial port talk to us? ---*/
  1263.         if (ttystat != E_FILE_PENDING) {
  1264.         stats_read++;
  1265. #ifdef HAVE_NFSSUPPORT
  1266.         if(protocol == 1 || (protocol == 2 && sch == PREFIX))
  1267.           DoWork ();
  1268.         else
  1269. #endif
  1270.           {
  1271. #ifdef HAVE_TERMEMU
  1272.         /* 
  1273.            Problem: bytewise reading and screen update is too slow.
  1274.            Let's try to read more if there is available. The problem
  1275.            is that there may be a protocol 2 command in the data.
  1276.            Therefore this is restricted to the "terminal only" mode.
  1277.          */
  1278.         if(protocol == 0)
  1279.           {
  1280.             *buf = sch;
  1281.             p_iow(serial, P_FTEST, &one);
  1282.             if(one > 0) /* hmmm */
  1283.               {
  1284.             if(one > 255) one = 255;
  1285.             p_iow (serial, P_FREAD, buf+1, &one);
  1286.               }
  1287.             one++;   /* the first byte is already read before */
  1288.             TtyEmu((unsigned char *)buf, one);
  1289.           }
  1290.         else
  1291.           TtyEmu(&sch, 1);
  1292. #endif
  1293.           }
  1294.  
  1295.             ShowStats ();
  1296.             one=1; p_ioa (serial, P_FREAD, &ttystat, &sch, &one);
  1297.             continue;
  1298.         }
  1299.  
  1300.         /*------------------------------------------ time for a timeout? ---*/
  1301.     if (timstat != E_FILE_PENDING)
  1302.       {
  1303.         UpdateModem();
  1304.             AddToHistory (0);
  1305.         wFlush();
  1306.         QueueTimer(timint);
  1307.       }
  1308.     }
  1309. }
  1310.