// // 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 }