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

Windows编程

开发平台:

Visual C++

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