home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / cmc.cli / cmccli.c next >
C/C++ Source or Header  |  1996-04-11  |  83KB  |  2,882 lines

  1. //
  2. //  C M C C L I . C
  3. //
  4. //      Sample CMC mail client for the MAPI 1.0 PDK.
  5. //      Uses the CMC interface without extensions.
  6. //
  7. //
  8.  
  9. #include <windows.h>
  10. #include <windowsx.h>
  11. #include <commdlg.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <lzexpand.h>
  16. #include <xcmc.h>
  17. #include <xcmcext.h>
  18. #include <xcmcmsxt.h>
  19. #include "pvalloc.h"
  20. #include "cmccli.h"
  21.  
  22. HINSTANCE hInst;
  23. HINSTANCE hlibCMC = (HINSTANCE)NULL;
  24.  
  25. LPFNCMCQUERYCONFIGURATION lpfnCMCQueryConfiguration = NULL;
  26. LPFNCMCLOGON lpfnCMCLogon = NULL;
  27. LPFNCMCLOGOFF lpfnCMCLogoff = NULL;
  28. LPFNCMCFREE lpfnCMCFree = NULL;
  29. LPFNCMCLOOKUP lpfnCMCLookUp = NULL;
  30. LPFNCMCLIST lpfnCMCList = NULL;
  31. LPFNCMCSEND lpfnCMCSend = NULL;
  32. LPFNCMCREAD lpfnCMCRead = NULL;
  33. LPFNCMCACTON lpfnCMCActOn = NULL;
  34.  
  35. // Static Data
  36.  
  37. static BOOL fPriority = 0;
  38. static BOOL fReturn = 0;
  39. static CMC_extension extMsgOpt[2] = \
  40.                      {{CMC_X_COM_PRIORITY, CMC_X_COM_NORMAL, NULL, 0}, \
  41.                       {CMC_X_MS_MESSAGE_DATA, 0, NULL, CMC_EXT_LAST_ELEMENT}};
  42.  
  43. static CMC_session_id lhSession = 0;
  44. static HBITMAP hReadBmp;
  45. static HBITMAP hReadABmp;
  46. static HBITMAP hUnReadBmp;
  47. static HBITMAP hUnReadABmp;
  48. static HCURSOR hWaitCur;
  49. static LPMSGID lpReadMsgNode=NULL;
  50. static CMC_message FAR *CmcMsg = NULL;
  51.  
  52. int PASCAL
  53. WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszCmd, int nCmdShow)
  54. {
  55.     MSG msg;
  56.  
  57.     hlibCMC = (HINSTANCE) NULL;
  58.  
  59.     if (!hPrevInst)
  60.         if (!InitApplication (hInstance))
  61.             return (FALSE);
  62.  
  63.     if (!InitInstance (hInstance, nCmdShow))
  64.         return (FALSE);
  65.  
  66.     while (GetMessage (&msg, (HWND) NULL, 0, 0))
  67.     {
  68.         TranslateMessage (&msg);
  69.         DispatchMessage (&msg);
  70.     }
  71.  
  72.     if (hReadBmp)
  73.         DeleteObject (hReadBmp);
  74.     if (hReadABmp)
  75.         DeleteObject (hReadABmp);
  76.     if (hReadBmp)
  77.         DeleteObject (hUnReadBmp);
  78.     if (hReadBmp)
  79.         DeleteObject (hUnReadABmp);
  80.  
  81.     DeinitApplication ();
  82.  
  83.     return (msg.wParam);
  84. }
  85.  
  86. //
  87. //  InitApplication
  88. //
  89. //  Purpose:
  90. //      Initialize the application.
  91. //
  92. //  Parameters:
  93. //      hInstance   - Instance handle
  94. //
  95. //  Returns:
  96. //      True/False
  97. //
  98. //
  99.  
  100. BOOL
  101. InitApplication (HINSTANCE hInstance)
  102. {
  103.     WNDCLASS wc;
  104.  
  105.     wc.style = 0;
  106.     wc.lpfnWndProc = MainWndProc;
  107.     wc.cbClsExtra = 0;
  108.     wc.cbWndExtra = 0;
  109.     wc.hInstance = hInstance;
  110.     wc.hIcon = LoadIcon (hInstance, "NoMail");
  111.     wc.hCursor = LoadCursor ((HINSTANCE) hInstance, IDC_ARROW);
  112.     wc.hbrBackground = GetStockObject (WHITE_BRUSH);
  113.     wc.lpszMenuName = "MailMenu";
  114.     wc.lpszClassName = "Client";
  115.  
  116.     return (RegisterClass (&wc));
  117. }
  118.  
  119. //
  120. //  InitInstance
  121. //
  122. //  Purpose:
  123. //      Initialize this instance.
  124. //
  125. //  Parameters:
  126. //      hInstance   - Instance handle
  127. //      nCmdShow    - Do we show the window?
  128. //
  129. //  Returns:
  130. //      True/False
  131. //
  132. //
  133.  
  134. BOOL
  135. InitInstance (HINSTANCE hInstance, int nCmdShow)
  136. {
  137.     HWND hWnd;
  138.     BOOL fInit;
  139.     CMC_return_code ulResult;
  140.     CMC_boolean UI_available;
  141.     CMC_extension ext;
  142.     CMC_X_COM_support sup[2];
  143.  
  144.     hInst = hInstance;
  145.  
  146.     hWnd = CreateWindow ("Client", "CMC Sample Mail Client", WS_OVERLAPPEDWINDOW,
  147.         5, 5, 300, 75, (HWND) NULL, (HMENU) NULL, hInst, NULL);
  148.  
  149.     if (!hWnd)
  150.         return (FALSE);
  151.  
  152.     ShowWindow (hWnd, nCmdShow);
  153.     UpdateWindow (hWnd);
  154.  
  155.     hReadBmp = LoadBitmap (hInst, MAKEINTRESOURCE (IDREAD));
  156.     hReadABmp = LoadBitmap (hInst, MAKEINTRESOURCE (IDREADA));
  157.     hUnReadBmp = LoadBitmap (hInst, MAKEINTRESOURCE (IDUNREAD));
  158.     hUnReadABmp = LoadBitmap (hInst, MAKEINTRESOURCE (IDUNREADA));
  159.  
  160.     hWaitCur = LoadCursor( (HINSTANCE) NULL, IDC_WAIT);
  161.  
  162.     if (fInit = InitSimpleCMC ())
  163.     {
  164.         if((ulResult = CMCQueryConfiguration(
  165.            (CMC_session_id) NULL, // no session handle yet!
  166.            CMC_CONFIG_UI_AVAIL,   // Make sure UI is available
  167.            &UI_available,         // return value
  168.            NULL))==CMC_SUCCESS)
  169.         {
  170.             sup[0].item_code = CMC_XS_COM;
  171.             sup[0].flags = 0;
  172.             sup[1].item_code = CMC_XS_MS;
  173.             sup[1].flags = 0;
  174.             ext.item_code = CMC_X_COM_SUPPORT_EXT;
  175.             ext.item_data = 2;
  176.             ext.item_reference = sup;
  177.             ext.extension_flags = CMC_EXT_LAST_ELEMENT;
  178.  
  179.             /* CMCLogon might yield control to Windows. So to prevent the user
  180.             from clicking "logon" while we are in the process of loggin on we
  181.             have to disable it*/
  182.             SecureMenu(hWnd, TRUE);
  183.  
  184.             if ((ulResult = CMCLogon (NULL, NULL, NULL, (CMC_enum)0,
  185.                                   (CMC_ui_id)hWnd, CMC_VERSION,
  186.                                   CMC_LOGON_UI_ALLOWED | CMC_ERROR_UI_ALLOWED,
  187.                                   &lhSession, &ext))==CMC_SUCCESS)
  188.             {
  189.                 if(sup[0].flags & CMC_X_COM_SUPPORTED)
  190.                     fPriority = TRUE;
  191.                 else
  192.                     fPriority = FALSE;
  193.                 if(sup[1].flags & CMC_X_COM_SUPPORTED)
  194.                     fReturn = TRUE;
  195.                 else
  196.                     fReturn = FALSE;
  197.  
  198.                 ToggleMenuState (hWnd, TRUE);
  199.             }
  200.             else
  201.             {
  202.                 SecureMenu(hWnd, FALSE);
  203.                 lhSession = 0;
  204.                 MakeMessageBox (hWnd, ulResult, IDS_LOGONFAIL, MBS_ERROR);
  205.             }
  206.         }
  207.         else
  208.         {
  209.             lhSession = 0;
  210.             MakeMessageBox (hWnd, ulResult, IDS_LOGONFAIL, MBS_ERROR);
  211.         }
  212.     }
  213.     return (fInit);
  214. }
  215.  
  216. //
  217. //  InitSimpleCMC
  218. //
  219. //  Purpose:
  220. //      Loads the DLL containing the simple CMC functions and sets
  221. //      up a pointer to each. Wrappers for the  function pointers
  222. //      are declared in CLIENT.H.
  223. //
  224. //  Returns:
  225. //      TRUE if sucessful, else FALSE
  226. //
  227. //  Side effects:
  228. //      Loads a DLL and sets up function pointers
  229. //
  230. BOOL
  231. InitSimpleCMC (void)
  232. {
  233.     char    szMsgBuf[512]="";
  234.     char    szLibName[32]
  235.         #ifdef WIN16
  236.             ="MAPI.DLL";
  237.         #else
  238.             ="MAPI32.dll";
  239.         #endif
  240.  
  241.     /*
  242.      *Check if CMC is installed on the system
  243.      */
  244.     if(!fCMCInstalled())
  245.         return FALSE;
  246.  
  247.  
  248.     // Get INI directives for alternate DLL PATH
  249.     
  250. #ifdef WIN16
  251.     GetProfileString( "Mail", "CMCDLLNAME", szLibName, szLibName, 
  252.             sizeof(szLibName) - 1 );
  253. #else
  254.     GetProfileString( "Mail", "CMCDLLNAME32", szLibName, szLibName, 
  255.             sizeof(szLibName) - 1 );
  256. #endif  
  257.  
  258. #ifdef WIN16
  259.     if ((hlibCMC = LoadLibrary (szLibName)) <  32)
  260. #else
  261.     if ((hlibCMC = LoadLibrary (szLibName)) <  (HINSTANCE) 32)
  262. #endif
  263.     {
  264.         wsprintf(szMsgBuf,"Cannot Load %s.  Check to see that you have %s in your path or '~SystemRoot~\\System' "
  265.                           "directory.  You may change the CMC dll path by adding a [MAIL] section to your "
  266.                           "WIN.INI file wtih the following entry: CMCDLLNAME=\\MAPI.REL\\MAPI.DLL",
  267.                           szLibName,szLibName);
  268.         MessageBox(NULL, szMsgBuf,"Error", MB_ICONSTOP | MB_OK);
  269.         return FALSE;
  270.     }
  271.  
  272.     if (!(lpfnCMCQueryConfiguration = (LPFNCMCQUERYCONFIGURATION)GetProcAddress (hlibCMC, "cmc_query_configuration") ))
  273.     {
  274.         wsprintf(szMsgBuf,"Cannot Load CMC process functions from %s.  Check that you do not have an "
  275.                           "outdated version of %s in your '~SystemRoot~\\System' directory.  If you do then you "
  276.                           "may change the CMC dll path by adding a [MAIL] section to your WIN.INI file with the "
  277.                           "following entry: CMCDLLNAME=\\MAPI.REL\\%s",szLibName,szLibName,szLibName);
  278.         MessageBox(NULL, szMsgBuf,"Error", MB_ICONSTOP | MB_OK);
  279.         return FALSE;
  280.     }
  281.  
  282.     if (!(lpfnCMCLogon  =  (LPFNCMCLOGON)GetProcAddress (hlibCMC, "cmc_logon") ))
  283.     {
  284.         MessageBox(NULL, "Cannot Load cmc_logon process address.","Error", MB_ICONSTOP | MB_OK);
  285.         return FALSE;
  286.     }
  287.  
  288.     if (!(lpfnCMCLogoff  =  (LPFNCMCLOGOFF)GetProcAddress (hlibCMC, "cmc_logoff") ))
  289.     {
  290.         MessageBox(NULL, "Cannot Load cmc_logoff process address.","Error", MB_ICONSTOP | MB_OK);
  291.         return FALSE;
  292.     }
  293.  
  294.     if (!(lpfnCMCFree  =  (LPFNCMCFREE)GetProcAddress (hlibCMC, "cmc_free") ))
  295.     {
  296.         MessageBox(NULL, "Cannot Load cmc_free process address.","Error", MB_ICONSTOP | MB_OK);
  297.         return FALSE;
  298.     }
  299.  
  300.     if (!(lpfnCMCLookUp  =  (LPFNCMCLOOKUP)GetProcAddress (hlibCMC, "cmc_look_up") ))
  301.     {
  302.         MessageBox(NULL, "Cannot Load cmc_look_up process address.","Error", MB_ICONSTOP | MB_OK);
  303.         return FALSE;
  304.     }
  305.  
  306.     if (!(lpfnCMCList  =  (LPFNCMCLIST)GetProcAddress (hlibCMC, "cmc_list") ))
  307.     {
  308.         MessageBox(NULL, "Cannot Load cmc_list process address.","Error", MB_ICONSTOP | MB_OK);
  309.         return FALSE;
  310.     }
  311.  
  312.     if (!(lpfnCMCSend  =  (LPFNCMCSEND)GetProcAddress (hlibCMC, "cmc_send") ))
  313.     {
  314.         MessageBox(NULL, "Cannot Load cmc_send process address.","Error", MB_ICONSTOP | MB_OK);
  315.         return FALSE;
  316.     }
  317.  
  318.     if (!(lpfnCMCRead  =  (LPFNCMCREAD)GetProcAddress (hlibCMC, "cmc_read") ))
  319.     {
  320.         MessageBox(NULL, "Cannot Load cmc_read process address.","Error", MB_ICONSTOP | MB_OK);
  321.         return FALSE;
  322.     }
  323.  
  324.     if (!(lpfnCMCActOn  =  (LPFNCMCACTON)GetProcAddress (hlibCMC, "cmc_act_on") ))
  325.     {
  326.         MessageBox(NULL, "Cannot Load cmc_acto_on process address.","Error", MB_ICONSTOP | MB_OK);
  327.         return FALSE;
  328.     }
  329.  
  330.     return (TRUE);
  331.  
  332. }
  333.  
  334.  
  335. /*
  336.  -  fCMCInstalled
  337.  -
  338.  *  Purpose:
  339.  *      Checks the appropriate win.ini/registry value to see if CMC is
  340.  *      installed in the system. 
  341.  *  
  342.  *  Returns:
  343.  *      TRUE if CMC is installed, else FALSE
  344.  *
  345.  */
  346. BOOL
  347. fCMCInstalled(void)
  348. {
  349. #ifdef _WIN32
  350.     /* on win32 the value to check is 
  351.         HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Messaging Subsystem\CMC
  352.     */
  353.     
  354.     LONG lr;
  355.     HKEY hkWMS;
  356.     
  357.     #define CMCVSize 8
  358.     char szCMCValue[CMCVSize];
  359.     DWORD dwType;
  360.     DWORD cbCMCValue = CMCVSize;
  361.  
  362.     lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  363.                     "SOFTWARE\\Microsoft\\Windows Messaging Subsystem",
  364.                      0, KEY_READ, &hkWMS);
  365.     if(ERROR_SUCCESS == lr)
  366.     {
  367.         lr = RegQueryValueEx(hkWMS, "CMC", 0, &dwType, szCMCValue, &cbCMCValue);
  368.         RegCloseKey(hkWMS);
  369.         if(ERROR_SUCCESS == lr)
  370.         {
  371.             if(lstrcmp(szCMCValue, "1") == 0)
  372.                 return TRUE;
  373.         }
  374.     }
  375.     
  376.     return FALSE;
  377.  
  378. #else /*_WIN32*/
  379.     
  380.     /*check the win.ini value*/
  381.     return GetProfileInt("Mail", "CMC", 0);
  382.  
  383. #endif /*_WIN32*/
  384. }
  385.  
  386.  
  387. void
  388. DeinitSimpleCMC ()
  389. {
  390.     if (hlibCMC)
  391.     {
  392.         FreeLibrary (hlibCMC);
  393.         hlibCMC = (HINSTANCE) NULL;
  394.     }
  395. }
  396.  
  397.  
  398. void
  399. DeinitApplication ()
  400. {
  401.     DeinitSimpleCMC ();
  402. }
  403.  
  404.  
  405. //
  406. //  MainWndProc
  407. //
  408. //  Purpose:
  409. //      Main Window Procedure for test program.
  410. //
  411. //  Parameters:
  412. //      hWnd
  413. //      message
  414. //      wParam
  415. //      lParam
  416. //
  417. //  Returns:
  418. //
  419. //
  420. //
  421.  
  422. LONG FAR PASCAL
  423. MainWndProc (HWND hWnd, UINT msg, UINT wParam, LPARAM lParam)
  424. {
  425.     CMC_return_code ulResult;
  426.     CMC_boolean UI_available;
  427.     CMC_message far *lpmsg;
  428.     ULONG cNewRecips;
  429.     CMC_recipient FAR *lpNewRecips;
  430.     CMC_extension ext;
  431.     char *szFoo[2];
  432.  
  433.     switch (msg)
  434.     {
  435.     case WM_COMMAND:
  436.         switch (LOWORD (wParam)) {
  437.         case IDM_LOGON:
  438.             if (!lhSession) {
  439.                 if ( (ulResult = CMCQueryConfiguration(
  440.                      (CMC_session_id) NULL, // no session handle yet!
  441.                     CMC_CONFIG_UI_AVAIL, // Make sure UI is available
  442.                     &UI_available, // return value
  443.                     NULL))==CMC_SUCCESS) { // no extensions
  444.  
  445.                     SecureMenu(hWnd, TRUE);
  446.  
  447.                     if ((ulResult = CMCLogon (NULL,  // Default service
  448.                            NULL,  // Prompt for username
  449.                            NULL,  // Prompt for password
  450.                            (CMC_enum)NULL, // Default Character set
  451.                            (CMC_ui_id) NULL, // Default UI ID
  452.                            CMC_VERSION,  // Version 1 CMC calls
  453.                            CMC_LOGON_UI_ALLOWED | CMC_ERROR_UI_ALLOWED, // full logon and allow errors
  454.                            &lhSession, // returned session id
  455.                            NULL))==CMC_SUCCESS) { // no extensions
  456.  
  457.                         ToggleMenuState (hWnd, TRUE);
  458.                     } else {
  459.                         SecureMenu(hWnd, FALSE);
  460.                         lhSession = 0;
  461.                         MakeMessageBox (hWnd, ulResult, IDS_LOGONFAIL, MBS_ERROR);
  462.                     }
  463.                 }
  464.             }
  465.             break;
  466.  
  467.         case IDM_LOGOFF:
  468.             if (lhSession) {
  469.                CMCLogoff (lhSession, (CMC_ui_id) NULL, 0, 0);
  470.                ToggleMenuState (hWnd, FALSE);
  471.                 lhSession = 0;
  472.             }
  473.             break;
  474.  
  475.         case IDM_COMPOSE_CUSTOM:
  476.             DialogBox (hInst, "ComposeNote", hWnd, ComposeDlgProc);
  477.             break;
  478.  
  479.         case IDM_COMPOSE_CMC:
  480.             lpmsg = (CMC_message far *)GlobalAllocPtr(GPTR, sizeof(CMC_message));
  481.             ulResult = CMCSend(lhSession, 
  482.                             lpmsg, 
  483.                             CMC_SEND_UI_REQUESTED | CMC_ERROR_UI_ALLOWED,
  484.                             (CMC_ui_id)hWnd, NULL);
  485.             if (ulResult != CMC_SUCCESS)
  486.             {
  487.                 if (ulResult != CMC_E_USER_CANCEL)
  488.                 MakeMessageBox (hWnd, ulResult, IDS_SENDERROR, MBS_ERROR);
  489.             }
  490.             else
  491.             GlobalFreePtr(lpmsg);
  492.             break;
  493.  
  494.         case IDM_READ:
  495.             DialogBox (hInst, "InBox", hWnd, InBoxDlgProc);
  496.             break;
  497.  
  498.         case IDM_ADDRBOOK:
  499.             if (lhSession)
  500.             {
  501.                 szFoo[0] = "";
  502.                 szFoo[1] = "";
  503.                 cNewRecips = 0;
  504.                 ext.item_code = CMC_X_MS_ADDRESS_UI;
  505.                 ext.item_data = 0;
  506.                 ext.item_reference = szFoo;
  507.                 ext.extension_flags = CMC_EXT_LAST_ELEMENT;
  508.                 ulResult = CMCLookUp (lhSession, NULL, CMC_LOOKUP_ADDRESSING_UI,
  509.                     (CMC_ui_id)hWnd, &cNewRecips, &lpNewRecips, &ext);
  510.  
  511.                 if (ulResult != CMC_SUCCESS)
  512.                 {
  513.                     if (ulResult != CMC_E_USER_CANCEL)
  514.                         MakeMessageBox (hWnd, ulResult, IDS_ADDRBOOKFAIL, MBS_ERROR);
  515.                 }
  516.             }
  517.             break;
  518.  
  519.         case IDM_ABOUT:
  520.             DialogBox (hInst, "AboutBox", hWnd, AboutDlgProc);
  521.             break;
  522.  
  523.         case IDM_EXIT:
  524.             if (lhSession) {
  525.                CMCLogoff (lhSession, (CMC_ui_id) NULL, 0, 0);
  526.                ToggleMenuState (hWnd, FALSE);
  527.                 lhSession = 0;
  528.             }
  529.  
  530.             PostQuitMessage (0);
  531.             break;
  532.  
  533.         default:
  534.             return (DefWindowProc (hWnd, msg, wParam, lParam));
  535.         }
  536.         break;
  537.  
  538.     case WM_ENDSESSION:
  539.         DestroyWindow (hWnd);
  540.         break;
  541.  
  542.     case WM_CLOSE:
  543.     case WM_DESTROY:
  544.         if (lhSession) {
  545.            CMCLogoff (lhSession, (CMC_ui_id) NULL, 0, 0);
  546.            ToggleMenuState (hWnd, FALSE);
  547.             lhSession = 0;
  548.         }
  549.         PostQuitMessage (0);
  550.         break;
  551.  
  552.     default:
  553.         return (DefWindowProc (hWnd, msg, wParam, lParam));
  554.     }
  555.     return FALSE;
  556. }
  557.  
  558. //
  559. //  AboutDlgProc
  560. //
  561. //  Purpose:
  562. //      About box dialog procedure
  563. //
  564. //  Parameters:
  565. //      hDlg
  566. //      message
  567. //      wParam
  568. //      lParam
  569. //
  570. //  Returns:
  571. //      True/False
  572. //
  573. //
  574.  
  575. BOOL FAR PASCAL
  576. AboutDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam)
  577. {
  578.     char    rgchVersion[80];
  579.  
  580.     switch (msg)
  581.     {
  582.     case WM_INITDIALOG:
  583.         sprintf(rgchVersion, "Version %01.1f", ((float)CMC_VERSION)/100);
  584.         SetDlgItemText(hDlg, IDC_VERSION, rgchVersion);
  585.         return TRUE;
  586.  
  587.     case WM_COMMAND:
  588.         if (wParam == IDOK || wParam == IDCANCEL)
  589.         {
  590.             EndDialog (hDlg, TRUE);
  591.             return TRUE;
  592.         }
  593.         break;
  594.     }
  595.     return FALSE;
  596. }
  597.  
  598.  
  599. //
  600. //  ComposeDlgProc
  601. //
  602. //  Purpose:
  603. //      Dialog procedure for the ComposeNote dialog.
  604. //
  605. //  Parameters:
  606. //      hDlg
  607. //      message
  608. //      wParam
  609. //      lParam
  610. //
  611. //  Returns:
  612. //      True/False
  613. //
  614. //
  615.  
  616. BOOL FAR PASCAL
  617. ComposeDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam)
  618. {
  619.     char szUnResNames[TO_EDIT_MAX];
  620.     char szDisplayNames[TO_EDIT_MAX];
  621.     char szAttach[FILE_ATTACH_MAX];
  622.     BOOL fUnResTo, fUnResCc;
  623.     LONG cb, cLines;
  624.     ULONG ulResult;
  625.     HCURSOR hOldCur;
  626.     static CMC_string lpszSubject;
  627.     static CMC_string lpszTextNote;
  628.     static ULONG cRecips;
  629.     static ULONG cNewRecips;
  630.     static ULONG cAttach;
  631.     static CMC_recipient FAR *lpRecips;
  632.     static CMC_recipient FAR *lpNewRecips;
  633.     static CMC_attachment FAR *lpAttach;
  634.     CMC_extension ext;
  635.     char *szFoo[2]={"",""};
  636.  
  637.     switch (msg) {
  638.     case WM_INITDIALOG:
  639.         if (CmcMsg)
  640.         {
  641.             //  ComposeNote is being called to either forward or reply
  642.             //  to a message in the Inbox.  So, we'll initialize the
  643.             //  ComposeNote form with data from the global CMC_message
  644.  
  645.             lpszSubject = CmcMsg->subject;
  646.             lpszTextNote = CmcMsg->text_note;
  647.  
  648.             lpRecips = CmcMsg->recipients;
  649.             lpAttach = CmcMsg->attachments;
  650.  
  651.             if (lpRecips == NULL)
  652.             {
  653.               cRecips = 0;
  654.             }
  655.             else
  656.             {
  657.                 cRecips = 0;
  658.                 while(!(lpRecips[cRecips].recip_flags & CMC_RECIP_LAST_ELEMENT))
  659.                     cRecips++;
  660.  
  661.                 cRecips++;
  662.             }
  663.  
  664.             if (lpAttach == NULL)
  665.             {
  666.               cAttach = 0;
  667.             }
  668.             else
  669.             {
  670.                 cAttach = 0;
  671.                 while(!(lpAttach[cAttach].attach_flags & CMC_ATT_LAST_ELEMENT))
  672.                     cAttach++;
  673.  
  674.                 cAttach++;
  675.             }
  676.  
  677.             if (cRecips)
  678.             {
  679.                 MakeDisplayNameStr (szDisplayNames, CMC_ROLE_TO, cRecips, lpRecips);
  680.                 if (*szDisplayNames)
  681.                     SetDlgItemText (hDlg, IDC_TO, szDisplayNames);
  682.  
  683.                 MakeDisplayNameStr (szDisplayNames, CMC_ROLE_CC, cRecips, lpRecips);
  684.                 if (*szDisplayNames)
  685.                     SetDlgItemText (hDlg, IDC_CC, szDisplayNames);
  686.             }
  687.             SetDlgItemText (hDlg, IDC_SUBJECT, CmcMsg->subject);
  688.             SetDlgItemText (hDlg, IDC_NOTE, CmcMsg->text_note);
  689.  
  690.             SendDlgItemMessage (hDlg, IDC_TO, EM_SETMODIFY, FALSE, 0);
  691.             SendDlgItemMessage (hDlg, IDC_CC, EM_SETMODIFY, FALSE, 0);
  692.             SendDlgItemMessage (hDlg, IDC_SUBJECT, EM_SETMODIFY, FALSE, 0);
  693.             SendDlgItemMessage (hDlg, IDC_NOTE, EM_SETMODIFY, FALSE, 0);
  694.             if(cRecips)
  695.                 SetFocus (GetDlgItem (hDlg, IDC_NOTE));
  696.             else
  697.                 SetFocus (GetDlgItem (hDlg, IDC_TO));
  698.         }
  699.  
  700.         else
  701.         {
  702.             if(CmcMsg)
  703.                 PvFree(CmcMsg);
  704.  
  705.             CmcMsg = (CMC_message *)PvAlloc(sizeof(CMC_message));
  706.             if (!CmcMsg)
  707.                 goto cleanup;
  708.  
  709.             _fmemset (CmcMsg, 0, sizeof (CMC_message));
  710.  
  711.             lpszSubject = NULL;
  712.             lpszTextNote = NULL;
  713.             cRecips = 0;
  714.             cAttach = 0;
  715.             lpRecips = NULL;
  716.             lpNewRecips = NULL;
  717.             lpAttach = NULL;
  718.  
  719.             SetFocus (GetDlgItem (hDlg, IDC_TO));
  720.         }
  721.         return FALSE;
  722.  
  723.     case WM_COMMAND:
  724.         switch (LOWORD (wParam))
  725.         {
  726.         case IDC_ATTACH:
  727.             if (GetNextFile (hDlg, (ULONG) -1, &cAttach, &lpAttach) == CMC_SUCCESS)
  728.             {
  729.                 //   Now, send a little render message to the text_note edit
  730.  
  731.                 wsprintf (szAttach, "<<File: %s>>",
  732.                     lpAttach[cAttach - 1].attach_title);
  733.  
  734.                 SendDlgItemMessage (hDlg, IDC_NOTE, EM_REPLACESEL, 0,
  735.                     (LPARAM) ((LPSTR) szAttach));
  736.             }
  737.             break;
  738.  
  739.         case IDC_ADDRBOOK:
  740.         
  741.             // To do:
  742.             // Add a parameter to ResolveFriendlyNames to prepare unresolved names
  743.             // but only as DN strings in recip list.
  744.             // When call returns from Address, rebuild the edit fields.
  745.  
  746.             cNewRecips = 0;
  747.             ext.item_code = CMC_X_MS_ADDRESS_UI;
  748.             ext.item_data = 2;
  749.             ext.item_reference = szFoo;
  750.             ext.extension_flags = CMC_EXT_LAST_ELEMENT;
  751.             
  752.             // include any recipients we've already resolved.
  753.             
  754.             ulResult = CMCLookUp (lhSession, lpRecips, CMC_LOOKUP_ADDRESSING_UI,
  755.                           (CMC_ui_id)hDlg, &cNewRecips, &lpNewRecips, &ext);
  756.  
  757.  
  758. //            cNewRecips = 0; // set to NULL to allow maximum number of names to be allocated
  759. //            ulResult = CMCLookUp (lhSession, lpRecips, CMC_LOOKUP_ADDRESSING_UI,
  760. //                                  (CMC_ui_id)hDlg, &cNewRecips, &lpNewRecips, NULL);
  761.  
  762.             if (ulResult)
  763.             {
  764.                 if (ulResult != CMC_E_USER_CANCEL)
  765.                     MakeMessageBox (hDlg, ulResult, IDS_ADDRBOOKFAIL, MBS_ERROR);
  766.             }
  767.             else
  768.             {
  769.                 if (cNewRecips)
  770.                 {
  771.                     PvFree(lpRecips);
  772.                     cRecips = 0;
  773.  
  774.                     lpRecips = (CMC_recipient far *)PvAlloc(cNewRecips * sizeof(CMC_recipient));
  775.  
  776.                     while(cRecips < cNewRecips)
  777.                     {
  778.                         if(CopyRecipient(lpRecips, &lpRecips[cRecips],
  779.                                          &lpNewRecips[cRecips]))
  780.                         {
  781.                             PvFree(lpRecips);
  782.                             lpRecips = NULL;
  783.                             cRecips = 0;
  784.                             break;
  785.                         }
  786.                         cRecips++;
  787.                     }
  788.  
  789.                     CMCFree(lpNewRecips);
  790.                     lpNewRecips = NULL;
  791.                     cNewRecips = 0;
  792.  
  793.                     MakeDisplayNameStr(szDisplayNames, CMC_ROLE_TO,
  794.                                        cRecips, lpRecips);
  795.                     if (*szDisplayNames)
  796.                         SetDlgItemText (hDlg, IDC_TO, szDisplayNames);
  797.  
  798.                     MakeDisplayNameStr(szDisplayNames, CMC_ROLE_CC,
  799.                                        cRecips, lpRecips);
  800.                     if (*szDisplayNames)
  801.                         SetDlgItemText (hDlg, IDC_CC, szDisplayNames);
  802.  
  803.                     SendDlgItemMessage (hDlg, IDC_TO, EM_SETMODIFY, FALSE, 0);
  804.                     SendDlgItemMessage (hDlg, IDC_CC, EM_SETMODIFY, FALSE, 0);
  805.                 }
  806.             }
  807.             break;
  808.  
  809.         case IDC_OPTIONS:
  810.             DialogBox (hInst, "Options", hDlg, OptionsDlgProc);
  811.             break;
  812.  
  813.         case IDC_SEND:
  814.         case IDC_RESOLVE:
  815.             fUnResTo = FALSE;
  816.             fUnResCc = FALSE;
  817.  
  818.             hOldCur = SetCursor(hWaitCur);
  819.  
  820.             //   Get the names from the To: field and resolve them first
  821.  
  822.             if (SendDlgItemMessage (hDlg, IDC_TO, EM_GETMODIFY, 0, 0) &&
  823.                 (cb = SendDlgItemMessage (hDlg, IDC_TO, WM_GETTEXT,
  824.                     (WPARAM)sizeof(szUnResNames),
  825.                     (LPARAM) (LPSTR) szUnResNames)))
  826.             {
  827.                 if (!ResolveFriendlyNames (hDlg, szUnResNames, CMC_ROLE_TO,
  828.                         &cRecips, &lpRecips))
  829.                 {
  830.                     MakeDisplayNameStr (szDisplayNames, CMC_ROLE_TO,
  831.                         cRecips, lpRecips);
  832.                     if (*szDisplayNames)
  833.                     {
  834.                         if (*szUnResNames)
  835.                         {
  836.                             lstrcat (szDisplayNames, "; ");
  837.                             lstrcat (szDisplayNames, szUnResNames);
  838.                             fUnResTo = TRUE;
  839.                         }
  840.  
  841.                         SetDlgItemText (hDlg, IDC_TO, szDisplayNames);
  842.                     }
  843.                     else
  844.                     {
  845.                         if (*szUnResNames)
  846.                         {
  847.                             SetDlgItemText (hDlg, IDC_TO, szUnResNames);
  848.                             fUnResTo = TRUE;
  849.                         }
  850.                     }
  851.                 }
  852.                 SendDlgItemMessage (hDlg, IDC_TO, EM_SETMODIFY, FALSE, 0);
  853.             }
  854.  
  855.             //   Now, get the names from the Cc: field and resolve them
  856.  
  857.             if (SendDlgItemMessage (hDlg, IDC_CC, EM_GETMODIFY, 0, 0) &&
  858.                 (cb = SendDlgItemMessage (hDlg, IDC_CC, WM_GETTEXT,
  859.                     (WPARAM)sizeof(szUnResNames), (LPARAM)(LPSTR)szUnResNames)))
  860.             {
  861.                 if (!ResolveFriendlyNames (hDlg, szUnResNames, CMC_ROLE_CC,
  862.                         &cRecips, &lpRecips))
  863.                 {
  864.                     MakeDisplayNameStr (szDisplayNames, CMC_ROLE_CC,
  865.                         cRecips, lpRecips);
  866.                     if (*szDisplayNames)
  867.                     {
  868.                         if (*szUnResNames)
  869.                         {
  870.                             lstrcat (szDisplayNames, "; ");
  871.                             lstrcat (szDisplayNames, szUnResNames);
  872.                             fUnResCc = TRUE;
  873.                         }
  874.  
  875.                         SetDlgItemText (hDlg, IDC_CC, szDisplayNames);
  876.                     }
  877.                     else
  878.                     {
  879.                         if (*szUnResNames)
  880.                         {
  881.                             SetDlgItemText (hDlg, IDC_CC, szUnResNames);
  882.                             fUnResCc = TRUE;
  883.                         }
  884.                     }
  885.                 }
  886.                 SendDlgItemMessage (hDlg, IDC_CC, EM_SETMODIFY, FALSE, 0);
  887.             }
  888.  
  889.             //   If we were just Resolving Names then we can leave now
  890.  
  891.             if (LOWORD (wParam) == IDC_RESOLVE)
  892.             {
  893.                 SetCursor(hOldCur);
  894.                 break;
  895.             }
  896.  
  897.             if (cRecips == 0 || fUnResTo || fUnResCc)
  898.             {
  899.                 if (!cRecips)
  900.                     MakeMessageBox (hDlg, 0, IDS_NORECIPS, MBS_OOPS);
  901.  
  902.                 if (fUnResTo)
  903.                     SetFocus (GetDlgItem (hDlg, IDC_TO));
  904.                 else if (fUnResCc)
  905.                     SetFocus (GetDlgItem (hDlg, IDC_CC));
  906.                 else
  907.                     SetFocus (GetDlgItem (hDlg, IDC_TO));
  908.  
  909.                 SetCursor(hOldCur);
  910.                 break;
  911.             }
  912.  
  913.             //   Everything is OK so far, lets get the Subject
  914.             //   and the text_note and try to send the message.
  915.  
  916.             //   Get Subject from Edit
  917.  
  918.             if (SendDlgItemMessage (hDlg, IDC_SUBJECT, EM_GETMODIFY, 0, 0))
  919.             {
  920.                 cb = SendDlgItemMessage (hDlg, IDC_SUBJECT, EM_LINELENGTH, 0, 0L);
  921.  
  922.                 CMCFree (lpszSubject);
  923.                 lpszSubject = (LPSTR)PvAlloc(cb + 1);
  924.                 if (!lpszSubject)
  925.                     goto cleanup;
  926.  
  927.                 GetDlgItemText (hDlg, IDC_SUBJECT, lpszSubject, (int)cb+1);
  928.             }
  929.  
  930.             //   Get the text_note from Edit
  931.  
  932.             if (SendDlgItemMessage (hDlg, IDC_NOTE, EM_GETMODIFY, 0, 0))
  933.             {
  934.                 cLines = SendDlgItemMessage (hDlg, IDC_NOTE,
  935.                     EM_GETLINECOUNT, 0, 0L);
  936.  
  937.                 if (cLines)
  938.                 {
  939.                     //   Get the total number of bytes in the multi-line
  940.  
  941.                     cb = SendDlgItemMessage (hDlg, IDC_NOTE, EM_LINEINDEX,
  942.                         (WPARAM) cLines - 1, 0L);
  943.                     cb += SendDlgItemMessage (hDlg, IDC_NOTE, EM_LINELENGTH,
  944.                         (WPARAM)cb, 0L);
  945.  
  946.                     //   The next line is to account for CR-LF pairs per line.
  947.  
  948.                     cb += cLines * 2;
  949.  
  950.                     CMCFree (lpszTextNote);
  951.                     lpszTextNote = (LPSTR)PvAlloc(cb + 1);
  952.                     if (!lpszTextNote)
  953.                         goto cleanup;
  954.  
  955.                     //   Get the Note Text from the edit
  956.  
  957.                     GetDlgItemText (hDlg, IDC_NOTE, lpszTextNote, (int)cb);
  958.                 }
  959.                 else
  960.                 {
  961.                     //   Make an empty string for text_note
  962.  
  963.                     lpszTextNote = (LPSTR)PvAlloc(1);
  964.                     *lpszTextNote = '\0';
  965.                 }
  966.             }
  967.  
  968.             CmcMsg->subject = lpszSubject;
  969.             CmcMsg->text_note = lpszTextNote;
  970.             CmcMsg->recipients = lpRecips;
  971.             CmcMsg->attachments = lpAttach;
  972.             CmcMsg->message_extensions = extMsgOpt;
  973.  
  974.             ulResult = CMCSend(lhSession, CmcMsg, CMC_ERROR_UI_ALLOWED,
  975.                                (CMC_ui_id)hDlg, (CMC_extension far *)NULL);
  976.  
  977.             LogSendMail(ulResult);
  978.  
  979.             if (ulResult)
  980.             {
  981.                 MakeMessageBox (hDlg, ulResult, IDS_SENDERROR, MBS_ERROR);
  982.                 SetCursor(hOldCur);
  983.                 break;
  984.             }
  985. cleanup:
  986.         case IDCANCEL:
  987.             SetCursor(hOldCur);
  988.             PvFree(CmcMsg->message_type);
  989.             PvFree(CmcMsg);
  990.             PvFree(lpRecips);
  991.             PvFree(lpAttach);
  992.             PvFree(lpszSubject);
  993.             PvFree(lpszTextNote);
  994.             CmcMsg = NULL;
  995.  
  996.             EndDialog (hDlg, TRUE);
  997.             return TRUE;
  998.             break;
  999.  
  1000.         default:
  1001.             break;
  1002.         }
  1003.         break;
  1004.     }
  1005.     return FALSE;
  1006. }
  1007.  
  1008. /*
  1009.  -  OptionsDlgProc
  1010.  -
  1011.  *  Purpose:
  1012.  *      Message Options dialog procedure
  1013.  *
  1014.  *  Parameters:
  1015.  *      hDlg
  1016.  *      message
  1017.  *      wParam
  1018.  *      lParam
  1019.  *
  1020.  *  Returns:
  1021.  *      True/False
  1022.  *
  1023.  */
  1024.  
  1025. BOOL FAR PASCAL
  1026. OptionsDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam)
  1027. {
  1028.     switch (msg)
  1029.     {
  1030.     case WM_INITDIALOG:
  1031.         CheckDlgButton (hDlg, IDC_RETURN,
  1032.             (UINT)(extMsgOpt[1].item_data & (CMC_uint32)CMC_X_MS_MSG_RECEIPT_REQ));
  1033.  
  1034.         switch(extMsgOpt[0].item_data)
  1035.         {
  1036.         case CMC_X_COM_URGENT:
  1037.             CheckRadioButton(hDlg, IDC_URGENT, IDC_LOW, IDC_URGENT);
  1038.             break;
  1039.  
  1040.         case CMC_X_COM_NORMAL:
  1041.             CheckRadioButton(hDlg, IDC_URGENT, IDC_LOW, IDC_NORMAL);
  1042.             break;
  1043.  
  1044.         case CMC_X_COM_LOW:
  1045.             CheckRadioButton(hDlg, IDC_URGENT, IDC_LOW, IDC_LOW);
  1046.             break;
  1047.         }
  1048.         return TRUE;
  1049.  
  1050.     case WM_COMMAND:
  1051.         switch (LOWORD (wParam))
  1052.         {
  1053.         case IDC_RETURN:
  1054.             CheckDlgButton(hDlg, IDC_RETURN,
  1055.                          !IsDlgButtonChecked(hDlg, IDC_RETURN));
  1056.             break;
  1057.  
  1058.         case IDC_URGENT:
  1059.             CheckRadioButton(hDlg, IDC_URGENT, IDC_LOW, IDC_URGENT);
  1060.             extMsgOpt[0].item_data = CMC_X_COM_URGENT;
  1061.             break;
  1062.  
  1063.         case IDC_NORMAL:
  1064.             CheckRadioButton(hDlg, IDC_URGENT, IDC_LOW, IDC_NORMAL);
  1065.             extMsgOpt[0].item_data = CMC_X_COM_NORMAL;
  1066.             break;
  1067.  
  1068.         case IDC_LOW:
  1069.             CheckRadioButton(hDlg, IDC_URGENT, IDC_LOW, IDC_LOW);
  1070.             extMsgOpt[0].item_data = CMC_X_COM_LOW;
  1071.             break;
  1072.  
  1073.         case IDOK:
  1074.             if (IsDlgButtonChecked (hDlg, IDC_RETURN))
  1075.                 extMsgOpt[1].item_data |= CMC_X_MS_MSG_RECEIPT_REQ;
  1076.             else
  1077.                 extMsgOpt[1].item_data &= ~CMC_X_MS_MSG_RECEIPT_REQ;
  1078.  
  1079.         case IDCANCEL:
  1080.             EndDialog (hDlg, TRUE);
  1081.             return TRUE;
  1082.         }
  1083.         break;
  1084.     }
  1085.     return FALSE;
  1086. }
  1087.  
  1088.  
  1089. //
  1090. //  InBoxDlgProc
  1091. //
  1092. //  Purpose:
  1093. //      Dialog procedure for the InBox dialog.
  1094. //
  1095. //  Parameters:
  1096. //      hDlg
  1097. //      message
  1098. //      wParam
  1099. //      lParam
  1100. //
  1101. //  Returns:
  1102. //      True/False
  1103. //
  1104.  
  1105.  
  1106. BOOL FAR PASCAL
  1107. InBoxDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam)
  1108. {
  1109.     MEASUREITEMSTRUCT* pmis;
  1110.     DRAWITEMSTRUCT *pdis;
  1111.     CMC_message_summary far * lpMsgSum = NULL;
  1112.     LPMSGID lpMsgNode;
  1113.     static LPMSGID lpMsgIdList = NULL;
  1114.     CMC_return_code ulResult;
  1115.     WORD nIndex;
  1116.     RECT Rect;
  1117.     HCURSOR hOldCur;
  1118.  
  1119.     CMC_uint32 iCount = 0;
  1120.     CMC_uint32 i;
  1121.  
  1122.     switch (msg)
  1123.     {
  1124.     case WM_INITDIALOG:
  1125.         hOldCur = SetCursor(hWaitCur);
  1126.  
  1127.         //   Populate List Box with all messages in InBox.
  1128.  
  1129.         ulResult = CMCList(lhSession, NULL, (CMC_flags) 0, NULL,
  1130.                            &iCount, (CMC_ui_id)hDlg, &lpMsgSum, NULL);
  1131.  
  1132.         if (ulResult == CMC_SUCCESS)
  1133.         {
  1134.             for (i = 0; i < iCount; i++)
  1135.             {
  1136.                 lpMsgNode = MakeMsgNode (&lpMsgSum[i]);
  1137.  
  1138.                 if (lpMsgNode)
  1139.                 {
  1140.                     InsertMsgNode (lpMsgNode, &lpMsgIdList);
  1141.  
  1142.                     SendDlgItemMessage (hDlg, IDC_MSG, LB_ADDSTRING,
  1143.                         0, (LONG) lpMsgNode);
  1144.                 }
  1145.             }
  1146.             CMCFree (lpMsgSum);
  1147.         }
  1148.         else
  1149.         {
  1150.             MakeMessageBox(hDlg, ulResult, IDS_READFAIL, MBS_ERROR);
  1151.         }
  1152.  
  1153.         SetCursor(hOldCur);
  1154.         SetFocus (GetDlgItem (hDlg, IDC_MSG));
  1155.         return TRUE;
  1156.         break;
  1157.  
  1158.     case WM_SETFOCUS:
  1159.         SetFocus (GetDlgItem (hDlg, IDC_MSG));
  1160.         break;
  1161.  
  1162.     case WM_MEASUREITEM:
  1163.         //   Sets the height of the owner-drawn List-Box
  1164.         pmis = (MEASUREITEMSTRUCT *) lParam;
  1165.         pmis->itemHeight = 15;
  1166.         break;
  1167.  
  1168.     case WM_DRAWITEM:
  1169.         pdis = (DRAWITEMSTRUCT *) lParam;
  1170.         DrawMsgItem (pdis);
  1171.         break;
  1172.  
  1173.     case WM_DELETEITEM:
  1174.         //   This message is handled by the IDC_DELETE message
  1175.         return TRUE;
  1176.         break;
  1177.  
  1178.     case WM_COMMAND:
  1179.         switch (LOWORD (wParam))
  1180.         {
  1181.         case IDC_NEW:
  1182.             hOldCur = SetCursor(hWaitCur);
  1183.  
  1184.             ulResult = CMCList(lhSession, NULL, CMC_LIST_UNREAD_ONLY, NULL,
  1185.                                &iCount, (CMC_ui_id)hDlg, &lpMsgSum, NULL);
  1186.  
  1187.             if (ulResult == CMC_SUCCESS) {
  1188.                 for (i = 0; i < iCount; i++) {
  1189.                     if (!FindNode(lpMsgIdList,lpMsgSum[i].message_reference))
  1190.                     {
  1191.                         lpMsgNode = MakeMsgNode (&lpMsgSum[i]);
  1192.  
  1193.                         if (lpMsgNode)
  1194.                         {
  1195.                             InsertMsgNode (lpMsgNode, &lpMsgIdList);
  1196.  
  1197.                             SendDlgItemMessage (hDlg, IDC_MSG, LB_ADDSTRING,
  1198.                                 0, (LONG) lpMsgNode);
  1199.                         }
  1200.                     }
  1201.                 }
  1202.                 CMCFree (lpMsgSum);
  1203.             }
  1204.  
  1205.             SetCursor(hOldCur);
  1206.             break;
  1207.  
  1208.         case IDC_MSG:
  1209. #ifdef _WIN32
  1210.             if(HIWORD(wParam) != LBN_DBLCLK)
  1211. #else
  1212.             if(HIWORD(lParam) != LBN_DBLCLK)
  1213. #endif
  1214.                 break;
  1215.  
  1216.         case IDC_READ:
  1217.             nIndex = (WORD) SendDlgItemMessage (hDlg, IDC_MSG, LB_GETCURSEL, 0, 0);
  1218.  
  1219.             if (nIndex == LB_ERR)
  1220.                 break;
  1221.  
  1222.             lpReadMsgNode = (LPMSGID) SendDlgItemMessage(hDlg, IDC_MSG,
  1223.                                                     LB_GETITEMDATA, nIndex, 0L);
  1224.  
  1225.             if (lpReadMsgNode == (LPMSGID) LB_ERR || !lpReadMsgNode) // Nothing is selected
  1226.                 break;
  1227.             else
  1228.                 DialogBox(hInst, "ReadNote", hDlg, ReadMailDlgProc);
  1229.  
  1230.             //   Update the Messages List-Box with new icon
  1231.  
  1232.             SendDlgItemMessage (hDlg, IDC_MSG, LB_GETITEMRECT,
  1233.                                 (WPARAM)nIndex, (LPARAM)(RECT far *)&Rect);
  1234.             InvalidateRect(GetDlgItem(hDlg, IDC_MSG), &Rect, FALSE);
  1235.             break;
  1236.  
  1237.         case IDC_DELETE:
  1238.             nIndex = (WORD) SendDlgItemMessage (hDlg, IDC_MSG, LB_GETCURSEL,
  1239.                                                 (WPARAM) 0, (LPARAM) 0);
  1240.  
  1241.             if (nIndex == LB_ERR)
  1242.                 break;
  1243.  
  1244.             lpMsgNode = (LPMSGID) SendDlgItemMessage (hDlg, IDC_MSG,
  1245.                                                       LB_GETITEMDATA, nIndex, 0);
  1246.  
  1247.             if (lpMsgNode == (LPMSGID) LB_ERR || !lpMsgNode) // Nothing is selected
  1248.                 break;
  1249.             else
  1250.             {
  1251.                 ulResult = CMCActOn(lhSession, lpMsgNode->message_reference,
  1252.                                     CMC_ACT_ON_DELETE, CMC_ERROR_UI_ALLOWED,
  1253.                                     (CMC_ui_id)hDlg, NULL);
  1254.  
  1255.                 DeleteMsgNode (lpMsgNode, &lpMsgIdList);
  1256.             }
  1257.  
  1258.             SendDlgItemMessage (hDlg, IDC_MSG, LB_DELETESTRING, nIndex, 0);
  1259.             break;
  1260.  
  1261.         case IDC_CLOSE:
  1262.         case IDCANCEL:
  1263.             FreeMsgList (lpMsgIdList);
  1264.             lpMsgIdList = NULL;
  1265.             EndDialog (hDlg, TRUE);
  1266.             return TRUE;
  1267.             break;
  1268.  
  1269.         default:
  1270.             break;
  1271.         }
  1272.         break;
  1273.     }
  1274.  
  1275.     return FALSE;
  1276. }
  1277.  
  1278.  
  1279. //
  1280. //  ReadMailDlgProc
  1281. //
  1282. //  Purpose:
  1283. //      Dialog procedure for the ReadMail dilaog.
  1284. //
  1285. //  Parameters:
  1286. //      hDlg
  1287. //      message
  1288. //      wParam
  1289. //      lParam
  1290. //
  1291. //  Returns:
  1292. //      True/False
  1293. //
  1294.  
  1295. BOOL FAR PASCAL
  1296. ReadMailDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam)
  1297. {
  1298.     ULONG ulResult;
  1299.     char szTo[TO_EDIT_MAX];
  1300.     char szCc[TO_EDIT_MAX];
  1301.     char szChangeMsg[512];
  1302.     ULONG idx;
  1303.     static CMC_message far *lpReadMsg;
  1304.     char lpszDateDisplay[TO_EDIT_MAX];
  1305.     static ULONG cRecips;
  1306.     static ULONG cNewRecips;
  1307.     static ULONG cAttach;
  1308.     static CMC_recipient FAR *lpRecips;
  1309.     static CMC_recipient FAR *lpNewRecips;
  1310.     static CMC_attachment FAR *lpAttach;
  1311.     CMC_return_code rc;
  1312.     OFSTRUCT ofs;
  1313.  
  1314.     switch (msg)
  1315.     {
  1316.     case WM_INITDIALOG:
  1317.         ulResult = CMCRead(lhSession, lpReadMsgNode->message_reference,
  1318.                         CMC_ERROR_UI_ALLOWED, &lpReadMsg, (CMC_ui_id)hDlg, NULL);
  1319.         if (ulResult)
  1320.         {
  1321.             MakeMessageBox(hDlg, ulResult, IDS_READFAIL, MBS_ERROR);
  1322.             EndDialog (hDlg, TRUE);
  1323.             return TRUE;
  1324.         }
  1325.  
  1326.         lpReadMsgNode->fRead = TRUE;
  1327.  
  1328.         szTo[0] = '\0';
  1329.         szCc[0] = '\0';
  1330.  
  1331.         idx = 0;
  1332.         do
  1333.         {
  1334.             if (lpReadMsg->recipients[idx].role == CMC_ROLE_TO)
  1335.             {
  1336.                 lstrcat (szTo, lpReadMsg->recipients[idx].name);
  1337.                 lstrcat (szTo, "; ");
  1338.             }
  1339.             else if (lpReadMsg->recipients[idx].role == CMC_ROLE_CC)
  1340.             {
  1341.                 lstrcat (szCc, lpReadMsg->recipients[idx].name);
  1342.                 lstrcat (szCc, "; ");
  1343.             }
  1344.             else
  1345.             {
  1346.                 //   Must be Bcc, lets ignore it!
  1347.             }
  1348.  
  1349.         }while(!(lpReadMsg->recipients[idx++].recip_flags & CMC_RECIP_LAST_ELEMENT));
  1350.  
  1351.         if(*szTo)
  1352.             szTo[lstrlen (szTo) - 2] = '\0';
  1353.         if(*szCc)
  1354.             szCc[lstrlen (szCc) - 2] = '\0';
  1355.  
  1356.         SetDlgItemText (hDlg, IDC_RFROM,
  1357.             (lpReadMsgNode->from ? lpReadMsgNode->from : ""));
  1358.         ConvertDateRec (&lpReadMsgNode->time_sent,
  1359.             lpszDateDisplay);
  1360.  
  1361.         SetDlgItemText (hDlg, IDC_RDATE,  (lpszDateDisplay ? lpszDateDisplay : ""));
  1362.         SetDlgItemText (hDlg, IDC_RTO, szTo);
  1363.         SetDlgItemText (hDlg, IDC_RCC, szCc);
  1364.         SetDlgItemText (hDlg, IDC_RSUBJECT, (lpReadMsg->subject ? lpReadMsg->subject : ""));
  1365.         SetDlgItemText (hDlg, IDC_READNOTE, (lpReadMsg->text_note ? lpReadMsg->text_note : ""));
  1366.  
  1367.         if (!lpReadMsg->attachments)
  1368.         {
  1369.             EnableWindow (GetDlgItem (hDlg, IDC_SAVEATTACH), FALSE);
  1370.             EnableWindow (GetDlgItem (hDlg, IDC_ATTACHMENT), FALSE);
  1371.             EnableWindow (GetDlgItem (hDlg, IDT_ATTACHMENT), FALSE);
  1372.         }
  1373.         else
  1374.         {
  1375.             idx = 0;
  1376.             do
  1377.             {
  1378.                 if (lpReadMsg->attachments[idx].attach_title)
  1379.                     SendDlgItemMessage(hDlg, IDC_ATTACHMENT, LB_ADDSTRING, 0,
  1380.                         (LPARAM)lpReadMsg->attachments[idx].attach_title);
  1381.             }while(!(lpReadMsg->attachments[idx++].attach_flags & CMC_ATT_LAST_ELEMENT));
  1382.  
  1383.             SendDlgItemMessage(hDlg, IDC_ATTACHMENT, LB_SETCURSEL, 0, 0L);
  1384.         }
  1385.  
  1386.         SetFocus (GetDlgItem (hDlg, IDC_READNOTE));
  1387.         return FALSE;
  1388.  
  1389.     case WM_COMMAND:
  1390.         switch (LOWORD (wParam))
  1391.         {
  1392.         case IDC_SAVECHANGES:
  1393.             if (SendDlgItemMessage (hDlg, IDC_READNOTE, EM_GETMODIFY, 0, 0))
  1394.                 ulResult = SaveMsgChanges (hDlg, lpReadMsg);
  1395.             SendDlgItemMessage (hDlg, IDC_READNOTE, EM_SETMODIFY, 0, 0);
  1396.             break;
  1397.  
  1398.         case IDC_ATTACHMENT:
  1399. #ifdef _WIN32
  1400.             if(HIWORD(wParam) != LBN_DBLCLK)
  1401. #else
  1402.             if(HIWORD(lParam) != LBN_DBLCLK)
  1403. #endif
  1404.                 break;
  1405.  
  1406.         case IDC_SAVEATTACH:
  1407.             idx = SendDlgItemMessage(hDlg, IDC_ATTACHMENT, LB_GETCURSEL, 0, 0L);
  1408.  
  1409.             if(idx != LB_ERR)
  1410.             {
  1411.                 SaveFileAttachments(hDlg, &lpReadMsg->attachments[idx]);
  1412.                 SetFocus(GetDlgItem (hDlg, IDC_ATTACHMENT));
  1413.                 return FALSE;
  1414.  
  1415.             }
  1416.             break;
  1417.  
  1418.         case IDC_REPLY:
  1419.         case IDC_REPLYALL:
  1420.         case IDC_FORWARD:
  1421.             if(rc = MakeNewMessage (lpReadMsg, LOWORD (wParam)))
  1422.                 MakeMessageBox(hDlg, rc, IDS_MAKENEWFAIL, MBS_ERROR);
  1423.  
  1424.             if(rc = CMCSend(lhSession, CmcMsg, CMC_SEND_UI_REQUESTED | CMC_ERROR_UI_ALLOWED,
  1425.                     (CMC_ui_id)hDlg, NULL))
  1426.                 MakeMessageBox(hDlg, rc, IDS_SENDERROR, MBS_ERROR);
  1427.  
  1428.             PvFree(CmcMsg->message_type);
  1429.             PvFree(CmcMsg->subject);
  1430.             PvFree(CmcMsg->text_note);
  1431.             PvFree(CmcMsg->recipients);
  1432.             PvFree(CmcMsg->attachments);
  1433.             PvFree(CmcMsg);
  1434.             CmcMsg = NULL;
  1435.             break;
  1436.  
  1437.         case IDCANCEL:
  1438.             if (SendDlgItemMessage (hDlg, IDC_READNOTE, EM_GETMODIFY, 0, 0))
  1439.             {
  1440.                 wsprintf (szChangeMsg, "Save changes to: '%s' in Inbox?",
  1441.                     (lpReadMsg->subject ? lpReadMsg->subject : ""));
  1442.  
  1443.                 if(MessageBox (hDlg, szChangeMsg, "Mail", MB_YESNO) == IDYES)
  1444.                 {
  1445.                     ulResult = SaveMsgChanges (hDlg, lpReadMsg);
  1446.                 }
  1447.             }
  1448.  
  1449.             //   If there were file attachments, then delete the temps
  1450.  
  1451.             if(lpReadMsg->attachments)
  1452.             {
  1453.                 idx = 0;
  1454.                 do
  1455.                 {
  1456.                     if (lpReadMsg->attachments[idx].attach_filename)
  1457.                         OpenFile(lpReadMsg->attachments[idx].attach_filename, &ofs, OF_DELETE);
  1458.  
  1459.                 }while(!(lpReadMsg->attachments[idx++].attach_flags & CMC_ATT_LAST_ELEMENT));
  1460.             }
  1461.  
  1462.             CMCFree (lpReadMsg);
  1463.             lpReadMsg = NULL;
  1464.             EndDialog (hDlg, TRUE);
  1465.             return TRUE;
  1466.         }
  1467.         break;
  1468.     }
  1469.     return FALSE;
  1470. }
  1471.  
  1472. //
  1473. //  MakeMessageBox
  1474. //
  1475. //  Purpose:
  1476. //      Gets resource string and displays an error message box.
  1477. //
  1478. //  Parameters:
  1479. //      hWnd            - Handle to parent window
  1480. //      idString        - Resource ID of message in StringTable
  1481. //
  1482. //  Returns:
  1483. //      Void
  1484. //
  1485. //
  1486.  
  1487. void
  1488. MakeMessageBox (HWND hWnd, CMC_return_code ulResult, UINT idString, UINT fStyle)
  1489. {
  1490.     char szMessage[512];
  1491.     char szCmcReturn[256];
  1492.     UINT uResult;
  1493.  
  1494.     LoadString (hInst, idString, szMessage, sizeof(szMessage)-sizeof(szCmcReturn)-1);
  1495.  
  1496.     if (ulResult)
  1497.     {
  1498.         uResult = (UINT) ulResult;
  1499.         LoadString (hInst, uResult, szCmcReturn, sizeof(szCmcReturn)-1);
  1500.         lstrcat (szMessage, "\nReturn Code: ");
  1501.         lstrcat (szMessage, szCmcReturn);
  1502.     }
  1503.  
  1504.     MessageBox (hWnd, szMessage, "Problem", fStyle);
  1505. }
  1506.  
  1507.  
  1508. //
  1509. //  ResolveFriendlyNames
  1510. //
  1511. //  Purpose:
  1512. //      Helper function to convert a string of ';' delimited friendly
  1513. //      names into an array of CMC_recipients.
  1514. //
  1515. //  Side Effects:
  1516. //      The display string passed in is modified to contain the
  1517. //      friendly names of the mail users as found in the sample
  1518. //      address book.
  1519. //
  1520. //  Note:
  1521. //      Duplicate names in the address book will result in undefined
  1522. //      behavior.
  1523. //
  1524. //  Parameters:
  1525. //      hWnd                - Handle to parent window
  1526. //      lpszDisplayNames    - string of ';' delimited user names
  1527. //      ulRecipRole         - either CMC_ROLE_TO, CMC_ROLE_CC, or CMC_BCC
  1528. //      lpcRecips           - Address of recipient count to be returned
  1529. //      lppRecips           - Address of recipient array to be returned
  1530. //
  1531. //  Return:
  1532. //      ulResult
  1533.  
  1534.  
  1535. CMC_return_code
  1536. ResolveFriendlyNames(HWND hWnd, LPSTR lpszDisplayNames, CMC_enum ulRecipRole,
  1537.                      ULONG * lpcRecips, CMC_recipient FAR * * lppRecips)
  1538. {
  1539.     char szResolve[TO_EDIT_MAX];
  1540.     LPSTR lpszNameToken;
  1541.     ULONG cRecips = 0;
  1542.     ULONG cFails = 0;
  1543.     ULONG idx;
  1544.     CMC_return_code ulResult;
  1545.     CMC_recipient Recip;
  1546.     CMC_recipient FAR * lpNewRecip;
  1547.     CMC_recipient FAR * lpRecipList;
  1548.     CMC_uint32 cNewRecip;
  1549.  
  1550.     *szResolve = '\0';
  1551.     lpszNameToken = _fstrtok (lpszDisplayNames, ";\n");
  1552.  
  1553.     while (lpszNameToken)
  1554.     {
  1555.         //   Strip leading blanks from name
  1556.  
  1557.         while (*lpszNameToken == ' ')
  1558.             lpszNameToken++;
  1559.  
  1560.         //   Check if name has already been resolved
  1561.  
  1562.         if (!FNameInList (lpszNameToken, *lpcRecips, *lppRecips))
  1563.         {
  1564.             lstrcat (szResolve, lpszNameToken);
  1565.             lstrcat (szResolve, "; ");
  1566.             cRecips++;
  1567.         }
  1568.  
  1569.         //   Get Next Token
  1570.  
  1571.         lpszNameToken = _fstrtok (NULL, ";\n");
  1572.     }
  1573.  
  1574.     *lpszDisplayNames = '\0';
  1575.  
  1576.     if (!szResolve[0])
  1577.     {
  1578.         ulResult = CMC_SUCCESS;
  1579.         goto err;
  1580.     }
  1581.  
  1582.     szResolve[lstrlen (szResolve) - 2] = '\0';
  1583.  
  1584.     lpRecipList = (CMC_recipient *)PvAlloc((cRecips + *lpcRecips) * sizeof (CMC_recipient));
  1585.     if (!lpRecipList)
  1586.     {
  1587.         ulResult = CMC_E_INSUFFICIENT_MEMORY;
  1588.         goto err;
  1589.     }
  1590.     _fmemset (lpRecipList, 0, (UINT)(cRecips + *lpcRecips) * sizeof (CMC_recipient));
  1591.  
  1592.     cRecips = 0;
  1593.  
  1594.     while (cRecips < *lpcRecips)
  1595.     {
  1596.         ulResult = CopyRecipient (lpRecipList, &lpRecipList[cRecips],
  1597.             *lppRecips + cRecips);
  1598.  
  1599.         if (ulResult)
  1600.         {
  1601.             PvFree(lpRecipList);
  1602.             goto err;
  1603.         }
  1604.  
  1605.         cRecips++;
  1606.     }
  1607.  
  1608.     PvFree(*lppRecips);
  1609.  
  1610.     lpszNameToken = _fstrtok (szResolve, ";\n");
  1611.  
  1612.     while (lpszNameToken)
  1613.     {
  1614.         //   Strip leading blanks
  1615.  
  1616.         while (*lpszNameToken == ' ')
  1617.             lpszNameToken++;
  1618.  
  1619.         cNewRecip = 1; // just looking for one resolved name
  1620.         Recip.name      = lpszNameToken;
  1621.         Recip.name_type = CMC_TYPE_INDIVIDUAL;
  1622.         Recip.role      = ulRecipRole;
  1623.         Recip.recip_flags = CMC_RECIP_LAST_ELEMENT;
  1624.         Recip.address     = NULL;
  1625.         Recip.recip_extensions = NULL;
  1626.  
  1627.         ulResult = CMCLookUp(lhSession, (CMC_recipient far *)&Recip,
  1628.                              CMC_LOOKUP_RESOLVE_UI | CMC_ERROR_UI_ALLOWED
  1629.                              | CMC_LOOKUP_RESOLVE_PREFIX_SEARCH,
  1630.                              (CMC_ui_id)hWnd, &cNewRecip, &lpNewRecip, NULL);
  1631.  
  1632.         if (ulResult == CMC_SUCCESS)
  1633.         {
  1634.             lpNewRecip->role = ulRecipRole;
  1635.             ulResult = CopyRecipient (lpRecipList, &lpRecipList[cRecips], lpNewRecip);
  1636.  
  1637.             CMCFree(lpNewRecip);
  1638.  
  1639.             if(ulResult)
  1640.                 goto cleanup;
  1641.  
  1642.             cRecips++;
  1643.         }
  1644.         else
  1645.         {
  1646.             MakeMessageBox (NULL, ulResult, IDS_ADDRBOOKFAIL, MBS_ERROR);
  1647.             lstrcat (lpszDisplayNames, lpszNameToken);
  1648.             lstrcat (lpszDisplayNames, "; ");
  1649.             cFails++;
  1650.         }
  1651.         lpszNameToken = _fstrtok (NULL, ";\n");
  1652.     }
  1653.  
  1654.     //   if cFails > 0 then we have partial success
  1655.  
  1656.     ulResult = CMC_SUCCESS;
  1657.  
  1658.     if (cFails)
  1659.         MakeMessageBox (hWnd, 0, IDS_UNRESOLVEDNAMES, MBS_INFO);
  1660.  
  1661. cleanup:
  1662.     /* Re-position our LAST_ELEMENT flag in the list */
  1663.     if(*lpcRecips = cRecips)
  1664.     {
  1665.         for(idx = 0; idx < cRecips-1; idx++)
  1666.             lpRecipList[idx].recip_flags &= ~CMC_RECIP_LAST_ELEMENT;
  1667.         lpRecipList[idx].recip_flags |= CMC_RECIP_LAST_ELEMENT;
  1668.  
  1669.         *lppRecips = lpRecipList;
  1670.     }
  1671.     else
  1672.     {
  1673.         *lppRecips = NULL;
  1674.         PvFree(lpRecipList);
  1675.     }
  1676.  
  1677. err:
  1678.     if (*lpszDisplayNames)
  1679.         lpszDisplayNames[lstrlen (lpszDisplayNames) - 2] = '\0';
  1680.  
  1681.     return ulResult;
  1682. }
  1683.  
  1684.  
  1685. //
  1686. //  CopyRecipient
  1687. //
  1688. //  Purpose:
  1689. //      Called in support of ResolveFriendlyNames() to build an array
  1690. //      of chained CMC_recipients.
  1691. //
  1692. //  Parameters:
  1693. //      lpParent        - Parent memory that allocations get chained to
  1694. //      lpDest          - Destination Recipient
  1695. //      lpSrc           - Source Recipient
  1696. //
  1697. //  Return:
  1698. //      ulResult
  1699.  
  1700.  
  1701. CMC_return_code
  1702. CopyRecipient (CMC_recipient FAR * lpParent,
  1703.     CMC_recipient FAR * lpDest,
  1704.     CMC_recipient FAR * lpSrc)
  1705. {
  1706.     ULONG cRecipExt,cRE;
  1707.     lpDest->role = lpSrc->role;
  1708.     lpDest->name_type = lpSrc->name_type;
  1709.     lpDest->recip_flags = lpSrc->recip_flags;
  1710.  
  1711.  
  1712.     if (lpSrc->name)
  1713.     {
  1714.         lpDest->name = (CMC_string)PvAllocMore(lstrlen(lpSrc->name) + 1, lpParent);
  1715.         if (!lpDest->name)
  1716.                 return CMC_E_INSUFFICIENT_MEMORY;
  1717.  
  1718.         lstrcpy (lpDest->name, lpSrc->name);
  1719.     }
  1720.     else
  1721.         lpDest->name = NULL;
  1722.  
  1723.     if (lpSrc->address)
  1724.     {
  1725.         lpDest->address = (CMC_string)PvAllocMore(lstrlen(lpSrc->address) + 1, lpParent);
  1726.         if (!lpDest->address)
  1727.             return CMC_E_INSUFFICIENT_MEMORY;
  1728.  
  1729.         lstrcpy (lpDest->address, lpSrc->address);
  1730.     }
  1731.     else
  1732.         lpDest->address = NULL;
  1733.  
  1734.     if(lpSrc->recip_extensions && (lpSrc->recip_extensions->item_code == CMC_X_COM_RECIP_ID))
  1735.     {
  1736.  
  1737.         cRecipExt = 0;
  1738.         while (!(lpSrc->recip_extensions[cRecipExt].extension_flags & CMC_EXT_LAST_ELEMENT))
  1739.             cRecipExt++;
  1740.  
  1741.         cRecipExt++;
  1742.  
  1743.         lpDest->recip_extensions = (CMC_extension *)PvAllocMore(sizeof(CMC_extension)*cRecipExt, lpParent);
  1744.         if(!lpDest->recip_extensions)
  1745.                return CMC_E_INSUFFICIENT_MEMORY;
  1746.  
  1747.         for (cRE = 0;cRE < cRecipExt;cRE++)
  1748.         {
  1749.  
  1750.             lpDest->recip_extensions[cRE].item_reference = \
  1751.                    (CMC_buffer)PvAllocMore( sizeof(CMC_message_reference)+
  1752.                    lpSrc->recip_extensions[cRE].item_data, lpParent);
  1753.             if(!lpDest->recip_extensions[cRE].item_reference)
  1754.                 return CMC_E_INSUFFICIENT_MEMORY;
  1755.  
  1756.             lpDest->recip_extensions[cRE].item_code = CMC_X_COM_RECIP_ID;
  1757.             lpDest->recip_extensions[cRE].item_data = lpSrc->recip_extensions[cRE].item_data;
  1758.             lpDest->recip_extensions[cRE].extension_flags = lpSrc->recip_extensions[cRE].extension_flags;
  1759.             if (lpSrc->recip_extensions[cRE].item_reference)
  1760.                 _fmemcpy(lpDest->recip_extensions[cRE].item_reference,
  1761.                     lpSrc->recip_extensions[cRE].item_reference,
  1762.                     sizeof(CMC_message_reference)+(size_t)lpSrc->recip_extensions[cRE].item_data);
  1763.             else
  1764.                 // NULL item_reference (BUG?)
  1765.                 lpDest->recip_extensions[cRE].item_reference = lpSrc->recip_extensions[cRE].item_reference;
  1766.  
  1767.         }
  1768.  
  1769.     }
  1770.     else
  1771.         lpDest->recip_extensions = NULL;
  1772.  
  1773.     return CMC_SUCCESS;
  1774. }
  1775.  
  1776. //
  1777. //  GetNextFile
  1778. //
  1779. //  Purpose:
  1780. //      Called when user clicks 'Attach' button in Compose Note form.
  1781. //      We will build a chained memory chunk for more than one file
  1782. //      attachment so the memory can be freed with a single call to
  1783. //      CMCFree.
  1784. //
  1785. //  Parameters:
  1786. //      hWnd            - Window handle of Compose Note dialog
  1787. //      nPos            - Render position of attachment in Notetext.
  1788. //      lpcAttach       - Pointer to the count of attachments.
  1789. //      lppAttach       - Pointer to the CMC_attachment array.
  1790. //
  1791. //  Return:
  1792. //      ulResult.
  1793.  
  1794. CMC_return_code
  1795. GetNextFile (HWND hWnd, ULONG nPos, ULONG * lpcAttach,
  1796.     CMC_attachment FAR * * lppAttach)
  1797. {
  1798.     CMC_attachment FAR * lpAttach;
  1799.     CMC_attachment FAR * lpAttachT;
  1800.     OPENFILENAME ofn;
  1801.     char szAttachFilename[256] = "";
  1802.     char szFilter[256];
  1803.     static char szFileTitle[16];
  1804.     static char szDirName[256] = "";
  1805.     LPSTR lpszEndPath;
  1806.     ULONG idx;
  1807.     CMC_return_code ulResult = CMC_SUCCESS;
  1808.  
  1809.     if (!szDirName[0])
  1810.         GetSystemDirectory ((LPSTR) szDirName, 255);
  1811.     else
  1812.         lstrcpy (szAttachFilename, szFileTitle);
  1813.  
  1814.     LoadString(hInst, IDS_FILTER, szFilter, sizeof(szFilter));
  1815.  
  1816.     for (idx = 0; szFilter[idx] != '\0'; idx++)
  1817.         if (szFilter[idx] == '|')
  1818.             szFilter[idx] = '\0';
  1819.  
  1820.     ofn.lStructSize = sizeof (OPENFILENAME);
  1821.     ofn.hwndOwner = (HWND) NULL;
  1822.     ofn.hInstance = (HINSTANCE) NULL;
  1823.     ofn.lpstrFilter = szFilter;
  1824.     ofn.lpstrCustomFilter = NULL;
  1825.     ofn.nMaxCustFilter = 0L;
  1826.     ofn.nFilterIndex = 1L;
  1827.     ofn.lpstrFile = szAttachFilename;
  1828.     ofn.nMaxFile = 256;
  1829.     ofn.lpstrFileTitle = szFileTitle;
  1830.     ofn.nMaxFileTitle = 16;
  1831.     ofn.lpstrInitialDir = szDirName;
  1832.     ofn.lpstrTitle = "Attach";
  1833.     ofn.nFileOffset = 0;
  1834.     ofn.nFileExtension = 0;
  1835.     ofn.lpstrDefExt = NULL;
  1836.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  1837.  
  1838.     if (!GetOpenFileName (&ofn))
  1839.         return CMC_E_USER_CANCEL;
  1840.  
  1841.     //   Save the directory for the next time we call this
  1842.  
  1843.     lstrcpy (szDirName, szAttachFilename);
  1844.     if (lpszEndPath = strstr (szDirName, szFileTitle))
  1845.         *(--lpszEndPath) = '\0';
  1846.  
  1847.     lpAttach = (CMC_attachment *)PvAlloc((*lpcAttach + 1) * sizeof(CMC_attachment));
  1848.     if (!lpAttach)
  1849.         goto err;
  1850.  
  1851.     _fmemset (lpAttach, 0, ((UINT) *lpcAttach + 1) *sizeof (CMC_attachment));
  1852.  
  1853.     lpAttachT = *lppAttach;
  1854.  
  1855.     for (idx = 0; idx < *lpcAttach; idx++)
  1856.         if(ulResult = CopyAttachment (lpAttach, &lpAttach[idx], &lpAttachT[idx]))
  1857.             goto err;
  1858.  
  1859.     lpAttach[idx-1].attach_flags &= ~CMC_ATT_LAST_ELEMENT;
  1860.     lpAttach[idx].attach_flags = CMC_ATT_LAST_ELEMENT;
  1861.     lpAttach[idx].attach_type = NULL;
  1862.     lpAttach[idx].attach_extensions = NULL;
  1863.  
  1864.     lpAttach[idx].attach_filename = (CMC_string)PvAllocMore(lstrlen(szAttachFilename) + 1,  lpAttach);
  1865.     if(!lpAttach[idx].attach_filename)
  1866.         goto err;
  1867.  
  1868.     lpAttach[idx].attach_title = (CMC_string)PvAllocMore(lstrlen(szFileTitle) + 1, lpAttach);
  1869.     if (!lpAttach[idx].attach_title)
  1870.         goto err;
  1871.  
  1872.     lstrcpy (lpAttach[idx].attach_filename, szAttachFilename);
  1873.     lstrcpy (lpAttach[idx].attach_title, szFileTitle);
  1874.  
  1875.     PvFree(lpAttachT);
  1876.  
  1877.     *lppAttach = lpAttach;
  1878.     (*lpcAttach)++;
  1879.  
  1880. err:
  1881.     if(ulResult)
  1882.         PvFree(lpAttach);
  1883.  
  1884.     return ulResult;
  1885. }
  1886.  
  1887.  
  1888. //
  1889. //  CopyAttachment
  1890. //
  1891. //  Purpose:
  1892. //      Called in support of GetNextFile() to re-build an array
  1893. //      of chained CMC_attachments.
  1894. //
  1895. //  Parameters:
  1896. //      lpParent        - Parent memory that allocations get chained to
  1897. //      lpDest          - Destination Recipient
  1898. //      lpSrc           - Source Recipient
  1899. //
  1900. //  Return:
  1901. //      Void.
  1902.  
  1903. ULONG
  1904. CopyAttachment(CMC_attachment FAR * lpParent,
  1905.                CMC_attachment FAR * lpDest,
  1906.                CMC_attachment FAR * lpSrc)
  1907. {
  1908.     lpDest->attach_flags = lpSrc->attach_flags;
  1909.  
  1910.     if (lpSrc->attach_title)
  1911.     {
  1912.         lpDest->attach_title = (CMC_string)PvAllocMore(lstrlen(lpSrc->attach_title) + 1, (LPVOID)lpParent);
  1913.         if (!lpDest->attach_title)
  1914.             return CMC_E_INSUFFICIENT_MEMORY;
  1915.  
  1916.         lstrcpy (lpDest->attach_title, lpSrc->attach_title);
  1917.     }
  1918.     else
  1919.         lpDest->attach_title = NULL;
  1920.  
  1921.     if (lpSrc->attach_type)
  1922.     {
  1923.         lpDest->attach_type = (CMC_object_identifier)PvAllocMore(lstrlen(lpSrc->attach_type) + 1, (LPVOID)lpParent);
  1924.         if (!lpDest->attach_type)
  1925.             return CMC_E_INSUFFICIENT_MEMORY;
  1926.  
  1927.         lstrcpy (lpDest->attach_type, lpSrc->attach_type);
  1928.     }
  1929.     else
  1930.         lpDest->attach_type = NULL;
  1931.  
  1932.     if (lpSrc->attach_filename)
  1933.     {
  1934.         lpDest->attach_filename = (CMC_string)PvAllocMore(lstrlen(lpSrc->attach_filename) + 1, (LPVOID)lpParent);
  1935.         if (!lpDest->attach_filename)
  1936.             return CMC_E_INSUFFICIENT_MEMORY;
  1937.  
  1938.         lstrcpy (lpDest->attach_filename, lpSrc->attach_filename);
  1939.     }
  1940.     else
  1941.         lpDest->attach_filename = NULL;
  1942.  
  1943.     lpDest->attach_extensions = NULL;
  1944.  
  1945.     return CMC_SUCCESS;
  1946. }
  1947.  
  1948.  
  1949. //
  1950. //  FNameInList
  1951. //
  1952. //  Purpose:
  1953. //      To find lpszName in an array of recipients.  Used to determine
  1954. //      if user name has already been resolved.
  1955. //
  1956. //  Parameters:
  1957. //      lpszName        - Friendly name to search for
  1958. //      cRecips         - Count of recipients in lpRecips
  1959. //      lpRecips        - Array of CMC_recipients
  1960. //
  1961. //  Return:
  1962. //      TRUE/FALSE
  1963.  
  1964.  
  1965. BOOL
  1966. FNameInList (LPSTR lpszName, ULONG cRecips, CMC_recipient FAR * lpRecips)
  1967. {
  1968.     //   Case sensitive compare of each friendly name in list.
  1969.  
  1970.     if (!cRecips || !lpRecips)
  1971.         return FALSE;
  1972.  
  1973.     while (cRecips--)
  1974.         if (!lstrcmp (lpszName, lpRecips[cRecips].name))
  1975.             return TRUE;
  1976.  
  1977.     return FALSE;
  1978. }
  1979.  
  1980.  
  1981. //
  1982. //  DrawMsgItem
  1983. //
  1984. //  Purpose:
  1985. //      Paint the client area of the owner drawn listbox.
  1986. //
  1987. //  Parameters:
  1988. //      pdis        - Pointer to a DRAWITEMSTRUCT
  1989. //      cMsgIds     - Count of MsgId structs in List of current messages
  1990. //      lpMsgIds    - Pointer to linked-list of MsgIds
  1991. //
  1992. //  Returns:
  1993. //      void
  1994. //
  1995.  
  1996.  
  1997. void
  1998. DrawMsgItem (DRAWITEMSTRUCT * pdis)
  1999. {
  2000.     LPMSGID lpMsg;
  2001.     HBITMAP hBmp;
  2002.     char szDateRec[32];
  2003.     HBRUSH hSolidBrush, hOldBrush;
  2004.  
  2005.     hSolidBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  2006.     hOldBrush = SelectObject(pdis->hDC, hSolidBrush);
  2007.  
  2008.     if (ODA_DRAWENTIRE & pdis->itemAction)
  2009.     {
  2010.         //   Clear the item Rectangle
  2011.  
  2012.         PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top,
  2013.             pdis->rcItem.right - pdis->rcItem.left,
  2014.             pdis->rcItem.bottom - pdis->rcItem.top, PATCOPY);
  2015.  
  2016.         //   Draw the item
  2017.  
  2018.         lpMsg = (LPMSGID) pdis->itemData;
  2019.  
  2020.         if (lpMsg->fRead)
  2021.         {
  2022.             if (lpMsg->fHasAttach)
  2023.                 hBmp = hReadABmp;
  2024.             else
  2025.                 hBmp = hReadBmp;
  2026.         }
  2027.         else
  2028.         {
  2029.             if (lpMsg->fHasAttach)
  2030.                 hBmp = hUnReadABmp;
  2031.             else
  2032.                 hBmp = hUnReadBmp;
  2033.         }
  2034.  
  2035.         DrawMsgIcon (pdis->hDC, hBmp, pdis->rcItem.left + 2, pdis->rcItem.top,
  2036.             pdis->rcItem.left + 18, pdis->rcItem.top + 15);
  2037.  
  2038.  
  2039.         // Show originator
  2040.         TextOut (pdis->hDC, pdis->rcItem.left + 20, pdis->rcItem.top+2,
  2041.             (lpMsg->from ? lpMsg->from : ""),
  2042.             lstrlen ((lpMsg->from ? lpMsg->from : "")));
  2043.  
  2044.  
  2045.         // Show subject
  2046.         TextOut (pdis->hDC, pdis->rcItem.left + 120, pdis->rcItem.top+2,
  2047.             (lpMsg->subject ? lpMsg->subject : ""),
  2048.             lstrlen ((lpMsg->subject ? lpMsg->subject : "")));
  2049.  
  2050.         // Show time sent
  2051.         ConvertDateRec (&lpMsg->time_sent, szDateRec);
  2052.         TextOut (pdis->hDC, pdis->rcItem.left + 270, pdis->rcItem.top+2,
  2053.             szDateRec, lstrlen (szDateRec));
  2054.  
  2055.         //   Invert item rectangle if item is selected
  2056.  
  2057.         if (ODS_SELECTED & pdis->itemState)
  2058.             PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top,
  2059.                 pdis->rcItem.right - pdis->rcItem.left,
  2060.                 pdis->rcItem.bottom - pdis->rcItem.top, DSTINVERT);
  2061.  
  2062.         //   Draw a focus rectangle if item has focus
  2063.  
  2064.         if (ODS_FOCUS & pdis->itemState)
  2065.             DrawFocusRect (pdis->hDC, &pdis->rcItem);
  2066.     }
  2067.     else
  2068.     {
  2069.         //   Invert the item if the selection state is changing
  2070.  
  2071.         if (ODA_SELECT & pdis->itemAction)
  2072.             PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top,
  2073.                 pdis->rcItem.right - pdis->rcItem.left,
  2074.                 pdis->rcItem.bottom - pdis->rcItem.top, DSTINVERT);
  2075.  
  2076.         //   Draw a focus if the focus state is changing
  2077.  
  2078.         if (ODA_FOCUS & pdis->itemAction)
  2079.             DrawFocusRect (pdis->hDC, &pdis->rcItem);
  2080.     }
  2081.  
  2082.     SelectObject(pdis->hDC, hOldBrush);
  2083.     DeleteObject(hSolidBrush);
  2084. }
  2085.  
  2086. //
  2087. //  DrawMsgIcon
  2088. //
  2089. //  Purpose:
  2090. //      Paint the client area of an owner drawn List Box.
  2091. //
  2092. //  Parameters:
  2093. //      hDC         - Device context of button to be drawn on
  2094. //      hBitMap     - Handle to a bitmap
  2095. //      lx          - Upper left x coordinate
  2096. //      ly          - Upper left y coordinate
  2097. //      lcx         - Width of paint area
  2098. //      lcy         - Height of paint area
  2099. //
  2100. //  Returns:
  2101. //      None.
  2102. //
  2103.  
  2104.  
  2105. void
  2106. DrawMsgIcon (HDC hDC, HBITMAP hBmp, int x, int y, int cx, int cy)
  2107. {
  2108.     HDC hDCMem;
  2109.     HBITMAP hBmpOld;
  2110.  
  2111.     hDCMem = CreateCompatibleDC (hDC);
  2112.     hBmpOld = SelectObject (hDCMem, hBmp);
  2113.  
  2114.     if (hBmpOld)
  2115.     {
  2116.         BitBlt (hDC, x, y, cx, cy, hDCMem, 0, 0, SRCCOPY);
  2117.         SelectObject (hDCMem, hBmpOld);
  2118.     }
  2119.  
  2120.     DeleteDC (hDCMem);
  2121. }
  2122.  
  2123. //
  2124. //  ConvertDateRec
  2125. //
  2126. //  Purpose:
  2127. //      To convert the CMC_time field of a message to a
  2128. //      more paletable display format; namely: mm/dd/yy hh:mmAM.
  2129. //
  2130. //  Parameters:
  2131. //      stime         - Original format
  2132. //      lpszDateDisplay     - Display format
  2133. //
  2134. //  Return:
  2135. //      Void.
  2136.  
  2137.  
  2138. void
  2139. ConvertDateRec (CMC_time far *lpTime, LPSTR lpszDateDisplay)
  2140. {
  2141.     static char szCentury[2][3] =
  2142.     {"19", "20"};
  2143.  
  2144.     static char szAMPM[2][3] =
  2145.     {"AM", "PM"};
  2146.  
  2147.  
  2148.     wsprintf (lpszDateDisplay, "%i/%i/%s%2.2i %i:%2.2i%s",
  2149.         lpTime->month+1, // zero based
  2150.         lpTime->day,
  2151.          szCentury[(lpTime->year > 99 ? 1 : 0)],
  2152.         (lpTime->year > 99) ? lpTime->year - 100 : lpTime->year,
  2153.         (lpTime->hour == 0) ? 12 : ((lpTime->hour > 12) ? lpTime->hour - 12 : lpTime->hour),
  2154.         lpTime->minute,
  2155.         szAMPM[(lpTime->hour > 11 ? 1 : 0)]);
  2156. }
  2157.  
  2158. //
  2159. //  MakeMsgNode
  2160. //
  2161. //  Purpose:
  2162. //      Allocate memory for a new MSGID node and initialize its
  2163. //      data members to the values passed in.
  2164. //
  2165. //  Parameters:
  2166. //      lpMsg           - Pointer to a CMC_message
  2167. //      msgReference       - Opaque message identifier
  2168. //
  2169. //  Return:
  2170. //      lpMsgNode       - Pointer to new node
  2171.  
  2172.  
  2173. LPMSGID
  2174. MakeMsgNode (CMC_message_summary FAR *lpMsgSummary)
  2175. {
  2176.     CMC_return_code ulResult;
  2177.     LPMSGID lpMsgNode = NULL;
  2178.     CMC_message far * lpMessage;
  2179.  
  2180.     if (!lpMsgSummary)
  2181.         goto err;
  2182.  
  2183.  
  2184.     lpMsgNode = (LPMSGID)PvAlloc(sizeof(MSGID));
  2185.     if (!lpMsgNode)
  2186.         goto err;
  2187.  
  2188.     _fmemset (lpMsgNode, 0, sizeof (MSGID));
  2189.  
  2190.     // copy message regerence
  2191.     lpMsgNode->message_reference = (CMC_message_reference *)PvAllocMore( \
  2192.             sizeof(CMC_message_reference)+lpMsgSummary->message_reference->length,
  2193.             lpMsgNode);
  2194.  
  2195.     _fmemcpy(lpMsgNode->message_reference->string,
  2196.              lpMsgSummary->message_reference->string,
  2197.              (size_t) lpMsgSummary->message_reference->length);
  2198.  
  2199.     lpMsgNode->message_reference->length = lpMsgSummary->message_reference->length;
  2200.  
  2201.     // Who is the originator?
  2202.     if (lpMsgSummary->originator)
  2203.     {
  2204.         if (lpMsgSummary->originator->name)
  2205.         {
  2206.             lpMsgNode->from = (CMC_string)PvAllocMore(lstrlen(lpMsgSummary->originator->name) + 1, lpMsgNode);
  2207.             if (!lpMsgNode->from)
  2208.                 goto err;
  2209.     
  2210.             lstrcpy (lpMsgNode->from, lpMsgSummary->originator->name);
  2211.         }
  2212.         else
  2213.         {
  2214.             lpMsgNode->from = NULL;
  2215.         }
  2216.     }
  2217.     else
  2218.     {
  2219.         lpMsgNode->from = NULL;
  2220.     }
  2221.  
  2222.  
  2223.     // What is the subject?
  2224.     if (lpMsgSummary->subject)
  2225.     {
  2226.         lpMsgNode->subject = (CMC_string)PvAllocMore(lstrlen(lpMsgSummary->subject) + 1, lpMsgNode);
  2227.         if (!lpMsgNode->subject)
  2228.             goto err;
  2229.  
  2230.         lstrcpy (lpMsgNode->subject, lpMsgSummary->subject);
  2231.     }
  2232.     else
  2233.     {
  2234.         lpMsgNode->subject = NULL;
  2235.     }
  2236.  
  2237.     // Time sent
  2238.     _fmemcpy(&lpMsgNode->time_sent, &lpMsgSummary->time_sent, sizeof(CMC_time));
  2239.  
  2240.     // Query Attachments and Read/Unread status
  2241.     ulResult = CMCRead( lhSession, lpMsgSummary->message_reference,
  2242.                 CMC_MSG_AND_ATT_HDRS_ONLY | CMC_DO_NOT_MARK_AS_READ, 
  2243.                 &lpMessage, (CMC_ui_id)NULL, NULL );
  2244.         
  2245.     if ( ulResult )
  2246.         goto err;
  2247.  
  2248.     if (!ulResult && lpMessage->attachments)
  2249.         lpMsgNode->fHasAttach = CMC_TRUE;
  2250.  
  2251.     // Has the message been read?
  2252.     if (lpMessage->message_flags & CMC_MSG_READ)
  2253.         lpMsgNode->fRead = CMC_TRUE;
  2254.     else
  2255.         lpMsgNode->fRead = CMC_FALSE;
  2256.  
  2257.     
  2258.     CMCFree( lpMessage );
  2259.  
  2260.     lpMsgNode->lpPrev = NULL;
  2261.     lpMsgNode->lpNext = NULL;
  2262.  
  2263.     return lpMsgNode;
  2264.  
  2265. err:
  2266.     PvFree(lpMsgNode);
  2267.     return NULL;
  2268. }
  2269.  
  2270. //
  2271. //  InsertMsgNode
  2272. //
  2273. //  Purpose:
  2274. //      Currently (for simplicity) we will insert the nodes
  2275. //      at the beginning of the list.  This can later be
  2276. //      replaced with a routine that can insert sorted on
  2277. //      different criteria, like DateReceived, From, or
  2278. //      Subject.  But for now...
  2279. //
  2280. //  Parameters:
  2281. //      lpMsgNode       - Pointer to a MSGID node
  2282. //      lppMsgHead      - Pointer to the head of the list
  2283. //
  2284. //  Return:
  2285. //      Void.
  2286.  
  2287.  
  2288. void
  2289. InsertMsgNode (LPMSGID lpMsgNode, LPMSGID  * lppMsgHead)
  2290. {
  2291.     if (*lppMsgHead)
  2292.     {
  2293.         lpMsgNode->lpNext = *lppMsgHead;
  2294.         (*lppMsgHead)->lpPrev = lpMsgNode;
  2295.     }
  2296.     else
  2297.         lpMsgNode->lpNext = NULL;
  2298.  
  2299.     //   The next 2 assignments are here in case the node came from somewhere
  2300.     //   other than a call to MakeMsgNode () in which case we aren't sure
  2301.     //   they're already NULL.
  2302.  
  2303.     lpMsgNode->lpPrev = NULL;
  2304.     *lppMsgHead = lpMsgNode;
  2305. }
  2306.  
  2307. //
  2308. //  DeleteMsgNode
  2309. //
  2310. //  Purpose:
  2311. //      Removes the node passed in from the list.  This
  2312. //      may seem like a strange way to do this but it's
  2313. //      not, because the Owner-Drawn List Box gives us
  2314. //      direct access to elements in the list that makes
  2315. //      it easier to do things this way.
  2316. //
  2317. //  Parameters:
  2318. //      lpMsgNode       - Pointer to the MSGID node to delete
  2319. //      lppMsgHead      - Pointer to the head of the list
  2320. //
  2321. //  Return:
  2322. //      Void.
  2323.  
  2324.  
  2325. void
  2326. DeleteMsgNode (LPMSGID lpMsgNode, LPMSGID * lppMsgHead)
  2327. {
  2328.     if (!lpMsgNode)
  2329.         return;
  2330.  
  2331.     //   Check if we are the first node
  2332.  
  2333.     if (lpMsgNode->lpPrev)
  2334.         lpMsgNode->lpPrev->lpNext = lpMsgNode->lpNext;
  2335.  
  2336.     //   Check if we are the last node
  2337.  
  2338.     if (lpMsgNode->lpNext)
  2339.         lpMsgNode->lpNext->lpPrev = lpMsgNode->lpPrev;
  2340.  
  2341.     //   check if we are the only node
  2342.  
  2343.     if(lpMsgNode == *lppMsgHead)
  2344.         *lppMsgHead = NULL;
  2345.  
  2346.     PvFree(lpMsgNode);
  2347.     return;
  2348. }
  2349.  
  2350.  
  2351.  
  2352. //
  2353. //  FindNode
  2354. //
  2355. //  Purpose:
  2356. //      Returns a pointer to the node containing msgReference.
  2357. //      Returns NULL if node doesn't exist or msgReference is NULL.
  2358. //
  2359. //  Parameters:
  2360. //      lpMsgHead       - Pointer to the head of the list
  2361. //      msgReference       - Message ID to search for
  2362. //
  2363. //  Return:
  2364. //      lpMsgNode       - Pointer to the node returned
  2365.  
  2366.  
  2367. LPMSGID
  2368. FindNode (LPMSGID lpMsgHead, CMC_message_reference FAR *msgReference)
  2369. {
  2370.     if (!msgReference)
  2371.         return NULL;
  2372.  
  2373.     while (lpMsgHead)
  2374.     {
  2375.         if ((lpMsgHead->message_reference->length == msgReference->length) &&
  2376.                 !_fmemcmp((void far *)lpMsgHead->message_reference->string,
  2377.                       (void far *)msgReference->string, (size_t)msgReference->length))
  2378.             break;
  2379.  
  2380.         lpMsgHead = lpMsgHead->lpNext;
  2381.     }
  2382.  
  2383.     return lpMsgHead;
  2384. }
  2385.  
  2386.  
  2387.  
  2388. //
  2389. //  FreeMsgList
  2390. //
  2391. //  Purpose:
  2392. //      Walks down the MsgList and frees each node.
  2393. //
  2394. //  Parameters:
  2395. //      lpMsgHead       - Pointer to the head of the list
  2396. //
  2397. //  Return:
  2398. //      Void.
  2399.  
  2400.  
  2401. void
  2402. FreeMsgList (LPMSGID lpMsgHead)
  2403. {
  2404.     LPMSGID lpT;
  2405.  
  2406.     while (lpMsgHead)
  2407.     {
  2408.         lpT = lpMsgHead;
  2409.         lpMsgHead = lpMsgHead->lpNext;
  2410.         PvFree(lpT);
  2411.     }
  2412. }
  2413.  
  2414. //
  2415. //  MakeDisplayNameStr
  2416. //
  2417. //  Purpose:
  2418. //      Finds all recipients of type ulRecipRole in lpRecips and adds
  2419. //      their friendly name to the display string.
  2420. //
  2421. //  Parameters:
  2422. //      lpszDisplay         - Destination string for names
  2423. //      ulRecipRole        - Recipient types to search for
  2424. //      cRecips             - Count of recipients in lpRecips
  2425. //      lpRecips            - Pointer to array of CMC_recipients
  2426. //
  2427. //  Return:
  2428. //      Void.
  2429.  
  2430.  
  2431. void
  2432. MakeDisplayNameStr (LPSTR lpszDisplay, CMC_enum ulRecipRole,
  2433.     ULONG cRecips, CMC_recipient FAR * lpRecips)
  2434. {
  2435.     ULONG idx;
  2436.  
  2437.     *lpszDisplay = '\0';
  2438.  
  2439.     for (idx = 0; idx < cRecips; idx++)
  2440.     {
  2441.         if (lpRecips[idx].role == ulRecipRole)
  2442.         {
  2443.             lstrcat (lpszDisplay, lpRecips[idx].name);
  2444.             lstrcat (lpszDisplay, "; ");
  2445.         }
  2446.     }
  2447.  
  2448.     if (*lpszDisplay)
  2449.         lpszDisplay[lstrlen (lpszDisplay) - 2] = '\0';
  2450. }
  2451.  
  2452.  
  2453. //
  2454. //  SaveMsgChanges
  2455. //
  2456. //  Purpose:
  2457. //      If while reading a message the user changes the notetext at all
  2458. //      then this function is called to save those changes in the Inbox.
  2459. //
  2460. //  Parameters:
  2461. //      hWnd            - handle to the window/dialog who called us
  2462. //      lpMsg           - pointer to the CMC message to be saved
  2463. //      msgReference       - ID of the message to save
  2464. //
  2465. //  Return:
  2466. //      ulResult        - Indicating success/failure
  2467.  
  2468.  
  2469. CMC_return_code
  2470. SaveMsgChanges (HWND hWnd, CMC_message far *lpMsg)
  2471. {
  2472.     LPSTR lpszT;
  2473.     LPSTR lpszTextNote = NULL;
  2474.     LONG cLines, cb;
  2475.     CMC_return_code ulResult = CMC_SUCCESS;
  2476.     CMC_extension   ext;
  2477.  
  2478.     lpszT = lpMsg->text_note;
  2479.  
  2480.     cLines = SendDlgItemMessage (hWnd, IDC_READNOTE, EM_GETLINECOUNT, 0, 0L);
  2481.     cb = (LRESULT) SendDlgItemMessage (hWnd,
  2482.                 IDC_READNOTE,
  2483.                 EM_LINEINDEX,
  2484.                 (WPARAM) cLines - 1,
  2485.                 0L);
  2486.     cb += (LRESULT) SendDlgItemMessage (hWnd, IDC_READNOTE, EM_LINELENGTH, (WPARAM)cb, 0L);
  2487.     cb += cLines * 2;
  2488.  
  2489.     lpszTextNote = (LPSTR)PvAlloc(cb + 1 );
  2490.  
  2491.     if (!lpszTextNote)
  2492.         goto err;
  2493.  
  2494.     SendDlgItemMessage (hWnd, IDC_READNOTE, WM_GETTEXT,
  2495.         (WPARAM) cb, (LPARAM) lpszTextNote);
  2496.  
  2497.     lpMsg->text_note = lpszTextNote;
  2498.  
  2499.     ext.item_data       = 0;
  2500.     ext.item_code       = CMC_X_COM_SAVE_MESSAGE;
  2501.     ext.item_reference  = (CMC_buffer)lpMsg;
  2502.     ext.extension_flags = CMC_EXT_REQUIRED | CMC_EXT_LAST_ELEMENT;
  2503.  
  2504.     ulResult = CMCActOn(lhSession, lpMsg->message_reference, CMC_ACT_ON_EXTENDED,
  2505.                         CMC_ERROR_UI_ALLOWED, (CMC_ui_id)hWnd, &ext);
  2506.  
  2507.     PvFree(lpszTextNote);
  2508.  
  2509. err:
  2510.     lpMsg->text_note = lpszT;
  2511.     return ulResult;
  2512. }
  2513.  
  2514. //
  2515. //  MakeNewMessage
  2516. //
  2517. //  Purpose:
  2518. //      This function is used to construct a new message for the
  2519. //      ComposeNote UI.  This gets called as a result of a Reply,
  2520. //      ReplyAll, or a Forward action on a message being read.
  2521. //      The destination for the new message is CmcMsg, the global
  2522. //      CMC_message struct pointer used by ComposeNoteDlgProc.
  2523. //      ComposeNoteDlgProc always frees the memory consumed by
  2524. //      this object whether it allocated it or not.
  2525. //
  2526. //  Parameters:
  2527. //      lpSrcMsg            - CMC_message to be copied
  2528. //      flType              - Specifies the action that caused this call
  2529. //                            either: IDC_REPLY, IDC_REPLYALL, or IDC_FORWARD
  2530. //
  2531. //  Return:
  2532. //      ulResult            - Indicates success/failure
  2533.  
  2534.  
  2535. CMC_return_code
  2536. MakeNewMessage (CMC_message far *lpSrcMsg, CMC_flags flType)
  2537. {
  2538.  
  2539. #define REPLY_SEPERATOR "\r\n--------------------------\r\n"
  2540.  
  2541.     ULONG cOldRecips;
  2542.     ULONG cNewRecips;
  2543.     ULONG cAttach;
  2544.     ULONG idx;
  2545.     CMC_return_code     ulResult = CMC_SUCCESS;
  2546.     CMC_uint32          cCurrentUser = 1;
  2547.     CMC_recipient FAR * CurrentUser = NULL;
  2548.  
  2549.  
  2550.     if (!lpSrcMsg)
  2551.         return CMC_E_FAILURE;
  2552.  
  2553.     if(CmcMsg)
  2554.         PvFree(CmcMsg);
  2555.  
  2556.     CmcMsg = (CMC_message far *)PvAlloc(sizeof(CMC_message));
  2557.  
  2558.     if (!CmcMsg)
  2559.         goto err;
  2560.  
  2561.     _fmemset (CmcMsg, 0, sizeof (CMC_message));
  2562.  
  2563.     if (lpSrcMsg->subject)
  2564.     {
  2565.         CmcMsg->subject = (LPSTR)PvAlloc(lstrlen(lpSrcMsg->subject) + 5);
  2566.         if (!CmcMsg->subject)
  2567.             goto err;
  2568.  
  2569.         if (flType == IDC_FORWARD)
  2570.             lstrcpy (CmcMsg->subject, "FW: ");
  2571.         else
  2572.             lstrcpy (CmcMsg->subject, "RE: ");
  2573.  
  2574.         lstrcat (CmcMsg->subject, lpSrcMsg->subject);
  2575.     }
  2576.  
  2577.     if (lpSrcMsg->text_note)
  2578.     {
  2579.         CmcMsg->text_note = (CMC_string)PvAlloc(lstrlen(lpSrcMsg->text_note) + 32);
  2580.         if (!CmcMsg->text_note)
  2581.             goto err;
  2582.  
  2583.         lstrcpy (CmcMsg->text_note, REPLY_SEPERATOR);
  2584.         lstrcat (CmcMsg->text_note, lpSrcMsg->text_note);
  2585.     }
  2586.  
  2587.     if (lpSrcMsg->message_type)
  2588.     {
  2589.         CmcMsg->message_type = (CMC_string)PvAlloc(lstrlen(lpSrcMsg->message_type) + 1);
  2590.         if (!CmcMsg->message_type)
  2591.             goto err;
  2592.  
  2593.         lstrcpy (CmcMsg->message_type, lpSrcMsg->message_type);
  2594.     }
  2595.  
  2596.     if (lpSrcMsg->attachments)
  2597.     {
  2598.         cAttach = 0;
  2599.         while (!(lpSrcMsg->attachments[cAttach].attach_flags & CMC_ATT_LAST_ELEMENT))
  2600.             cAttach++;
  2601.  
  2602.         cAttach++;
  2603.  
  2604.         CmcMsg->attachments = (CMC_attachment far *)PvAlloc(cAttach * sizeof(CMC_attachment));
  2605.         if (!CmcMsg->attachments)
  2606.             goto err;
  2607.  
  2608.         _fmemset (CmcMsg->attachments, 0, (size_t)cAttach*sizeof(CMC_attachment));
  2609.  
  2610.         for (idx = 0; idx < cAttach; idx++)
  2611.             CopyAttachment (CmcMsg->attachments, &CmcMsg->attachments[idx], &lpSrcMsg->attachments[idx]);
  2612.  
  2613.     }
  2614.  
  2615.     if (flType == IDC_REPLY || flType == IDC_REPLYALL)
  2616.     {
  2617.         cOldRecips = 0;
  2618.  
  2619.         while (!(lpSrcMsg->recipients[cOldRecips].recip_flags & CMC_RECIP_LAST_ELEMENT))
  2620.             cOldRecips++;
  2621.         cOldRecips++;
  2622.  
  2623.         if(flType == IDC_REPLYALL)
  2624.             cNewRecips = cOldRecips;
  2625.         else
  2626.             cNewRecips = 1;
  2627.  
  2628.         CmcMsg->recipients = (CMC_recipient far *)PvAlloc(cNewRecips * sizeof(CMC_recipient));
  2629.  
  2630.         if (!CmcMsg->recipients)
  2631.             goto err;
  2632.  
  2633.         _fmemset (CmcMsg->recipients, 0, (size_t)cNewRecips*sizeof(CMC_recipient));
  2634.  
  2635.         // Look up current user address
  2636.         ulResult = CMCLookUp(lhSession, NULL, CMC_LOOKUP_RESOLVE_IDENTITY,
  2637.                              (CMC_ui_id)NULL, &cCurrentUser, &CurrentUser, NULL);
  2638.  
  2639.         cNewRecips = 0;
  2640.         for (idx = 0; idx < cOldRecips; idx++)
  2641.         {
  2642.             // Always Reply to the originator and change their role
  2643.             if (lpSrcMsg->recipients[idx].role == CMC_ROLE_ORIGINATOR)
  2644.             {
  2645.                 CopyRecipient(CmcMsg->recipients, &CmcMsg->recipients[cNewRecips],
  2646.                               &lpSrcMsg->recipients[idx]);
  2647.                 CmcMsg->recipients[cNewRecips].role = CMC_ROLE_TO;
  2648.                 cNewRecips++;
  2649.                 if(flType == IDC_REPLY)
  2650.                     break;
  2651.             }
  2652.             else if((flType == IDC_REPLYALL) &&
  2653.                     (ulResult || lstrcmp(lpSrcMsg->recipients[idx].address,
  2654.                                          CurrentUser->address)))
  2655.             {
  2656.                 // Don't reply to ourselves if replying to all
  2657.                 CopyRecipient(CmcMsg->recipients, &CmcMsg->recipients[cNewRecips],
  2658.                               &lpSrcMsg->recipients[idx]);
  2659.                 cNewRecips++;
  2660.             }
  2661.         }
  2662.  
  2663.         if(cNewRecips)
  2664.             CmcMsg->recipients[cNewRecips-1].recip_flags |= CMC_RECIP_LAST_ELEMENT;
  2665.  
  2666.         CMCFree(CurrentUser);
  2667.     }
  2668.  
  2669.     return ulResult;
  2670.  
  2671. err:
  2672.     PvFree(CmcMsg->subject);
  2673.     PvFree(CmcMsg->text_note);
  2674.     PvFree(CmcMsg->message_type);
  2675.     PvFree(CmcMsg->recipients);
  2676.     PvFree(CmcMsg->attachments);
  2677.     PvFree(CmcMsg);
  2678.     CmcMsg = NULL;
  2679.  
  2680.     return ulResult;
  2681. }
  2682.  
  2683. //
  2684. //  LogSendMail
  2685. //
  2686. //  Purpose:
  2687. //      Used to track how many messages were sent with this client.
  2688. //      This information is used strictly for gathering stats on
  2689. //      how many messages were pumped through the spooler/transport.
  2690. //
  2691. //  Usage:
  2692. //      Add the following to the win.ini file:
  2693. //          [CMC Client]
  2694. //          LogFile=filepath
  2695. //
  2696. //      where: filepath can be a full UNC path or some local path & file
  2697. //
  2698. //  Parameters:
  2699. //      ulResult        - Currently unused; should be used to count errors
  2700. //
  2701. //  Result:
  2702. //      Void.
  2703.  
  2704.  
  2705. void LogSendMail(ULONG ulResult)
  2706. {
  2707.     char szLogFile[128];
  2708.     char szCount[32];
  2709.     OFSTRUCT ofs;
  2710.     HFILE hf = HFILE_ERROR;
  2711.     int cSent = 1;
  2712.  
  2713.     if(!GetProfileString("CMC Client", "LogFile", "CMCcli.log",
  2714.             szLogFile, sizeof(szLogFile)))
  2715.         return;
  2716.  
  2717.     if((hf = OpenFile(szLogFile, &ofs, OF_READWRITE)) == HFILE_ERROR)
  2718.     {
  2719.         if((hf = OpenFile(szLogFile, &ofs, OF_CREATE|OF_READWRITE)) == HFILE_ERROR)
  2720.             return;
  2721.     }
  2722.     else
  2723.     {
  2724.         if(!_lread(hf, szCount, sizeof(szCount)))
  2725.         {
  2726.             _lclose(hf);
  2727.             return;
  2728.         }
  2729.  
  2730.         cSent = atoi(szCount) + 1;
  2731.     }
  2732.  
  2733.     wsprintf(szCount, "%d", cSent);
  2734.  
  2735.     _llseek(hf, 0, 0);
  2736.  
  2737.     _lwrite(hf, szCount, lstrlen(szCount));
  2738.     _lclose(hf);
  2739.  
  2740.     return;
  2741. }
  2742.  
  2743. //
  2744. //  SaveFileAttachments
  2745. //
  2746. //  Purpose:
  2747. //      Displays a 'Save As' common dialog to allow the user to save
  2748. //      file attachments contained in the current message.
  2749. //
  2750. //  Parameters:
  2751. //      hWnd            - Window handle of calling WndProc
  2752. //      cFiles          - Count of the files in the file array
  2753. //      lpFiles         - Array of CMC_attachments
  2754. //
  2755. //  Return:
  2756. //      Void.
  2757.  
  2758.  
  2759. void SaveFileAttachments(HWND hWnd, CMC_attachment FAR * lpFile)
  2760. {
  2761.     OPENFILENAME ofn;
  2762.     char szFileName[256];
  2763.     char szFilter[256];
  2764.     static char szFileTitle[16];
  2765.     static char szDirName[256] = "";
  2766.     LPSTR lpszEndPath;
  2767.     ULONG idx;
  2768. #ifdef WIN16
  2769.     OFSTRUCT ofStrSrc;
  2770.     OFSTRUCT ofStrDest;
  2771.     HFILE hfSrcFile, hfDstFile;
  2772. #endif
  2773.  
  2774.     _fmemset(&ofn, 0, sizeof(OPENFILENAME));
  2775.  
  2776.     if (!lpFile)
  2777.         return;
  2778.  
  2779.     if (!szDirName[0])
  2780.         GetWindowsDirectory ( szDirName,sizeof(szDirName));
  2781.  
  2782.     LoadString(hInst, IDS_FILTER, szFilter, sizeof(szFilter));
  2783.  
  2784.     for (idx = 0; szFilter[idx] != '\0'; idx++)
  2785.         if (szFilter[idx] == '|')
  2786.             szFilter[idx] = '\0';
  2787.  
  2788.     lstrcpy(szFileName, lpFile->attach_title);
  2789.  
  2790.     ofn.lStructSize = sizeof (OPENFILENAME);
  2791.     ofn.hwndOwner = hWnd;
  2792.     ofn.lpstrFilter = szFilter;
  2793.     ofn.lpstrFile = szFileName;
  2794.     ofn.nMaxFile = sizeof(szFileName);
  2795.     ofn.lpstrFileTitle = szFileTitle;
  2796.     ofn.nMaxFileTitle = sizeof(szFileTitle);
  2797.     ofn.lpstrInitialDir = szDirName;
  2798.     ofn.lpstrTitle = "Save Attachment";
  2799.     ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
  2800.  
  2801.     if (!GetSaveFileName (&ofn))
  2802.         return;
  2803.  
  2804.     //   Save the directory for the next time we call this
  2805.  
  2806.     lstrcpy (szDirName, szFileName);
  2807.     if (lpszEndPath = strstr (szDirName, szFileTitle))
  2808.         *(--lpszEndPath) = '\0';
  2809.  
  2810. #ifdef WIN16
  2811.     // Use CopyLZFile to copy the file.
  2812.     // Open, copy, and then close the file.
  2813.  
  2814.     hfSrcFile = LZOpenFile(lpFile->attach_filename, &ofStrSrc, OF_READ);
  2815.  
  2816.     hfDstFile = LZOpenFile(szFileName, &ofStrDest, OF_CREATE);
  2817.     if (LZCopy(hfSrcFile, hfDstFile) < 0)
  2818.         MakeMessageBox (hWnd, 0, IDS_SAVEATTACHERROR, MBS_ERROR);
  2819.     LZClose(hfSrcFile);
  2820.     LZClose(hfDstFile);
  2821.  
  2822. #else
  2823.     /* Use CopyFile to carry out the operation. */
  2824.  
  2825.     if(!CopyFile(lpFile->attach_filename, szFileName, FALSE))
  2826.         MakeMessageBox (hWnd, 0, IDS_SAVEATTACHERROR, MBS_ERROR);
  2827. #endif
  2828.  
  2829. }
  2830.  
  2831. //
  2832. //  ToggleMenuState
  2833. //
  2834. //  Purpose:
  2835. //      Enables/Disables menu items depending on the session state.
  2836. //
  2837. //  Parameters:
  2838. //      hWnd            - handle to the window/dialog who called us
  2839. //      fLoggedOn       - TRUE if logged on, FALSE if logged off
  2840. //
  2841. //  Return:
  2842. //      Void.
  2843. //
  2844.  
  2845. void ToggleMenuState(HWND hWnd, BOOL fLoggedOn)
  2846. {
  2847.     EnableMenuItem (GetMenu (hWnd), IDM_LOGOFF,         !fLoggedOn);
  2848.     EnableMenuItem (GetMenu (hWnd), IDM_COMPOSE_CMC,    !fLoggedOn);
  2849.     EnableMenuItem (GetMenu (hWnd), IDM_COMPOSE_CUSTOM, !fLoggedOn);
  2850.     EnableMenuItem (GetMenu (hWnd), IDM_READ,           !fLoggedOn);
  2851.     EnableMenuItem (GetMenu (hWnd), IDM_ADDRBOOK,       !fLoggedOn);
  2852.     EnableMenuItem (GetMenu (hWnd), IDM_LOGON,          fLoggedOn);
  2853.     EnableMenuItem (GetMenu (hWnd), IDM_EXIT,           FALSE);
  2854. }
  2855.  
  2856. //
  2857. //  SecureMenu
  2858. //
  2859. //  Purpose:
  2860. //      Enables/Disables Logon and Exit menu items.
  2861. //      CMCLogon might yield control to Windows, so the user might be able to
  2862. //      access the window menu (for example click Logon) after we call
  2863. //      CMCLogon, but before it returns.
  2864. //
  2865. //  Parameters:
  2866. //      hWnd            - handle to the window/dialog who called us
  2867. //      fBeforeLogon    - TRUE when this function is called when we are about
  2868. //                      to call CMCLogon, FALSE if called after logon (failed)
  2869. //                      if Logon succeddes ToggleMenuState is called instead of
  2870. //                      this function.
  2871. //
  2872. //  Return:
  2873. //      Void.
  2874. //
  2875.  
  2876.  
  2877. void SecureMenu(HWND hWnd, BOOL fBeforeLogon)
  2878. {
  2879.     EnableMenuItem (GetMenu (hWnd), IDM_LOGON, fBeforeLogon);
  2880.     EnableMenuItem (GetMenu (hWnd), IDM_EXIT,  fBeforeLogon);
  2881. }
  2882.