home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / MODEM / UWPC201.ZIP / UW-SRC.ZIP / UW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-04  |  28.0 KB  |  923 lines

  1. //-------------------------------------------------------------------------
  2. //
  3. // UW.CPP - Declarations for the UW protocol within UW/PC.
  4. // 
  5. // NOTE: If "UWMaster::protocol" is -1, then an intermediate state for the
  6. //       protocol exit on the request from the remote host is in effect
  7. //       and "UWProtocol::exit" will reset it to 0 after clean-up.  If
  8. //     the value is -2, then quick exits required by UW/PC are needed
  9. //     where the server no longer exists.  If the value is -3, a
  10. //     user-requested exit is in progress.
  11. //
  12. //  This file is part of UW/PC - a multi-window comms package for the PC.
  13. //  Copyright (C) 1990-1991  Rhys Weatherley
  14. //
  15. //  This program is free software; you can redistribute it and/or modify
  16. //  it under the terms of the GNU General Public License as published by
  17. //  the Free Software Foundation; either version 1, or (at your option)
  18. //  any later version.
  19. //
  20. //  This program is distributed in the hope that it will be useful,
  21. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23. //  GNU General Public License for more details.
  24. //
  25. //  You should have received a copy of the GNU General Public License
  26. //  along with this program; if not, write to the Free Software
  27. //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28. //
  29. // Revision History:
  30. // ================
  31. //
  32. //  Version  DD/MM/YY  By  Description
  33. //  -------  --------  --  --------------------------------------
  34. //    1.0    23/03/91  RW  Original Version of UW.CPP
  35. //    1.1    05/05/91  RW  Many bug fixes and cleanups.
  36. //    1.2    26/05/91  RW  Add command-line to "jumpdos".
  37. //    1.3    08/06/91  RW  Add mouse support to the clients.
  38. //    1.4    31/10/91  RW  Port this module to Windows 3.0.
  39. //
  40. // You may contact the author by:
  41. // =============================
  42. //
  43. //  e-mail: rhys@cs.uq.oz.au
  44. //    mail: Rhys Weatherley
  45. //          5 Horizon Drive
  46. //          Jamboree Heights
  47. //          Queensland 4074
  48. //        Australia
  49. //
  50. //-------------------------------------------------------------------------
  51.  
  52. #include "uw.h"            // Declarations for this module.
  53. #include "comms.h"        // Communications routines.
  54. #include "client.h"        // Client declarations.
  55. #include "config.h"        // Configuration declarations.
  56. #include "uwproto.h"        // UW protocol constants.
  57. #include "display.h"        // UW client display routines.
  58. #include "keys.h"        // Keyboard handling routines.
  59. #ifdef    UWPC_DOS
  60. #include "screen.h"        // Screen handling routines.
  61. #include "timer.h"        // System timer handlers.
  62. #include "mouse.h"        // Mouse accessing routines.
  63. #else    /* UWPC_DOS */
  64. #include "win3.h"        // Windows 3.0 resource definitions.
  65. #endif    /* UWPC_DOS */
  66. #include <stdio.h>        // "sprintf" is defined here.
  67. #include <string.h>        // String handling routines.
  68. #include <dos.h>        // "delay" is defined here.
  69.  
  70. #pragma    warn    -par
  71.  
  72. //
  73. // Define the master object for handling the UW protocol.
  74. //
  75. UWProtocol    UWMaster;
  76.  
  77. //
  78. // Define the special control codes to be translated.
  79. //
  80. #define    IAC    001
  81. #define XON    021
  82. #define    XOFF    023
  83.  
  84. #ifdef    UWPC_DOS
  85.  
  86. //
  87. // Define the title string to be displayed on startup.
  88. //
  89. extern    char    *TitleString;
  90.  
  91. #endif    /* UWPC_DOS */
  92.  
  93. //
  94. // Define the class to use when creating new terminals.
  95. //
  96. #define    UW_TERM_CLASS    UWTermDesc
  97.  
  98. // Transmit a character to the remote host.
  99. inline    void    transmit (int ch)
  100. {
  101.   comsend (UWConfig.ComPort,ch);
  102. } // transmit //
  103.  
  104. // Send a UW command to the remote host.
  105. void    UWProtocol::command (int cmd)
  106. {
  107.   transmit (P1_IAC);
  108.   transmit (cmd | P1_DIR_CTOH);
  109. } // UWProtocol::command //
  110.  
  111. // Send a character to the remote host in the
  112. // round-robin service window.  This is called by
  113. // the function UWClient::send.
  114. void    UWProtocol::send (int ch)
  115. {
  116.   if (protocol < 1)
  117.     transmit (ch);
  118.    else
  119.     {
  120.       if (LastInput != RoundWindow)
  121.         {
  122.       // Send a new input window command to host //
  123.       command (P1_FN_ISELW | RoundWindow);
  124.       LastInput = RoundWindow;
  125.     }
  126.       if (ch & 0x80)            // Escape the top-most bit.
  127.         command (P1_FN_META);
  128.       ch &= 0x7F;            // Strip down to 7 bits.
  129.       switch (ch)
  130.         {
  131.       case IAC:  command (P1_FN_CTLCH | P1_CC_IAC);  break;
  132.       case XON:  command (P1_FN_CTLCH | P1_CC_XON);  break;
  133.       case XOFF: command (P1_FN_CTLCH | P1_CC_XOFF); break;
  134.       default:   transmit (ch);              break;
  135.     }
  136.     }
  137. } // UWProtocol::send //
  138.  
  139. // Send a character to the "remote" method of
  140. // the client attached to the output window.
  141. void    UWProtocol::remote (int ch)
  142. {
  143.   if (clients[OutputWindow])
  144.     {
  145.       RoundWindow = OutputWindow;
  146.       clients[OutputWindow] -> remote (ch);
  147.     }
  148. } // UWProtocol::remote //
  149.  
  150. extern    int    DebugMode;
  151. extern    FILE    *DebugFile;
  152.  
  153. // Process a character incoming from the host
  154. void    UWProtocol::fromhost (int ch)
  155. {
  156.   int arg,temp;
  157.   if (DebugMode)
  158.     fputc (ch,DebugFile);    // Save character in the debugging file.
  159.   if (protocol > 0 || (UWConfig.StripHighBit && !dirproc))
  160.     ch &= 0x7F;        // Strip unwanted parity bit.
  161.    else
  162.     ch &= 0xFF;        // Make a little more 8-bit clean.
  163.   if (getpcl)
  164.     {
  165.       // Process the character for a protocol negotiation //
  166.       int proto;
  167.       proto = ch - ' ' + 1;        // Get protocol number from remote
  168.       if (proto != 1)            // Check for a Protocol 1 suggestion
  169.         {
  170.       // Cancel the server's suggested protocol and suggest Protocol 1 //
  171.       command (P1_FN_MAINT | P1_MF_CANPCL);
  172.       transmit (' ');
  173.     }
  174.        else if (getpcl == P1_MF_CANPCL)    // If a Protocol 1 suggestion, set it
  175.         {
  176.       // Protocol is acceptable - tell server to set it //
  177.       command (P1_FN_MAINT | P1_MF_SETPCL);
  178.       transmit (' ');
  179.     }
  180.       getpcl = 0;
  181.       return;                // Exit - character processed
  182.     }
  183.   if (gotiac)
  184.     {
  185.       gotiac = 0;
  186.       if ((ch & P1_DIR) != P1_DIR_HTOC)
  187.         return;                // Skip command - wrong direction.
  188.       arg = ch & P1_FN_ARG;        // Get function argument.
  189.       switch (ch & P1_FN)
  190.         {
  191.       case P1_FN_NEWW:
  192.           if (protocol < 1 || arg < 1)
  193.           break;
  194.           if (!(temp = create (arg))) // Attempt to create a window.
  195.           {
  196.             // Send a kill command back to the remote host if
  197.             // the window could not be created on this client.
  198.             command (P1_FN_KILLW | arg);
  199.           }
  200.          else if (UWConfig.PopUpNewWindow)
  201.           top (temp);        // Bring new window to top.
  202.           break;
  203.       case P1_FN_KILLW:
  204.           if (protocol < 1 || arg < 1)
  205.           break;
  206.           kill (arg);        // Kill the requested window.
  207.           break;
  208.       case P1_FN_OSELW:
  209.           if (protocol < 1)    // Ignore command in Protocol 0.
  210.           break;
  211.         if (clients[arg] != 0 && arg > 0)
  212.           OutputWindow = arg;
  213.           break;
  214.           case P2_FN_WOPT:        // Process Protocol 2 window options.
  215.           if (protocol < 2)    // Ignore options in Protocol 0/1.
  216.           break;
  217.           break;
  218.       case P1_FN_META:
  219.           if (protocol < 1)    // Ignore command in Protocol 0.
  220.           break;
  221.         if (protocol > 1 && arg)
  222.           {
  223.             // Extract the meta encoding in Protocol 2 //
  224.             switch (arg)
  225.               {
  226.                 case P1_CC_IAC:  remote (IAC  | 0x80); break;
  227.                 case P1_CC_XON:  remote (XON  | 0x80); break;
  228.                 case P1_CC_XOFF: remote (XOFF | 0x80); break;
  229.                 default:     break;
  230.               } /* switch */
  231.           } /* then */
  232.          else
  233.             gotmeta = 1;        // Enable the next meta bit.
  234.           break;
  235.       case P1_FN_CTLCH:
  236.           if (protocol < 1)    // Ignore command in Protocol 0.
  237.           break;
  238.         switch (arg)
  239.           {
  240.             case P1_CC_IAC:  ch = IAC;  break;
  241.             case P1_CC_XON:  ch = XON;  break;
  242.             case P1_CC_XOFF: ch = XOFF; break;
  243.             default:         ch = 0;
  244.           }
  245.         if (ch)
  246.           {
  247.             if (gotmeta)
  248.               {
  249.                 gotmeta = 0;
  250.             ch |= 0x80;
  251.               }
  252.             remote (ch);
  253.           }
  254.           break;
  255.       case P1_FN_MAINT:
  256.           switch (arg)
  257.           {
  258.             case P1_MF_ENTRY:            // Enter protocol 1
  259.                     if (protocol < 1)
  260.                   {
  261.                     protocol = 1;
  262.                     // Start protocol negotiation.
  263.                     command (P1_FN_MAINT | P1_MF_ASKPCL);
  264.                   }
  265.                 break;
  266.             case P1_MF_CANPCL:
  267.             case P1_MF_SETPCL:
  268.                     getpcl = arg;
  269.                 break;
  270.             case P1_MF_EXIT:            // Exit protocol 1
  271.                     protocol = -1;        // Special exit mode
  272.                     exit ();
  273.                 break;
  274.             default:    break;
  275.           }
  276.           break;
  277.       default: break;
  278.     }
  279.     }
  280.    else if (ch == P1_IAC && !dirproc && !UWConfig.DisableUW)
  281.     gotiac = 1;
  282.    else
  283.     {
  284.       if (gotmeta)
  285.         {
  286.       ch |= 0x80;        // Enable the received meta bit.
  287.       gotmeta = 0;
  288.     }
  289.       remote (ch);
  290.     }
  291. } // UWProtocol::fromhost //
  292.  
  293. // Display a new status line on the screen bottom
  294. void    UWProtocol::status (void)
  295. {
  296. #ifdef    UWPC_DOS        // Windows 3.0 doesn't have status lines.
  297.   static char Buffer[STR_LEN + 20];
  298.   static char TermName[6];
  299.   int len,window,posn,startposn,attrbytes,sposn;
  300.   char far *name;
  301.   char *sformat;
  302.   attrbytes = 0;
  303.   sformat = clients[CurrWindow] -> getstatus (); // Get the status format.
  304.   sposn = UWConfig.StatusPosn;        // Save status line position.
  305.   if (UWConfig.DisableStatusLine && !sformat)
  306.     {
  307.       displays[0] -> status (0,0);    // Clear the status line.
  308.       return;                // Skip rest of this function.
  309.     }
  310.   if (!sformat)
  311.     sformat = UWConfig.StatusFormat;    // Get the configured status line.
  312.    else
  313.     UWConfig.StatusPosn = STATUS_CENTRE; // Centre alternate status lines.
  314.   len = 0;
  315.   name = clients[CurrWindow] -> name ();// Get the name of the client.
  316.   while (len < 5 && *name)
  317.     TermName[len++] = *name++;
  318.   TermName[len] = '\0';
  319.   posn = 0;
  320.   while (posn < (STR_LEN - 1) && *sformat)
  321.     {
  322.       if (*sformat == '%')
  323.         {
  324.       switch (*(++sformat))
  325.         {
  326.           case '\0':--sformat; break;
  327.           case '%':    Buffer[posn++] = '%'; break;
  328.           case 'a': startposn = posn;
  329.               for (window = 1;window < NUM_UW_WINDOWS;++window)
  330.                 {
  331.                   if (displays[window] != 0)
  332.                       {
  333.                   if (CurrWindow == window)
  334.                       {
  335.                           Buffer[posn++] = '\001';
  336.                           Buffer[posn++] = window + '0';
  337.                           Buffer[posn++] = '\002';
  338.                     attrbytes += 2;
  339.                       }
  340.                     else
  341.                       Buffer[posn++] = window + '0';
  342.                   Buffer[posn++] = ' ';
  343.                   }
  344.                   }
  345.             while ((posn - startposn) < 16) // 14 + 2 attr chars
  346.               Buffer[posn++] = ' ';
  347.             break;
  348.           case 'e': strcpy (Buffer + posn,TermName);
  349.                   posn += len;
  350.             if (len < 5)
  351.               {
  352.                 int pad;
  353.                 pad = len;
  354.                 while (pad++ < 5)
  355.                   Buffer[posn++] = ' ';
  356.               }
  357.             break;
  358.           case 'h': Buffer[posn++] = '\001'; // Turn on highlight.
  359.                   attrbytes++; break;
  360.           case 'i': Buffer[posn++] = '\002'; // Turn off highlight.
  361.                   attrbytes++; break;
  362.           case 'n':    window = NUM_UW_WINDOWS - 1;
  363.                   while (window > 0 && !clients[window])
  364.               --window;
  365.             Buffer[posn++] = '0' + window;
  366.             break;
  367.           case 'o': if (comcarrier (UWConfig.ComPort))
  368.               strcpy (Buffer + posn,"Online ");
  369.              else
  370.               strcpy (Buffer + posn,"Offline");
  371.             posn += 7;
  372.             break;
  373.           case 'p': strcpy (Buffer + posn,UWConfig.DeviceParameters);
  374.                   posn += strlen (UWConfig.DeviceParameters);
  375.             break;
  376.           case 's': startposn = CurrentTime;    // Get current time.
  377.                   Buffer[posn++] = (startposn / 600) + '0';
  378.             startposn %= 600;
  379.             Buffer[posn++] = (startposn / 60) + '0';
  380.             startposn %= 60;
  381.             Buffer[posn++] = ':';
  382.             Buffer[posn++] = (startposn / 10) + '0';
  383.             Buffer[posn++] = (startposn % 10) + '0';
  384.             break;
  385.           case 't': if (comcarrier (UWConfig.ComPort))
  386.                     {
  387.                       startposn = OnlineTime;    // Get current time.
  388.                       Buffer[posn++] = (startposn / 600) + '0';
  389.                 startposn %= 600;
  390.                 Buffer[posn++] = (startposn / 60) + '0';
  391.                 startposn %= 60;
  392.                 Buffer[posn++] = ':';
  393.                 Buffer[posn++] = (startposn / 10) + '0';
  394.                 Buffer[posn++] = (startposn % 10) + '0';
  395.               }
  396.              else
  397.               {
  398.                 strcpy (Buffer + posn,"     ");
  399.                 posn += 5;
  400.               }
  401.             break;
  402.           case 'u': if (protocol > 0)
  403.                     strcpy (Buffer + posn,"UW");
  404.              else
  405.               strcpy (Buffer + posn,"  ");
  406.             posn += 2;
  407.             break;
  408.           case 'v': Buffer[posn++] = '\263'; break;
  409.           case 'w': Buffer[posn++] = '0' + CurrWindow; break;
  410.           default:    if (*sformat >= '0' && *sformat <= '9')
  411.                     {
  412.                 int arg;
  413.                 arg = clients[CurrWindow] -> getstatarg
  414.                         (*sformat - '0');
  415.                 sprintf (Buffer + posn,"%d",arg);
  416.                 posn = strlen (Buffer);
  417.               }
  418.             break;
  419.         }
  420.     }
  421.        else
  422.         Buffer[posn++] = *sformat;
  423.       ++sformat;
  424.     }
  425.   Buffer[posn] = '\0';
  426.   displays[0] -> status (Buffer,strlen (Buffer) - attrbytes);
  427.   UWConfig.StatusPosn = sposn;        // Restore the status position.
  428. #endif    /* UWPC_DOS */
  429. } // UWProtocol::status //
  430.  
  431. #define    SLICE_SIZE    5
  432.  
  433. // Start the processing of the UW protocol.  When
  434. // this method exits, the program has been terminated.
  435. // On startup, an initial dumb terminal is created.
  436. // Returns NULL or an error message.
  437. char    *UWProtocol::start (void)
  438. {
  439.   int ch,window,carrier,newcarrier,slice;
  440.   char *str;
  441. #ifdef    UWPC_WINDOWS
  442.   MSG msg;
  443.   extern HWND hMainWnd;
  444.   extern HANDLE hAccTable;
  445. #else
  446.   int lasttime,lastonline;
  447. #endif    /* UWPC_WINDOWS */
  448.   terminate = 0;
  449.   exitmulti = 0;
  450.   protocol = 0;
  451.   CurrWindow = 0;
  452.   LastInput = 0;
  453.   RoundWindow = 0;
  454.   OutputWindow = 0;
  455.   gotmeta = 0;
  456.   gotiac = 0;
  457.   getpcl = 0;
  458.   numwinds = 0;
  459.   freelist = 0;
  460.   dirproc = 0;
  461.   for (window = 0;window < NUM_UW_WINDOWS;++window)
  462.     {
  463.       clients[window] = 0;
  464.       displays[window] = 0;
  465.     }
  466.   if ((displays[0] = new UWDisplay (0)) == 0 || displays[0] -> width == 0 ||
  467.       (clients[0] = new UW_TERM_CLASS (displays[0])) == 0)
  468.     return ("Not enough memory for primary terminal");
  469.   if (clients[0] -> isaterminal)
  470.     ((UWTermDesc *)clients[0]) -> setemul (UWConfig.P0TermType);
  471.   displays[0] -> top (1);
  472. #ifdef    UWPC_DOS
  473.   lasttime = CurrentTime;
  474.   lastonline = OnlineTime;
  475.   status ();        // Draw the status line
  476. #else    /* UWPC_DOS */
  477.   hMainWnd = displays[0] -> hWnd;    // Record the main window's handle.
  478. #endif    /* UWPC_DOS */
  479.  
  480. #ifdef    UWPC_DOS
  481.   // Display the title string in the window just created.
  482.   HideMouse ();
  483.   str = TitleString;
  484.   while (*str)
  485.     {
  486.       if (*str == '\n')
  487.         {
  488.       displays[0] -> cr ();
  489.       displays[0] -> lf ();
  490.       ++str;
  491.     }
  492.        else
  493.         displays[0] -> send (*str++);
  494.     }
  495.   ShowMouse ();
  496. #endif    /* UWPC_DOS */
  497.  
  498.   // Enable the communications port
  499.   comenable (UWConfig.ComPort);
  500.   comparams (UWConfig.ComPort,UWConfig.ComParams);
  501.  
  502.   // Send the initialisation string to the modem.
  503. #ifdef    UWPC_DOS
  504.   // Do some checks under DOS, but always send under Windows 3.0 //
  505.   if (UWConfig.CarrierInit || !comcarrier (UWConfig.ComPort))
  506. #else    /* UWPC_DOS */
  507.   // Display a "I am doing something" message //
  508.   if (UWConfig.InitString[0] != '\0')
  509.     {
  510.       str = "Initialising the modem...";
  511.       while (*str)
  512.         displays[0] -> send (*str++);
  513.       displays[0] -> cr ();
  514.       displays[0] -> lf ();
  515.     } /* if */
  516. #endif    /* UWPC_DOS */
  517.     sendstring (UWConfig.InitString);
  518.  
  519.   // Go into a processing loop to process incoming events //
  520.   carrier = comcarrier (UWConfig.ComPort);
  521.   slice = 0;
  522.   while (!terminate)
  523.     {
  524.       // Determine if the carrier status has changed //
  525.       if ((newcarrier = comcarrier (UWConfig.ComPort)) != carrier)
  526.         {
  527.       carrier = newcarrier;
  528. #ifdef    UWPC_DOS
  529.       if (carrier)
  530.         ResetOnline ();        // Reset the online time.
  531.       status ();            // Redraw the status line.
  532. #endif    /* UWPC_DOS */
  533.       if (!newcarrier && protocol > 0)
  534.         {
  535.           // Carrier has dropped - leave Protocol 1 //
  536.           protocol = -2;
  537.           exit ();
  538.         }
  539.     }
  540.  
  541. #ifdef    UWPC_DOS
  542.       // Determine if the current system time has changed //
  543.       if (lasttime != CurrentTime)
  544.         {
  545.       lasttime = CurrentTime;
  546.       status ();            // Redraw the status line.
  547.     }
  548.  
  549.       // Determine if the current online time has changed //
  550.       if (carrier && lastonline != OnlineTime)
  551.         {
  552.       lastonline = OnlineTime;
  553.       status ();            // Redraw the status line.
  554.     }
  555. #endif    /* UWPC_DOS */
  556.  
  557.       // Process characters received from the remote host //
  558.       if ((ch = comreceive (UWConfig.ComPort)) >= 0)
  559.     fromhost (ch);
  560.  
  561. #ifdef    UWPC_DOS
  562.       // Under Windows 3.0, the keyboard and mouse events come   //
  563.       // through the ordinary Windows 3.0 event processing loops //
  564.       // but under DOS we need to do it ourselves.         //
  565.  
  566.       // Process keypresses from the user //
  567.       if ((ch = GetKeyPress ()) != -1)
  568.         {
  569.       RoundWindow = CurrWindow;
  570.       clients[CurrWindow] -> key (ch);
  571.       if (exitmulti)        // Check for user-requested exit.
  572.         {
  573.           // This check is required because otherwise objects //
  574.           // will be destroyed while they are being called on //
  575.           exit ();            // Do the protocol exit.
  576.           exitmulti = 0;
  577.         }
  578.     }
  579.  
  580.       // Process the mouse events if necessary //
  581.       if (MouseChange)
  582.         {
  583.       RoundWindow = CurrWindow;
  584.       SendMouseEvent (clients[CurrWindow]);
  585.     }
  586. #endif    /* UWPC_DOS */
  587.  
  588.       if (!(slice = (slice + 1) % SLICE_SIZE))
  589.         {
  590.           // Send a "tick" to every currently active window //
  591.           for (window = 0;window < NUM_UW_WINDOWS;++window)
  592.             {
  593.           RoundWindow = window;
  594.           if (clients[window])
  595.             clients[window] -> tick ();
  596.         }
  597.       // Clean up unwanted clients from the free list //
  598.       if (freelist)
  599.         {
  600.           UWClient *temp;
  601.           temp = freelist -> under ();
  602.           delete freelist;
  603.           freelist = temp;
  604.         }
  605.     }
  606.  
  607. #ifdef    UWPC_WINDOWS
  608.       // Let the other applications do some work //
  609.       Yield ();
  610.  
  611.       // Process the Windows 3.0 messages that are waiting for processing //
  612.       if (!PeekMessage (&msg,NULL,NULL,NULL,PM_NOYIELD | PM_REMOVE))
  613.     continue;
  614.       if (msg.message == WM_QUIT)
  615.         break;        // The application has terminated.
  616.       if (!TranslateAccelerator (hMainWnd,hAccTable,&msg))
  617.         {
  618.       TranslateMessage (&msg);
  619.       DispatchMessage (&msg);
  620.     }
  621. #endif    /* UWPC_WINDOWS */
  622.     }
  623.  
  624.   // Destroy all active windows and exit UW protocol handling //
  625.   exit ();
  626. #ifdef    UWPC_WINDOWS
  627.   delete displays[0];        // Remove the protocol 0 window.
  628. #endif    /* UWPC_WINDOWS */
  629.  
  630.   comdisable (UWConfig.ComPort,1);
  631.   return (0);
  632. } // UWProtocol::start //
  633.  
  634. // Pass a keypress from outside the UW protocol master.
  635. // This is only called in the Windows 3.0 version.
  636. void    UWProtocol::sendkey (int wind,int key)
  637. {
  638.   // NOTE: This should mirror the GetKeyPress handling in ::start
  639.   // for the DOS version of the program.
  640.   RoundWindow = wind;
  641.   clients[wind] -> key (key);
  642.   if (exitmulti)        // Check for user-requested exit.
  643.     {
  644.       // This check is required because otherwise objects //
  645.       // will be destroyed while they are being called on //
  646.       exit ();            // Do the protocol exit.
  647.       exitmulti = 0;
  648.     }
  649. } // UWProtocol::sendkey //
  650.  
  651. // Force the exit from Protocol 1 or higher, and a
  652. // return to Protocol 0 (ignored in Protocol 0).
  653. void    UWProtocol::exit (void)
  654. {
  655.   int window;
  656.   if (protocol == 0)
  657.     return;            // Ignore request in protocol 0
  658.    else if (protocol > 0)
  659.     protocol = -3;        // User-requested exit from protocol 1.
  660.   for (window = 1;window < NUM_UW_WINDOWS;++window)
  661.     kill (window);        // Kill all currently present windows.
  662.   if (protocol == -3)        // Only send exit command on user-request.
  663.     command (P1_FN_MAINT | P1_MF_EXIT); // Send the exit command to remote host
  664.   top (0);            // Return window 0 to the top.
  665.   protocol = 0;            // Now return to protocol 0
  666.   OutputWindow = 0;        // Reset input and output windows.
  667.   LastInput = 0;
  668.   numwinds = 0;            // Resync number of windows (just in case).
  669.   status ();            // Reset the status line.
  670. #ifdef    UWPC_WINDOWS
  671.   // Disable the Protocol 1 specific menu items //
  672.   HMENU hMenu;
  673.   extern HWND hMainWnd;
  674.   hMenu = GetMenu (hMainWnd);
  675.   EnableMenuItem (hMenu,IDM_EXIT,MF_GRAYED);
  676.   EnableMenuItem (hMenu,IDM_NEW,MF_GRAYED);
  677.   EnableMenuItem (hMenu,IDM_KILL,MF_GRAYED);
  678.   EnableMenuItem (hMenu,IDM_NEXTWIN,MF_GRAYED);
  679.   EnableMenuItem (hMenu,IDM_MINALL,MF_GRAYED);
  680.   EnableMenuItem (hMenu,IDM_START,MF_ENABLED);
  681. #endif    /* UWPC_WINDOWS */
  682. } // UWProtocol::exit //
  683.  
  684. // Create a new window (ignored in Protocol 0).  Returns
  685. // the identifier, or 0 if no window could be created.
  686. // If number != 0, then the number has been supplied
  687. // explicitly, usually by the remote host.
  688. int    UWProtocol::create (int number)
  689. {
  690.   int docreate=0;
  691.   if (protocol < 1)
  692.     return (0);            // Abort request in protocol 0.
  693.   if (number > 0)
  694.     {
  695.       if (clients[number] != 0)
  696.         return (number);    // Window already exists - ignore request.
  697.     }
  698.    else
  699.     {
  700.       docreate = 1;
  701.       number = 1;
  702.       while (number < NUM_UW_WINDOWS && clients[number] != 0)
  703.         ++number;
  704.       if (number >= NUM_UW_WINDOWS)
  705.         return (0);        // Already at window limit.
  706.     }
  707.   if ((displays[number] = new UWDisplay (number)) == 0)
  708.     return (0);            // Not enough memory for the display.
  709.   if (displays[number] -> width == 0 ||
  710.       (clients[number] = new UW_TERM_CLASS (displays[number])) == 0)
  711.     {
  712.       delete displays[number];    // Remove display that was created.
  713.       displays[number] = 0;
  714.       return (0);
  715.     }
  716.   if (clients[number] -> isaterminal)
  717.     ((UWTermDesc *)clients[number]) -> setemul (UWConfig.P1TermType);
  718.   if (numwinds == 0)        // If this is the first window in Protocol 1
  719.     {                // then display it at the top.
  720.       top (number);
  721. #ifdef    UWPC_WINDOWS
  722.       // Minimize the main window when entering Protocol 1 to get it //
  723.       // out of the way on the Windows 3.0 desktop.             //
  724.       ShowWindow (displays[0] -> hWnd,SW_MINIMIZE);
  725.  
  726.       // Enable the Protocol 1 specific menu items //
  727.       HMENU hMenu;
  728.       extern HWND hMainWnd;
  729.       hMenu = GetMenu (hMainWnd);
  730.       EnableMenuItem (hMenu,IDM_EXIT,MF_ENABLED);
  731.       EnableMenuItem (hMenu,IDM_NEW,MF_ENABLED);
  732.       EnableMenuItem (hMenu,IDM_KILL,MF_ENABLED);
  733.       EnableMenuItem (hMenu,IDM_NEXTWIN,MF_ENABLED);
  734.       EnableMenuItem (hMenu,IDM_MINALL,MF_ENABLED);
  735.       EnableMenuItem (hMenu,IDM_START,MF_GRAYED);
  736. #endif    /* UWPC_WINDOWS */
  737.     } /* if */
  738.   ++numwinds;
  739.   status ();            // Redraw the status line.
  740.   if (docreate)
  741.     command (P1_FN_NEWW | number); // Send a create command to remote host.
  742.   return (number);        // Window successfully created.
  743. } // UWProtocol::create //
  744.  
  745. // Install a new client on top of the one in the current
  746. // round-robin window.
  747. void    UWProtocol::install (UWClient *newclient)
  748. {
  749.   newclient -> setunder (clients[RoundWindow]);
  750.   clients[RoundWindow] = newclient;
  751.   status ();
  752. } // UWProtocol::install //
  753.  
  754. // Remove the top-most client from the current round-
  755. // robin window, and return to the client underneath.
  756. void    UWProtocol::remove (void)
  757. {
  758.   UWClient *temp;
  759.   temp = clients[RoundWindow];
  760.   clients[RoundWindow] = temp -> under ();
  761.   temp -> setunder (freelist);    // Save client on the free list.
  762.   freelist = temp;
  763.   status ();
  764. } // UWProtocol::remove //
  765.  
  766. // Turn direct character processing in protocol 0 on or off.
  767. void    UWProtocol::direct (int on)
  768. {
  769.   if (protocol == 0)
  770.     dirproc = on;
  771. } // UWProtocol::direct //
  772.  
  773. // Kill a particular window.  Once all Protocol 1 or 2
  774. // windows have been destroyed, "exit" is automatically
  775. // called to exit the protocol service.  If number == 0,
  776. // then the current window is killed.
  777. void    UWProtocol::kill (int number)
  778. {
  779.   UWClient *client,*temp;
  780.   if (protocol == 0)
  781.     return;            // Ignore request in protocol 0.
  782.   if (number == 0)
  783.     number = CurrWindow;    // Set the default window to kill.
  784.   if (clients[number] == 0)
  785.     return;            // Ignore if window number is illegal.
  786.   if (protocol != -2 && protocol != -1) // Only worry about user-req. kills.
  787.     command (P1_FN_KILLW | number); // Send kill command to remote host.
  788.   delete displays[number];    // Delete the display window.
  789.   client = clients[number];    // Delete the stacked clients in the window.
  790.   while (client)
  791.     {
  792.       temp = client -> under (); // Get the client under this one.
  793.       delete client;         // Delete the current client.
  794.       client = temp;         // Move onto the next client.
  795.     }
  796.   clients[number] = 0;        // Mark the window as unused.
  797.   displays[number] = 0;
  798.   --numwinds;
  799.   if (protocol < 0)        // Ignore rest if quick exit wanted.
  800.     return;
  801.   number = 1;            // Search for a new top window on a normal kill
  802.   while (number < NUM_UW_WINDOWS && clients[number] == 0)
  803.     ++number;
  804.   if (number < NUM_UW_WINDOWS)
  805.     {
  806.       top (number);        // Set a new top window.
  807.       CurrWindow = number;
  808.     }
  809.    else
  810.     exit ();            // Last destroyed - exit protocol.
  811. } // UWProtocol::kill //
  812.  
  813. // Bring a particular window to the top (i.e. make it
  814. // the current window).
  815. void    UWProtocol::top (int number)
  816. {
  817.   if (protocol == 0 || clients[number] == 0)
  818.     return;
  819.   if (displays[CurrWindow])
  820.     displays[CurrWindow] -> top (0);    // Remove current window from top.
  821.   CurrWindow = number;
  822.   displays[CurrWindow] -> top (1);    // Make the new current window the top.
  823.   status ();                // Redraw the status line.
  824. } // UWProtocol::top //
  825.  
  826. // Cycle around to the next window in Protocol 1/2.
  827. void    UWProtocol::nextwindow (void)
  828. {
  829.   int newwin;
  830.   if (protocol == 0)
  831.     return;                // Cannot cycle windows in Protocol 0.
  832.   newwin = CurrWindow + 1;
  833.   if (newwin >= NUM_UW_WINDOWS)
  834.     newwin = 1;
  835.   while (newwin != CurrWindow && clients[newwin] == 0)
  836.     {
  837.       ++newwin;
  838.       if (newwin >= NUM_UW_WINDOWS)
  839.         newwin = 1;
  840.     } /* while */
  841.   top (newwin);                // Bring the new window to the top.
  842. } // UWProtocol::nextwindow //
  843.  
  844. // Jump out to a DOS shell, and fix everything on return.
  845. // Optionally execute a command in DOS.
  846. void    UWProtocol::jumpdos (char *cmdline)
  847. {
  848. #ifdef    UWPC_DOS
  849.   HardwareScreen.jumpdos (cmdline);    // Clear screen and jump out to DOS.
  850.   comfix (UWConfig.ComPort);        // Fix the communications port.
  851.   displays[CurrWindow] -> top (1);    // Redraw the top-most window.
  852.   status ();                // Redraw the status line.
  853. #endif    /* UWPC_DOS */
  854. } // UWProtocol::jumpdos //
  855.  
  856. // Hangup the modem and return to Protocol 0.
  857. void    UWProtocol::hangup (void)
  858. {
  859.   if (protocol > 0)            // Exit protocol 1 if necessary.
  860.     protocol = -2;
  861.   exit ();
  862.   comdropdtr (UWConfig.ComPort);    // Drop the COM port's DTR signal
  863.   DELAY_FUNC (100);            // Wait for 100 ms before raising
  864.   comraisedtr (UWConfig.ComPort);    // Raise the DTR signal again
  865.   if (comcarrier (UWConfig.ComPort))    // If the carrier is still present
  866.     sendstring (UWConfig.HangupString);    // then send the hangup string
  867. } // UWProtocol::hangup //
  868.  
  869. // Send a modem control string through the current window.
  870. // Modem control strings include initialisation, hangup, etc.
  871. void    UWProtocol::sendstring (char *str)
  872. {
  873.   while (*str)
  874.     {
  875.       if (*str == '~')
  876.         DELAY_FUNC (500);        // Wait 1/2th a second for '~'
  877.        else if (*str == '^')
  878.         {
  879.       if (*(str + 1))
  880.         send (*(++str) & 0x1F);    // Send an escaped control code
  881.     }
  882.        else if (*str == '#')
  883.         {
  884.       if (*(str + 1))
  885.         send (*(++str));        // Send following character direct.
  886.     }
  887.        else
  888.         send (*str);            // Send the character direct
  889.       ++str;
  890.     }
  891. } // UWProtocol::sendstring //
  892.  
  893. // Exit protocol 1 and send a modem line break.
  894. void    UWProtocol::sendbreak (void)
  895. {
  896.   if (protocol > 0)            // Exit protocol 1 if necessary.
  897.     protocol = -2;
  898.   exit ();
  899.   combreak (UWConfig.ComPort,1);    // Turn on the BREAK signal.
  900.   DELAY_FUNC (500);            // Wait for 500ms for the pulse.
  901.   combreak (UWConfig.ComPort,0);    // Turn off the BREAK signal.
  902. } // UWProtocol::sendbreak //
  903.  
  904. // Minimize all windows except the given window.  This only
  905. // has an effect in the Windows 3.0 version.
  906. void    UWProtocol::minall (int wind)
  907. {
  908. #ifdef    UWPC_WINDOWS
  909.   int window;
  910.   for (window = 0;window < NUM_UW_WINDOWS;++window)
  911.     {
  912.       if (window != wind && displays[window])
  913.         ShowWindow(displays[window] -> hWnd,SW_MINIMIZE);
  914.     } /* if */
  915. #endif    /* UWPC_WINDOWS */
  916. } // UWProtocol::minall //
  917.  
  918. // Send a character from a client to the remote host.
  919. void    UWClient::send (int ch)
  920. {
  921.   UWMaster.send (ch);
  922. } // UWClient::send //
  923.