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

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