home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 03 / megaphon / megaphon.c < prev    next >
Text File  |  1991-01-17  |  35KB  |  1,177 lines

  1. /*****************************************************************************
  2.  
  3.     PROGRAM: Megaphone
  4.     AUTHOR : Mike Klein
  5.     VERSION: 1.0
  6.     FILE   : megaphon.exe
  7.     CREATED: 10-25-90
  8.  
  9.     REQUIREMENTS: Windows 3.x and a Novell NetWare 2.1x or compatible network
  10.  
  11.     PURPOSE     : Messaging and simple information system for Novell NetWare.
  12.                   Allows quick replies to messages from coworkers and
  13.                         miscellaneous login information about them.
  14.  
  15. *****************************************************************************/
  16.  
  17.  
  18. #define NOCOMM                                                                                      
  19.  
  20.  
  21. #include <windows.h>
  22. #include <direct.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <time.h>
  26.  
  27. #include <nwbindry.h>
  28. #include <nwconn.h>
  29. #include <nwdir.h>
  30. #include <nwmsg.h>
  31. #include <nwwrkenv.h>
  32.  
  33. #include "megaphon.h"
  34.  
  35.  
  36. HANDLE hInstMegaphone;          /* Original instance of Megaphone           */
  37.  
  38. /* These are handles to commonly accessed controls in different dialogs     */
  39.  
  40. HWND hWndCurrent;        /* handle to currently active window on screen     */
  41. HWND hDlgMegaphone;      /* handle to Megaphone dialog window               */
  42. HWND hWndUserListBox;
  43. HWND hWndServerComboBox;
  44. HWND hWndMessageEditBox;
  45. HWND hWndSendButton;
  46.  
  47. /* Set up some additional global variables to commonly used NetWare stuff   */
  48.  
  49. WORD DefaultConnectionID;
  50. BYTE ServerName[48];
  51.  
  52. WORD UserConnectionNum;
  53. BYTE UserName[48];
  54. BYTE UserLoginTime[7];
  55.  
  56. WORD SelUserConnectionNum;
  57. BYTE SelUserNetworkAddr[4];
  58. BYTE SelUserNodeAddr[6];
  59. BYTE SelUserName[48];
  60. BYTE SelUserFullName[48];
  61. BYTE SelUserLoginTime[7];
  62.  
  63. BOOL AcceptMessages = TRUE;
  64. BOOL IconizeMessages = FALSE;
  65. BOOL AllUsers = FALSE;
  66.  
  67. BYTE Text[100];
  68.  
  69.  
  70. /*****************************************************************************
  71.  
  72.     FUNCTION: WinMain
  73.  
  74.     PURPOSE : Calls initialization function, processes message loop
  75.  
  76. *****************************************************************************/
  77.  
  78. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine,
  79.     int nCmdShow)
  80. {
  81.     WNDCLASS wc;
  82.     MSG      msg;
  83.  
  84.     if(!hPrevInstance)                    /* Other instances of app running? */
  85.     {
  86.         hInstMegaphone = hInstance;        /* Remember original instance      */
  87.  
  88.         /* Fill in window class structure with parameters that describe the   */
  89.         /* main window.                                                       */
  90.  
  91.         wc.style         = CS_DBLCLKS;     /* Process double click msgs       */
  92.         wc.lpfnWndProc   = MainWndProc;    /* Function to retrieve msgs for   */
  93.                                          /* windows of this class.          */
  94.         wc.cbClsExtra    = 0;              /* No per-class extra data.        */
  95.         wc.cbWndExtra    = DLGWINDOWEXTRA; /* Set becuase we used the CLASS   */
  96.                                          /* statement in dialog box         */
  97.         wc.hInstance     = hInstance;      /* Application that owns the class.*/
  98.         wc.hIcon         = LoadIcon(hInstance, "Megaphone");
  99.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  100.         wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  101.         wc.lpszMenuName  = "Megaphone";
  102.         wc.lpszClassName = "Megaphone";
  103.  
  104.         if(!RegisterClass(&wc))
  105.             return(FALSE);
  106.  
  107.         /* Fill in window class structure with parameters that describe the   */
  108.         /* message window.                                                    */
  109.  
  110.         wc.style         = NULL;           /* Process double click msgs       */
  111.         wc.lpfnWndProc   = MessageHandler;
  112.         wc.cbClsExtra    = 0;              /* No per-class extra data.        */
  113.         wc.cbWndExtra    = DLGWINDOWEXTRA; /* Set becuase we used the CLASS   */
  114.                                          /* statement in dialog box         */
  115.         wc.hInstance     = hInstance;      /* Application that owns the class.*/
  116.         wc.hIcon         = LoadIcon(hInstance, "Message");
  117.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  118.         wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  119.         wc.lpszMenuName  = NULL;
  120.         wc.lpszClassName = "Message";
  121.  
  122.         if(!RegisterClass(&wc))
  123.             return(FALSE);
  124.  
  125.         /* Fill in window class structure with parameters that describe the   */
  126.         /* userinfo window.                                                   */
  127.  
  128.         wc.style         = NULL;           /* Process double click msgs       */
  129.         wc.lpfnWndProc   = UserInfo;
  130.         wc.cbClsExtra    = 0;              /* No per-class extra data.        */
  131.         wc.cbWndExtra    = DLGWINDOWEXTRA; /* Set becuase we used the CLASS   */
  132.                                          /* statement in dialog box         */
  133.         wc.hInstance     = hInstance;      /* Application that owns the class.*/
  134.         wc.hIcon         = LoadIcon(hInstance, "User");
  135.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  136.         wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  137.         wc.lpszMenuName  = NULL;
  138.         wc.lpszClassName = "User";
  139.  
  140.         if(!RegisterClass(&wc))
  141.             return(FALSE);
  142.  
  143.         /* Create the main dialog window Megaphone, get window handles to     */
  144.         /* several of the controls, send the message edit box a message to    */
  145.         /* limit itself to MAX_MESSAGE_LEN characters, and set the system     */
  146.         /* font (mono-spaced) for server combo box and user list box.         */
  147.  
  148.         hDlgMegaphone = CreateDialog(hInstance, "Megaphone", NULL, 0L);
  149.  
  150.         hWndUserListBox     = GetDlgItem(hDlgMegaphone, IDC_USERLISTBOX);
  151.         hWndServerComboBox  = GetDlgItem(hDlgMegaphone, IDC_SERVERCOMBOBOX);
  152.         hWndMessageEditBox  = GetDlgItem(hDlgMegaphone, IDC_MESSAGEEDITBOX);
  153.         hWndSendButton      = GetDlgItem(hDlgMegaphone, IDC_SENDBUTTON);
  154.  
  155.         SendMessage(hWndMessageEditBox, EM_LIMITTEXT, MAX_MESSAGE_LEN - 1, 0L);
  156.         SendMessage(hWndUserListBox, WM_SETFONT,
  157.             GetStockObject(SYSTEM_FIXED_FONT), FALSE);
  158.         SendMessage(hWndServerComboBox, WM_SETFONT,
  159.             GetStockObject(SYSTEM_FIXED_FONT), FALSE);
  160.  
  161.         /* Finally, show the Megaphone dialog box                             */
  162.  
  163.         ShowWindow(hDlgMegaphone, nCmdShow);
  164.         UpdateWindow(hDlgMegaphone);
  165.  
  166.         /* Initialize the network stuff, and fill in list boxes               */
  167.  
  168.         InitNetStuff();
  169.     }
  170.     else
  171.     {
  172.         /* If there was another instance of Megaphone running, then switch to */
  173.         /* it by finding any window of class = "Megaphone". Then, if it's an  */
  174.         /* icon, open the window, otherwise just make it active.              */
  175.  
  176.         hDlgMegaphone = FindWindow("Megaphone", NULL);
  177.         if(IsIconic(hDlgMegaphone))
  178.             ShowWindow(hDlgMegaphone, SW_SHOWNORMAL);
  179.         SetActiveWindow(hDlgMegaphone);
  180.  
  181.         return(FALSE);
  182.     }
  183.  
  184.     /* Acquire and dispatch messages until a WM_QUIT message is received.    */
  185.     /* The window handle hWndCurrent points to the currently active window,  */
  186.     /* and is used to identify and process keystrokes going to any modeless  */
  187.     /* dialog box.                                                           */
  188.  
  189.     while(GetMessage(&msg, NULL, NULL, NULL))
  190.         if(hWndCurrent == NULL || !IsDialogMessage(hWndCurrent, &msg))
  191.         {
  192.             TranslateMessage(&msg);
  193.             DispatchMessage(&msg);
  194.         }
  195. }
  196.  
  197.  
  198. /*****************************************************************************
  199.  
  200.     FUNCTION: MainWndProc
  201.  
  202.     PURPOSE :  Processes messages for Megaphone dialog box
  203.  
  204. *****************************************************************************/
  205.  
  206. long FAR PASCAL MainWndProc(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  207. {
  208.     FARPROC lpProc;            /* Far procedure ptr to be used for About box */
  209.  
  210.     HWND    hWndTemp;
  211.     HWND    hDlgMessage;
  212.  
  213.     BYTE *ptr;
  214.     int  Index = 100;
  215.  
  216.     BYTE MessageCaption[100];
  217.     BYTE MessageDate[9];
  218.     BYTE MessageTime[9];
  219.  
  220.     switch(wMsg)
  221.     {
  222.         case WM_COMMAND              :
  223.  
  224.             switch(wParam)
  225.             {
  226.                 /* When wParam == 1, return was pressed in either the list box, */
  227.                 /* combo box, check boxes, or edit control.                     */
  228.  
  229.                 case 1                  :
  230.  
  231.                     /* Find out the current control (window) and process ENTER   */
  232.                     /* key accordingly.                                          */
  233.  
  234.                     switch(GetDlgCtrlID(GetFocus()))
  235.                     {
  236.                         case IDC_USERLISTBOX    :
  237.  
  238.                             ShowUserInformation();
  239.                             break;
  240.  
  241.                         case IDC_SERVERCOMBOBOX :
  242.  
  243.                             SendMessage(hWndServerComboBox, WM_KILLFOCUS, NULL, 0L);
  244.                             SendMessage(hWndServerComboBox, WM_SETFOCUS, NULL, 0L);
  245.                             break;
  246.  
  247.                         case IDC_MESSAGEEDITBOX :
  248.  
  249.                             if(IsWindowEnabled(hWndSendButton))
  250.                             {
  251.                                 SendMessage(hWndSendButton, WM_LBUTTONDOWN, 0, 0L);
  252.                                 SendMessage(hWndSendButton, WM_LBUTTONUP, 0, 0L);
  253.                                 SendMessage(hDlgMegaphone, WM_NEXTDLGCTL,
  254.                                     hWndMessageEditBox, TRUE);
  255.                             }
  256.                             else
  257.                             {
  258.                                 MessageBeep(0);
  259.                                 MessageBox(hDlgMegaphone, "You need a message and a user(s)",
  260.                                     "ERROR", MB_ICONEXCLAMATION | MB_OK);
  261.                             }
  262.                             break;
  263.  
  264.                         default                 :
  265.  
  266.                             break;
  267.                     }
  268.                     break;
  269.  
  270.                 case IDC_USERLISTBOX         :
  271.  
  272.                     if(HIWORD(lParam) == LBN_DBLCLK)
  273.                     {
  274.                         /* Restore the list box item's selection state. If it     */
  275.                         /* isn't flagged, then flag it, and vice versa.           */
  276.  
  277.                         Index = (int) SendMessage(hWndUserListBox, LB_GETCURSEL, 0, 0L);
  278.                         if(SendMessage(hWndUserListBox, LB_GETSEL, Index, 0L))
  279.                             SendMessage(hWndUserListBox, LB_SETSEL, FALSE, Index);
  280.                         else
  281.                             SendMessage(hWndUserListBox, LB_SETSEL, TRUE, Index);
  282.  
  283.                         ShowUserInformation();
  284.                     }
  285.                     else
  286.                         EnableOrDisableSendButton();
  287.  
  288.                     break;
  289.  
  290.                 case IDC_SERVERCOMBOBOX      :
  291.  
  292.                     if(HIWORD(lParam) == CBN_SELCHANGE)
  293.                     {
  294.                         if((Index = (int) SendMessage(hWndServerComboBox, CB_GETCURSEL,
  295.                             0, 0L)) == CB_ERR)
  296.                             break;
  297.  
  298.                         SendMessage(hWndServerComboBox, CB_GETLBTEXT, Index,
  299.                             (LONG) (LPSTR) ServerName);
  300.  
  301.                         if(!GetConnectionID(ServerName, &DefaultConnectionID))
  302.                         {
  303.                             SetPreferredConnectionID(DefaultConnectionID);
  304.                             InitNetStuff();
  305.                         }
  306.                     }
  307.                     break;
  308.  
  309.                 case IDC_MESSAGEEDITBOX      :
  310.  
  311.                     EnableOrDisableSendButton();
  312.                     break;
  313.  
  314.                 case IDC_SENDBUTTON          :
  315.  
  316.                     if(HIWORD(lParam) == BN_CLICKED)
  317.                         SendNetWareMessageToUsers();
  318.                     break;
  319.  
  320.                 case IDM_EXIT                :
  321.                 case IDC_EXITBUTTON          :
  322.  
  323.                     SendMessage(hDlgMegaphone, WM_CLOSE, 0, 0L);
  324.                     break;
  325.  
  326.                 case IDM_ABOUT               :
  327.  
  328.                     lpProc = MakeProcInstance(About, hInstMegaphone);
  329.                     DialogBox(hInstMegaphone, "About", hWnd, lpProc);
  330.                     FreeProcInstance(lpProc);
  331.                     break;
  332.  
  333.                 case IDM_REFRESH             :
  334.  
  335.                     InitNetStuff();
  336.                     break;
  337.  
  338.                 case IDC_SETTINGSBUTTON      :
  339.  
  340.                     lpProc = MakeProcInstance(Settings, hInstMegaphone);
  341.                     DialogBox(hInstMegaphone, "Settings", hWnd, lpProc);
  342.                     FreeProcInstance(lpProc);
  343.                     break;
  344.  
  345.                 default                      :
  346.  
  347.                     break;
  348.             }
  349.  
  350.             break;
  351.  
  352.         case WM_TIMER                :
  353.  
  354.             /* This is the Windows timer for retrieving messages that goes off */
  355.             /* every five seconds.                                             */
  356.  
  357.             GetBroadcastMessage(Text);
  358.  
  359.             if(*Text)
  360.             {
  361.                 /* Create the message reply dialog box and limit the edit box   */
  362.                 /* to NetWare's limit of 56 or so characters.                   */
  363.  
  364.                 hDlgMessage = CreateDialog(hInstMegaphone, "Message",
  365.                     hDlgMegaphone, 0L);
  366.  
  367.                 SendDlgItemMessage(hDlgMessage, IDC_REPLYEDITBOX, EM_LIMITTEXT,
  368.                     MAX_MESSAGE_LEN - 1, 0L);
  369.  
  370.                 /* Parse the incoming string of 'username[station#]message'     */
  371.  
  372.                 if((ptr = strchr(Text, '[')) == NULL)
  373.                 {
  374.                     /* If the incoming message isn't formatted by NetWare's      */
  375.                     /* SEND command, SESSION program, or Megaphone, then we      */
  376.                     /* can't use the REPLY button, so disable it.                */
  377.  
  378.                     SelUserName[0] = '\0';
  379.                     SelUserConnectionNum = 0;
  380.                     EnableWindow(GetDlgItem(hDlgMessage, IDC_REPLYBUTTON), FALSE);
  381.                 }
  382.                 else
  383.                 {
  384.                     /* Pull up the user name and connection#, and message, which */
  385.                     /* is right after the ']'.                                   */
  386.  
  387.                     strncpy(SelUserName, Text, ptr - Text);
  388.                     SelUserName[ptr - Text] = '\0';
  389.                     SelUserConnectionNum = atoi(ptr + 1);
  390.                     if((ptr = strchr(Text, ']')) != NULL)
  391.                         lstrcpy((LPSTR) Text, (LPSTR) (ptr + 1));
  392.  
  393.                     /* Check again to see if we pulled up a valid Conn#. If we   */
  394.                     /* didn't, then disable the REPLY button.                    */
  395.  
  396.                     if(SelUserConnectionNum < 1 || SelUserConnectionNum > 255)
  397.                         EnableWindow(GetDlgItem(hDlgMessage, IDC_REPLYBUTTON), FALSE);
  398.                 }
  399.  
  400.                 /* Put the retrieved message in the dialog's edit box           */
  401.                 
  402.                 SetDlgItemText(hDlgMessage, IDC_REPLYEDITBOX, Text);
  403.  
  404.                 /* Record the date and time that the message came in at and     */
  405.                 /* make it reflected in the message caption.                    */
  406.  
  407.                 _strdate(MessageDate);
  408.                 _strtime(MessageTime);
  409.                 wsprintf(MessageCaption, "%s %s %s", (LPSTR) SelUserName,
  410.                     (LPSTR) MessageDate, (LPSTR) MessageTime);
  411.                 SetWindowText(hDlgMessage, MessageCaption);
  412.  
  413.                 /* Finally, show (or minimize) the completed message dialog box */
  414.                 
  415.                 if(IconizeMessages)
  416.                     ShowWindow(hDlgMessage, SW_SHOWMINNOACTIVE);
  417.                 else
  418.                     ShowWindow(hDlgMessage, SW_SHOWNORMAL);
  419.  
  420.                 MessageBeep(0);
  421.             }
  422.  
  423.             return(0L);
  424.  
  425.         case WM_CLOSE                :
  426.  
  427.             /* Check before closing the main window if there are any           */
  428.             /* outstanding messages that haven't been closed.                  */
  429.  
  430.             if(hWndTemp = FindWindow((LPSTR) "Message", NULL))
  431.             {
  432.                 if(MessageBox(hDlgMegaphone,
  433.                     "Quit without disposing of/reading messages?",
  434.                     "Messages Outstanding", MB_YESNO | MB_APPLMODAL |
  435.                     MB_ICONEXCLAMATION | MB_DEFBUTTON2) == IDYES)
  436.                 {
  437.                     DestroyWindow(hDlgMegaphone);
  438.                 }
  439.                 else
  440.                 {
  441.                     ShowWindow(hWndTemp, SW_SHOWNORMAL);
  442.                     SetActiveWindow(hWndTemp);
  443.                 }
  444.             }
  445.             else
  446.                 DestroyWindow(hDlgMegaphone);
  447.  
  448.             return(0L);
  449.  
  450.         case WM_SETFOCUS             :
  451.  
  452.             if(IsWindowEnabled(hWndMessageEditBox))
  453.                 SendMessage(hDlgMegaphone, WM_NEXTDLGCTL, hWndMessageEditBox, TRUE);
  454.             else
  455.                 SendMessage(hDlgMegaphone, WM_NEXTDLGCTL,
  456.                     GetDlgItem(hDlgMegaphone, IDC_EXITBUTTON), TRUE);
  457.  
  458.             return(0L);
  459.  
  460.         case WM_ACTIVATE             :
  461.  
  462.             hWndCurrent = (wParam == NULL) ? NULL : hWnd;
  463.             break;
  464.  
  465.         case WM_DESTROY              :
  466.  
  467.             PostQuitMessage(0);
  468.             return(0L);
  469.  
  470.         default                      :
  471.  
  472.             break;
  473.  
  474.     }
  475.     return(DefDlgProc(hWnd, wMsg, wParam, lParam));
  476. }
  477.  
  478.  
  479. /*****************************************************************************
  480.  
  481.     FUNCTION: SendNetWareMessageToUsers
  482.  
  483.     PURPOSE : Do I really need to explain this one?
  484.  
  485. *****************************************************************************/
  486.  
  487. VOID PASCAL SendNetWareMessageToUsers(VOID)
  488. {
  489.     BYTE Message[MAX_MESSAGE_LEN];
  490.     WORD ConnectionsToSend[MAX_CONNECTIONS];
  491.     BYTE ResultList[MAX_CONNECTIONS];
  492.     int  NumUsers;
  493.     int  i, j;
  494.  
  495.     /* Get text inside message edit box and format message so it includes    */
  496.     /* the username, connection#, and message. The first two fields are      */
  497.     /* needed for replying back since there's nothing in NetWare's messaging */
  498.     /* facility to tell you who sent the message.                            */
  499.  
  500.     GetDlgItemText(hDlgMegaphone, IDC_MESSAGEEDITBOX, (LPSTR) Text, MAX_MESSAGE_LEN);
  501.  
  502.     wsprintf(Message, "%s[%d]%s", (LPSTR) UserName, UserConnectionNum,
  503.         (LPSTR) Text);
  504.  
  505.     /* Get total number of users in list box and check to see if they've     */
  506.     /* been selected or not. If they have, get their Connection# and put it  */
  507.     /* in the ConnectionsToSend array.                                       */
  508.  
  509.     NumUsers = (int) SendMessage(hWndUserListBox, LB_GETCOUNT, 0, 0L);
  510.     
  511.     for(i = j = 0; i < NumUsers; i++)
  512.         if(SendMessage(hWndUserListBox, LB_GETSEL, i, 0L))
  513.         {
  514.             SendMessage(hWndUserListBox, LB_GETTEXT, i, (LONG) (LPSTR) Text);
  515.             ConnectionsToSend[j++] = atoi(&Text[18]);
  516.         }
  517.  
  518.     /* Send the message to users in the array.                               */
  519.  
  520.     SendBroadcastMessage(Message, ConnectionsToSend, ResultList, j);
  521.  
  522.     /* Scan through the ResultList array checking for messages that had      */
  523.     /* problems. Selecting OK will continue to check the status of the other */
  524.     /* messages, where selecting CANCEL from the message box will abort the  */
  525.     /* send status checking altogether.                                      */
  526.  
  527.     for(i = 0; i < j; i++)
  528.         switch(ResultList[i])
  529.         {
  530.             case 0xfc :
  531.  
  532.                 wsprintf(Text, "Message to Connection %d", ConnectionsToSend[i]);
  533.                 if(MessageBox(hDlgMegaphone,
  534.                     "Message not sent - User already has message pending",
  535.                     Text, MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
  536.                 {
  537.                     i = j;
  538.                 }
  539.                 break;
  540.  
  541.             case 0xfd :
  542.  
  543.                 wsprintf(Text, "Message to Connection %d", ConnectionsToSend[i]);
  544.                 if(MessageBox(hDlgMegaphone,
  545.                     "Message not sent - Invalid connection number",
  546.                     Text, MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
  547.                 {
  548.                     i = j;
  549.                 }
  550.                 break;
  551.  
  552.             case 0xff :
  553.  
  554.                 wsprintf(Text, "Message to Connection %d", ConnectionsToSend[i]);
  555.                 if(MessageBox(hDlgMegaphone,
  556.                     "Message not sent - User has blocking turned on",
  557.                     Text, MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
  558.                 {
  559.                     i = j;
  560.                 }
  561.                 break;
  562.  
  563.             default   :
  564.  
  565.                 break;
  566.         }
  567. }
  568.  
  569.  
  570. /*****************************************************************************
  571.  
  572.     FUNCTION: EnableOrDisableSendButton
  573.  
  574.     PURPOSE : Based on a message being in the edit box and at least one
  575.               selected user, the send button is enabled or disabled
  576.  
  577. *****************************************************************************/
  578.  
  579. VOID PASCAL EnableOrDisableSendButton(VOID)
  580. {
  581.     /* Check to see if at least one user is selected and at least a one      */
  582.     /* character message in the edit box. If there is, then enable the SEND  */
  583.     /* button and thicken it to make it the default response when ENTER is   */
  584.     /* pressed.                                                              */
  585.  
  586.     if(SendMessage(hWndUserListBox, LB_GETSELCOUNT, 0, 0L) &&
  587.         SendMessage(hWndMessageEditBox, EM_LINELENGTH, -1, 0L))
  588.     {
  589.         EnableWindow(hWndSendButton, TRUE);
  590.     }
  591.     else
  592.     {
  593.         EnableWindow(hWndSendButton, FALSE);
  594.     }
  595. }
  596.  
  597.  
  598. /*****************************************************************************
  599.  
  600.     FUNCTION: InitNetStuff
  601.  
  602.     PURPOSE : Initialize network connections and fill in combo and list boxes
  603.  
  604. *****************************************************************************/
  605.  
  606. BOOL PASCAL InitNetStuff(VOID)
  607. {
  608.     HCURSOR hOldCursor;
  609.  
  610.     WORD NumberOfConnections;
  611.     WORD NumberOfServers;
  612.  
  613.     int  Index;
  614.     BYTE DirHandle;
  615.  
  616.     BYTE TempServerName[48];
  617.     WORD ObjectType;
  618.     WORD ConnID;
  619.     WORD ConnectionList[MAX_CONNECTIONS];
  620.     BYTE SearchObjectName[48] = "*";
  621.     BYTE ObjectName[48];
  622.     long ObjectID;
  623.     BYTE ObjectHasProperties;
  624.     BYTE ObjectFlag;
  625.     BYTE ObjectSecurity;
  626.  
  627.     /* Check to see if a connection has been made to any server              */
  628.  
  629.     if(UserConnectionNum = GetConnectionNumber())
  630.         if(!GetConnectionInformation(UserConnectionNum, UserName, &ObjectType,
  631.             &ObjectID, UserLoginTime))
  632.             if(*UserName)
  633.             {
  634.                 /* If we have a preferred connection ID, then were supposed to  */
  635.                 /* use it for all of our requests. If we don't, then check to   */
  636.                 /* see if we're sitting on a local drive (bit 0 or 1 not set).  */
  637.                 /* If we are, then set the default connection ID to that of the */
  638.                 /* primary server. If we're sitting on a network drive, then    */
  639.                 /* requests go to the associated server.                        */
  640.  
  641.                 if(GetPreferredConnectionID())
  642.                     DefaultConnectionID = GetPreferredConnectionID();
  643.                 else
  644.                 {
  645.                     if(!(GetDriveInformation((BYTE) (_getdrive() - 1), &ConnID,
  646.                         &DirHandle) & 3))
  647.                     {
  648.                         DefaultConnectionID = GetPrimaryConnectionID();
  649.                     }
  650.                     SetPreferredConnectionID(DefaultConnectionID);
  651.                 }
  652.  
  653.                 /* Set NetWare's message mode so that Megaphone can poll for       */
  654.                 /* messages instead of automatically having them sent to the       */
  655.                 /* station.                                                        */
  656.                 
  657.                 EnableBroadcasts();
  658.                 SetBroadcastMode(3);
  659.  
  660.                 /* Set up a Windows timer so that every 5 seconds, the server is   */
  661.                 /* polled for waiting messages.                                    */
  662.  
  663.                 SetTimer(hDlgMegaphone, IDT_MESSAGETIMER, 5000, NULL);
  664.  
  665.                 EnableWindow(GetDlgItem(hDlgMegaphone, IDC_SETTINGSBUTTON), TRUE);
  666.             }
  667.  
  668.     if(!UserConnectionNum)
  669.     {
  670.         EnableWindow(GetDlgItem(hDlgMegaphone, IDC_SETTINGSBUTTON), FALSE);
  671.         MessageBox(hDlgMegaphone, "Must be logged into a NetWare server",
  672.             "ERROR - NO USERS", MB_ICONSTOP | MB_OK);
  673.         return(FALSE);
  674.     }
  675.  
  676.     /* Now that we've established a network connection, let's fill in the    */
  677.     /* drop-down combo box with file servers and the list box with users of  */
  678.     /* whatever the node's preferred server is.                              */
  679.  
  680.     /* Turn off re-drawing of the list box so it doesn't flicker, reset the  */
  681.     /* contents of both boxes, capture and intercept all mouse activity, and */
  682.     /* turn the cursor into an hourglass.                                    */
  683.  
  684.     SendMessage(hWndUserListBox, WM_SETREDRAW, FALSE, 0L);
  685.     SendMessage(hWndUserListBox, LB_RESETCONTENT, 0, 0L);
  686.     SendMessage(hWndServerComboBox, CB_RESETCONTENT, 0, 0L);
  687.     SetCapture(hDlgMegaphone);
  688.     hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  689.  
  690.     /* Scan through the possible ConnectionID#'s (1-8) and see what file     */
  691.     /* servers are attached, if any are, and put them in the combo box.      */
  692.  
  693.     for(ConnID = 1; ConnID < 9; ++ConnID)
  694.     {
  695.         GetFileServerName(ConnID, TempServerName);
  696.         if(*TempServerName)
  697.             SendMessage(hWndServerComboBox, CB_ADDSTRING, NULL,
  698.                 (LONG) (LPSTR) TempServerName);
  699.     }
  700.  
  701.     /* Get default server                                                    */
  702.  
  703.     GetFileServerName(DefaultConnectionID, ServerName);
  704.  
  705.     /* Search the NetWare bindery for active user connections, putting       */
  706.     /* them into the list box                                                */
  707.  
  708.     ObjectID = -1;
  709.     while(!ScanBinderyObject(SearchObjectName, OT_USER, &ObjectID, ObjectName,
  710.         &ObjectType, &ObjectHasProperties, &ObjectFlag, &ObjectSecurity))
  711.     {
  712.         GetObjectConnectionNumbers(ObjectName, OT_USER, &NumberOfConnections,
  713.             ConnectionList, MAX_CONNECTIONS);
  714.  
  715.         /* If there are multiple connections for a single user then we        */
  716.         /* have to make sure and get all of them.                             */
  717.  
  718.         if(!NumberOfConnections)
  719.         {
  720.             if(AllUsers)
  721.             {
  722.                 wsprintf(Text, "[%s]", (LPSTR) ObjectName);
  723.                 SendMessage(hWndUserListBox, LB_ADDSTRING, NULL, (LONG) (LPSTR) Text);
  724.             }
  725.         }
  726.         else
  727.             for(Index = 0; Index < (int) NumberOfConnections; ++Index)
  728.             {
  729.                 if(UserConnectionNum == ConnectionList[Index])
  730.                     wsprintf(Text, "%-16.16s *%3d", (LPSTR) ObjectName, ConnectionList[Index]);
  731.                 else
  732.                     wsprintf(Text, "%-17.17s %3d", (LPSTR) ObjectName, ConnectionList[Index]);
  733.                 SendMessage(hWndUserListBox, LB_ADDSTRING, NULL, (LONG) (LPSTR) Text);
  734.             }
  735.     }
  736.  
  737.     /* Turn re-drawing for the list box back on and make the first item in   */
  738.     /* the server combo box and user list box the default.                   */
  739.  
  740.     InvalidateRect(hWndUserListBox, NULL, TRUE);
  741.     SendMessage(hWndUserListBox, LB_SETSEL, 0, 0L);
  742.     SendMessage(hWndUserListBox, WM_SETREDRAW, TRUE, 0L);
  743.  
  744.     /* Select the default server in the server combo box                     */
  745.  
  746.     SendMessage(hWndServerComboBox, CB_SELECTSTRING, -1, (LONG) (LPSTR) ServerName);
  747.  
  748.     /* Add the # of servers and users to the caption on the server and list  */
  749.     /* boxes.                                                                */
  750.  
  751.     NumberOfConnections = (int) SendMessage(hWndUserListBox,    LB_GETCOUNT, 0, 0L);
  752.     wsprintf(Text, "%d &Users on %s", NumberOfConnections, (LPSTR) ServerName);
  753.     SetDlgItemText(hDlgMegaphone, IDC_USERLISTBOXTITLE, (LPSTR) Text);
  754.  
  755.     NumberOfServers = (int) SendMessage(hWndServerComboBox, CB_GETCOUNT, 0, 0L);
  756.     wsprintf(Text, "%d Ser&vers", NumberOfServers);
  757.     SetDlgItemText(hDlgMegaphone, IDC_SERVERCOMBOBOXTITLE, (LPSTR) Text);
  758.  
  759.     /* Restore mouse activity, set the cursor back to normal, and initially  */
  760.     /* disable the Send button.                                              */
  761.  
  762.     ReleaseCapture();
  763.     SetCursor(hOldCursor);
  764.     EnableOrDisableSendButton();
  765.  
  766.     return(TRUE);
  767. }
  768.  
  769.  
  770. /*****************************************************************************
  771.  
  772.     FUNCTION: About
  773.  
  774.     PURPOSE : Processes messages for About box
  775.  
  776. *****************************************************************************/
  777.  
  778. BOOL FAR PASCAL About(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  779. {
  780.     switch(wMsg)
  781.     {
  782.         case WM_INITDIALOG :
  783.  
  784.             return(TRUE);
  785.  
  786.         case WM_COMMAND    :
  787.  
  788.             if(wParam == IDOK || wParam == IDCANCEL)
  789.             {
  790.                 EndDialog(hWnd, TRUE);
  791.                 return(TRUE);
  792.             }
  793.             break;
  794.  
  795.         default            :
  796.  
  797.             break;
  798.     }
  799.     return(FALSE);
  800. }
  801.  
  802.  
  803. /*****************************************************************************
  804.  
  805.     FUNCTION: Settings
  806.  
  807.     PURPOSE : Processes messages for Settings window
  808.  
  809. *****************************************************************************/
  810.  
  811. BOOL FAR PASCAL Settings(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  812. {
  813.     switch(wMsg)
  814.     {
  815.         case WM_INITDIALOG :
  816.  
  817.             CheckDlgButton(hWnd, IDC_ACCEPTMESSAGES, AcceptMessages);
  818.             CheckDlgButton(hWnd, IDC_ICONIZEMESSAGES, IconizeMessages);
  819.  
  820.             if(AllUsers)
  821.                 CheckRadioButton(hWnd, IDC_ALLUSERSINBINDERY,
  822.                     IDC_ALLUSERSINBINDERY, IDC_ALLUSERSINBINDERY);
  823.             else
  824.                 CheckRadioButton(hWnd, IDC_ONLYATTACHEDUSERS,
  825.                     IDC_ONLYATTACHEDUSERS, IDC_ONLYATTACHEDUSERS);
  826.  
  827.             break;
  828.  
  829.         case WM_COMMAND    :
  830.  
  831.             switch(wParam)
  832.             {
  833.                  case IDC_ACCEPTMESSAGES    :
  834.  
  835.                     if(IsDlgButtonChecked(hWnd, IDC_ACCEPTMESSAGES))
  836.                     {
  837.                         EnableBroadcasts();
  838.                         SetTimer(hDlgMegaphone, IDT_MESSAGETIMER, 5000, NULL);
  839.                         AcceptMessages = TRUE;
  840.                     }
  841.                     else
  842.                     {
  843.                         DisableBroadcasts();
  844.                         KillTimer(hDlgMegaphone, IDT_MESSAGETIMER);
  845.                         AcceptMessages = FALSE;
  846.                     }
  847.  
  848.                     break;
  849.  
  850.                 case IDC_ICONIZEMESSAGES    :
  851.  
  852.                     if(IsDlgButtonChecked(hWnd, IDC_ICONIZEMESSAGES))
  853.                         IconizeMessages = TRUE;
  854.                     else
  855.                         IconizeMessages = FALSE;
  856.  
  857.                     break;
  858.  
  859.                 case IDC_ONLYATTACHEDUSERS :
  860.  
  861.                     AllUsers = FALSE;
  862.                     InitNetStuff();
  863.                     break;
  864.  
  865.                 case IDC_ALLUSERSINBINDERY :
  866.  
  867.                     AllUsers = TRUE;
  868.                     InitNetStuff();
  869.                     break;
  870.  
  871.                 case IDOK                  :
  872.                 case IDCANCEL              :
  873.  
  874.                     EndDialog(hWnd, TRUE);
  875.                     return(TRUE);
  876.  
  877.                 default            :
  878.  
  879.                     break;
  880.             }
  881.     }
  882.     return(FALSE);
  883. }
  884.  
  885.  
  886. /*****************************************************************************
  887.  
  888.     FUNCTION: MessageHandler
  889.  
  890.     PURPOSE : Processes messages for user message dialog box/window
  891.  
  892. *****************************************************************************/
  893.  
  894. long FAR PASCAL MessageHandler(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  895. {
  896.     BYTE Message[MAX_MESSAGE_LEN];
  897.     WORD ConnectionsToSend[1];
  898.     BYTE ResultList[1];
  899.  
  900.     switch(wMsg)
  901.     {
  902.         case WM_COMMAND  :
  903.  
  904.             switch(wParam)
  905.             {
  906.                 case 1               :
  907.  
  908.                     /* A '1' is generated when ENTER is pressed while in a       */
  909.                     /* control in a dialog box and there's no default button     */
  910.                     /* defined. This is to trap the ENTER key when in the reply  */
  911.                     /* edit box. We'll simulate the pressing of the REPLY button */
  912.  
  913.                     if(IsWindowEnabled(GetDlgItem(hWnd, IDC_REPLYBUTTON)))
  914.                     {
  915.                         SendMessage(GetDlgItem(hWnd, IDC_REPLYBUTTON),
  916.                             WM_LBUTTONDOWN, 0, 0L);
  917.                         SendMessage(GetDlgItem(hWnd, IDC_REPLYBUTTON),
  918.                             WM_LBUTTONUP, 0, 0L);
  919.                     }
  920.                     else
  921.                     {
  922.                         MessageBeep(0);
  923.                         MessageBox(hWnd, "You cannot reply to this message",
  924.                             "ERROR", MB_ICONEXCLAMATION | MB_OK);
  925.                     }
  926.                     break;
  927.  
  928.                 case IDC_SAVEBUTTON  :
  929.  
  930.                     /* "Save" the message by iconizing it                        */
  931.  
  932.                     CloseWindow(hWnd);
  933.                     break;
  934.  
  935.                 case IDC_REPLYBUTTON :
  936.  
  937.                     /* Get text from edit box located in message dialog box      */
  938.  
  939.                     GetDlgItemText(hWnd, IDC_REPLYEDITBOX, (LPSTR) Text,
  940.                         MAX_MESSAGE_LEN);
  941.  
  942.                     /* Set up my connection# to send to, format the message, and */
  943.                     /* send it to the user.                                      */
  944.  
  945.                     ConnectionsToSend[0] = SelUserConnectionNum;
  946.                     wsprintf(Message, "%s[%d]%s", (LPSTR) SelUserName,
  947.                         SelUserConnectionNum, (LPSTR) Text);
  948.  
  949.                     SendBroadcastMessage(Message, ConnectionsToSend, ResultList, 1);
  950.  
  951.                     /* Possible results of sending a message                     */
  952.  
  953.                     switch(ResultList[0])
  954.                     {
  955.                         case 0xfc :
  956.  
  957.                             wsprintf(Text, "Message to Connection %d",
  958.                                 ConnectionsToSend[0]);
  959.                             MessageBox(hDlgMegaphone,
  960.                                 "Message not sent - User already has message pending",
  961.                                 Text, MB_OK | MB_ICONEXCLAMATION);
  962.                             break;
  963.  
  964.                         case 0xfd :
  965.  
  966.                             wsprintf(Text, "Message to Connection %d",
  967.                                 ConnectionsToSend[0]);
  968.                             MessageBox(hDlgMegaphone,
  969.                                 "Message not sent - Invalid connection number",
  970.                                 Text, MB_OK | MB_ICONEXCLAMATION);
  971.     
  972.                             break;
  973.  
  974.                         case 0xff :
  975.     
  976.                             wsprintf(Text, "Message to Connection %d",
  977.                                 ConnectionsToSend[0]);
  978.                             MessageBox(hDlgMegaphone,
  979.                                 "Message not sent - User has blocking turned on",
  980.                                 Text, MB_OK | MB_ICONEXCLAMATION);
  981.     
  982.                             break;
  983.  
  984.                         default   :
  985.  
  986.                             break;
  987.                     }
  988.  
  989.                     /* Get rid of the message reply dialog box/window            */
  990.  
  991.                     DestroyWindow(hWnd);
  992.                     return(0L);
  993.  
  994.                 case IDCANCEL        :
  995.  
  996.                     DestroyWindow(hWnd);
  997.                     return(0L);
  998.  
  999.                 default              :
  1000.  
  1001.                     break;
  1002.             }
  1003.             break;
  1004.  
  1005.         case WM_CLOSE         :
  1006.  
  1007.             DestroyWindow(hWnd);
  1008.             return(0L);
  1009.  
  1010.         case WM_SETFOCUS      :
  1011.  
  1012.             /* Set the focus to the edit control.                              */
  1013.  
  1014.             SendMessage(hWnd, WM_NEXTDLGCTL, GetDlgItem(hWnd, IDC_REPLYEDITBOX),
  1015.                 TRUE);
  1016.  
  1017.             return(0L);
  1018.  
  1019.         case WM_ACTIVATE      :
  1020.  
  1021.             hWndCurrent = (wParam == NULL) ? NULL : hWnd;
  1022.             break;
  1023.  
  1024.         default          :
  1025.  
  1026.             break;
  1027.     }
  1028.     return(DefDlgProc(hWnd, wMsg, wParam, lParam));
  1029. }
  1030.  
  1031.  
  1032. /*****************************************************************************
  1033.  
  1034.     FUNCTION: ShowUserInformation
  1035.  
  1036.     PURPOSE : Shows user information on current or double-clicked entry
  1037.  
  1038. *****************************************************************************/
  1039.  
  1040. VOID PASCAL ShowUserInformation(VOID)
  1041. {
  1042.     int Index;
  1043.     BYTE *ptr;
  1044.  
  1045.     HWND hDlgUserInfo;
  1046.  
  1047.     WORD ObjectType;
  1048.     long ObjectID;
  1049.     WORD SocketNum;
  1050.     BYTE PropertyValue[128];
  1051.     BYTE MoreSegments;
  1052.     BYTE PropertyFlags;
  1053.  
  1054.     /* Get an index to the user name underneath the cursor,   */
  1055.     /* and then get the user's connection number so we can    */
  1056.     /* retrieve NetWare information on him/her.               */
  1057.  
  1058.     Index = (int) SendMessage(hWndUserListBox, LB_GETCURSEL, 0, 0L);
  1059.     SendMessage(hWndUserListBox, LB_GETTEXT, Index, (LONG) (LPSTR) Text);
  1060.  
  1061.     /* If entry in list box doesn't have a connection #, then we need to get */
  1062.     /* the login name by parsing the list box string, we can't use a call to */
  1063.     /* GetConnectionInformation().                                           */
  1064.  
  1065.     memset(SelUserLoginTime, '\0', 7);
  1066.     memset(SelUserNetworkAddr, '\0', 4);
  1067.     memset(SelUserNodeAddr, '\0', 6);
  1068.     SelUserFullName[0] = '\0';
  1069.     SelUserConnectionNum = 0;
  1070.  
  1071.     if(Text[0] == '[')
  1072.     {
  1073.         ptr = strchr(Text, ']');
  1074.         strncpy(SelUserName, Text + 1, ptr - Text - 1);
  1075.         SelUserName[ptr - Text - 1] = '\0';
  1076.     }
  1077.     else
  1078.     {
  1079.         ptr = strchr(Text, ' ');
  1080.         strncpy(SelUserName, Text, ptr - Text);
  1081.         SelUserConnectionNum = atoi(&Text[18]);
  1082.         SelUserName[ptr - Text] = '\0';
  1083.  
  1084.         /* We can get connection info only for users that are logged in to a  */
  1085.         /* server. So, get the user name and login time, network and node     */
  1086.         /* address, and full name for specified connection#.                  */
  1087.  
  1088.         GetConnectionInformation(SelUserConnectionNum, SelUserName, &ObjectType,
  1089.             &ObjectID, SelUserLoginTime);
  1090.  
  1091.         GetInternetAddress(SelUserConnectionNum, SelUserNetworkAddr,
  1092.             SelUserNodeAddr, &SocketNum);
  1093.     }
  1094.  
  1095.     if(!ReadPropertyValue(SelUserName, OT_USER, "IDENTIFICATION", 1,
  1096.         PropertyValue, &MoreSegments, &PropertyFlags))
  1097.     {
  1098.         wsprintf(SelUserFullName, "%s", (LPSTR) PropertyValue);
  1099.     }
  1100.  
  1101.     /* Create userinfo dialog box and change caption to the   */
  1102.     /* user's login name.                                     */
  1103.  
  1104.     hDlgUserInfo = CreateDialog(hInstMegaphone, "UserInfo", hDlgMegaphone, 0L);
  1105.     SetWindowText(hDlgUserInfo, SelUserName);
  1106.  
  1107.     /* Initialize the user info dialog box by changing */
  1108.     /* the values of different static text fields to   */
  1109.     /* reflect acquired user information               */
  1110.  
  1111.     wsprintf(Text, ": %s", (LPSTR) SelUserName);
  1112.     SetDlgItemText(hDlgUserInfo, IDC_USERNAME, (LPSTR) Text);
  1113.  
  1114.     wsprintf(Text, ": %d", SelUserConnectionNum);
  1115.     SetDlgItemText(hDlgUserInfo, IDC_STATION, (LPSTR) Text);
  1116.  
  1117.     wsprintf(Text, ": %s", (LPSTR) SelUserFullName);
  1118.     SetDlgItemText(hDlgUserInfo, IDC_FULLNAME, (LPSTR) Text);
  1119.  
  1120.     wsprintf(Text, ": %02d/%02d/%02d %02d:%02d:%02d",
  1121.         SelUserLoginTime[1], SelUserLoginTime[2], SelUserLoginTime[0],
  1122.         SelUserLoginTime[3], SelUserLoginTime[4], SelUserLoginTime[5]);
  1123.     SetDlgItemText(hDlgUserInfo, IDC_LOGINTIME, (LPSTR) Text);
  1124.  
  1125.     wsprintf(Text, ": %02X%02X%02X%02X",
  1126.         SelUserNetworkAddr[0], SelUserNetworkAddr[1],
  1127.         SelUserNetworkAddr[2], SelUserNetworkAddr[3]);
  1128.     SetDlgItemText(hDlgUserInfo, IDC_NETWORK, (LPSTR) Text);
  1129.  
  1130.     wsprintf(Text, ": %02X%02X%02X%02X%02X%02X",
  1131.         SelUserNodeAddr[0], SelUserNodeAddr[1], SelUserNodeAddr[2],
  1132.         SelUserNodeAddr[3], SelUserNodeAddr[4], SelUserNodeAddr[5]);
  1133.     SetDlgItemText(hDlgUserInfo, IDC_NODE, (LPSTR) Text);
  1134.  
  1135.     ShowWindow(hDlgUserInfo, SW_SHOWNORMAL);
  1136. }
  1137.  
  1138.  
  1139. /*****************************************************************************
  1140.  
  1141.     FUNCTION: UserInfo
  1142.  
  1143.     PURPOSE : Processes messages for user info box
  1144.  
  1145. *****************************************************************************/
  1146.  
  1147. long FAR PASCAL UserInfo(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  1148. {
  1149.     switch(wMsg)
  1150.     {
  1151.         case WM_COMMAND :
  1152.  
  1153.             if(wParam == IDOK || wParam == IDCANCEL)
  1154.             {
  1155.                 DestroyWindow(hWnd);
  1156.                 return(0L);
  1157.             }
  1158.             break;
  1159.  
  1160.         case WM_CLOSE   :
  1161.  
  1162.             DestroyWindow(hWnd);
  1163.             return(0L);
  1164.  
  1165.         case WM_ACTIVATE      :
  1166.  
  1167.             hWndCurrent = (wParam == NULL) ? NULL : hWnd;
  1168.             break;
  1169.  
  1170.         default         :
  1171.  
  1172.             break;
  1173.     }
  1174.     return(DefDlgProc(hWnd, wMsg, wParam, lParam));
  1175. }
  1176.  
  1177.