www.pudn.com > finger31.zip > FINGER.C


// 
// Finger Version 3.1, a Windows Sockets Finger Client 
// 
// Copyright 1992, 1993 Network Research Corporation 
// 
// Permission to use, modify, and distribute this software and its 
// documentation for any purpose and without fee is hereby granted, provided 
// that the above copyright notice appears in all copies and that both 
// that copyright notice and this permission notice appear in supporting 
// documentation.  NRC makes no claims as to the suitability of this software 
// for any purpose. 
// 
// Module FINGER provides the user interface for the finger client, and 
// depends on NETWRK for TCP/IP network services, and upon DSPLIST 
// retrieve and dispose of "display lists".  The display list represents 
// the remote finger server's return in a form suitable for scrolling text 
// display.  FINGER prompts the user for a host name (or internet address), 
// invokes NETWRK to finger the specified host, and paints the window 
// client area with the returned display list.  FINGER uses a view 
// (a logical window onto a portion of the display list) to render 
// that portion of the list which is currently visable. 
// 
// 02/12/92 Lee Murach     Created. 
// 06/19/92 Mark Towfiq    Adapted to Windows Socket draft rev 1.0. 
// 09/25/92 Ian Merritt    Adapted for Windows Sockets 1.0B compatability. 
// 10/20/92 Lee Murach     Restructured (Ray Duncan-ized) & added scrollbars. 
// 12/02/92 Lee Murach     Split FingerHost() into FingerStart() & 
//                         FingerFinish(), for NETWORK_ module interface. 
// 03/25/93 Lee Murach     Added per-user finger support. 
// 
 
#include  
#include  
#include  
#include  
#include "finger.h" 
 
#define MAXTEXT   132 
#define THUMBPOS  LOWORD(lParam)    // Win 16 
 
typedef struct                      // associates an error code with text 
{ 
   UINT err; 
   char *sztext; 
} ERRENTRY; 
 
