home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / cmccli / cmccli.c next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  78.4 KB  |  2,785 lines

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