home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / winsock / fingd100 / src / fingerd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  38.2 KB  |  1,656 lines

  1. // Contents ---------------------------------------------------------------
  2. //
  3. //   fingerd.c  -- a Windows Socket Finger Daemon
  4. //
  5. //   Version 1.00
  6. //
  7. //   Copyright (C) Frederick W. Bent 1994
  8. //   All rights reserved.
  9. //
  10. //
  11. // Description
  12. //
  13. //      FINGERD is both the user interface and the network interface.
  14. //    FINGERD is a server, its 'users' are FINGER clients, so the user
  15. //    interface requirements of the daemon are rather simple.  FINGERD
  16. //      simply updates its display with outbound buffer traffic.  We also
  17. //      display winsock errors in the server display.
  18. //
  19. //      FINGERD uses WSAAsyncSelect() to receive the SOCKET_MESSAGE window
  20. //      messages that notify FINGERD of pending client requests, causing
  21. //    FINGERD to respond.  When an FD_ACCEPT is received, the socket is
  22. //      added to the linked list of clients.
  23. //
  24. //      FINGERD speaks the finger protocol, and will reply to finger
  25. //    (e.g., the MS-Windows 3.x winsock finger client).
  26. //
  27. // Ends -------------------------------------------------------------------
  28.  
  29. // History ----------------------------------------------------------------
  30. //
  31. // 6/28/94  1.0  Fred Bent    First release
  32. //
  33. // Ends -------------------------------------------------------------------
  34.  
  35. // Legal Stuff ------------------------------------------------------------
  36. //
  37. // Permission to use, modify, and distribute this software and its
  38. // documentation for any purpose and without fee is hereby granted,
  39. // provided that the above copyright notice appears in all copies and
  40. // that both that copyright notice and this permission notice appear in
  41. // supporting documentation.  The author makes no claims as to the
  42. // suitability of this software and documentation for any purpose.
  43. //
  44. // Legal Stuff Ends -------------------------------------------------------
  45.  
  46. // Interface Dependencies -------------------------------------------------
  47.  
  48. #define STRICT    1
  49.  
  50. #include <windows.h>
  51. #include <windowsx.h>
  52. #include <ctl3d.h>
  53. #include <winsock.h>
  54. #include <string.h>
  55. #include <stdlib.h>
  56. #include <stdio.h>
  57. #include <stdarg.h>
  58. #include <dir.h>
  59. #include "fingerd.h"
  60. #include "file.h"
  61. #include "strlib.h"
  62.  
  63. #pragma    warn -par
  64.  
  65. // End Interface Dependencies ---------------------------------------------
  66.  
  67. // External Declarations --------------------------------------------------
  68.  
  69. extern  SOCKET  sListen;          // awaits connection requests
  70. extern    HWND    hwndNetwork;      // our invisible network "window"
  71. extern  char    szNetworkClass[]; // class name of network window
  72.  
  73. // End External Declarations ----------------------------------------------
  74.  
  75.  
  76. // Server Implementation --------------------------------------------------
  77.  
  78.     HWND    hwndMain;      // handle of main window
  79. //    HWND    hwndEdit;
  80.     HWND    hScroll;
  81.     HINSTANCE    hInst;         // our main instance
  82.  
  83.     char szAppName[] = APP_NAME;    // the name of the application
  84.     char szAppClass[] = APP_CLASS;    // the class name of the main window
  85.     char szMainBuffer[SENDBUFLEN];    // transfer buffer holds in/outbound text
  86.     char szDispBuffer[SENDBUFLEN];    //
  87.     char szLocalFile[MAX_PATH];            // filename
  88.     char szFileDir[MAX_PATH];        // file path
  89.     char szHelpFileName[MAX_PATH];    /* Help file name*/
  90.  
  91.     int  iDebugLevel = DEBUG_OFF;    // level of logging to perform
  92.     BOOL bOnlySnark = FALSE;        // only allow snark file
  93.  
  94.  
  95. #ifdef OLD_DSP_LIST
  96.     LINEITEM *pLineItems = NULL;           // ptr to display list LINEITEMS
  97.     LINEITEM *pTopLine;                 // pts to topmost displayable LINEITEM
  98. #else
  99.     HLOCAL    pLineItems = NULL;
  100.     HLOCAL    pTopLine;
  101. #endif
  102.  
  103.     int      nLineItems = 0;            // number of items in display list
  104.     int      nTopLine = 0;              // line number of topmost displayed line
  105.     int      nClientLines;              // # of text lines in view
  106.     
  107.     int    CharY;
  108.  
  109.     LPCLIENT fingerClientsHead = NULL;    // linked list root
  110.  
  111. DECODEWORD frameMsgs[] =               // windows messages & handlers
  112. {
  113.    {WM_CREATE,       DoCreate},
  114.    {WM_ACTIVATE,   DoActivate},
  115.    {WM_COMMAND,    DoCommand},
  116.    {WM_PAINT,      DoPaint},
  117.    {WM_CLOSE,      DoClose},
  118.    {WM_DESTROY,    DoDestroy},
  119.    {WM_SETFOCUS,    DoSetFocus},
  120.    {WM_INITMENUPOPUP, DoInitMenuPopup},
  121.    {WM_SIZE,       DoSize},
  122.    {WM_KEYDOWN,       DoVScroll},
  123.    {WM_VSCROLL,       DoVScroll}
  124. };
  125.  
  126. DECODEWORD menuItems[] =            // menu items & associated handlers
  127. {
  128.    {IDM_ABOUT,     DoMenuAbout},
  129.    {IDM_OPTIONS,   DoMenuOptions},
  130.    {IDM_HELP,       DoMenuHelp},
  131.    {IDM_EXIT,       DoMenuExit},
  132.    {IDE_EDIT,       DoEdit},
  133.    {IDM_COPY,       DoEditCopy},
  134.    {IDM_CLEAR,    DoEditClear},
  135.    {IDM_SELALL,    DoEditSelall},
  136.    {0,           NULL}
  137. };
  138.  
  139.     VOID RelScroll(HWND hWnd, int nlines);
  140.     VOID PosView(int nlines);
  141.     VOID Repaint(VOID);
  142.     VOID SetScroll(VOID);
  143.  
  144.  
  145.  
  146. // Main Function
  147.  
  148.     int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  149.              LPSTR lpCmdLine, int nCmdShow)
  150.  
  151. // Summary ----------------------------------------------------------------
  152. //
  153. //
  154. // Parameters
  155. //
  156. //    hWnd    Handle of the window.
  157. //
  158. //    Msg    Message.
  159. //
  160. //    wParam    First message paramter.
  161. //
  162. //    lParam    Second message parameter.
  163. //
  164. // Ends -------------------------------------------------------------------
  165.  
  166.     {
  167.         WSADATA    WSAData;    // windows sockets info return
  168.         HACCEL    hAccel;
  169.         MSG     msg;        // holds current message
  170.         int     err;
  171.         WORD    wVersionRequested;
  172.  
  173.  
  174.         hInst = hInstance;           // save this instance handle
  175.  
  176.         // We can only have one server at a time :-)
  177.  
  178.         if (hPrevInstance != NULL) return(NULL);
  179.  
  180. #ifdef USE_CTL3D
  181.         Ctl3dRegister(hInstance);
  182.         Ctl3dAutoSubclass(hInstance);
  183. #endif
  184.  
  185.         if (!(InitApp(hInstance) && InitInstance(hInstance, nCmdShow)))
  186.               return(FALSE);                         // can't start, so bail
  187.  
  188.         // setup global variables
  189.  
  190.         InitFinger(hInstance, INI_FILE);
  191.  
  192.         // connect to WinSock.DLL
  193.  
  194.         wVersionRequested = WSVERSION_REQ;
  195.         err = WSAStartup(wVersionRequested, (LPWSADATA) &WSAData);
  196.  
  197.         if (err != 0)
  198.         {
  199.             MessageBeep(MB_ICONSTOP);
  200.             MessageBox(hwndMain, WSErrorString(err), szAppName, MB_ICONSTOP | MB_OK);
  201.             DestroyWindow(hwndMain);
  202. #ifdef USE_CTL3D
  203.             Ctl3dUnregister(hInstance);
  204. #endif
  205.  
  206.             return(NULL);
  207.         }
  208.  
  209.         if ( ( LOBYTE(WSAData.wVersion) < WSVERSION_MAJOR ) ||
  210.              ( LOBYTE(WSAData.wVersion) == WSVERSION_MAJOR &&
  211.                HIBYTE(WSAData.wVersion) < WSVERSION_MINOR) )
  212.         {
  213.                     MessageBeep(MB_ICONSTOP);
  214.             MessageBox(hwndMain, WSErrorString(IDS_BAD_VERSION), szAppName, MB_ICONSTOP | MB_OK);
  215.             DestroyWindow(hwndMain);
  216. #ifdef USE_CTL3D
  217.             Ctl3dUnregister(hInstance);
  218. #endif
  219.             WSACleanup();
  220.             return(NULL);
  221.         }
  222.  
  223.         // OK, now start the server
  224.  
  225.         if ( netInit() ) {
  226.             MessageBox(hwndMain, WSErrorString(WSAGetLastError()), szAppName, MB_ICONSTOP | MB_OK);
  227.             DestroyWindow(hwndMain);
  228. #ifdef USE_CTL3D
  229.             Ctl3dUnregister(hInstance);
  230. #endif
  231.             WSACleanup();
  232.             return(NULL);
  233.         }
  234.  
  235.         hAccel = LoadAccelerators(hInstance, szAppClass);
  236.         if ( hAccel == NULL )
  237.         {
  238.                     MessageBeep(MB_ICONSTOP);
  239.             MessageBox(hwndMain, WSErrorString(IDS_INITIALIZE), szAppName, MB_ICONSTOP | MB_OK );
  240.             DestroyWindow(hwndMain);
  241. #ifdef USE_CTL3D
  242.             Ctl3dUnregister(hInstance);
  243. #endif
  244.             WSACleanup();
  245.             return(NULL);
  246.         }
  247.  
  248.         // loop until WM_QUIT
  249.  
  250.         while ( GetMessage(&msg, NULL, 0, 0) )
  251.         {
  252.             if (!TranslateAccelerator(hwndMain, hAccel, &msg))
  253.                     {
  254.               TranslateMessage(&msg);
  255.               DispatchMessage(&msg);
  256.             }
  257.         }
  258.  
  259.         WSACleanup();
  260. #ifdef USE_CTL3D
  261.         Ctl3dUnregister(hInstance);
  262. #endif
  263.         return(msg.wParam);
  264.     }
  265.  
  266.  
  267. // Function
  268.  
  269.     BOOL InitApp( HINSTANCE hInstance )
  270.  
  271. // Summary ----------------------------------------------------------------
  272. //
  273. //      Initialization for all instances of the application.  This
  274. //    registers the main window class.
  275. //
  276. //
  277. // Parameters
  278. //
  279. //      hInstance
  280. //
  281. // Return
  282. //
  283. //    BOOL    Returns FALSE if error
  284. //
  285. // Ends -------------------------------------------------------------------
  286.  
  287.     {
  288.         WNDCLASS    wndclass;
  289.  
  290.         /*
  291.          * Has it's own DC because of the font selection
  292.          */
  293.         wndclass.style         = CS_HREDRAW | CS_VREDRAW;    // CS_OWNDC
  294.         wndclass.lpfnWndProc   = FrameWndProc;
  295.         wndclass.cbClsExtra    = 0;
  296.         wndclass.cbWndExtra    = 0;
  297.         wndclass.hInstance     = hInstance;
  298.         wndclass.hIcon         = LoadIcon(hInstance, "Icon");
  299.         wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  300. #ifndef USE_CTL3D
  301.         wndclass.hbrBackground = CreateSolidBrush( GetSysColor(COLOR_WINDOW) );
  302. #else
  303.         wndclass.hbrBackground = CreateSolidBrush( GetSysColor(COLOR_BTNFACE) );
  304. #endif
  305.         wndclass.lpszMenuName  = "Menu";
  306.         wndclass.lpszClassName = szAppClass;
  307.  
  308.         return(RegisterClass(&wndclass));
  309.     }
  310.  
  311.  
  312. // Function
  313.  
  314.     BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
  315.  
  316. // Summary ----------------------------------------------------------------
  317. //
  318. //      Initializes this specific instance of the application, and creates
  319. //    the main windows.  The handle to the main window is stored in the
  320. //    global variable hwndMain.  The class name is gotten from the
  321. //    global variable szAppName.
  322. //
  323. //
  324. // Parameters
  325. //
  326. //      hInstance
  327. //
  328. //      nCmdShow
  329. //
  330. // Returns
  331. //
  332. //    BOOL    Returns FALSE if there was an error during initialization.
  333. //
  334. // Ends -------------------------------------------------------------------
  335.  
  336.     {
  337.         hwndMain = CreateWindow(  szAppClass, szAppName,
  338.                WS_OVERLAPPEDWINDOW | WS_VSCROLL,
  339.                CW_USEDEFAULT, CW_USEDEFAULT,
  340.                CW_USEDEFAULT, CW_USEDEFAULT,
  341.                NULL, NULL, hInstance, NULL);
  342.         if (hwndMain == NULL) return(FALSE);
  343.  
  344.         SizeWindow(hwndMain);                     // set window & char sizes
  345.         ShowWindow(hwndMain, nCmdShow);
  346.         UpdateWindow(hwndMain);
  347.  
  348.         return(TRUE);                             // connections
  349.     }
  350.  
  351.  
  352. // Function
  353.  
  354.     BOOL InitFinger(HINSTANCE hInst, PSTR pFilename)
  355.  
  356. // Summary ----------------------------------------------------------------
  357. //
  358. //    This function is called to initialize some global variables
  359. //    using an .INI file.
  360. //
  361. // Parameters
  362. //
  363. //    pFilename    ASCIIZ string of the .INI file to look for.
  364. //
  365. // Ends -------------------------------------------------------------------
  366.  
  367.  
  368.     {
  369.         LPSTR    lpStr;
  370.  
  371.         lstrcpy((LPSTR)szNetworkClass, (LPCSTR) CLASS_NETWORK);
  372.  
  373.         GetModuleFileName( hInst, szFileDir, sizeof(szFileDir) );
  374.         lpStr = lstrrchr( szFileDir, '\\' );
  375.         *lpStr = '\0';
  376.  
  377.         lstrcpy(szLocalFile, szFileDir);
  378.         lstrcat(szLocalFile, DEFAULTFILE );
  379.  
  380.  
  381.         MakeHelpPathName(hInst, (LPSTR)szHelpFileName);
  382.  
  383.         // Get the default file name
  384.  
  385.         GetPrivateProfileString( SECTION_MAIN
  386.                    , ENTRY_DEFAULTFILE
  387.                    , (LPCSTR) DEFAULTFILE
  388.                    , (LPSTR) szLocalFile
  389.                    , sizeof(szLocalFile)
  390.                    , (LPCSTR) pFilename);
  391.  
  392. //        getcwd( szFileDir, sizeof(szFileDir) );
  393.  
  394.         GetPrivateProfileString( SECTION_MAIN
  395.                    , ENTRY_DIR
  396.                    , (LPCSTR) szFileDir
  397.                    , (LPSTR) szFileDir
  398.                    , sizeof(szFileDir)
  399.                    , (LPCSTR) pFilename);
  400.  
  401.             // Get the debugging level stuff
  402.  
  403.         iDebugLevel = GetPrivateProfileInt( SECTION_MAIN
  404.                 , ENTRY_DEBUG
  405.                 , DEBUG_OFF
  406.                 , (LPCSTR) pFilename);
  407.  
  408.         bOnlySnark = GetPrivateProfileInt( SECTION_MAIN
  409.                 , ENTRY_ONLYSNARK
  410.                 , FALSE
  411.                 , (LPCSTR) pFilename);
  412.  
  413.         fingerClientsHead = NULL;
  414. //        iDispBufLen = 0;
  415. //        szDispBuffer[0] = '\0';
  416.         szMainBuffer[0] = '\0';
  417.  
  418. //        bHaveInfo = FALSE;
  419. //        nCurrent = 0;
  420.  
  421.         OpenDisplayList();        // start a new display list
  422.         pLineItems = NULL;           // ptr to display list LINEITEMS
  423.         nLineItems = 0;            // number of items in display list
  424.  
  425.         return(FALSE);
  426.     }
  427.  
  428.  
  429. // Function
  430.  
  431.     void SizeWindow(HWND hWnd)
  432.  
  433. // Summary ----------------------------------------------------------------
  434. //
  435. //    Sets the window's character and external dimesions.
  436. //
  437. // Parameters
  438. //
  439. //    hWnd    The handle of the window.
  440. //
  441. // Ends -------------------------------------------------------------------
  442.  
  443.     {
  444.        HDC hdc;
  445.        TEXTMETRIC tm;
  446.        RECT rect;
  447.        int cyChar, cxChar;
  448.  
  449.        hdc = GetDC(hWnd);
  450.        SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
  451.        GetTextMetrics(hdc, &tm);
  452.        cyChar = tm.tmHeight; // + tm.tmExternalLeading;
  453.        CharY = cyChar;
  454.        cxChar = tm.tmAveCharWidth;
  455.        ReleaseDC(hWnd, hdc);
  456.  
  457.        // set initial window width & height in chars
  458.        GetWindowRect(hWnd, &rect);
  459.        MoveWindow( hWnd
  460.                 , rect.left, rect.top
  461.              , 80 * cxChar + GetSystemMetrics(SM_CXVSCROLL)
  462.              , 24 * cyChar + GetSystemMetrics(SM_CYCAPTION)
  463.                   + GetSystemMetrics(SM_CYMENU)
  464.              , FALSE);
  465.     }
  466.  
  467.  
  468. // Function
  469.  
  470.     void UpdateDisplay(LPSTR szBuffer, int iLen)
  471.  
  472. // Summary ----------------------------------------------------------------
  473. //
  474. //      Prepares to display the string in szBuffer, so we store the size,
  475. //    and force a repaint by invalidating the main window.
  476. //
  477. // Parameters
  478. //
  479. //      szBuffer    The string to be displayed in the server window.
  480. //
  481. //    len        The length of the string to be displayed.
  482. //
  483. // Return
  484. //
  485. //    BOOL    Returns FALSE if error
  486. //
  487. // Ends -------------------------------------------------------------------
  488.  
  489.     {
  490.         int     i;
  491.  
  492.         if ( iLen == 0 ) return;
  493.  
  494.         lstrcpyn((LPSTR)szDispBuffer, szBuffer, (iLen+1));
  495.  
  496.         PushChars(szDispBuffer, iLen);          // add the buffer
  497.         GetDisplayList(&pLineItems, &nLineItems); // update the pointers
  498.  
  499.         i = FALSE;
  500.         while ( nLineItems > MAX_DISP_LINES )
  501.         {
  502.                     i = TRUE;
  503.                     RemoveFirstDisplayLine();
  504.             GetDisplayList(&pLineItems, &nLineItems); // get new one
  505.             nTopLine--;
  506.             if (nTopLine < 0) nTopLine = 0;
  507.         }
  508.  
  509.         if ( i )
  510.         {
  511.             PosView(0);
  512.             SetScroll();
  513.                 }
  514.     }
  515.  
  516.  
  517.  
  518. // WindowProc Function
  519.  
  520.     LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  521.  
  522. // Summary ----------------------------------------------------------------
  523. //
  524. //    The callback function of the network window.
  525. //
  526. // Parameters
  527. //
  528. //    hWnd    Handle of the window.
  529. //
  530. //    Msg    Message.
  531. //
  532. //    wParam    First message paramter.
  533. //
  534. //    lParam    Second message parameter.
  535. //
  536. // Returns
  537. //
  538. //    BOOL    Returns FALSE when it has processed the message, otherwise
  539. //        returns the result of DefWindowProc().
  540. //
  541. // Ends -------------------------------------------------------------------
  542.  
  543.     {
  544.         int i;
  545.  
  546.         for (i = 0; i < dim(frameMsgs); i++)
  547.         {
  548.             if (wMsg == frameMsgs[i].Code)
  549.                 return(*frameMsgs[i].Fxn)(hWnd, wMsg, wParam, lParam);
  550.         }
  551.  
  552.         /* If not handled, then use default... */
  553.  
  554.          return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  555.     }
  556.  
  557.  
  558.  
  559. // Window Function
  560.  
  561.     LRESULT DoCommand(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  562.  
  563. // Summary ----------------------------------------------------------------
  564. //
  565. //     Demultiplexes WM_COMMAND messages resulting from menu selections,
  566. //    and routes to corresponding menu item handler.  Sends back any
  567. //    unrecognized messages to windows.
  568. //
  569. // Parameters
  570. //
  571. //    hWnd    Handle of the window.
  572. //
  573. //    Msg    Message.
  574. //
  575. //    wParam    First message paramter.
  576. //
  577. //    lParam    Second message parameter.
  578. //
  579. // Ends -------------------------------------------------------------------
  580.  
  581.     {
  582.         int i;
  583.  
  584.         for (i = 0; i < dim(menuItems); i++)
  585.         {
  586.             if (wParam == menuItems[i].Code)
  587.                 return(*menuItems[i].Fxn)(hWnd, wMsg, wParam, lParam);
  588.         }
  589.  
  590.         return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  591.     }
  592.  
  593. // Window Function
  594.  
  595.  
  596.     LRESULT DoCreate(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  597.  
  598. // Summary ----------------------------------------------------------------
  599. //
  600. //     Responds to WM_CLOSE message by refusing pending client connects
  601. //     and terminating connections in progress, then kills window.
  602. //
  603. // Parameters
  604. //
  605. //    hWnd    Handle of the window.
  606. //
  607. //    Msg    Message.
  608. //
  609. //    wParam    First message paramter.
  610. //
  611. //    lParam    Second message parameter.
  612. //
  613. // Returns
  614. //
  615. //    LRESULT    Returns zero to create the window.
  616. //
  617. // Ends -------------------------------------------------------------------
  618.  
  619.     {
  620.         HTASK    hTask;
  621.  
  622.         hTask = GetCurrentTask();
  623.         fingerLog(DEBUG_OFF | LOG_TIME, IDS_DAEMON_START, hTask);
  624. //        nCurrent = 0;
  625. //        SetScrollRange(hScroll, SB_VERT, 0, 0, FALSE);
  626. //        SetScrollPos(hScroll, SB_VERT, 0, FALSE);
  627. //        hwndEdit = CreateWindow("edit", NULL
  628. //            , WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL
  629. //              | ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL
  630. //            , 0, 0
  631. //            , 0, 0
  632. //            , hWnd
  633. //            , (HMENU) IDE_EDIT    /* handle of menu or child control id */
  634. //            , hInst
  635. //            , NULL );
  636. //        SendMessage(hwndEdit, EM_LIMITTEXT, 32000, 0L);
  637.  
  638.                 return 0L;
  639.         }
  640.  
  641.  
  642. // Window Function
  643.  
  644.     LRESULT DoClose(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  645.  
  646. // Summary ----------------------------------------------------------------
  647. //
  648. //     Responds to WM_CLOSE message by refusing pending client connects
  649. //     and terminating connections in progress, then kills window.
  650. //
  651. // Parameters
  652. //
  653. //    hWnd    Handle of the window.
  654. //
  655. //    Msg    Message.
  656. //
  657. //    wParam    First message paramter.
  658. //
  659. //    lParam    Second message parameter.
  660. //
  661. // Ends -------------------------------------------------------------------
  662.  
  663.     {
  664.         LPCLIENT    lpClient;
  665.         char    szBuffer[MAXLINE];
  666.  
  667.                 int    result;
  668.  
  669.         lpClient = fingerClientsHead->lpNextClient;
  670.  
  671.         if ( lpClient != NULL )
  672.         {
  673.             LoadString(hInst, IDS_EXIT_ACTIVE, (LPSTR)szBuffer, MAXLINE);
  674.  
  675.             MessageBeep(MB_ICONEXCLAMATION);
  676.             result = MessageBox(hWnd, (LPSTR) szBuffer, szAppName,
  677.                 MB_ICONEXCLAMATION | MB_OKCANCEL | MB_DEFBUTTON2 );
  678.         }
  679.         else
  680.                 {
  681.             LoadString(hInst, IDS_EXITING, (LPSTR)szBuffer, MAXLINE);
  682.              result = MessageBox(hWnd, szBuffer, szAppName,
  683.                 MB_ICONQUESTION | MB_YESNO);
  684.         }
  685.  
  686.                 if ((result == IDYES) || (result == IDOK))
  687.         {
  688.             netClose();
  689.             DestroyWindow(hWnd);
  690.         }
  691.         return(FALSE);
  692.     }
  693.  
  694.  
  695. // Window Function
  696.  
  697.     LRESULT DoDestroy(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  698.  
  699. // Summary ----------------------------------------------------------------
  700. //
  701. //     Responds to a WM_DESTROY message by posting a WM_QUIT message to
  702. //    the task's win queue, which causes the main translate & dispatch
  703. //    loop to exit, and the app to terminate.
  704. //
  705. // Parameters
  706. //
  707. //    hWnd    Handle of the window.
  708. //
  709. //    Msg    Message.
  710. //
  711. //    wParam    First message paramter.
  712. //
  713. //    lParam    Second message parameter.
  714. //
  715. // Ends -------------------------------------------------------------------
  716.  
  717.     {
  718.         CloseDisplayList();              // stop old display
  719.         FreeDisplayList();
  720.         DestroyStrings();
  721.         PostQuitMessage(0);
  722.         return(FALSE);
  723.     }
  724.  
  725.  
  726.  
  727. // Window Function
  728.  
  729.     LRESULT DoSetFocus(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  730.  
  731. // Summary ----------------------------------------------------------------
  732. //
  733. //     Responds to a WM_DESTROY message by posting a WM_QUIT message to
  734. //    the task's win queue, which causes the main translate & dispatch
  735. //    loop to exit, and the app to terminate.
  736. //
  737. // Parameters
  738. //
  739. //    hWnd    Handle of the window.
  740. //
  741. //    Msg    Message.
  742. //
  743. //    wParam    First message paramter.
  744. //
  745. //    lParam    Second message parameter.
  746. //
  747. // Ends -------------------------------------------------------------------
  748.  
  749.     {
  750. //        SetFocus(hwndEdit);
  751.         return(FALSE);
  752.     }
  753.  
  754.  
  755. // Window Function
  756.  
  757.     LRESULT DoSize(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  758.  
  759. // Summary ----------------------------------------------------------------
  760. //
  761. //     Responds to a WM_DESTROY message by posting a WM_QUIT message to
  762. //    the task's win queue, which causes the main translate & dispatch
  763. //    loop to exit, and the app to terminate.
  764. //
  765. // Parameters
  766. //
  767. //    hWnd    Handle of the window.
  768. //
  769. //    Msg    Message.
  770. //
  771. //    wParam    First message paramter.
  772. //
  773. //    lParam    Second message parameter.
  774. //
  775. // Ends -------------------------------------------------------------------
  776.  
  777.     {
  778.         int    cyClient;
  779.  
  780.         cyClient = HIWORD(lParam);
  781.  
  782.         nClientLines = max(1, cyClient / CharY);
  783.  
  784.         PosView(0);
  785.         SetScroll();
  786.  
  787.         return(FALSE);
  788.     }
  789.  
  790.  
  791. // Window Function
  792.  
  793.     LRESULT DoPaint(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  794.  
  795. // Summary ----------------------------------------------------------------
  796. //
  797. //     Responds to a WM_PAINT message by painting the client window with
  798. //    the contents of the transfer buffer.
  799. //
  800. // Parameters
  801. //
  802. //    hWnd    Handle of the window.
  803. //
  804. //    Msg    Message.
  805. //
  806. //    wParam    First message paramter.
  807. //
  808. //    lParam    Second message parameter.
  809. //
  810. // Ends -------------------------------------------------------------------
  811.  
  812.     {
  813.         HDC hdc;
  814.         PAINTSTRUCT ps;
  815.         int     i;
  816. #ifdef OLD_DSP_LIST
  817.         LINEITEM    *pline;           // pts to topmost displayable LINEITEM
  818. #else
  819.         HLOCAL        pline;
  820. #endif
  821.  
  822.  
  823.         hdc = BeginPaint(hWnd, &ps);
  824.  
  825.         SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
  826. #ifndef USE_CTL3D
  827.         SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  828.         SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  829. #else
  830.         SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
  831.         SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
  832. #endif
  833.  
  834.         pline = pTopLine;
  835.  
  836.         for (i = 0; i <= nClientLines; i++)
  837.         {
  838.             if (pline != NULL)
  839.             {
  840. #ifdef    OLD_DSP_LIST
  841.                 TextOut(hdc, 0, i * CharY, (LPSTR)pline->sztext, pline->len);
  842.                 pline = pline->next;
  843. #else
  844.                 PSTR    sztext;
  845.                 LINEITEM *p;
  846.                                 HLOCAL    hNext;
  847.  
  848.                 p = LocalLock(pline);
  849.                 hNext = p->next;
  850.                 if ( p->hText != NULL )
  851.                                 {
  852.                     sztext = LocalLock(p->hText);
  853.  
  854.                     TextOut(hdc, 0, i * CharY, (LPSTR)sztext, p->len);
  855.  
  856.                     LocalUnlock(p->hText);
  857.                 }
  858.                 LocalUnlock(pline);
  859.                 pline = hNext;
  860. #endif
  861.             } else
  862.                 break;
  863.         }
  864.  
  865.         EndPaint(hWnd, &ps);
  866.  
  867.         return(FALSE);
  868.     }
  869.  
  870.  
  871. // Window Function
  872.  
  873.     LRESULT DoEdit(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  874.  
  875. // Summary ----------------------------------------------------------------
  876. //
  877. //     Responds to a WM_PAINT message by painting the client window with
  878. //    the contents of the transfer buffer.
  879. //
  880. // Parameters
  881. //
  882. //    hWnd    Handle of the window.
  883. //
  884. //    Msg    Message.
  885. //
  886. //    wParam    First message paramter.
  887. //
  888. //    lParam    Second message parameter.
  889. //
  890. // Ends -------------------------------------------------------------------
  891.  
  892.     {
  893. //        if (LOWORD(lParam))
  894. //        {
  895. //            switch (HIWORD(lParam))
  896. //            {
  897. //            case EN_UPDATE :
  898. //                return(FALSE);
  899. //            case EN_ERRSPACE:
  900. //                MessageBeep(MB_ICONSTOP);
  901. //                MessageBox(hWnd, "Edit control out of space."
  902. //                    , szAppName, MB_OK | MB_ICONSTOP );
  903. //                /* Clear entire contents of edit control */
  904. //                SendMessage(hwndEdit, EM_SETSEL, 0, MAKELONG(0,-1));
  905. //                SendMessage(hwndEdit, WM_CLEAR, 0, (LPARAM) 0L);
  906. //                return(FALSE);
  907. //            }
  908. //        }
  909.         return(TRUE);
  910.     }
  911.  
  912.  
  913.  
  914.  
  915. // Window Function
  916.  
  917.     LONG DoActivate(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  918.  
  919. // Summary ----------------------------------------------------------------
  920. //
  921. // DoActivate -- grabs the keyboard focus whenever our deminimized window
  922. // is activated.  This is so we can respond to VK_HOME, VK_END, etc.
  923. // virtual keys for scrolling. HIWORD(lParam) is TRUE for minimized, while
  924. // LOWORD(wParam) is FALSE for activation message.
  925. // 
  926. //
  927. // Parameters
  928. //
  929. //    hWnd    Handle of the window.
  930. //
  931. //    Msg    Message.
  932. //
  933. //    wParam    First message paramter.
  934. //
  935. //    lParam    Second message parameter.
  936. //
  937. //
  938. // Returns
  939. //
  940. //    LRESULT
  941. //
  942. //    Returns FALSE of the dialog message was handled, otherwise TRUE.
  943. //
  944. // Ends -------------------------------------------------------------------
  945.  
  946.     {
  947.         if (!HIWORD(lParam) && LOWORD(wParam))
  948.             SetFocus(hwndMain);
  949.  
  950.         return FALSE;
  951.     }
  952.  
  953.  
  954. // Window Function
  955.  
  956.     LRESULT DoInitMenuPopup(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  957.  
  958. // Summary ----------------------------------------------------------------
  959. //
  960. //     Responds to a WM_PAINT message by painting the client window with
  961. //    the contents of the transfer buffer.
  962. //
  963. // Parameters
  964. //
  965. //    hWnd    Handle of the window.
  966. //
  967. //    Msg    Message.
  968. //
  969. //    wParam    First message paramter.
  970. //
  971. //    lParam    Second message parameter.
  972. //
  973. // Ends -------------------------------------------------------------------
  974.  
  975.     {
  976.         LONG    lSelect;
  977.                 WORD    wEnabled;
  978.  
  979.         /*
  980.          * Is this the Edit popup?
  981.          */
  982.         if ( lParam == 1 )
  983.         {
  984. //            lSelect = SendMessage(hwndEdit, EM_GETSEL, 0, 0L);
  985.  
  986. //            if ( HIWORD(lSelect) == LOWORD(lSelect))
  987. //                wEnabled = MF_GRAYED;
  988. //            else
  989. //                wEnabled = MF_ENABLED;
  990.  
  991.             GetDisplayList(&pLineItems, &nLineItems); // list and get new one
  992.  
  993.             if ( nLineItems == 0 )
  994.                 wEnabled = MF_GRAYED;
  995.             else
  996.                 wEnabled = MF_ENABLED;
  997.  
  998.             EnableMenuItem((HMENU) wParam, IDM_COPY, wEnabled);
  999.             EnableMenuItem((HMENU) wParam, IDM_CLEAR, wEnabled );
  1000.         }
  1001.         return(FALSE);
  1002.     }
  1003.  
  1004.  
  1005. // Window Function
  1006.  
  1007.     LRESULT DoEditCopy(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1008.  
  1009. // Summary ----------------------------------------------------------------
  1010. //
  1011. //     Responds to a WM_PAINT message by painting the client window with
  1012. //    the contents of the transfer buffer.
  1013. //
  1014. // Parameters
  1015. //
  1016. //    hWnd    Handle of the window.
  1017. //
  1018. //    Msg    Message.
  1019. //
  1020. //    wParam    First message paramter.
  1021. //
  1022. //    lParam    Second message parameter.
  1023. //
  1024. // Ends -------------------------------------------------------------------
  1025.  
  1026.     {
  1027.         HGLOBAL hGlobal;
  1028.  
  1029.         hGlobal = CopyDisplayList();
  1030.         if (hGlobal == NULL)
  1031.         {
  1032.             MessageBox(hWnd, "Could not allocate global memory buffer!", szAppName, MB_ICONEXCLAMATION | MB_OK );
  1033.         } else {
  1034.             OpenClipboard(hWnd);
  1035.             EmptyClipboard();
  1036.             SetClipboardData(CF_TEXT, hGlobal);
  1037.             CloseClipboard();
  1038.                 }
  1039.  
  1040.         return(FALSE);
  1041.     }
  1042.  
  1043.  
  1044.  
  1045. // Window Function
  1046.  
  1047.     LRESULT DoEditClear(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1048.  
  1049. // Summary ----------------------------------------------------------------
  1050. //
  1051. //     Responds to a WM_PAINT message by painting the client window with
  1052. //    the contents of the transfer buffer.
  1053. //
  1054. // Parameters
  1055. //
  1056. //    hWnd    Handle of the window.
  1057. //
  1058. //    Msg    Message.
  1059. //
  1060. //    wParam    First message paramter.
  1061. //
  1062. //    lParam    Second message parameter.
  1063. //
  1064. // Ends -------------------------------------------------------------------
  1065.  
  1066.     {
  1067.         CloseDisplayList();    // stop old display
  1068.         FreeDisplayList();    // dispose old display
  1069.  
  1070.         pLineItems = NULL;
  1071.         nLineItems = 0;
  1072.  
  1073.         OpenDisplayList();    // start new display
  1074.  
  1075.         PosView(0);             // position view to top
  1076.         SetScroll();            // rescale (or delete)
  1077.         Repaint();              // scrollbar & force a repaint
  1078.  
  1079. //        SendMessage(hwndEdit, WM_CLEAR, 0, 0L);
  1080.         return(FALSE);
  1081.     }
  1082.  
  1083.  
  1084.     void    FingerFinished(void)
  1085.     {
  1086.         GetDisplayList(&pLineItems, &nLineItems); // list and get new one
  1087.  
  1088.         PosView(0);                               // position view to top
  1089.         SetScroll();                              // rescale (or delete)
  1090.         Repaint();                                // scrollbar & force a repaint
  1091.  
  1092.     }
  1093.  
  1094.  
  1095.  
  1096. // Window Function
  1097.  
  1098.     LRESULT DoEditSelall(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1099.  
  1100. // Summary ----------------------------------------------------------------
  1101. //
  1102. //     Responds to a WM_PAINT message by painting the client window with
  1103. //    the contents of the transfer buffer.
  1104. //
  1105. // Parameters
  1106. //
  1107. //    hWnd    Handle of the window.
  1108. //
  1109. //    Msg    Message.
  1110. //
  1111. //    wParam    First message paramter.
  1112. //
  1113. //    lParam    Second message parameter.
  1114. //
  1115. // Ends -------------------------------------------------------------------
  1116.  
  1117.     {
  1118. //        SendMessage(hwndEdit, EM_SETSEL, 0, MAKELONG(0, 32767));
  1119.         return(FALSE);
  1120.     }
  1121.  
  1122.  
  1123.  
  1124. // Callback function
  1125.  
  1126.     BOOL CALLBACK PaintStrCallback(LPSTR lpString, LPARAM lParam)
  1127.  
  1128. // Summary ----------------------------------------------------------------
  1129. //
  1130. //    Called by the string library to add each string to the list box
  1131. //
  1132. // Parameters
  1133. //
  1134. //    lpString    A far pointer to the string.
  1135. //
  1136. //    lParam        Argument to the function.
  1137. //
  1138. // Returns
  1139. //
  1140. //    BOOL        True if the string was added to the list box
  1141. //
  1142. // Ends -------------------------------------------------------------------
  1143.  
  1144.  
  1145.     {
  1146.         HWND    hDlg;
  1147.         UINT    nButton;
  1148.         LONG    lResult;
  1149.  
  1150.         hDlg = (HWND) HIWORD(lParam);
  1151.         nButton = LOWORD(lParam);
  1152.         lResult = SendDlgItemMessage(hDlg, nButton, LB_ADDSTRING, 0, (LPARAM) lpString);
  1153.  
  1154.         return TRUE;
  1155.     }
  1156.  
  1157.  
  1158. // Function
  1159.  
  1160.     void DisplayWSError(PSTR szString, ...)
  1161.  
  1162. // Summary ----------------------------------------------------------------
  1163. //
  1164. //    Display a WinSock error message in the server window.
  1165. //
  1166. // Parameters
  1167. //
  1168. //      szString    An ASCIIZ string
  1169. //
  1170. //    ...        Possible arguments of the string
  1171. //
  1172. // Return
  1173. //
  1174. //    BOOL    Returns FALSE if error
  1175. //
  1176. // Ends -------------------------------------------------------------------
  1177.  
  1178.     {
  1179.        va_list    vaArgs;
  1180.        char        szBuf[MAXLINE];
  1181.        char        szTemp[MAXLINE];
  1182.        int err = WSAGetLastError();
  1183.  
  1184.        szBuf[0] = '\0';
  1185.        va_start(vaArgs, szString);
  1186.        if ( szString != NULL )
  1187.        {
  1188.            wvsprintf((LPSTR)szBuf, szString, vaArgs);
  1189.            szMainBuffer[0] = '\0';
  1190.  
  1191.            if ( szString[0] == '\0' )
  1192.            {
  1193.             strncpy(szBuf, WSErrorString(err), sizeof(szBuf));
  1194.            }
  1195.        } else { strncpy(szBuf, WSErrorString(err), sizeof(szBuf)); }
  1196.        wsprintf((LPSTR)szTemp, "Windows Sockets error %d: %s", err, (LPCSTR) szBuf);
  1197.        UpdateDisplay((LPSTR)szTemp, strlen(szTemp));
  1198.         
  1199.        va_end(vaArgs);
  1200.     }
  1201.  
  1202.  
  1203. // Function
  1204.  
  1205.     PSTR WSErrorString(UINT ResourceID)
  1206.  
  1207. // Summary ----------------------------------------------------------------
  1208. //
  1209. //    Translates WinSock error number into an appropriate string.
  1210. //
  1211. //
  1212. // Parameters
  1213. //
  1214. //      ResourceID
  1215. //
  1216. //    The resource number of the string to be printed.
  1217. //
  1218. // Return
  1219. //
  1220. //    PSTR    A pointer to the string that is to be printed.
  1221. //
  1222. // Ends -------------------------------------------------------------------
  1223.  
  1224.     {
  1225.         int i;
  1226.         static char szBuffer[MAXLINE];
  1227.  
  1228.         if ( !LoadString(hInst, ResourceID, (LPSTR)szBuffer, MAXLINE) )
  1229.             wsprintf( (LPSTR) szBuffer, "Windows Sockets error %d", ResourceID );
  1230.  
  1231.         return(szBuffer);
  1232.     }
  1233.  
  1234.  
  1235. // Debugging function
  1236.  
  1237.     void DebugOut(LPSTR lps, ...)
  1238.  
  1239. // Summary ----------------------------------------------------------------
  1240. //
  1241. //    Sends a string to the AUX device (or debugger).
  1242. //
  1243. //
  1244. // Parameters
  1245. //
  1246. //      lps
  1247. //
  1248. //    The far pointer to the format string
  1249. //
  1250. // Return
  1251. //
  1252. //    Nothing.
  1253. //
  1254. // Ends -------------------------------------------------------------------
  1255.  
  1256.     {
  1257.         char    szBuf[MAXLINE];
  1258.         va_list vaArgs;
  1259.         LPSTR    lpArgs;
  1260.  
  1261.         va_start(vaArgs, lps);
  1262.         lpArgs = va_arg(vaArgs, LPSTR);
  1263.         if (lpArgs != NULL)
  1264.         {
  1265.             wvsprintf((LPSTR)szBuf, lps, lpArgs);
  1266.             OutputDebugString(szBuf);
  1267.         }
  1268.         va_end(vaArgs);
  1269.     }
  1270.  
  1271.  
  1272. // Function
  1273.  
  1274.     void    fingerLog(int iLevel, int ResourceID, ...)
  1275.  
  1276. // Summary ----------------------------------------------------------------
  1277. //
  1278. //    This function places a string into the string log.
  1279. //
  1280. // Parameters
  1281. //
  1282. //    iLevel        The level of the logging
  1283. //
  1284. //    ResourceID    The ID of the string template to use
  1285. //
  1286. // Return
  1287. //
  1288. //    nothing
  1289. //
  1290. // Ends -------------------------------------------------------------------
  1291.  
  1292.     {
  1293.         char    szString[MAXLINE];
  1294.         char    szLine[MAXLINE];
  1295.         char    szTime[30];
  1296.         LPSTR    lpArg1, lpArg2;
  1297.         va_list    vaArgs;
  1298.         DWORD    dwCount;
  1299.  
  1300. //        if ( iLevel < iDebugLevel ) return;
  1301.  
  1302.         va_start( vaArgs, ResourceID );
  1303.  
  1304.         if ( !LoadString(hInst, ResourceID, (LPSTR) szLine, MAXLINE) ) return;
  1305.  
  1306.         wvsprintf((LPSTR)szString, szLine, vaArgs);
  1307.  
  1308.         if ( iLevel & LOG_TIME )
  1309.         {
  1310.             netGetTimeAndDate(szTime, sizeof(szTime));
  1311.             wsprintf((LPSTR)szLine, "%s> %s", (LPSTR)szTime, (LPSTR)szString);
  1312.         } else {
  1313.             lstrcpy((LPSTR)szLine,(LPSTR)szString);
  1314.         }
  1315.  
  1316.         if ( !AddString(szLine) )
  1317.         {
  1318.             DeleteFirstString();
  1319.             AddString(szLine);
  1320.         }
  1321.  
  1322.         return;
  1323.     }
  1324.  
  1325.  
  1326. // Function
  1327.  
  1328.     BOOL    VerifyDir(PSTR szFilePath)
  1329.  
  1330. // Summary ----------------------------------------------------------------
  1331. //
  1332. //    This function verifies that the specified path does exist.
  1333. //
  1334. // Parameters
  1335. //
  1336. //    szFilePath
  1337. //
  1338. //    The path to be verified.
  1339. //
  1340. // Return
  1341. //
  1342. //    BOOL
  1343. //
  1344. // Ends -------------------------------------------------------------------
  1345.  
  1346.     {
  1347.         char    szBuffer[MAX_PATH] = "\0";
  1348.                 int    stat;
  1349.         int    drive = -1;
  1350.         HLOCAL    hOem;
  1351.         PSTR    szOemPath;
  1352.  
  1353.  
  1354.                 /* Dynamic Allocation */
  1355.  
  1356.         hOem = LocalAlloc(LHND, MAX_PATH);
  1357.         if ( hOem == NULL ) return(FALSE);
  1358.  
  1359.         szOemPath = LocalLock(hOem);
  1360.         if ( szOemPath == NULL ) { LocalFree(hOem); return(FALSE); }
  1361.  
  1362.  
  1363.         if ( szFilePath[1] == ':' )
  1364.                 {
  1365.             drive = szFilePath[0] - 'A';
  1366.                         drive++;
  1367.         } else {
  1368.             drive = getdisk();
  1369.         }
  1370.                 szBuffer[0] = (char) drive + 'A';
  1371.         szBuffer[1] = ':';
  1372.         szBuffer[2] = '\\';
  1373.  
  1374.         /*
  1375.          * Drive 0 = default, A = 1, B = 2, C = 3, etc.
  1376.          */
  1377.         getcurdir(drive, &szBuffer[3]);
  1378.  
  1379.         /* MS-DOS uses the OEM character set, so convert */
  1380.  
  1381.         AnsiToOem(szFilePath, szOemPath);
  1382.  
  1383.         stat = chdir( szOemPath );
  1384.         chdir( szBuffer );
  1385.  
  1386.         LocalUnlock(hOem);
  1387.         LocalFree(hOem);
  1388.  
  1389.         if ( stat == -1 ) return TRUE;
  1390.         else return FALSE;
  1391.  
  1392.     }
  1393.  
  1394.  
  1395. // Function
  1396.  
  1397.     void MakeHelpPathName(HINSTANCE hInst, LPSTR szFileName)
  1398.  
  1399. // Summary ----------------------------------------------------------------
  1400. //
  1401. //    This function will attempt to generate the full path name of
  1402. //    the help file from the path of the executable.  It assumes that
  1403. //    the .HLP file is in the same directory as the executable.
  1404. //
  1405. // Parameters
  1406. //
  1407. //
  1408. //    hInst
  1409. //
  1410. //    Identifies the module or the instance of the program.
  1411. //
  1412. //    szFileName
  1413. //
  1414. //    The buffer to accept the name of the help file.
  1415. //
  1416. //
  1417. // Return
  1418. //
  1419. //    nothing
  1420. //
  1421. // Ends -------------------------------------------------------------------
  1422.  
  1423.     {
  1424.         LPSTR   lpcFileName;
  1425.         int     nFileNameLen;
  1426.         const char    szHelpFile[] = HELP_FILE;
  1427.  
  1428.         nFileNameLen = GetModuleFileName(hInst, szFileName, MAX_PATH);
  1429.         lpcFileName = szFileName + nFileNameLen;
  1430.  
  1431.         /* Start looking in reverse for a backslash or full colon */
  1432.         while (lpcFileName > szFileName)
  1433.         {
  1434.             if ((*lpcFileName == '\\') || (*lpcFileName == ':'))
  1435.             {
  1436.                 *(++lpcFileName) = '\0';
  1437.         break;
  1438.             }
  1439.             nFileNameLen--;
  1440.             lpcFileName--;
  1441.         }
  1442.  
  1443.         /* Is there enough room to append the help file name? */
  1444.         if ( ( nFileNameLen + lstrlen((LPSTR)szHelpFile) ) < MAX_PATH)
  1445.         {
  1446.             lstrcat( szFileName, (LPSTR) szHelpFile );
  1447.         }
  1448.         else
  1449.         {
  1450.             lstrcat( szFileName, "?" );
  1451.         }
  1452.     
  1453.         return;
  1454.     }
  1455.  
  1456.  
  1457. // Function
  1458.  
  1459.     VOID PosView(int nlines)
  1460.  
  1461. // Summary ----------------------------------------------------------------
  1462. //
  1463. // PosView -- repositions the view relative to the top of the display list.
  1464. // The view is a logical "window" onto the display list.  The frame window's
  1465. // client area is painted with the view's contents.
  1466. //
  1467. //
  1468. // Paramters
  1469. //
  1470. //    nlines    The position in the display
  1471. //
  1472. // Returns
  1473. //
  1474. //    Nothing.
  1475. //
  1476. // Ends -------------------------------------------------------------------
  1477.  
  1478. {
  1479. #ifdef OLD_DSP_LIST
  1480.    LINEITEM *pline;
  1481. #else
  1482.    HLOCAL    pline;
  1483.    HLOCAL    hNext;
  1484.    LINEITEM *p;
  1485. #endif
  1486.    int i;
  1487.  
  1488.    pline = pLineItems;              // root of LINEITEM list
  1489.  
  1490.    for (i = 0; i < nlines; i++)
  1491.    {
  1492.       if (pline == NULL)
  1493.      break;
  1494.       else {
  1495. #ifdef OLD_DSP_LIST
  1496.      pline = pline->next;
  1497. #else
  1498.      p = LocalLock(pline);
  1499.      hNext = p->next;
  1500.      LocalUnlock(pline);
  1501.      pline = hNext;
  1502. #endif
  1503.       }
  1504.  
  1505.    }
  1506.  
  1507.    pTopLine = pline;                // ptr to LINEITEM in topmost view line
  1508.    nTopLine =+ nlines;              // offset of topmost view line
  1509. }
  1510.  
  1511.  
  1512. // Function
  1513.  
  1514.     VOID Repaint(VOID)
  1515.  
  1516. // Summary ----------------------------------------------------------------
  1517. //
  1518. // Repaint -- force refresh of client window.
  1519. // 
  1520. // Returns
  1521. //
  1522. //    Nothing.
  1523. //
  1524. // Ends -------------------------------------------------------------------
  1525.  
  1526.     {
  1527.         InvalidateRect(hwndMain, NULL, TRUE);
  1528.     }
  1529.  
  1530.  
  1531. // Function
  1532.  
  1533.     VOID SetScroll(VOID)
  1534.  
  1535. // Summary ----------------------------------------------------------------
  1536. //
  1537. // SetScroll -- sets the vertical scroll range to the length of the display
  1538. // list.  The Scrollbar disappears when the list fits within the view.
  1539. //
  1540. // Returns
  1541. //
  1542. //    Nothing.
  1543. //
  1544. // Ends -------------------------------------------------------------------
  1545.  
  1546. {
  1547.    if (nLineItems > nClientLines)
  1548.       SetScrollRange(hwndMain, SB_VERT, 0, nLineItems - nClientLines, FALSE);
  1549.    else
  1550.       SetScrollRange(hwndMain, SB_VERT, 0, 0, FALSE);
  1551.  
  1552.    SetScrollPos(hwndMain, SB_VERT, nTopLine, TRUE);
  1553. }
  1554.  
  1555.  
  1556. // number of lines below the bottom of the view.
  1557. #define NLINESBELOW (nLineItems - nTopLine - nClientLines)
  1558. #define THUMBPOS  LOWORD(lParam)    // Win 16
  1559.  
  1560. // Windows Function
  1561.  
  1562.     LRESULT DoVScroll(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  1563.  
  1564. // Summary ----------------------------------------------------------------
  1565. //
  1566. // DoVScroll -- process WM_VSCROLL & WM_KEYDOWN for main window.
  1567. //
  1568. // Parameters
  1569. //
  1570. //    hWnd    Handle of the window.
  1571. //
  1572. //    Msg    Message.
  1573. //
  1574. //    wParam    First message paramter.
  1575. //
  1576. //    lParam    Second message parameter.
  1577. //
  1578. //
  1579. // Returns
  1580. //
  1581. //    LRESULT
  1582. //
  1583. //    Returns FALSE of the dialog message was handled, otherwise TRUE.
  1584. //
  1585. // Ends -------------------------------------------------------------------
  1586.  
  1587. {
  1588.    switch (LOWORD(wParam))
  1589.    {
  1590.       case VK_HOME:
  1591.       case SB_TOP:
  1592.          if (nTopLine > 0) RelScroll(hWnd, -nTopLine);
  1593.          break;
  1594.  
  1595.       case VK_END:
  1596.       case SB_BOTTOM:
  1597.          if (NLINESBELOW) RelScroll(hWnd, NLINESBELOW);
  1598.      break;
  1599.  
  1600.       case VK_PRIOR:
  1601.       case SB_PAGEUP:
  1602.      if (nTopLine > 0) RelScroll(hWnd, max(-nClientLines, -nTopLine));
  1603.          break;
  1604.  
  1605.       case VK_NEXT:
  1606.       case SB_PAGEDOWN:
  1607.          if (NLINESBELOW) RelScroll(hWnd, min(nClientLines, NLINESBELOW));
  1608.          break;
  1609.  
  1610.       case VK_UP:
  1611.       case SB_LINEUP:
  1612.          if (nTopLine > 0) RelScroll(hWnd, -1);
  1613.          break;
  1614.  
  1615.       case VK_DOWN:
  1616.       case SB_LINEDOWN:
  1617.          if (NLINESBELOW) RelScroll(hWnd, 1);
  1618.          break;
  1619.  
  1620.       case SB_THUMBTRACK:
  1621.          RelScroll(hWnd, THUMBPOS - nTopLine);
  1622.      break;
  1623.    }
  1624.  
  1625.    SetScrollPos(hwndMain, SB_VERT, nTopLine, TRUE);
  1626.    return(FALSE);
  1627. }
  1628.  
  1629.  
  1630. // Function
  1631.  
  1632.     VOID RelScroll(HWND hWnd, int nlines)
  1633.  
  1634. // Summary ----------------------------------------------------------------
  1635. //
  1636. // RelScroll -- scroll up/down nlines from present position
  1637. //
  1638. //
  1639. // Parameters
  1640. //
  1641. //    hWnd    Handle of the window
  1642. //
  1643. //    nlines    The number of lines to scroll
  1644. //
  1645. // Returns
  1646. //
  1647. //    Nothing.
  1648. //
  1649. // Ends -------------------------------------------------------------------
  1650.  
  1651. {
  1652.     PosView(nTopLine + nlines);
  1653.     ScrollWindow(hWnd, 0, (-nlines * CharY), NULL, NULL);
  1654.     UpdateWindow(hWnd);
  1655. }
  1656.