int  APIENTRY WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); 
LONG FAR APIENTRY FrameWndProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
BOOL APIENTRY HostDlgProc(HWND hDlg, UINT wMsg, UINT wParam, LONG lParam); 
BOOL FAR APIENTRY AboutDlgProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
BOOL InitInstance(HANDLE hInstance, int nCmdShow); 
BOOL InitApp(HANDLE hInstance); 
LONG DoPaint(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoSize(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoCommand(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoDestroy(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoMouseMove(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoMenuHost(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoVScroll(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoActivate(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoClose(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoMenuExit(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
LONG DoMenuAbout(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam); 
VOID Repaint(VOID); 
VOID PosView(int nlines); 
VOID ReportWSError(UINT Err); 
VOID RelScroll(HWND hWnd, int nlines); 
VOID SetWinCaption(VOID); 
VOID SetScroll(VOID); 
VOID ReportWSError(UINT Err); 
 
char     szHostName[MAXHOST+1] = "";// name of host to finger 
char     szUser[MAXUSER+1] = "";    // query for this user id (can be null) 
char     szAppName[] = "Finger";    // application's name 
LINEITEM *pLineItems = 0;           // ptr to display list LINEITEMS 
int      nLineItems = 0;            // number of items in display list 
LINEITEM *pTopLine;                 // pts to topmost displayable LINEITEM 
int      nTopLine = 0;              // line number of topmost displayed line 
int      nClientLines;              // # of text lines in view 
int      CharY;                     // pixel character height 
HWND     hFrame;                    // finger main window handle 
HMENU    hMenu;                     // main window menu handle 
HANDLE   hInst;                     // this instance of finger 
HCURSOR  hCursor;                   // current cursor (either wait or normal) 
WSADATA  WSAData;             		// windows sockets info return 
 
DECODEWORD frameMsgs[] =            // windows messages & handlers 
{ 
   WM_ACTIVATE,   DoActivate, 
   WM_CLOSE,      DoClose, 
   WM_COMMAND,    DoCommand, 
   WM_DESTROY,    DoDestroy, 
   WM_MOUSEMOVE,  DoMouseMove, 
   WM_PAINT,      DoPaint, 
   WM_SIZE,       DoSize, 
   WM_VSCROLL,    DoVScroll, 
   WM_KEYDOWN,    DoVScroll, 
}; 
 
DECODEWORD menuItems[] =            // menu items & associated handlers 
{ 
   IDM_HOST,      DoMenuHost, 
   IDM_EXIT,      DoMenuExit, 
   IDM_ABOUT,     DoMenuAbout, 
}; 
 
ERRENTRY wsErrs[] =                 // error text for windows sockets errors 
{ 
   WSAVERNOTSUPPORTED,  "This version of Windows Sockets is not supported", 
   WSASYSNOTREADY,      "Windows Sockets is not present or is not responding", 
}; 
 
ERRENTRY finErrs[] =                // finger specific error text 
{ 
   FE_NOPORT,  "Cannot locate port for finger service", 
   FE_NOHOST,  "Unrecognized host name", 
   FE_NOSOCK,  "Cannot obtain socket for connection", 
   FE_NOCONN,  "Cannot connect to remote server", 
   FE_NOSEND,  "Cannot send query to remote server", 
   FE_NORECV,  "Error occurred during retrieval" 
}; 
 
// 
// WinMain -- windows calls this to start the application. 
// 
int APIENTRY WinMain(HANDLE hInstance, HANDLE hPrevInstance, 
    LPSTR lpCmdLine, int nCmdShow) 
{ 
   MSG msg;                                  // holds current message 
   int err; 
 
   hInst = hInstance;                        // save our instance handle 
 
   if (!hPrevInstance)                       // if first instance, 
      if (!InitApp(hInstance))               // register window classes 
      { 
         MessageBox(hFrame, "Can't initialize Finger", szAppName, 
            MB_ICONSTOP | MB_OK); 
         return(FALSE); 
      } 
 
   if (!InitInstance(hInstance, nCmdShow))   // per instance initialization & 
   {                                         // window creation 
      MessageBox(hFrame, "Can't initialize Finger", szAppName, 
         MB_ICONSTOP | MB_OK); 
         return(FALSE); 
   } 
 
   if (err = WSAStartup(WSVERSION, &WSAData))// register task with 
   {                                         // winsock tcp/ip API 
      ReportWSError(err);             
      DestroyWindow(hFrame);                 // kill application window & 
   }                                         // signal app exit 
 
   while (GetMessage(&msg, NULL, 0, 0))      // loop til WM_QUIT 
   { 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
   } 
 
   WSACleanup();                             // disconnect from winsock 
   return msg.wParam;                        // return to windows 
} 
 
// 
// InitApp -- initialization for all instances of application. 
// Registers main window class. 
// 
BOOL InitApp(HANDLE hInstance) 
{ 
   WNDCLASS    wndclass; 
 
   InitNetApp();  // initializes (per application) network module 
 
   wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 
   wndclass.lpfnWndProc   = FrameWndProc; 
   wndclass.cbClsExtra    = 0; 
   wndclass.cbWndExtra    = 0; 
   wndclass.hInstance     = hInstance; 
   wndclass.hIcon         = LoadIcon(hInst, "FingerIcon"); 
   wndclass.hCursor       = NULL; 
   wndclass.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); 
   wndclass.lpszMenuName  = "FingerMenu"; 
   wndclass.lpszClassName = szAppName; 
 
   return(RegisterClass(&wndclass)); 
} 
 
// 
// InitInstance -- initializes this instance of app, and creates windows. 
// 
BOOL InitInstance(HANDLE hInstance, int nCmdShow) 
{ 
   HDC hdc;                            // handle of device context 
   TEXTMETRIC tm;                      // contains font dimensions 
   RECT rect;                          // outer dimensions of window 
 
   hFrame = CreateWindow( szAppName, szAppName, 
               WS_OVERLAPPEDWINDOW | WS_VSCROLL, 
               CW_USEDEFAULT, CW_USEDEFAULT, 
               CW_USEDEFAULT, CW_USEDEFAULT, 
               NULL, NULL, hInstance, NULL); 
 
   if (!hFrame) 
      return(FALSE); 
 
   hCursor = LoadCursor(NULL, IDC_ARROW); 
   hMenu = GetMenu(hFrame); 
 
   InitNetInst(hFrame);  // initialize (per instance) the network module 
 
   // finger servers assume a fixed font 
   hdc = GetDC(hFrame); 
   SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); 
   GetTextMetrics(hdc, &tm); 
   CharY = tm.tmHeight + tm.tmExternalLeading; 
   ReleaseDC(hFrame, hdc); 
 
   // set initial window width & height to 50x10 chars 
   GetWindowRect(hFrame, &rect); 
   MoveWindow( hFrame, rect.left, rect.top, 
               65 * tm.tmAveCharWidth + GetSystemMetrics(SM_CXVSCROLL), 
               10 * CharY + GetSystemMetrics(SM_CYCAPTION) + 
               GetSystemMetrics(SM_CYMENU), FALSE); 
 
   ShowWindow(hFrame, nCmdShow); 
   UpdateWindow(hFrame); 
 
   return(TRUE); 
} 
  
// 
// FrameWndProc -- callback function for application frame (main) window. 
// Decodes message and routes to appropriate message handler. If no handler 
// found, calls DefWindowProc. 
//  
LONG FAR APIENTRY FrameWndProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   int i; 
 
   for (i = 0; i < dim(frameMsgs); i++) 
   { 
      if (wMsg == frameMsgs[i].Code) 
         return(*frameMsgs[i].Fxn)(hWnd, wMsg, wParam, lParam); 
   } 
 
   return(DefWindowProc(hWnd, wMsg, wParam, lParam)); 
} 
 
// 
// DoCommand -- demultiplexes WM_COMMAND messages resulting from menu 
// selections, and routes to corresponding menu item handler.  Sends back 
// any unrecognized messages to windows. 
// 
LONG DoCommand(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   int i; 
 
   for (i = 0; i < dim(menuItems); i++) 
   { 
      if (wParam == menuItems[i].Code) 
         return(*menuItems[i].Fxn)(hWnd, wMsg, wParam, lParam); 
   } 
 
   return(DefWindowProc(hWnd, wMsg, wParam, lParam)); 
} 
 
// 
// DoMenuHost -- handles the "Host..." menu item.  We prompt for a 
// Domain Name System (DNS) host name, or a "dotted IP address" (e.g., 
// 129.216.202.5).  The function invokes NETWRK_ module FingerStart() 
// routine to initiate a conversation with the finger server on the 
// remote host.  NETWRK_, in turn, calls FingerFinish() to signal 
// completion.  Note that the "Host..." menu item is disabled while the 
// finger operation is in progress.  This prevents the user from 
// starting yet another finger before the first is finished; Finger is 
// not designed to process simultaneous requests. 
// 
LONG DoMenuHost(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   FARPROC lpfnProc; 
   int ret; 
 
   // prompt for the host's domain name or ip address 
 
   lpfnProc = MakeProcInstance(HostDlgProc, hInst); 
   ret = DialogBox(hInst, szAppName, hWnd, lpfnProc); 
   FreeProcInstance(lpfnProc); 
 
   if (ret == IDOK && szHostName[0]) 
   { 
      SetCursor(hCursor = LoadCursor(NULL, IDC_WAIT)); 
      EnableMenuItem(hMenu, IDM_HOST, MF_GRAYED); 
      FingerStart(); 
   } 
 
   return(FALSE); 
} 
 
// 
// FingerFinish -- invoked when the finger operation is complete, 
// this function updates the display list & repaints the frame window 
// client area if the operation was successful. 
// 
VOID FingerFinish(UINT Err) 
{ 
   if (!Err) 
   { 
      FreeLineList(pLineItems);                 // dispose old display 
      GetDisplayList(&pLineItems, &nLineItems); // list and get new one 
 
      SetWinCaption();                          // set win title to host name 
      PosView(0);                               // position view to top 
      SetScroll();                              // rescale (or delete) 
      Repaint();                                // scrollbar & force a repaint 
   } 
 
   EnableMenuItem(hMenu, IDM_HOST, MF_ENABLED); 
   SetCursor(hCursor = LoadCursor(NULL, IDC_ARROW)); 
} 
 
// 
// DoMenuExit -- allows close via menu item.  Same as sys menu close. 
// 
LONG DoMenuExit(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   SendMessage(hWnd, WM_CLOSE, 0, 0); 
   return(FALSE); 
} 
 
// 
// DoMenuAbout -- respond to "About..." menu selection by invoking the 
// "About" dialog box. 
// 
LONG DoMenuAbout(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   WNDPROC lpProcAbout; 
 
   lpProcAbout = MakeProcInstance((WNDPROC)AboutDlgProc, hInst); 
   DialogBox(hInst, "AboutBox", hWnd, lpProcAbout); 
   FreeProcInstance(lpProcAbout); 
 
   return(FALSE); 
} 
 
// 
// DoDestroy -- posts a WM_QUIT message to the task's win queue, which 
// causes the main translate & dispatch loop to exit, and the app to 
// terminate. 
// 
LONG DoDestroy(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   PostQuitMessage(0); 
   return(FALSE); 
} 
 
// 
// DoClose -- cleans up display list & tells windows to deallocate 
// our window. 
// 
LONG DoClose(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   FreeLineList(pLineItems); 
   DestroyWindow(hWnd); 
 
   return(FALSE); 
} 
 
// 
// DoActivate -- grabs the keyboard focus whenever our deminimized window 
// is activated.  This is so we can respond to VK_HOME, VK_END, etc. 
// virtual keys for scrolling. HIWORD(lParam) is TRUE for minimized, while 
// LOWORD(wParam) is FALSE for activation message. 
//  
LONG DoActivate(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   if (!HIWORD(lParam) && LOWORD(wParam)) 
      SetFocus(hFrame); 
 
   return FALSE; 
} 
 
// 
// DoMouseMove -- resets the cursor back to the current cursor (either 
// a wait, or normal cursor) because Windows will otherwise redraw it 
// using the window's class. 
// 
LONG DoMouseMove(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   SetCursor(hCursor); 
   return(FALSE); 
} 
 
// 
// PosView -- repositions the view relative to the top of the display list. 
// The view is a logical "window" onto the display list.  The frame window's 
// client area is painted with the view's contents. 
// 
VOID PosView(int nlines) 
{ 
   LINEITEM *pline; 
   int i; 
 
   pline = pLineItems;              // root of LINEITEM list 
 
   for (i = 0; i < nlines; i++) 
   { 
      if (!pline) 
         break; 
      else 
         pline = pline->next; 
   } 
 
   pTopLine = pline;                // ptr to LINEITEM in topmost view line 
   nTopLine =+ nlines;              // offset of topmost view line 
} 
 
// 
// DoPaint -- Paint the client area with the contents of the view. 
// 
LONG DoPaint(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   HDC hdc;                   // scratch device context 
   PAINTSTRUCT ps;            // scratch paint structure 
   LINEITEM *pline;           // pts to topmost displayable LINEITEM 
   int i; 
 
   pline = pTopLine; 
   hdc = BeginPaint(hWnd, &ps); 
 
   for (i = 0; i <= nClientLines; i++) 
   { 
      if (pline) 
      { 
         TextOut(hdc, 0, i * CharY, pline->sztext, pline->len); 
         pline = pline->next; 
      } 
      else 
         break; 
   } 
 
   EndPaint(hWnd, &ps); 
   return(FALSE); 
} 
 
// 
// Repaint -- force refresh of client window. 
//  
VOID Repaint(VOID) 
{ 
   InvalidateRect(hFrame, NULL, TRUE); 
} 
 
// 
// SetScroll -- sets the vertical scroll range to the length of the display 
// list.  The Scrollbar disappears when the list fits within the view. 
// 
VOID SetScroll(VOID) 
{ 
   if (nLineItems > nClientLines) 
      SetScrollRange(hFrame, SB_VERT, 0, nLineItems - nClientLines, FALSE); 
   else 
      SetScrollRange(hFrame, SB_VERT, 0, 0, FALSE); 
  
   SetScrollPos(hFrame, SB_VERT, nTopLine, TRUE); 
} 
 
// number of lines below the bottom of the view. 
#define NLINESBELOW (nLineItems - nTopLine - nClientLines) 
 
// 
// DoVScroll -- process WM_VSCROLL & WM_KEYDOWN for main window. 
// 
LONG DoVScroll(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   switch (LOWORD(wParam)) 
   { 
      case VK_HOME: 
      case SB_TOP: 
         if (nTopLine > 0) 
            RelScroll(hWnd, -nTopLine); 
         break; 
 
      case VK_END: 
      case SB_BOTTOM: 
         if (NLINESBELOW) 
            RelScroll(hWnd, NLINESBELOW); 
         break; 
 
      case VK_PRIOR: 
      case SB_PAGEUP: 
         if (nTopLine > 0) 
            RelScroll(hWnd, max(-nClientLines, -nTopLine)); 
         break; 
 
      case VK_NEXT: 
      case SB_PAGEDOWN: 
         if (NLINESBELOW) 
            RelScroll(hWnd, min(nClientLines, NLINESBELOW)); 
         break; 
 
      case VK_UP: 
      case SB_LINEUP: 
         if (nTopLine > 0) 
            RelScroll(hWnd, -1); 
         break; 
 
      case VK_DOWN: 
      case SB_LINEDOWN: 
         if (NLINESBELOW) 
            RelScroll(hWnd, 1); 
         break; 
 
      case SB_THUMBTRACK: 
         RelScroll(hWnd, THUMBPOS - nTopLine); 
         break; 
   } 
 
   SetScrollPos(hFrame, SB_VERT, nTopLine, TRUE); 
   return(FALSE); 
} 
 
// 
// RelScroll -- scroll up/down nlines from present position 
// 
VOID RelScroll(HWND hWnd, int nlines) 
{ 
   PosView(nTopLine + nlines); 
   ScrollWindow(hWnd, 0, -nlines * CharY, NULL, NULL); 
   UpdateWindow(hWnd); 
} 
 
// 
// DoSize -- respond to WM_SIZE by recalculating the number of text lines 
// in the main window's client area. 
// 
LONG DoSize(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   nClientLines = HIWORD(lParam) / CharY; 
   PosView(0); 
   SetScroll(); 
 
   return(FALSE); 
} 
 
// 
// SetWinCaption -- set the frame window caption according to last 
// host fingered. 
// 
VOID SetWinCaption(VOID) 
{ 
   char szcaption[80]; 
    
   strcpy(szcaption, szAppName); 
   strcat(szcaption, " - "); 
   strcat(szcaption, szHostName); 
 
   SetWindowText(hFrame, szcaption); 
} 
 
// 
// ReportWSError -- prompt user with a windows sockets error message. 
// 
VOID ReportWSError(UINT Err) 
{ 
   int i; 
   char szerr[40]; 
 
   for (i = 0; i < dim(wsErrs); i++) 
   { 
      if (Err == wsErrs[i].err) 
      { 
         MessageBox(hFrame, wsErrs[i].sztext, szAppName, 
            MB_ICONSTOP | MB_OK); 
         return; 
      } 
   } 
 
   wsprintf(szerr, "Windows Sockets reports error %04x", Err); 
   MessageBox(hFrame, szerr, szAppName, MB_ICONSTOP | MB_OK); 
} 
 
// 
// ReportFingerErr -- prompt user with a finger specific error 
// 
VOID ReportFingerErr(UINT Err) 
{ 
   int i; 
 
   for (i = 0; i < dim(finErrs); i++) 
   { 
      if (Err == finErrs[i].err) 
      { 
         MessageBox(hFrame, finErrs[i].sztext, szAppName, 
            MB_ICONSTOP | MB_OK); 
         return; 
      } 
   } 
 
   MessageBox(hFrame, "Unrecognized finger error", szAppName, 
      MB_ICONSTOP | MB_OK); 
} 
 
// 
// HostDlgProc -- dialog box proc for "host dialog". 
// This box queries user for a host name in response to the user's 
// selection of the "Host..." main menu item. 
// 
BOOL APIENTRY HostDlgProc(HWND hDlg, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   switch(wMsg) 
   { 
      case WM_INITDIALOG: 
         SetDlgItemText(hDlg, IDC_HOSTNAME, szHostName); 
         SetDlgItemText(hDlg, IDC_USER, szUser); 
         return TRUE; 
  
      case WM_COMMAND: 
         switch(wParam) 
         { 
            case IDOK: 
               GetDlgItemText(hDlg, IDC_HOSTNAME, szHostName, MAXHOST); 
               GetDlgItemText(hDlg, IDC_USER, szUser, MAXUSER); 
               EndDialog(hDlg, IDOK); 
               return TRUE; 
 
            case IDCANCEL: 
               EndDialog(hDlg, IDCANCEL); 
               return TRUE; 
         } 
         break; 
   } 
 
   return FALSE; 
} 
 
// 
// AboutDlgProc -- callback for the "About" dialog box 
// 
BOOL FAR APIENTRY AboutDlgProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) 
{ 
   if ((wMsg == WM_COMMAND) && (wParam == IDOK))   // dismiss dialog if OK 
      EndDialog(hWnd, 0); 
  
   return(FALSE);                                  // otherwise just sit there 
}