home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / ddeml / msngr / msngr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-22  |  32.5 KB  |  1,096 lines

  1. /****************************** MODULE Header ******************************\
  2. * Module Name:  msngr.c - Messenger application
  3. *
  4. * Created:  1/1/89  sanfords
  5. *
  6. * Copyright (c) 1988, 1989  Microsoft Corporation
  7. \***************************************************************************/
  8.  
  9. #include "msngr.h"
  10. #include "string.h"
  11.  
  12. /************* FILE GLOBALS  ************/
  13.  
  14. char szMessengerClass[] = SZAPPCLASS;
  15. char szTitlePrefix[] = SZAPPTITLEPREFIX;
  16. char szTitle[MAX_TITLESTR + 1]="";
  17. char szEmailName[MAX_NAMESTR + 1] = "";
  18.  
  19. HCONVLIST hConvUserList = 0;    /* holds all client conversations */
  20. HAB  hab;
  21. HMQ  hmq;
  22. HWND hwndMsngrFrame;
  23. HWND hwndMsngr;
  24. HWND hwndHolder;
  25. HWND hwndLB;
  26. HHEAP hheap;
  27. HPOINTER hptrLink = 0;
  28. PFNWP lpfnSysEFWndProc;         /* holds the system edit control proc */
  29. NPUSERLIST gnpUL = 0;   /* relates hConvs to hszs. */
  30. SHORT cyText;
  31. ULONG ulTimeout = 500;
  32.  
  33. /*
  34.  * The following arrays define which interface functions to use for a given
  35.  * topic and item.
  36.  * Hszize() fills in the hsz portions of this array.
  37.  * Note: the order of some of these must corespond to the the index constants
  38.  *        in msngr.h.
  39.  */
  40.  
  41. HSZ hszEmailName = 0;
  42. HSZ hszAppName = 0;
  43.  
  44. /*                               HSZ    PROCEDURE       PSZ        */
  45.  
  46. ITEMLIST sysTopicItemList[] = {
  47.                                 { 0, TopicListXfer,  SZDDESYS_ITEM_TOPICS   },
  48.                                 { 0, ItemListXfer,   SZDDESYS_ITEM_SYSITEMS },
  49.                                 { 0, NotSupported,   SZDDESYS_ITEM_RTNMSG   },
  50.                                 { 0, NotSupported,   SZDDESYS_ITEM_STATUS   },
  51.                                 { 0, sysFormatsXfer, SZDDESYS_ITEM_FORMATS  },
  52.                               };
  53.  
  54. ITEMLIST msgTopicItemList[] = {
  55.                                 { 0, msgUserNameXfer, SZUSERNAME},
  56.                                 { 0, msgMessageXfer, SZMESSAGEDATA},
  57.                                 { 0, bmpXfer, SZBMAPDATA}, 
  58.                               };
  59.  
  60.  
  61. /*                           HSZ   PROCEDURE       #ofITEMS     PSZ     */
  62.    
  63. TOPICLIST topicList[] = {
  64.     /* The system topic is always assumed to be first. */
  65.                             { 0, sysTopicItemList, IIL_SYSLAST, SZDDESYS_TOPIC},
  66.                             { 0, msgTopicItemList, IIL_MSGLAST, SZDDEMSGTOPIC},
  67.                         };
  68.  
  69.  
  70. /***************************** Private Function ****************************\
  71. * DESCRIPTION:
  72. *   Main dude.
  73. * History:      1/1/89  Created         sanfords
  74. \***************************************************************************/
  75. void cdecl main(argc, argv)
  76. int argc;
  77. char *argv[];
  78. {
  79.     USHORT err;
  80.     HPS hps;
  81.     QMSG qmsg;
  82.     ULONG createFlags;
  83.  
  84.     /*
  85.      * check command line args
  86.      *  User can specify a email name up to MAX_NAMESTR
  87.      *  ! turns on a debug break
  88.      */
  89.     if (argc > 1) {
  90.         if (strlen(argv[1]) > MAX_NAMESTR)
  91.             NotifyUser(SZBADCOMPARAMS);
  92.         else if (*argv[1] != '!')
  93.             strcpy(szEmailName, argv[1]);
  94.     }
  95.     
  96.     hab = WinInitialize(0);
  97.     hheap = WinCreateHeap(0, 0, 0, 0, 0, HM_MOVEABLE | HM_VALIDSIZE);
  98.     hmq = WinCreateMsgQueue(hab, 100);  /* Note the larger than normal Q ! */
  99.  
  100.     WinRegisterClass(hab, SZHOLDINGCLASS, WinDefWindowProc, 0L, 0L);
  101.     WinRegisterClass(hab, SZAPPCLASS, MainWndProc, CS_SIZEREDRAW, 4L);
  102.     
  103.     /*
  104.      * set up cyText for later
  105.      */
  106.     {
  107.         FONTMETRICS fm;
  108.  
  109.         hps = WinGetPS(HWND_DESKTOP);
  110.         GpiQueryFontMetrics(hps, (LONG)sizeof(FONTMETRICS), &fm);
  111.         WinReleasePS(hps);
  112.         cyText = (SHORT)fm.lMaxBaselineExt;
  113.     }
  114.  
  115.     InitBmapModule();
  116.  
  117.     /*
  118.      * force the user to set up his email name.
  119.      */
  120.     if (szEmailName[0] == '\0')
  121.         WinDlgBox(HWND_DESKTOP, NULL, (PFNWP)GetNameDlgProc, (HMODULE)NULL,
  122.                 IDD_GETNAME, (PVOID)szEmailName);
  123.                 
  124.     /*
  125.      * Initialize the DDE manager
  126.      */
  127.     if ((err = DdeInitialize((PFNCALLBACK)Callback, 0L, 0L)) != NULL) {
  128.         DdePostError(err);
  129.         goto abort;
  130.     }
  131.  
  132.     /*
  133.      * Create all HSZs we expect to need
  134.      */
  135.     Hszize();
  136.  
  137.     /*
  138.      * Create our main window
  139.      */
  140.     createFlags = FCF_STANDARD;
  141.     hwndMsngrFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, NULL,
  142.         SZAPPCLASS, "", 0L, (HMODULE)NULL, IDR_MSNGR1, &hwndMsngr);
  143.         
  144.     WinSetWindowPos(hwndMsngrFrame, HWND_TOP, 0, 0,
  145.         250, 150, SWP_SHOW | SWP_ZORDER | SWP_SIZE);
  146.  
  147.     /*
  148.      * set up the initial title string.
  149.      */
  150.     SetEmailName(szEmailName);
  151.  
  152.     /*
  153.      * process the main window till dismissed.
  154.      */
  155.     while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
  156.         WinDispatchMsg(hab, &qmsg);
  157.  
  158. abort:
  159.     if (hptrLink != 0)
  160.         WinDestroyPointer(hptrLink);
  161.  
  162.     WinDestroyWindow(hwndMsngrFrame);
  163.     CloseBmapModule();
  164.     DdeAppNameServer(hszAppName, ANS_UNREGISTER | ANS_FILTERON);
  165.     UnHszize();
  166.     DdeUninitialize();
  167.     WinTerminate(hab);
  168.     DosExit(EXIT_PROCESS, 0);
  169. }
  170.  
  171.  
  172.  
  173.  
  174. /********** Msngr Window Procedure **************/
  175.  
  176. MRESULT EXPENTRY MainWndProc(hwnd, msg, mp1, mp2)
  177. HWND hwnd;
  178. USHORT msg;
  179. MPARAM mp1;
  180. MPARAM mp2;
  181. {
  182.     char szCaption[MAX_CAPTIONSTR + 1];
  183.     NPUSERLIST pUserItem;
  184.  
  185.     switch (msg) {
  186.     case WM_CREATE:
  187.         /*
  188.          * initialize globals
  189.          */
  190.         hwndMsngr = hwnd;
  191.         hwndLB = WinCreateWindow(hwndMsngr, WC_LISTBOX, "",
  192.                 WS_VISIBLE | LS_NOADJUSTPOS, 0, 0, 0, 0, hwndMsngr,
  193.                 HWND_TOP, WID_LISTBOX, NULL, NULL);
  194.  
  195.         /*
  196.          * create a holding window to be the owner of all the floating
  197.          * dialogs which need to be destroyed on exit.
  198.          */
  199.         hwndHolder = WinCreateWindow(HWND_OBJECT, SZHOLDINGCLASS, "", 0L,
  200.                 0, -1, 0, 0, (HWND)NULL, HWND_TOP, 0, (PVOID)NULL, (PVOID)NULL);
  201.         /*
  202.          * we register our name here so keeping track of who is out there
  203.          * is simplified.  The DLL will now let us know when other
  204.          * instances of this app come and go.
  205.          *
  206.          * As the DLL lets other msngr apps know we are here, they
  207.          * will connect with us, ask us our name, and poke to us their
  208.          * names.  Each poke will cause their name to be added to our
  209.          * user list.
  210.          *
  211.          * If our requested name happens to be the same as one of theirs,
  212.          * they will ignore our registration and assume we will change
  213.          * our name.
  214.          *
  215.          * If we find that a poke from them is the same as our name, we
  216.          * know that we are a duplicate.  We will then alter the email
  217.          * name to be unique and reregister ourselves with the AppNameServer.
  218.          * This will restart the registration notification process as
  219.          * described here.
  220.          */    
  221.         DdeAppNameServer(hszAppName, ANS_REGISTER | ANS_FILTERON);
  222.         break;
  223.  
  224.     case WM_SIZE:
  225.         WinSetWindowPos(hwndLB, HWND_TOP, -1, -1, SHORT1FROMMP(mp2) + 2,
  226.                 SHORT2FROMMP(mp2) + 2, SWP_SIZE | SWP_MOVE | SWP_SHOW);
  227.         break;
  228.  
  229.     case WM_COMMAND:
  230.         switch (LOUSHORT(mp1)) {
  231.         case IDM_DOSENDTEXT:
  232.             if (!(pUserItem = AccessSelection()))
  233.                 break;
  234.             WinDlgBox(HWND_DESKTOP, hwndMsngr, SendTextDlgProc, 0L,
  235.                     IDD_SENDTEXT, (PVOID)pUserItem);
  236.             break;
  237.  
  238.         case IDM_DOSENDBITMAP:
  239.             if (!(pUserItem = AccessSelection()))
  240.                 break;
  241.             WinDlgBox(HWND_DESKTOP, hwndMsngr, SendBitmapDlgProc,
  242.                     0L, IDD_SENDBITMAP, (PVOID)pUserItem);
  243.             break;
  244.  
  245.         case IDM_DOSENDSONG:
  246.             if (!(pUserItem = AccessSelection()))
  247.                 break;
  248.             WinDlgBox(HWND_DESKTOP, hwndMsngr, SendSongDlgProc, 0L,
  249.                     IDD_SENDSONG, (PVOID)pUserItem);
  250.             break;
  251.  
  252.         case IDM_INITLINK:
  253.             if (!(pUserItem = AccessSelection()))
  254.                 break;
  255.             if (!WinIsWindow(hab, pUserItem->hwndLink)) {
  256.                 CreateLinkWindow(pUserItem, LNKST_USERSTART);
  257.             } else {
  258.                 WinSetWindowPos(pUserItem->hwndLink, HWND_TOP,
  259.                         0, 0, 0, 0,
  260.                         SWP_SHOW | SWP_RESTORE | SWP_FOCUSACTIVATE);
  261.             }
  262.             break;
  263.         }
  264.         break;
  265.  
  266.     /*
  267.      * we use this message so we can do asynchronous incomming message
  268.      * notification.  This prevents us from eternal loops via the
  269.      * callback function.
  270.      */
  271.     case UM_MSG_NOTIFY:
  272.         lstrcat((PSZ)szCaption, (PSZ)SZMSGIN,
  273.                 (PSZ)&(((PSZ)mp1)[lstrlen((PSZ)mp1) + 1]));
  274.         NotifyUser2(szCaption, (PSZ)mp1);
  275.         WinFreeMem(hheap, (NPBYTE)(USHORT)mp1,
  276.                 MAX_MSGSTR + 1 + MAX_NAMESTR + 1);
  277.         break;
  278.  
  279.     case WM_CLOSE:
  280.         /*
  281.          * destroy the holder window, and with it, shutdown any floating
  282.          * dialogs.
  283.          */
  284.         WinDestroyWindow(hwndHolder);
  285.         /* fall through */
  286.     default:
  287.         return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  288.         break;
  289.     }
  290.     return(0);
  291. }
  292.  
  293.  
  294.  
  295.  
  296. /***************************** Private Function ****************************\
  297. * DESCRIPTION:
  298. * This dialog forces the user to enter a string.  It may be used for
  299. * entering the user's initial email name or it can be used to change
  300. * the current email name.
  301. *
  302. * It must be invoked with a psz specified for its cData which is where its
  303. * result will be stored.  The psz can be no larger than MAX_NAMESTR.
  304. *
  305. * History:      1/1/89  Created         sanfords
  306. \***************************************************************************/
  307. MRESULT EXPENTRY GetNameDlgProc(hwnd, msg, mp1, mp2)
  308. HWND hwnd;
  309. USHORT msg;
  310. MPARAM mp1;
  311. MPARAM mp2;
  312. {
  313.     PSZ pszName;
  314.  
  315.     switch (msg) {
  316.     case WM_INITDLG: {
  317.             HWND hwndEF;
  318.  
  319.             /*
  320.              * store pszName into window words for later access and set up the
  321.              * default name entry.
  322.              * This assumes mp2=pszText for this dialog's entryfield.
  323.              */
  324.             WinSetWindowULong(hwnd, QWL_USER, (ULONG)mp2);
  325.             if (*(PSZ)mp2 != '\0') {
  326.                 /*
  327.                  * we are changing a name because of a duplicate, change
  328.                  * the title apropriately.
  329.                  */
  330.                 WinSetDlgItemText(hwnd, FID_TITLEBAR, SZDUPTITLE);
  331.             }
  332.             /*
  333.              * set up our entryfield to be enhanced.
  334.              */
  335.             hwndEF = WinWindowFromID(hwnd, IDC_EF_NAME);
  336.             lpfnSysEFWndProc = WinSubclassWindow(hwndEF, EnhancedEFWndProc);
  337.  
  338.             WinSetWindowText(hwndEF, (PSZ)mp2);
  339.             WinSendMsg(hwndEF, EM_SETTEXTLIMIT, MPFROMSHORT(MAX_NAMESTR), 0L);
  340.             return(0L);
  341.         }
  342.         break;
  343.  
  344.     case ENHAN_ENTER:
  345.         /*
  346.          * when the user hits the enter key, it will be passed from the
  347.          * entryfield to here and we will use it as a signal to exit.
  348.          */
  349.         pszName = (PSZ)WinQueryWindowULong(hwnd, QWL_USER);
  350.         WinQueryDlgItemText(hwnd, IDC_EF_NAME, MAX_NAMESTR + 1,
  351.                 pszName);
  352.         if (*pszName != '\0') {
  353.             WinDismissDlg(hwnd, 0);
  354.         }
  355.         break;
  356.  
  357.     default:
  358.         return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  359.         break;
  360.     }
  361.     return(0);
  362. }
  363.  
  364.  
  365.  
  366.  
  367. /*****************************************************************************
  368. *┌──────────────────────────────────────────────────────────────────────────┐*
  369. *│This window proc, which is actually a subclass of the standard entryfield │*
  370. *│type of window, notifies its owner of more interesting things than the    │*
  371. *│origonal did.                                                             │*
  372. *└──────────────────────────────────────────────────────────────────────────┘*
  373. *****************************************************************************/
  374. MRESULT EXPENTRY EnhancedEFWndProc(hwnd, msg, mp1, mp2)
  375. HWND hwnd;
  376. USHORT msg;
  377. MPARAM mp1;
  378. MPARAM mp2;
  379. {
  380.     switch (msg) {
  381.     case WM_CHAR:
  382.         if (LOUSHORT(mp1) & KC_SCANCODE &&
  383.                 LOUSHORT(mp1) & KC_KEYUP &&
  384.                 /*---HACK ALERT!---*/
  385.                 LOBYTE(LOUSHORT(mp2)) == 0x0d) {
  386.             NOTIFYOWNER(hwnd, ENHAN_ENTER,
  387.                     (MPARAM)WinQueryWindowUShort(hwnd, QWS_ID), 0L);
  388.         }
  389.         break;
  390.     }
  391.     return(lpfnSysEFWndProc(hwnd, msg, mp1, mp2));
  392. }
  393.  
  394.  
  395.  
  396.  
  397.  
  398. MRESULT EXPENTRY SendTextDlgProc(hwnd, msg, mp1, mp2)
  399. HWND hwnd;
  400. USHORT msg;
  401. MPARAM mp1;
  402. MPARAM mp2;
  403. {
  404.     switch (msg) {
  405.     case WM_INITDLG:
  406.         /*
  407.          * mp2 should be set to the pUserItem of the person we are sending to.
  408.          */
  409.         WinSendDlgItemMsg(hwnd, IDC_EF_TEXT, EM_SETTEXTLIMIT,
  410.                 MPFROMSHORT(MAX_MSGSTR + 1), 0L);
  411.                 
  412.         if (((NPUSERLIST)(SHORT)mp2)->hConvMsg == 0) {
  413.             NotifyUser(SZCANTCONNECT);
  414.             WinDismissDlg(hwnd, 0);
  415.             return(0);
  416.         }
  417.         WinSetWindowULong(hwnd, QWL_USER, (ULONG)((NPUSERLIST)(SHORT)mp2)->hConvMsg);
  418.         return(0);
  419.         break;
  420.  
  421.     case WM_COMMAND:
  422.         switch (LOUSHORT(mp1)) {
  423.         case IDC_SENDTEXT:
  424.             {
  425.                 char szMsg[MAX_MSGSTR + 1 + MAX_NAMESTR + 1];
  426.  
  427.                 WinQueryDlgItemText(hwnd, IDC_EF_TEXT, MAX_MSGSTR + 1,
  428.                         (PSZ)szMsg);
  429.                 if (szMsg[0] == '\0') {
  430.                     NotifyUser(SZEMPTYMSG);
  431.                     return(0);
  432.                 }
  433.                 lstrpak((PSZ)szMsg, (PSZ)szMsg, (PSZ)szEmailName);
  434.                 if (!((USHORT)DdeClientXfer((PBYTE)szMsg,
  435.                         (ULONG)(lstrlen((PSZ)szMsg) + lstrlen((PSZ)szEmailName) + 2),
  436.                         (HCONV)WinQueryWindowULong(hwnd, QWL_USER),
  437.                         msgTopicItemList[IIL_MSGXFER].hszItem, DDEFMT_TEXT,
  438.                         XTYP_POKE, ulTimeout, NULL) & DDE_FACK)) {
  439.                     NotifyUser(SZSENDFAILED);
  440.                     MyPostError(DdeGetLastError());
  441.                     return(0);
  442.                 }
  443.             }
  444.             WinDismissDlg(hwnd, 0);
  445.             break;
  446.  
  447.         default:
  448.             /*
  449.              * This would handle the DID_OK exit.
  450.              */
  451.             return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  452.             break;
  453.         }
  454.         break;
  455.  
  456.     default:
  457.         return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  458.         break;
  459.     }
  460.     return(0);
  461. }
  462.  
  463.  
  464.  
  465.  
  466.  
  467. MRESULT EXPENTRY SendSongDlgProc(hwnd, msg, mp1, mp2)
  468. HWND hwnd;
  469. USHORT msg;
  470. MPARAM mp1;
  471. MPARAM mp2;
  472. {
  473.     switch (msg) {
  474.     default:
  475.         return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  476.         break;
  477.     }
  478.     return(0);
  479. }
  480.  
  481.  
  482.  
  483.  
  484.  
  485. /***************************** Public  Function ****************************\
  486. *
  487. * This function is called by the DDE manager DLL and passes control onto
  488. * the apropriate function pointed to by the global topic and item arrays.
  489. * It handles all DDE interaction generated by external events.
  490. *
  491. * History:  1/1/89  created     sanfords
  492. \***************************************************************************/
  493. HDMGDATA EXPENTRY Callback(hConv, hszTopic, hszItem, usFmt, usType,
  494.         hDmgData)
  495. HCONV hConv;
  496. HSZ hszTopic;
  497. HSZ hszItem;
  498. USHORT usFmt;
  499. USHORT usType;
  500. HDMGDATA hDmgData;
  501. {
  502.     SHORT i, j;
  503.     register ITEMLIST *pItemList;
  504.     USHORT iItemLast;
  505.     HDMGDATA hDmgDataRet;
  506.  
  507.     UNUSED usFmt;
  508.     UNUSED hConv;
  509.  
  510.     if (usType == XTYP_REGISTER || usType == XTYP_UNREGISTER) {
  511.         if (hszItem == hszAppName) 
  512.             /*
  513.              * we are being notified that another msngr app is starting up
  514.              * or going away.
  515.              * hDmgData should be the App handle to use for initiateing.
  516.              */
  517.             if (usType == XTYP_REGISTER) {
  518.                 RegisterUser(hDmgData, NULL, TRUE);
  519.             } else {
  520.                 UnregisterUser(hDmgData);
  521.             }
  522.         return(0);
  523.     }
  524.  
  525.  
  526.     if (usType == XTYP_WILDINIT) {
  527.         /*
  528.          * He wants a hsz list of all our available app/topic pairs
  529.          * that convorm to hszTopic and hszItem(App).
  530.          */
  531.         HSZ ahsz[(ITL_LAST + 3) * 2];
  532.  
  533.         if (hszItem != hszAppName && hszItem != NULL) 
  534.             return(0);
  535.  
  536.         j = 0;
  537.         for (i = 0; i <= ITL_LAST; i++) {
  538.             if (hszTopic == NULL || hszTopic == topicList[i].hszTopic) {
  539.                 ahsz[j++] = hszAppName;
  540.                 ahsz[j++] = topicList[i].hszTopic;    
  541.             }
  542.         }
  543.         
  544.         if (hszTopic == NULL || hszTopic == hszEmailName) {
  545.             ahsz[j++] = hszAppName;
  546.             ahsz[j++] = hszEmailName;
  547.         }
  548.             
  549.         ahsz[j++] = ahsz[j++] = 0L;
  550.         return(DdePutData((PBYTE)&ahsz[0], (ULONG)sizeof(HSZ) * j, 0L,
  551.                 (HSZ)0L, 0, 0));
  552.     }
  553.  
  554.  
  555.     /*
  556.      * Check for Topic/Item convention for Linking.  Remember that ADVDATA
  557.      * is client intended so its backwards.
  558.      */
  559.     if ((hszTopic == hszEmailName) ||
  560.             (usType == XTYP_ADVDATA && hszItem == hszEmailName)) {
  561.         return(LinkXfer((PXFERINFO)&hDmgData, hszTopic == hszEmailName ?
  562.                 hszItem : hszTopic));
  563.     }
  564.  
  565.     /*
  566.      * Check our hsz tables and send to the apropriate proc.
  567.      * We use DdeCmpHsz() so hsz comparisons are case insensitive.
  568.      */
  569.     for (i = 0; i <= ITL_LAST; i++) {
  570.         if (DdeCmpHsz(topicList[i].hszTopic, hszTopic) == 0) {
  571.             if (usType == XTYP_INIT) {
  572.                 /*
  573.                  * it must be a request to start another server conversation.
  574.                  */
  575.                 return(TRUE);
  576.             }
  577.             pItemList = topicList[i].pItemList;
  578.             iItemLast = topicList[i].iItemLast;
  579.             for (j = 0; j <= iItemLast; j++) {
  580.                 if (DdeCmpHsz(pItemList[j].hszItem, hszItem) == 0) {
  581.                     hDmgDataRet = (*pItemList[j].npfnCallback)
  582.                             ((PXFERINFO)&hDmgData);
  583.                     /*
  584.                      * The table functions return a boolean or data.
  585.                      * It gets translated here.
  586.                      */
  587.                     switch (usType & XCLASS_MASK) {
  588.                     case XCLASS_DATA:
  589.                         return(hDmgDataRet);
  590.                         break;
  591.                     case XCLASS_FLAGS:
  592.                         return(hDmgDataRet ? DDE_FACK : DDE_NOTPROCESSED);
  593.                         break;
  594.                     case XCLASS_BOOL:
  595.                         return(TRUE);
  596.                     default:
  597.                         return(0);
  598.                         break;
  599.                     }
  600.                     break;
  601.                 }
  602.             }
  603.             break;
  604.         }
  605.     }
  606.     return(0);
  607. }
  608.  
  609.  
  610.  
  611.  
  612.  
  613. /***************************** Private Function ****************************\
  614. * This passes out a standard tab-delimited list of topic names for this
  615. * application.
  616. *
  617. * This support is required for other apps to be able to
  618. * find out about us.  This kind of support should be in every DDE
  619. * application.
  620. *
  621. * History:  1/3/89  created     sanfords
  622. \***************************************************************************/
  623. HDMGDATA TopicListXfer(pXferInfo)
  624. PXFERINFO pXferInfo;
  625. {
  626.     USHORT cb, cbAlloc, iTopic, cch;
  627.     PSZ pszTopicList;
  628.     HDMGDATA hDmgData;
  629.     char szT[MAX_NAMESTR + 1];
  630.     SHORT lit;
  631.  
  632.     if (pXferInfo->usFmt != DDEFMT_TEXT ||
  633.             (pXferInfo->usType != XTYP_REQUEST &&
  634.             pXferInfo->usType != XTYP_ADVREQ))
  635.         return(0);
  636.     /*
  637.      * construct the list of topics we have
  638.      */
  639.     cbAlloc = 0;
  640.     for (iTopic = 0; iTopic <= ITL_LAST; iTopic++)
  641.         cbAlloc += lstrlen(topicList[iTopic].pszTopic) + 1;
  642.     lit = 0;
  643.     while (WinSendMsg(hwndLB, LM_QUERYITEMTEXT,
  644.             MPFROM2SHORT(lit, MAX_NAMESTR + 1), (MPARAM)szT)) {
  645.         cbAlloc += lstrlen(szT) + 1;
  646.         lit++;
  647.     }
  648.     pszTopicList = FarAllocMem(hheap, cbAlloc);
  649.     if (!LOUSHORT(pszTopicList)) 
  650.         return(0);
  651.     cb = 0;
  652.     for (iTopic = 0; iTopic <= ITL_LAST; iTopic++) {
  653.         cch = lstrlen(topicList[iTopic].pszTopic) + 1;
  654.         DdeCopyBlock(topicList[iTopic].pszTopic, pszTopicList + cb, (ULONG)cch);
  655.         cb += cch;
  656.         pszTopicList[cb - 1] = '\t';
  657.     }
  658.     lit = 0;
  659.     while (WinSendMsg(hwndLB, LM_QUERYITEMTEXT,
  660.             MPFROM2SHORT(lit, MAX_NAMESTR + 1), (MPARAM)szT)) {
  661.         cch = lstrlen(szT) + 1;
  662.         DdeCopyBlock(szT, pszTopicList + cb, (ULONG)cch);
  663.         cb += cch;
  664.         pszTopicList[cb - 1] = '\t';
  665.         lit++;
  666.     }
  667.     pszTopicList[cb - 1] = '\0';
  668.     hDmgData = DdePutData(pszTopicList, (ULONG)cb, 0L, pXferInfo->hszItem,
  669.             DDEFMT_TEXT, 0);
  670.     WinFreeMem(hheap, (NPBYTE)(SHORT)pszTopicList, cbAlloc);
  671.     return(hDmgData);
  672. }
  673.  
  674.  
  675.  
  676.  
  677. /***************************** Private Function ****************************\
  678. * This passes out a standard tab-delimited list of item names for the
  679. * specified topic.
  680. *
  681. * This support is required for other apps to be able to
  682. * find out about us.  This kind of support should be in every DDE
  683. * application.
  684. *
  685. * History:  1/3/89  created     sanfords
  686. \***************************************************************************/
  687. HDMGDATA ItemListXfer(pXferInfo)
  688. PXFERINFO pXferInfo;
  689. {
  690.     USHORT cb, cbAlloc, iTopic, iItem, iLast, cch;
  691.     ITEMLIST *pItemList = 0;
  692.     PSZ pszItemList;
  693.     HDMGDATA hDmgData;
  694.  
  695.     if (pXferInfo->usFmt != DDEFMT_TEXT ||
  696.                 (pXferInfo->usType != XTYP_REQUEST &&
  697.                 pXferInfo->usType != XTYP_ADVREQ))
  698.         return(0);
  699.     /*
  700.      * construct the list of items we support for this topic.
  701.      */
  702.     for (iTopic = 0; iTopic < ITL_LAST; iTopic++) {
  703.         if (pXferInfo->hszTopic == topicList[iTopic].hszTopic) {
  704.             pItemList = topicList[iTopic].pItemList;
  705.             iLast = topicList[iTopic].iItemLast;
  706.             break;
  707.         }
  708.     }
  709.     if (pItemList == 0)
  710.         return(0);
  711.     cbAlloc = 0;
  712.     for (iItem = 0; iItem < iLast; iItem++)
  713.         cbAlloc += lstrlen(pItemList[iItem].pszItem) + 1;
  714.     pszItemList = FarAllocMem(hheap, cbAlloc);
  715.     if (!LOUSHORT(pszItemList))
  716.         return(0);
  717.     cb = 0;
  718.     for (iItem = 0; iItem < iLast; iItem++) {
  719.         cch = lstrlen(pItemList[iItem].pszItem) + 1;
  720.         DdeCopyBlock(pItemList[iItem].pszItem, pszItemList + cb, (ULONG)cch);
  721.         cb += cch;
  722.         pszItemList[cb - 1] = '\t';
  723.     }
  724.     pszItemList[cb - 1] = '\0';
  725.     hDmgData = DdePutData(pszItemList, (ULONG)cb, 0L,
  726.             pXferInfo->hszItem, DDEFMT_TEXT, 0);
  727.     WinFreeMem(hheap, (NPBYTE)(USHORT)pszItemList, cbAlloc);
  728.     return(hDmgData);
  729. }
  730.  
  731.  
  732.  
  733.  
  734. /***************************** Private Function ****************************\
  735. * Used for unsupported transfers.
  736. *
  737. * History:  1/1/89  created     sanfords
  738. \***************************************************************************/
  739. HDMGDATA NotSupported(pXferInfo)
  740. PXFERINFO pXferInfo;
  741. {
  742.     pXferInfo;
  743.     
  744.     return(0);
  745. }
  746.  
  747.  
  748.  
  749.  
  750.  
  751. /***************************** Private Function ****************************\
  752. * Gives out a 0 terminated array of dde format numbers supported by this app.
  753. *
  754. * This support is required for other apps to be able to
  755. * find out about us.  This kind of support should be in every DDE
  756. * application.
  757. *
  758. * History:      1/1/89  Created         sanfords
  759. \***************************************************************************/
  760. HDMGDATA sysFormatsXfer(pXferInfo)
  761. PXFERINFO pXferInfo;
  762. {
  763.     USHORT Formats[2];
  764.  
  765.     if (pXferInfo->usFmt != DDEFMT_TEXT ||
  766.             (pXferInfo->usType != XTYP_REQUEST &&
  767.             pXferInfo->usType != XTYP_ADVREQ))
  768.         return(0);
  769.  
  770.     Formats[0] = DDEFMT_TEXT;
  771.     Formats[1] = 0;
  772.     return(DdePutData((PBYTE)Formats, 4L, 0L, pXferInfo->hszItem,
  773.             DDEFMT_TEXT, 0));
  774. }
  775.  
  776.  
  777.  
  778. /***************************** Private Function ****************************\
  779. * Gives out our szEmailName or registers someone elses.
  780. *
  781. * History:      1/1/89  Created         sanfords
  782. \***************************************************************************/
  783. HDMGDATA msgUserNameXfer(pXferInfo)
  784. PXFERINFO pXferInfo;
  785. {
  786.     CONVINFO ci;
  787.     
  788.     if (pXferInfo->usFmt != DDEFMT_TEXT)
  789.         return(0);
  790.  
  791.     switch (pXferInfo->usType) {
  792.     case XTYP_REQUEST:
  793.         /*
  794.          * someone wants to know our name...cool.
  795.          */
  796.         return(DdePutData(szEmailName, (ULONG)(lstrlen(szEmailName) + 1),
  797.                 0L, pXferInfo->hszItem, DDEFMT_TEXT, 0));
  798.         break;
  799.  
  800.     case XTYP_POKE:
  801.         /*
  802.          * Someone is responding to our initial registration.  Add them
  803.          * to our list.  If their name is the same as ours, WE are at
  804.          * fault and must change our email name and reregister.
  805.          */
  806.         DdeQueryConvInfo(pXferInfo->hConv, &ci, QID_SYNC);
  807.         RegisterUser(ci.hApp, pXferInfo->hDmgData, FALSE); 
  808.         return(1);
  809.         break;
  810.     }
  811.     return(0);
  812. }
  813.  
  814.  
  815.  
  816.  
  817.  
  818. /*
  819.  * This is used for receiving text messages.
  820.  */
  821. HDMGDATA msgMessageXfer(pXferInfo)
  822. PXFERINFO pXferInfo;
  823. {
  824.     PSZ pszMsg;
  825.  
  826.     if (pXferInfo->usFmt != DDEFMT_TEXT)
  827.         return(DDE_NOTPROCESSED);
  828.  
  829.     switch (pXferInfo->usType) {
  830.     case XTYP_POKE:
  831.         /*
  832.          * we have the message text followed by the users name.
  833.          */
  834.         pszMsg = FarAllocMem(hheap, MAX_MSGSTR + 1 + MAX_NAMESTR + 1);
  835.         DdeGetData(pXferInfo->hDmgData, (PBYTE)pszMsg,
  836.                 (ULONG)(MAX_MSGSTR + 1 + MAX_NAMESTR + 1), 0L);
  837.         DdeFreeData(pXferInfo->hDmgData);
  838.         /*
  839.          * We must do an assynchronous user notification so we don't
  840.          * clog up the DLL in our callback.
  841.          */
  842.         WinPostMsg(hwndMsngr, UM_MSG_NOTIFY, pszMsg, 0L);
  843.         return(1);
  844.         break;
  845.  
  846.     default:
  847.         break;
  848.     }
  849.     return(0);
  850. }
  851.  
  852.  
  853.  
  854.  
  855.  
  856. /***************************** Private Function ****************************\
  857. *  This creates often used global hszs from standard global strings.
  858. *  It also fills the hsz fields of the topic and item tables.
  859. *
  860. * History:      1/1/89  Created         sanfords
  861. \***************************************************************************/
  862. void Hszize()
  863. {
  864.     register ITEMLIST *pItemList;
  865.     USHORT iTopic, iItem;
  866.  
  867.     hszAppName = DdeGetHsz((PSZ)SZDDEAPPNAME, 0, 0);
  868.  
  869.     for (iTopic = 0; iTopic <= ITL_LAST; iTopic++) {
  870.         topicList[iTopic].hszTopic = DdeGetHsz(topicList[iTopic].pszTopic, 0, 0);
  871.         pItemList = topicList[iTopic].pItemList;
  872.         for (iItem = 0; iItem <= topicList[iTopic].iItemLast; iItem++) {
  873.             pItemList[iItem].hszItem = DdeGetHsz(pItemList[iItem].pszItem, 0, 0);
  874.         }
  875.     }
  876. }
  877.  
  878.  
  879.  
  880.  
  881.  
  882. /***************************** Private Function ****************************\
  883. *  This destroys often used global hszs from standard global strings.
  884. *
  885. * History:      1/1/89  Created         sanfords
  886. \***************************************************************************/
  887. void UnHszize()
  888. {
  889.     register ITEMLIST *pItemList;
  890.     USHORT iTopic, iItem;
  891.  
  892.     DdeFreeHsz(hszAppName);
  893.     DdeFreeHsz(hszEmailName);
  894.  
  895.     for (iTopic = 0; iTopic <= ITL_LAST; iTopic++) {
  896.         DdeFreeHsz(topicList[iTopic].hszTopic);
  897.         pItemList = topicList[iTopic].pItemList;
  898.         for (iItem = 0; iItem <= topicList[iTopic].iItemLast; iItem++) {
  899.             DdeFreeHsz(pItemList[iItem].hszItem);
  900.         }
  901.     }
  902. }
  903.  
  904.  
  905.  
  906.  
  907.  
  908.  
  909.  
  910. /***************************** Private Function ****************************\
  911. * DESCRIPTION:
  912. *   This routine returns the userlist item pointed to by the listbox selection.
  913. *   It notifies the user of any errors and returns 0 in that case.
  914. *
  915. * History:      1/17/89     Created         sanfords
  916. \***************************************************************************/
  917. NPUSERLIST AccessSelection()
  918. {
  919.     NPUSERLIST pUserItem;
  920.     SHORT lit;
  921.  
  922.     lit = (SHORT)WinSendMsg(hwndLB, LM_QUERYSELECTION, 0L, 0L);
  923.     if (lit == LIT_NONE) {
  924.         NotifyUser(SZMAKESELECTION);
  925.         return(0);
  926.     }
  927.     pUserItem = (NPUSERLIST)(SHORT)WinSendMsg(hwndLB, LM_QUERYITEMHANDLE,
  928.             (MPARAM)lit, 0L);
  929.     return(pUserItem);
  930. }
  931.  
  932.  
  933.  
  934. /*
  935.  * if fRegister : (We got the name via a request)
  936.  * This routine creates a connection with hApp on the msgTopic and
  937.  * gets the user's name from the connection.  It then looks for the
  938.  * user's name in our current list.  If the name is already there
  939.  * we fail - he is a fault, otherwise we add the user name to our
  940.  * list of users. We then poke our name to the server we connected
  941.  * with so he knows who we are.
  942.  *
  943.  * else :   (We got the name via a poke)
  944.  * hData contains a valid user name which we will add.
  945.  * If it is a dup of ours, we must change our name and reregister.  The
  946.  * data handle is freed on return.
  947.  */
  948. BOOL RegisterUser(
  949. HAPP hApp,
  950. HDMGDATA hData,
  951. BOOL fRegister)
  952. {
  953.     HCONV hConv;
  954.     HSZ hsz;
  955.     BOOL fDup;
  956.  
  957.     hConv = DdeConnect(hszAppName, topicList[ITL_MSG].hszTopic, NULL, hApp);
  958.     if (!hConv)  {
  959.         return(FALSE);
  960.     }
  961.         
  962.     if (fRegister) 
  963.         hData = DdeClientXfer(NULL, 0L, hConv,
  964.                 msgTopicItemList[IIL_MSGUSERNAME].hszItem,
  965.                 DDEFMT_TEXT, XTYP_REQUEST, DEFTIMEOUT, NULL);
  966.         
  967.     if (!hData) 
  968.         return(FALSE);
  969.         
  970.     hsz = DdeGetHsz(DdeAccessData(hData), 0, 0);
  971.     DdeFreeData(hData);
  972.     
  973.     fDup = (hsz == hszEmailName) || FindUser(gnpUL, hsz);
  974.     
  975.     if (fDup && !fRegister) {
  976.         /*
  977.          * OOPS - we are a duplicate name! - Change our name and reregister!!!
  978.          * (we must first stop callbacks so the dialog modal loop
  979.          *  doesn't allow more messy callbacks to come in.)
  980.          */
  981.         DdeEnableCallback(NULL, FALSE);
  982.         while (gnpUL) 
  983.             DestroyUser(gnpUL);
  984.         WinSendMsg(hwndLB, LM_DELETEALL, 0L, 0L);
  985.         WinDlgBox(HWND_DESKTOP, NULL, (PFNWP)GetNameDlgProc, (HMODULE)NULL,
  986.                 IDD_GETNAME, (PVOID)szEmailName);
  987.         SetEmailName(szEmailName);
  988.         DdeEnableCallback(NULL, TRUE);
  989.         /*
  990.          * reregister with the name server so others know we changed our name.
  991.          */
  992.         DdeAppNameServer(hszAppName, ANS_UNREGISTER);
  993.         DdeAppNameServer(hszAppName, ANS_REGISTER);
  994.         DdeFreeHsz(hsz);
  995.         DdeFreeData(hData);
  996.         DdeDisconnect(hConv);
  997.         return(FALSE);
  998.     } 
  999.     
  1000.     if (!fDup)
  1001.         AddUser(hConv, hsz, hApp);
  1002.     /*
  1003.      * Now poke our name to him (if he is registering), so he gets updated
  1004.      * or discovers he's a duplicate.
  1005.      */
  1006.     if (fRegister) {
  1007.         DdeClientXfer(szEmailName, lstrlen(szEmailName) + 1L,
  1008.                 hConv, msgTopicItemList[IIL_MSGUSERNAME].hszItem,
  1009.                 DDEFMT_TEXT, XTYP_POKE, DEFTIMEOUT, NULL);
  1010.     }
  1011.     return(TRUE);
  1012. }
  1013.  
  1014.  
  1015.  
  1016. /* 
  1017.  * We search for the hApp in our user list.  If its not there we fail.
  1018.  * Otherwise, we destroy any associated connections or windows and
  1019.  * remove the entry from our list.
  1020.  *
  1021.  * The case of duplicate name re-registration is covered here since
  1022.  * we ignore duplicate registrations and so we will not find hApp
  1023.  * if a duplicate name is being unregistered.
  1024.  */
  1025. BOOL UnregisterUser(
  1026. HAPP hApp)
  1027. {
  1028.     NPUSERLIST npUser;
  1029.     SHORT lit;
  1030.  
  1031.     if (hApp == 0) {
  1032.         return(FALSE);
  1033.     }
  1034.     npUser = gnpUL;
  1035.     while (npUser) {
  1036.         if (hApp == npUser->hApp)
  1037.             break;
  1038.         npUser = npUser->next;
  1039.     }
  1040.     
  1041.     if (!npUser) {
  1042.         return(FALSE);
  1043.     }
  1044.     
  1045.     /*
  1046.      * Remove item from listbox.
  1047.      */        
  1048.     if (lit = (SHORT)WinSendMsg(hwndLB, LM_QUERYITEMCOUNT, 0L, 0L)) {
  1049.         while (lit--) {
  1050.             if (npUser == (NPUSERLIST)(SHORT)WinSendMsg(hwndLB,
  1051.                     LM_QUERYITEMHANDLE, MPFROMSHORT(lit), 0L)) {
  1052.                 WinSendMsg(hwndLB, LM_DELETEITEM, MPFROMSHORT(lit), 0L);   
  1053.                 break;
  1054.             }
  1055.         }
  1056.     }
  1057.     DestroyUser(npUser);
  1058. }
  1059.  
  1060.  
  1061.  
  1062. VOID SetEmailName(psz)
  1063. PSZ psz;
  1064. {
  1065.     if (hszEmailName) 
  1066.         DdeFreeHsz(hszEmailName);
  1067.     hszEmailName = DdeGetHsz(psz, 0, 0);
  1068.     lstrcpy(szEmailName, psz);
  1069.     lstrcat(szTitle, szTitlePrefix, szEmailName);
  1070.     WinSetWindowText(hwndMsngrFrame, szTitle);
  1071. }
  1072.  
  1073.  
  1074.  
  1075.  
  1076. void NotifyUser(psz)
  1077. PSZ psz;
  1078. {
  1079.     WinMessageBox(HWND_DESKTOP, hwndMsngr, psz, SZNOTIFYCAPTION,
  1080.             WID_NOTIFY1,
  1081.             MB_OK | MB_DEFBUTTON1 | MB_ICONASTERISK | MB_MOVEABLE);
  1082. }
  1083.  
  1084.  
  1085.  
  1086.  
  1087. void NotifyUser2(pszCaption, pszText)
  1088. PSZ pszCaption;
  1089. PSZ pszText;
  1090. {
  1091.     WinMessageBox(HWND_DESKTOP, hwndMsngr, pszText, pszCaption, WID_NOTIFY2,
  1092.             MB_OK | MB_DEFBUTTON1 | MB_ICONASTERISK | MB_MOVEABLE);
  1093. }
  1094.  
  1095.  
  1096.