home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / winsock / globchat / server / globchat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  29.4 KB  |  855 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1997  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   generic.c
  9. //
  10. //  PURPOSE:   Implement the windows procedure for the main application
  11. //    windows.  Also implement the generic message and command dispatchers.
  12. //
  13. //  FUNCTIONS:
  14. //    WndProc      - Processes messages for the main window.
  15. //    MsgCreate    - Handles the WM_CREATE message.  Sets up Display and
  16. //                   initializes listening sockets.  Also advertises the 
  17. //                   service
  18. //    MsgSize      - Resizes the Listboxes to fit nicely in main window.
  19. //    MsgTimer     - Handles the WM_TIMER messages which alert us to the
  20. //                   fact that its time to send a SAP packet
  21. //    MsgConnected - Handles new connection notifications
  22. //    MsgDataready - Handles recv data notifications and close socket
  23. //                   notifications
  24. //    MsgCommand   - Handle the WM_COMMAND messages for the main window.
  25. //    MsgDestroy   - Handles the WM_DESTROY message by calling
  26. //                   PostQuitMessage().
  27. //    CmdExit      - Handles the file exit command by calling destory
  28. //                   window on the main window.
  29. //
  30. //  COMMENTS:
  31. //
  32.  
  33. #include <windows.h>            // required for all Windows applications
  34. #include <windowsx.h>
  35. #include <wsipx.h>
  36. #include <wsnetbs.h>
  37. #include <svcguid.h>
  38. #include "globals.h"            // prototypes specific to this application
  39.  
  40.  
  41. // Main window message table definition.
  42. MSD rgmsd[] =
  43. {
  44.     {WM_CREATE,    MsgCreate},
  45.     {WM_SIZE,      MsgSize},
  46.     {WM_TIMER,     MsgTimer},
  47.     {WM_COMMAND,   MsgCommand},
  48.     {WM_DESTROY,   MsgDestroy},
  49.     {MW_CONNECTED, MsgConnected},
  50.     {MW_DATAREADY, MsgDataready}
  51. };
  52.  
  53. MSDI msdiMain =
  54. {
  55.     sizeof(rgmsd) / sizeof(MSD),
  56.     rgmsd,
  57.     edwpWindow
  58. };
  59.  
  60.  
  61. // Main window command table definition.
  62. CMD rgcmd[] =
  63. {
  64.     {IDM_EXIT,  CmdExit},
  65.     {IDM_ABOUT, CmdAbout}
  66. };
  67.  
  68. CMDI cmdiMain =
  69. {
  70.     sizeof(rgcmd) / sizeof(CMD),
  71.     rgcmd,
  72.     edwpWindow
  73. };
  74.  
  75.  
  76. //
  77. //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
  78. //
  79. //  PURPOSE:  Processes messages for the main window.
  80. //
  81. //  PARAMETERS:
  82. //    hwnd     - window handle
  83. //    uMessage - message number
  84. //    wparam   - additional information (dependant on message number)
  85. //    lparam   - additional information (dependant on message number)
  86. //
  87. //  RETURN VALUE:
  88. //    The return value depends on the message number.  If the message
  89. //    is implemented in the message dispatch table, the return value is
  90. //    the value returned by the message handling function.  Otherwise,
  91. //    the return value is the value returned by the default window procedure.
  92. //
  93. //  COMMENTS:
  94. //    Call the DispMessage() function with the main window's message dispatch
  95. //    information (msdiMain) and the message specific information.
  96. //
  97.  
  98. LRESULT CALLBACK WndProc(HWND   hwnd,
  99.                          UINT   uMessage,
  100.                          WPARAM wparam,
  101.                          LPARAM lparam)
  102. {
  103.     return DispMessage(&msdiMain, hwnd, uMessage, wparam, lparam);
  104. }
  105.  
  106. //
  107. //  FUNCTION: MsgCreate(HWND, UINT, WPARAM, LPARAM)
  108. //
  109. //  PURPOSE:  Sets up child windows, initializes listening sockets, and advertises
  110. //            the existence of the service
  111. //
  112. //  PARAMETERS:
  113. //
  114. //    hwnd      - Window handle
  115. //    uMessage  - Message number (Unused)
  116. //    wparam    - Extra data     (Unused)
  117. //    lparam    - Extra data     (Unused)
  118. //
  119. //  RETURN VALUE:
  120. //
  121. //    Always returns 0 - Message handled
  122. //
  123. //  COMMENTS:
  124. //
  125. //
  126.  
  127. LRESULT MsgCreate(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  128. {
  129.     int sizeProtBuf = 0; 
  130.     int cNumProt;
  131.     int j, k;
  132.     int GoodProts[40];
  133.     WORD wVersionRequested;
  134.     WSADATA wsaData;
  135.     char outtext[80];
  136.     int tabwidth[1] = {100};
  137.     BOOL bcaststat;
  138.     int addrlen;
  139.  
  140.     // Create Protocol listbox
  141.     hwndProtocolList = CreateWindow("LISTBOX",
  142.                                     NULL,
  143.                                     WS_BORDER | WS_CHILD | WS_VISIBLE | LBS_STANDARD | LBS_USETABSTOPS,
  144.                                     0, 0, 0, 0,
  145.                                     hwnd,
  146.                                     (HMENU)ID_PROTOCOLBOX,
  147.                                     (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),
  148.                                     0);
  149.     // Set tabs
  150.     SendMessage(hwndProtocolList, LB_SETTABSTOPS, 1, (LPARAM)tabwidth);
  151.  
  152.     // Create Client List listbox
  153.     hwndClientList = CreateWindow("LISTBOX",
  154.                                   NULL,
  155.                                   WS_BORDER | WS_CHILD | WS_VISIBLE | LBS_STANDARD | LBS_USETABSTOPS | LBS_HASSTRINGS,
  156.                                   0, 0, 0, 0,
  157.                                   hwnd,
  158.                                   (HMENU)ID_CLIENTBOX,
  159.                                   (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),
  160.                                   0);
  161.     // Set tab stops
  162.     SendMessage(hwndClientList, LB_SETTABSTOPS, 1, (LPARAM)tabwidth);
  163.  
  164.     // First allocate Connected Sockets Heap
  165.     if((ConnectHeap = HeapCreate(0, sizeof(SOCKDATA) * 5, sizeof(SOCKDATA) * 100)) == NULL)
  166.     {
  167.         // ERROR - abort
  168.         return 0;
  169.     }
  170.     if(((LPVOID)ConnectedSockets = HeapAlloc(ConnectHeap,0, sizeof(SOCKDATA) * 5)) == NULL)
  171.     {
  172.         // ERROR - abort
  173.         return 0;
  174.     }
  175.     NextFree = 0;  // First available SOCKDATA struct
  176.     MaxConnects = 5; // Allocate only 5 structures at a time
  177.  
  178.     // Load winsock dll
  179.     wVersionRequested = MAKEWORD(1, 1);
  180.     if (WSAStartup(wVersionRequested, &wsaData) != 0)
  181.     {
  182.         // ERROR -abort
  183.         return 0;
  184.     }
  185.  
  186.     // Determine size of buffer needed
  187.     if (EnumProtocols(NULL, NULL, &sizeProtBuf) != SOCKET_ERROR)
  188.     {
  189.         // ERROR
  190.         return 0;
  191.     }
  192.  
  193.     // Allocate buffer of appropriate size
  194.     if (((LPVOID)lpProtBuf = VirtualAlloc(NULL,
  195.                                           sizeProtBuf,
  196.                                           MEM_COMMIT,
  197.                                           PAGE_READWRITE)) == NULL)
  198.     {
  199.         // ERROR
  200.         return 0;
  201.     }
  202.  
  203.     // Do the real EnumProtocols call--note that there is no GETNEXT mechanism here.
  204.     // We have to allocate a single buffer big enough to hold everything.
  205.     if ((cNumProt = EnumProtocols(NULL, lpProtBuf, &sizeProtBuf)) == SOCKET_ERROR)
  206.     {
  207.         // ERROR
  208.         return 0;
  209.     }
  210.  
  211.     // Now that we know how many protocols we have, allocate array of globchat
  212.     // SOCKDATA structures to hold info on each.
  213.     if (((LPVOID)ServerSockets = VirtualAlloc(NULL,
  214.                                               cNumProt * sizeof(SOCKDATA),
  215.                                               MEM_COMMIT,
  216.                                               PAGE_READWRITE)) == NULL)
  217.     {
  218.         // ERROR
  219.         return 0;
  220.     }
  221.  
  222.     // Walk through available protocols, j is index to list of all protocols, k is index to list of
  223.     // protocols we can use.
  224.     for (j = 0, k = 0; j < cNumProt; j++)
  225.     {
  226.         // Only want connection oriented protocols
  227.         if((lpProtBuf[j].dwServiceFlags & XP_CONNECTIONLESS) == 0)  
  228.         {
  229.             // Attempt to setup listen and fill in SOCKDATA struct
  230.             if (MakeServSock(hwnd, &ServerSockets[k], &lpProtBuf[j]))
  231.             {
  232.                 // Successfully using protocol...add it to our list box
  233.                 wsprintf(outtext, "%s\t%d", ServerSockets[k].lpProtocolName, ServerSockets[k].currconnects);
  234.                 SendMessage(hwndProtocolList, LB_ADDSTRING, 0, (LPARAM)&outtext);
  235.  
  236.                 // Found a good protocol!
  237.                 GoodProts[k++] = j;
  238.             }
  239.         }
  240.     }
  241.  
  242.     cNumProt = k;  // Number of good protocols
  243.  
  244.  
  245.  
  246.  
  247.     // Register with Name Spaces
  248.  
  249.     // In the future this will be done transparently, but for now must do it
  250.     // manually for specific protocols.  The only NSPs we have are DNS and SAP.
  251.     // Since DNS is static, that just leaves us with SAP to do.
  252.  
  253.     
  254.     if((SAPSocket = socket(AF_IPX,                // IPX family
  255.                            SOCK_DGRAM,               // SAPs are broadcasted
  256.                            NSPROTO_IPX + 4)          // Uses IPX packet type 4
  257.                            ) != INVALID_SOCKET)
  258.     {
  259.         // Find IPX address which we are bound to
  260.         for(k = 0;k < cNumProt; k++)
  261.         {
  262.             if(ServerSockets[k].protocol == NSPROTO_SPXII)
  263.             {
  264.                 // Initialize SAP data
  265.                 SAPData.operation = 0x200;         // 2 = SAP response(network order)
  266.                 SAPData.servicetype = 0x5607;  // 0756 Assigned by Novell specifically for GLOBCHAT only!!!!
  267.                 strcpy(SAPData.name, "GLOBCHAT");  // My service name
  268.                 memcpy((void *)SAPData.network,    // Copy address into SAP body
  269.                        (void *)(ServerSockets[k].addr.sa_data), 
  270.                        12);
  271.                 SAPData.hops = 0;                 // Hop count starts at zero
  272.  
  273.                 SAPSockAddr.sa_family = AF_IPX;   // SAP packets sent over IPX
  274.                 AtoH((char *)&SAPSockAddr.sa_socket, "0452", 2);  // SAP destination socket address is 0452.
  275.             
  276.                 // Bind to SAP socket
  277.                 if (bind(SAPSocket, (PSOCKADDR) &SAPSockAddr, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR)
  278.                 {
  279.                     // Error binding to SAP socket
  280.                     return 0;
  281.                 }
  282.                 else
  283.                 {
  284.                     // build destination address for SAP's IPX header (broadcast)
  285.                     SAPDestSockAddr.sa_family = AF_IPX;
  286.                     AtoH("00000000",SAPDestSockAddr.sa_netnum, 4);
  287.                     AtoH("FFFFFFFFFFFF", SAPDestSockAddr.sa_nodenum, 6);
  288.                     AtoH("0452", (char *)&SAPDestSockAddr.sa_socket, 2);
  289.  
  290.                     // Setup socket to allow broadcasts
  291.                     bcaststat = TRUE;
  292.                     addrlen = sizeof(bcaststat);
  293.                     setsockopt(SAPSocket, SOL_SOCKET, SO_BROADCAST, (char *)&bcaststat, sizeof(bcaststat));
  294.                     sendto(SAPSocket, (char *)&SAPData, sizeof(SAPData), MSG_DONTROUTE, (struct sockaddr *)&SAPDestSockAddr, sizeof(SAPDestSockAddr));
  295.  
  296.                     // Set timer to remind us to send SAP packet every 60 seconds.
  297.                     SetTimer(hwnd, SAPTIMER, 60000, NULL);
  298.                 }
  299.                 break;
  300.             }
  301.         }
  302.     }
  303.     return 0;
  304. }
  305.  
  306. //
  307. //  FUNCTION: MsgSize(HWND, UINT, WPARAM, LPARAM)
  308. //
  309. //  PURPOSE:  Resizes child listboxes to fit nicely within parent
  310. //
  311. //  PARAMETERS:
  312. //
  313. //    hwnd      - Window handle
  314. //    uMessage  - Message number (Unused)
  315. //    wparam    - Extra data     (Unused)
  316. //    lparam    - Window dimensions
  317. //
  318. //  RETURN VALUE:
  319. //
  320. //    Always returns 0 - Message handled
  321. //
  322. //  COMMENTS:
  323. //
  324. //
  325.  
  326. LRESULT MsgSize(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  327. {
  328.     MoveWindow(hwndProtocolList,
  329.                1, (HIWORD(lparam) / 4),
  330.                (LOWORD(lparam) / 2),
  331.                (HIWORD(lparam) * 3) / 4,
  332.                TRUE);
  333.  
  334.     MoveWindow(hwndClientList,
  335.                LOWORD(lparam) /2,
  336.                HIWORD(lparam) / 4,
  337.                LOWORD(lparam) / 2,
  338.                (HIWORD(lparam) * 3) / 4,
  339.                TRUE);
  340.     return 0;
  341. }
  342.  
  343. //
  344. //  FUNCTION: MsgTimer(HWND, UINT, WPARAM, LPARAM)
  345. //
  346. //  PURPOSE: Sends out SAP packet every 60 seconds
  347. //
  348. //  PARAMETERS:
  349. //
  350. //    hwnd      - Window handle
  351. //    uMessage  - Message number (Unused)
  352. //    wparam    - Should be = SAPTIMER
  353. //    lparam    - Extra data     (Unused)
  354. //
  355. //  RETURN VALUE:
  356. //
  357. //    Always returns 0 - Message handled
  358. //
  359. //  COMMENTS:
  360. //
  361. //
  362.  
  363. LRESULT MsgTimer(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  364. {
  365.     sendto(SAPSocket, (char *) &SAPData, sizeof(SAPData), MSG_DONTROUTE, (struct sockaddr *)&SAPDestSockAddr, sizeof(SAPDestSockAddr));
  366.     return 0;
  367. }
  368.  
  369. //
  370. //  FUNCTION: MsgConnected(HWND, UINT, WPARAM, LPARAM)
  371. //
  372. //  PURPOSE: Handles new connection notifications
  373. //
  374. //  PARAMETERS:
  375. //
  376. //    hwnd      - Window handle
  377. //    uMessage  - Message number (Unused)
  378. //    wparam    - socket which has the connection
  379. //    lparam    - loword = event, hiword = error code
  380. //
  381. //  RETURN VALUE:
  382. //
  383. //    Always returns 0 - Message handled
  384. //
  385. //  COMMENTS:
  386. //
  387. //
  388.  
  389. LRESULT MsgConnected(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  390. {
  391.     int k, addrlen;
  392.     int index;
  393.     char outtext[80];
  394.  
  395.     // May have to increase our heap size
  396.     if(NextFree >= MaxConnects)
  397.     {
  398.         if(HeapAlloc(ConnectHeap, 0, sizeof(SOCKDATA) * 5) == NULL)
  399.         {
  400.            // ERROR on heap allocation...don't accept new connections
  401.            return 0;
  402.         }
  403.         MaxConnects += 5;  // We've got five more connect entries available
  404.     }
  405.  
  406.     // find socket that connect is refering to
  407.     k = 0;
  408.     while(ServerSockets[k].sock != wparam) k++;
  409.  
  410.     // Lets keep track of our progress
  411.     ServerSockets[k].status = SOCKSTAT_ACCEPTING;
  412.  
  413.     // Some address our bigger than a sockaddr struct.  I threw in some reserved bytes to cover it.
  414.     addrlen = sizeof(ConnectedSockets[NextFree].addr) + sizeof(ConnectedSockets[NextFree].reserved);
  415.  
  416.     // Accept the connect request
  417.     if ((ConnectedSockets[NextFree].sock = accept(ServerSockets[k].sock,
  418.                                                  &ConnectedSockets[NextFree].addr,
  419.                                                  &addrlen)) == INVALID_SOCKET)
  420.     {
  421.         // ERROR clean up ConnectedSockets (that is don't increment NextFree) and go on our way
  422.         return 0;
  423.     }
  424.     if(WSAAsyncSelect(ConnectedSockets[NextFree].sock, hwnd, MW_DATAREADY, FD_READ | FD_CLOSE) == SOCKET_ERROR)
  425.     {
  426.         // ERROR clean up connection
  427.         closesocket(ConnectedSockets[NextFree].sock);
  428.         return 0;
  429.     }
  430.     // Fill in SOCKDATA structure for client socket
  431.     ConnectedSockets[NextFree].protocol = ServerSockets[k].protocol;
  432.     ConnectedSockets[NextFree].type = ServerSockets[k].type;
  433.     ConnectedSockets[NextFree].servsockindex = k;
  434.     ConnectedSockets[NextFree++].status = SOCKSTAT_CONNECTED;
  435.     // Increment protocol connection count and display
  436.     ServerSockets[k].currconnects ++;
  437.     index = SendMessage(hwndProtocolList, LB_FINDSTRING, (WPARAM)-1, (LPARAM)ServerSockets[k].lpProtocolName);
  438.     SendMessage(hwndProtocolList, LB_DELETESTRING, index, 0);
  439.     wsprintf(outtext, "%s\t%d", ServerSockets[k].lpProtocolName, ServerSockets[k].currconnects);
  440.     SendMessage(hwndProtocolList, LB_ADDSTRING, 0, (LPARAM)&outtext);
  441.  
  442.     // Don't forget to set server socket status back to listening
  443.     ServerSockets[k].status = SOCKSTAT_LISTENING;
  444.  
  445.     return 0;
  446. }
  447.  
  448. //
  449. //  FUNCTION: MsgDataready(HWND, UINT, WPARAM, LPARAM)
  450. //
  451. //  PURPOSE: Handles incoming socket data notifications and close socket
  452. //           notifications
  453. //
  454. //  PARAMETERS:
  455. //
  456. //    hwnd      - Window handle
  457. //    uMessage  - Message number
  458. //    wparam    - socket which has the data
  459. //    lparam    - loword = event, hiword = error code
  460. //
  461. //  RETURN VALUE:
  462. //
  463. //    Always returns 0 - Message handled
  464. //
  465. //  COMMENTS:
  466. //
  467. //
  468.  
  469. LRESULT MsgDataready(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  470. {
  471.     int k, j, l;
  472.     int totalbytesread;
  473.     int index;
  474.     char outtext[80];
  475.  
  476.     // Find the appropriate socket...allow for the reuse of a closed socket handle
  477.     for (k = 0; k < NextFree; k++)
  478.     {
  479.         if((ConnectedSockets[k].sock == wparam) && (ConnectedSockets[k].status != SOCKSTAT_CLOSED))
  480.             break;
  481.     }
  482.  
  483.     if(LOWORD(lparam) == FD_CLOSE)
  484.     {
  485.         // Socket closed notification--cleanup!
  486.         closesocket(ConnectedSockets[k].sock);
  487.  
  488.         // Delete name from client list display
  489.         UpdateClientList(ConnectedSockets[k].name, SOCKSTAT_CLOSED, NULL);
  490.  
  491.         // Take name off of other clients' available list
  492.         if (ConnectedSockets[k].status == SOCKSTAT_AVAILABLE)
  493.         {
  494.             deregistername(ConnectedSockets[k].name);
  495.         }
  496.  
  497.         // if this connection was in session with another peer...notify peer of disconnect
  498.  
  499.         // First, find peer
  500.         for (j = 0; j < NextFree; j++)
  501.         {
  502.             if((ConnectedSockets[j].sock == ConnectedSockets[k].peer) &&
  503.                (ConnectedSockets[j].status == SOCKSTAT_INSESSION))
  504.             {
  505.                 break;
  506.             }
  507.         }
  508.         if (j < NextFree)  // Did we find a peer?
  509.         {
  510.             // Yes, build message header
  511.             xferbuf.hdr.signature = MYSIGNATURE;
  512.             xferbuf.hdr.length = totalbytesread = HDRSIZE;
  513.             xferbuf.hdr.command = SESSION_CLOSE;
  514.             // Send session close message
  515.             senddatamessage(ConnectedSockets[j].sock, &xferbuf);
  516.             // Update Peer's displayed status
  517.             ConnectedSockets[j].status = SOCKSTAT_AVAILABLE;
  518.             UpdateClientList(ConnectedSockets[j].name, SOCKSTAT_AVAILABLE, NULL);
  519.             // Propagate the fact that the peer is now available for other chats
  520.             // and give peer list of other available clients
  521.             for (l = 0; l < NextFree; l++)
  522.             {
  523.                 if ((l != j) && (ConnectedSockets[l].status == SOCKSTAT_AVAILABLE))
  524.                 {
  525.                     xferbuf.hdr.command = REGISTER_NAME;
  526.                     lstrcpy(xferbuf.data, ConnectedSockets[l].name);
  527.                     xferbuf.hdr.length = REALLEN(ConnectedSockets[l].name) + HDRSIZE;
  528.                     senddatamessage(ConnectedSockets[j].sock, &xferbuf);
  529.  
  530.                     lstrcpy(xferbuf.data, ConnectedSockets[j].name);
  531.                     xferbuf.hdr.length = REALLEN(ConnectedSockets[j].name) + HDRSIZE;
  532.                     senddatamessage(ConnectedSockets[l].sock, &xferbuf);
  533.                 }
  534.             }
  535.         }
  536.         // Cleanup ConnectedSockets array
  537.         ConnectedSockets[k].status = SOCKSTAT_CLOSED;
  538.         j = ConnectedSockets[k].servsockindex;
  539.         // Fix protocol connection count display
  540.         ServerSockets[j].currconnects --;
  541.         index = SendMessage(hwndProtocolList, LB_FINDSTRING, (WPARAM)-1, (LPARAM)ServerSockets[j].lpProtocolName);
  542.         SendMessage(hwndProtocolList, LB_DELETESTRING, index, 0);
  543.         wsprintf(outtext, "%s\t%d", ServerSockets[j].lpProtocolName, ServerSockets[j].currconnects);
  544.         SendMessage(hwndProtocolList, LB_ADDSTRING, 0, (LPARAM)&outtext);
  545.         return 0;
  546.     }
  547.  
  548.     // There's data to read...read it!
  549.  
  550.     if(!recvdatamessage(&ConnectedSockets[k], &xferbuf))
  551.     {
  552.         return 0;
  553.     }
  554.  
  555.     // We've got our whole message!  Now switch() on the command flag
  556.  
  557.     switch(xferbuf.hdr.command)
  558.     {
  559.         case REGISTER_NAME:  // First message we should receive on a connection
  560.             if(ConnectedSockets[k].status != SOCKSTAT_CONNECTED)
  561.             {
  562.                 // ERROR -- we weren't expecting this...drop it
  563.                 return 0;
  564.             }
  565.             // Get name and add to internal structs and display
  566.             lstrcpy(ConnectedSockets[k].name, xferbuf.data);
  567.             ConnectedSockets[k].status = SOCKSTAT_AVAILABLE;
  568.             UpdateClientList(ConnectedSockets[k].name, SOCKSTAT_AVAILABLE, NULL);
  569.  
  570.             // Send notification to other "AVAILABLE" sockets that we have a new peer available
  571.             for (j = 0; j < NextFree; j++)
  572.             {
  573.                 if((j != k) && (ConnectedSockets[j].status == SOCKSTAT_AVAILABLE))
  574.                 {
  575.                     // message in xferbuf should be able to be sent just like it is
  576.                     senddatamessage(ConnectedSockets[j].sock, &xferbuf);
  577.                 }
  578.             }
  579.  
  580.             // Send notifications back to registering peer of all the currently available peers
  581.  
  582.             for (j = 0; j < NextFree; j++)
  583.             {
  584.                 if((j != k) && (ConnectedSockets[j].status == SOCKSTAT_AVAILABLE))
  585.                 {
  586.                     // found one...build message and send it
  587.                     xferbuf.hdr.signature = MYSIGNATURE;
  588.                     xferbuf.hdr.length = REALLEN(ConnectedSockets[j].name) + HDRSIZE;
  589.                     xferbuf.hdr.command = REGISTER_NAME;
  590.                     lstrcpy(xferbuf.data, ConnectedSockets[j].name);
  591.                     senddatamessage(ConnectedSockets[k].sock, &xferbuf);
  592.                 }
  593.             }
  594.  
  595.             return 0;
  596.  
  597.         case XFER_DATA:   // For passing data between two insession peers
  598.             if(ConnectedSockets[k].status != SOCKSTAT_INSESSION)
  599.             {
  600.                 // ERROR -- we weren't expecting this...drop data
  601.                 return 0;
  602.             }
  603.  
  604.             // forward the message to peer...should be able transfer
  605.             // message without modification
  606.             senddatamessage(ConnectedSockets[k].peer, &xferbuf);
  607.             return 0;
  608.  
  609.         case REQUEST_SESSION:  // Client is asking another peer for a chat
  610.             if(ConnectedSockets[k].status != SOCKSTAT_AVAILABLE)
  611.             {
  612.                 // ERROR -- we weren't expecting this...drop data
  613.                 return 0;
  614.             }
  615.  
  616.             ConnectedSockets[k].status = SOCKSTAT_REQSESSION;
  617.             UpdateClientList(ConnectedSockets[k].name, SOCKSTAT_REQSESSION, xferbuf.data);
  618.  
  619.             // Find the socket which corresponds to the name
  620.  
  621.             for(j = 0; j < NextFree; j++)
  622.             {
  623.                 if(lstrcmp(ConnectedSockets[j].name, xferbuf.data) == 0)
  624.                 {
  625.                     if(ConnectedSockets[j].status == SOCKSTAT_AVAILABLE)
  626.                     {
  627.                         // Found It!
  628.                         break;
  629.                     }
  630.                 }
  631.             }
  632.  
  633.             if (j == NextFree) return 0;
  634.  
  635.             // Copy requester's name into send data buffer
  636.             lstrcpy(xferbuf.data, ConnectedSockets[k].name);
  637.             xferbuf.hdr.length = HDRSIZE + REALLEN(ConnectedSockets[k].name);
  638.             senddatamessage(ConnectedSockets[j].sock, &xferbuf);
  639.  
  640.             // Update connected sockets structures
  641.             ConnectedSockets[j].status = SOCKSTAT_REQSESSION;
  642.             UpdateClientList(ConnectedSockets[j].name, SOCKSTAT_REQSESSION, ConnectedSockets[k].name);
  643.             ConnectedSockets[j].peer = ConnectedSockets[k].sock;
  644.             ConnectedSockets[k].peer = ConnectedSockets[j].sock;
  645.             return 0;
  646.  
  647.         case SESSION_REQUEST_RESPONSE:  // Response to session request
  648.  
  649.             if(ConnectedSockets[k].status != SOCKSTAT_REQSESSION)
  650.             {
  651.                 // ERROR -- not expecting this...drop packet
  652.                 return 0;
  653.             }
  654.  
  655.             // find peer entry
  656.             for (j = 0; j < NextFree; j++)
  657.             {
  658.                 if ((ConnectedSockets[j].sock == ConnectedSockets[k].peer) &&
  659.                     (ConnectedSockets[j].status == SOCKSTAT_REQSESSION))
  660.                 {
  661.                     // Found it!
  662.                     break;
  663.                 }
  664.             }
  665.  
  666.             if (j == NextFree)
  667.             {
  668.                 // ERROR -- couldn't find peer...drop packet
  669.                 return 0;
  670.             }
  671.  
  672.             // forward response to requester
  673.             senddatamessage(ConnectedSockets[k].peer, &xferbuf);
  674.  
  675.             if(*(xferbuf.data) == 1)
  676.             {
  677.                 // Session accepted, change status of sockets
  678.                 ConnectedSockets[k].status = SOCKSTAT_INSESSION;
  679.                 ConnectedSockets[j].status = SOCKSTAT_INSESSION;
  680.                 UpdateClientList(ConnectedSockets[k].name, SOCKSTAT_INSESSION, ConnectedSockets[j].name);
  681.                 UpdateClientList(ConnectedSockets[j].name, SOCKSTAT_INSESSION, ConnectedSockets[k].name);
  682.                 deregistername(ConnectedSockets[k].name);
  683.                 deregistername(ConnectedSockets[j].name);
  684.             }
  685.             else
  686.             {
  687.                 // Session not accepted, make sockets available
  688.                 ConnectedSockets[k].status = SOCKSTAT_AVAILABLE;
  689.                 ConnectedSockets[j].status = SOCKSTAT_AVAILABLE;
  690.                 UpdateClientList(ConnectedSockets[k].name, SOCKSTAT_AVAILABLE, NULL);
  691.                 UpdateClientList(ConnectedSockets[j].name, SOCKSTAT_AVAILABLE, NULL);
  692.             }
  693.  
  694.             return 0;
  695.  
  696.         case SESSION_CLOSE:  // Insession client chose "End Chat" option
  697.             if (ConnectedSockets[k].status != SOCKSTAT_INSESSION)
  698.             {
  699.                 // We weren't expecting this...drop packet
  700.                 return 0;
  701.             }
  702.  
  703.             // Find Peer
  704.             for (j = 0; j < NextFree; j++)
  705.             {
  706.                 if((ConnectedSockets[j].sock == ConnectedSockets[k].peer) &&
  707.                    (ConnectedSockets[j].status == SOCKSTAT_INSESSION))
  708.                 {
  709.                     // Found it
  710.                     break;
  711.                 }
  712.             }
  713.  
  714.             if(j == NextFree)
  715.             {
  716.                 // ERROR - couldn't find peer...drop message
  717.                 return 0;
  718.             }
  719.  
  720.             // forward message
  721.             senddatamessage(ConnectedSockets[k].peer,&xferbuf);
  722.  
  723.             // Change Status
  724.             ConnectedSockets[k].status = SOCKSTAT_AVAILABLE;
  725.             ConnectedSockets[j].status = SOCKSTAT_AVAILABLE;
  726.             UpdateClientList(ConnectedSockets[k].name, SOCKSTAT_AVAILABLE, NULL);
  727.             UpdateClientList(ConnectedSockets[j].name, SOCKSTAT_AVAILABLE, NULL);
  728.  
  729.             // register names of both peers with other available clients.  Also
  730.             // provide current available client names to both peers
  731.  
  732.             for (l = 0; l < NextFree; l++)  // l = index to all connected sockets
  733.                                             // k = index of current peer
  734.                                             // j = index of socket who generated message
  735.             {
  736.                 if (ConnectedSockets[l].status == SOCKSTAT_AVAILABLE)
  737.                 {
  738.                     if ( l != k)
  739.                     {
  740.                         xferbuf.hdr.signature = MYSIGNATURE;
  741.                         xferbuf.hdr.length = REALLEN(ConnectedSockets[k].name) + HDRSIZE;
  742.                         xferbuf.hdr.command = REGISTER_NAME;
  743.                         lstrcpy(xferbuf.data, ConnectedSockets[k].name);
  744.                         senddatamessage(ConnectedSockets[l].sock, &xferbuf);
  745.  
  746.                         if (l != j)
  747.                         {
  748.                             xferbuf.hdr.length = REALLEN(ConnectedSockets[l].name) + HDRSIZE;
  749.                             lstrcpy(xferbuf.data, ConnectedSockets[l].name);
  750.                             senddatamessage(ConnectedSockets[k].sock, &xferbuf);
  751.                         }
  752.                     }
  753.                     if (l != j)
  754.                     {
  755.                         xferbuf.hdr.signature = MYSIGNATURE;
  756.                         xferbuf.hdr.length = REALLEN(ConnectedSockets[j].name) + HDRSIZE;
  757.                         xferbuf.hdr.command = REGISTER_NAME;
  758.                         lstrcpy(xferbuf.data, ConnectedSockets[j].name);
  759.                         senddatamessage(ConnectedSockets[l].sock, &xferbuf);
  760.  
  761.                         if (l != k)
  762.                         {
  763.                             xferbuf.hdr.length = REALLEN(ConnectedSockets[l].name) + HDRSIZE;
  764.                             lstrcpy(xferbuf.data, ConnectedSockets[l].name);
  765.                             senddatamessage(ConnectedSockets[j].sock, &xferbuf);
  766.                         }
  767.                     }
  768.                 }
  769.             }
  770.             return 0;
  771.  
  772.     } // End message command switch
  773.  
  774.     // ERROR -- If we get here, we had an invalid message... drop it
  775.     return 0;
  776. }
  777.  
  778. //
  779. //  FUNCTION: MsgCommand(HWND, UINT, WPARAM, LPARAM)
  780. //
  781. //  PURPOSE: Handle the WM_COMMAND messages for the main window.
  782. //
  783. //  PARAMETERS:
  784. //    hwnd     - window handle
  785. //    uMessage - WM_COMMAND (Unused)
  786. //    GET_WM_COMMAND_ID(wparam, lparam)   - Command identifier
  787. //    GET_WM_COMMAND_HWND(wparam, lparam) - Control handle
  788. //
  789. //  RETURN VALUE:
  790. //    The return value depends on the message number.  If the message
  791. //    is implemented in the message dispatch table, the return value is
  792. //    the value returned by the message handling function.  Otherwise,
  793. //    the return value is the value returned by the default window procedure.
  794. //
  795. //  COMMENTS:
  796. //    Call the DispCommand() function with the main window's command dispatch
  797. //    information (cmdiMain) and the command specific information.
  798. //
  799.  
  800. LRESULT MsgCommand(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  801. {
  802.     return DispCommand(&cmdiMain, hwnd, wparam, lparam);
  803. }
  804.  
  805.  
  806. //
  807. //  FUNCTION: MsgDestroy(HWND, UINT, WPARAM, LPARAM)
  808. //
  809. //  PURPOSE: Calls PostQuitMessage().
  810. //
  811. //  PARAMETERS:
  812. //
  813. //    hwnd      - Window handle  (Unused)
  814. //    uMessage  - Message number (Unused)
  815. //    wparam    - Extra data     (Unused)
  816. //    lparam    - Extra data     (Unused)
  817. //
  818. //  RETURN VALUE:
  819. //
  820. //    Always returns 0 - Message handled
  821. //
  822. //  COMMENTS:
  823. //
  824. //
  825.  
  826. LRESULT MsgDestroy(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  827. {
  828.     PostQuitMessage(0);
  829.     return 0;
  830. }
  831.  
  832. //
  833. //  FUNCTION: CmdExit(HWND, WORD, WORD, HWND)
  834. //
  835. //  PURPOSE: Exit the application.
  836. //
  837. //  PARAMETERS:
  838. //    hwnd     - The window.
  839. //    wCommand - IDM_EXIT (unused)
  840. //    wNotify  - Notification number (unused)
  841. //    hwndCtrl - NULL (unused)
  842. //
  843. //  RETURN VALUE:
  844. //    Always returns 0 - command handled.
  845. //
  846. //  COMMENTS:
  847. //
  848. //
  849.  
  850. LRESULT CmdExit(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  851. {
  852.     DestroyWindow(hwnd);
  853.     return 0;
  854. }
  855.