GLOBCHAT.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:29k
源码类别:

Windows编程

开发平台:

Visual C++

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