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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  -  ROUTE.C
  3.  *
  4.  *
  5.  *      Functions used to implement routing.
  6.  *
  7.  *      To create a new routing message call:
  8.  *         DialogBoxParam(hInst, "RouteNote", hWnd, RouteNoteDlgProc, (LPARAM) NULL );
  9.  *      To route a routed message to the next recipient call:
  10.  *          DialogBoxParam(hInst, "RouteNote", hWnd, RouteNoteDlgProc, (LPARAM) pmsg );
  11.  *              where pmsg is a pointer to the message you want to route.
  12.  *      To find out if a message was routed by this program call:
  13.  *          HasRougingSlip();
  14.  *
  15.  *
  16.  *      To use this functions in your own program change the line (in route.h):
  17.  *          #define lpszSmplRTMsgClass "IPM.Note.SampleRoutingForm"
  18.  *      to reflect the name of your own class for routing messages.
  19.  *
  20.  *
  21.  *  Copyright 1986-1996, Microsoft Corporation. All Rights Reserved.
  22.  */
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #ifdef _WIN32
  28. #include <objerror.h>
  29. #include <objbase.h>
  30. #endif
  31. #ifdef WIN16
  32. #include <compobj.h>
  33. #include <commdlg.h>
  34. #endif
  35. #include <mapiutil.h>
  36. #include <mapix.h>
  37. #include <mapiwin.h>
  38. #include <mapidbg.h>
  39. #include <cindex.h>
  40. #ifdef WIN16
  41. #define GWL_USERDATA    DWL_USER
  42. #endif
  43. /*
  44.  To use a GUID XXX in a program you have to initialize it in exactly one
  45. obj file of your project.
  46. Line "#define USES_XXX" tells the compiler that you are going to use GUID XXX
  47. in this file.
  48. Lines "#define INITGUID"  and "#include<initguid.h>"
  49. tell the compiler to init GUIDs in this file.*/
  50. /* the GUID we'll be using */
  51. #define USES_PS_ROUTING_EMAIL_ADDRESSES 1
  52. #define USES_PS_ROUTING_ADDRTYPE 1
  53. #define USES_PS_ROUTING_DISPLAY_NAME 1
  54. #define USES_PS_ROUTING_ENTRYID 1
  55. #define USES_PS_ROUTING_SEARCH_KEY 1
  56. #define USES_PS_PUBLIC_STRINGS  1
  57. #define USES_IID_IMessage 1
  58. #define USES_IID_IMAPIStatus 1
  59. #define USES_IID_IMAPIForm 1
  60. /*initialize the GUIDs in this file*/
  61. #define INITGUID 1
  62. #include <initguid.h>
  63. #include <mapiguid.h>
  64. #include <pdkver.h>
  65. #include "client.h"
  66. #include "bitmap.h"
  67. #include "route.h"
  68. /* Routing Data. Used in RouteNoteDlgProc that handles composing/sending/reading of
  69. routing messages */
  70. typedef struct _ROUTEDATA
  71. {
  72.     LPADRLIST palAddrListOld;
  73.     LPADRLIST palAddrListActive;
  74.     ULONG nCurrentRouteRecip;
  75.     ULONG nTotalRouteRecip;
  76.     LPMAPITABLE ptblAttach;
  77.     BOOL bNewMessage;
  78.     LPMESSAGE pmsgRouteMsg;
  79.     ULONG tagCurrent;
  80.     ULONG tagTotal;
  81.     ULONG cbConvIdx;
  82.     LPBYTE lpbConvIdx;
  83. } ROUTEDATA, FAR * LPROUTEDATA;
  84. BOOL MakeNewRouteMessage(LPMESSAGE pmsgRead, LPROUTEDATA FAR * ppRouteData);
  85. BOOL SetRouteProps(LPROUTEDATA pRouteData);
  86. BOOL DelRouteProps(LPROUTEDATA pRouteData);
  87. BOOL GetRoutePropTagArray(ULONG cb, LPMESSAGE lpM, LPSPropTagArray FAR * lppspta);
  88. BOOL GetRoutePropTagArrayFast(ULONG nTotalRecip, LPMESSAGE lpM, BOOL fCreate,
  89.                                 LPSPropTagArray FAR * lppspta);
  90. BOOL GetRouteIndices(LPROUTEDATA pRouteData);
  91. BOOL SetRouteIndices(LPROUTEDATA pRouteData);
  92. BOOL CreateOutMessage(LPMESSAGE FAR * lpmSrcMsgI);
  93. BOOL GetRouteAddrLists(LPROUTEDATA pRouteData);
  94. UINT FirstRecipient(LPADRLIST lpAL);
  95. BOOL SetMessageClass(LPMESSAGE lpM, LPSTR lpszClass);
  96. BOOL HasAttachment(LPMESSAGE lpM);
  97. BOOL PopulateAttachList(HWND hDlg, LPROUTEDATA pRouteData);
  98. BOOL CreateNewAttachment(HWND hDlg);
  99. void SaveAttachment( HWND hDlg, UINT indx);
  100. void RT_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify);
  101. BOOL RT_OnInitDialog(HWND hDlg, HWND hwndFocus, LPARAM lParam);
  102. BOOL RBox_OnInitDialog(HWND hDlg, HWND hwndFocus, LPARAM lParam);
  103. void RBox_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify);
  104. void DeInitRouteData(LPROUTEDATA pRouteData);
  105. BOOL CALLBACK RouteBoxDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
  106. void InitRouteNameIDArray(ULONG cb, LPMAPINAMEID lpPropNames);
  107. void PopulateRouteListBox(HWND hDlg);
  108. void ConfigMoveButtons(HWND hDlg, HWND hLB);
  109. typedef enum _ROUTEPROPSETS
  110. {
  111.     ROUTEPROPSET_EMAIL_ADDRESS = 0,
  112.     ROUTEPROPSET_ADDRTYPE,
  113.     ROUTEPROPSET_DISPLAY_NAME,
  114.     ROUTEPROPSET_ENTRYID,
  115.     ROUTEPROPSET_SEARCH_KEY,
  116.     ROUTEPROPSETDIM     /* used for dimension*/
  117. } ROUTEPROPSETS;
  118. LPGUID  lpguidA[ROUTEPROPSETDIM]  =
  119. {
  120.     (LPGUID)&PS_ROUTING_EMAIL_ADDRESSES,
  121.     (LPGUID)&PS_ROUTING_ADDRTYPE,
  122.     (LPGUID)&PS_ROUTING_DISPLAY_NAME,
  123.     (LPGUID)&PS_ROUTING_ENTRYID,
  124.     (LPGUID)&PS_ROUTING_SEARCH_KEY
  125. };
  126. ULONG  ulRoutePropTypes [ROUTEPROPSETDIM] =
  127. {
  128.     PT_STRING8,
  129.     PT_STRING8,
  130.     PT_STRING8,
  131.     PT_BINARY,
  132.     PT_BINARY
  133. };
  134. /*  used for PrepareRecips call*/
  135. SizedSPropTagArray(ROUTEPROPSETDIM, sptRouteProps) =
  136. {
  137.     ROUTEPROPSETDIM,
  138.     {
  139.         PR_EMAIL_ADDRESS,
  140.         PR_ADDRTYPE,
  141.         PR_DISPLAY_NAME,
  142.         PR_ENTRYID,
  143.         PR_SEARCH_KEY
  144.     }
  145. };
  146. enum {EMSG_SUBJ = 0, EMSG_BODY, EMSG_MSGFLAGS, EMSG_CONVIDX, EMSGPROPDIM};
  147. SizedSPropTagArray( EMSGPROPDIM, tagaMsgProps) =
  148. {
  149.     EMSGPROPDIM,
  150.     {PR_SUBJECT, PR_BODY, PR_MESSAGE_FLAGS, PR_CONVERSATION_INDEX}
  151. };
  152. /*
  153. //
  154. // the number of entries could vary from
  155. // EXCLUDED_PROPS_ON_REPLY to EXCLUDED_PROPS_ON_REPLY - 1 and vice versa,
  156. // depending if the message is being reply or fowarded. If forwarded, the
  157. // PR_MESSAGE_ATTACHMENTS property is included in the forwarded message
  158. // otherwise it is excluded
  159. */
  160. #define EXCLUDED_PROPS_ON_REPLY     29
  161. SizedSPropTagArray (EXCLUDED_PROPS_ON_REPLY, sptExcludedProps) =
  162. {
  163.     EXCLUDED_PROPS_ON_REPLY,
  164.     {
  165.         PR_SENDER_NAME,
  166.         PR_SENDER_ENTRYID,
  167.         PR_SENDER_SEARCH_KEY,
  168.         PR_SENDER_EMAIL_ADDRESS,
  169.         PR_SENDER_ADDRTYPE,
  170.         PR_RECEIVED_BY_NAME,
  171.         PR_RECEIVED_BY_ENTRYID,
  172.         PR_RECEIVED_BY_SEARCH_KEY,
  173.         PR_SENT_REPRESENTING_NAME,
  174.         PR_SENT_REPRESENTING_ENTRYID,
  175.         PR_SENT_REPRESENTING_SEARCH_KEY,
  176.         PR_SENT_REPRESENTING_EMAIL_ADDRESS,
  177.         PR_SENT_REPRESENTING_ADDRTYPE,
  178.         PR_RCVD_REPRESENTING_NAME,
  179.         PR_RCVD_REPRESENTING_ENTRYID,
  180.         PR_RCVD_REPRESENTING_SEARCH_KEY,
  181.         PR_MESSAGE_FLAGS,
  182.         PR_MESSAGE_RECIPIENTS,
  183.         PR_READ_RECEIPT_ENTRYID,
  184.         PR_REPORT_ENTRYID,
  185.         PR_REPLY_RECIPIENT_ENTRIES,
  186.         PR_REPLY_RECIPIENT_NAMES,
  187.         PR_PARENT_KEY,
  188.         PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED,
  189.         PR_READ_RECEIPT_REQUESTED,
  190.         PR_CLIENT_SUBMIT_TIME,
  191.         PR_MESSAGE_DELIVERY_TIME,
  192.         PR_MESSAGE_DOWNLOAD_TIME,
  193. //        PR_SUBJECT_PREFIX,
  194.         PR_MESSAGE_ATTACHMENTS
  195.     }
  196. };
  197. LPADRBOOK
  198. OpenAddressBook(HWND hwnd)
  199. {
  200.     HRESULT hr;
  201.     LPADRBOOK pabAddrBook = NULL;
  202.     Assert(pses);
  203.     hr = pses->lpVtbl->OpenAddressBook(pses, (ULONG) hwnd, NULL, 0, &pabAddrBook);
  204.     if(HR_FAILED(hr))
  205.     {
  206.         MakeMessageBox(hwnd, GetScode(hr),IDS_OPENAB, NULL, MBS_ERROR);
  207.         return NULL;
  208.     }
  209.     if(hr) /*if we have a warning*/
  210.     {
  211.         LPMAPIERROR perr = NULL;
  212.         pses->lpVtbl->GetLastError(pses, hr, 0, &perr);
  213.         MakeMessageBox(hwnd, GetScode(hr), IDS_OPENABWARN, perr, MBS_ERROR);
  214.         MAPIFreeBuffer(perr);
  215.     }
  216.     return pabAddrBook;
  217. }
  218. /*
  219.  *  Handles the RouteSlipbox
  220.  *
  221.  *  Extracts all necessary data from GWL_USERDATA window long of
  222.  *  its parent which is RouteNote dialog.
  223.  */
  224. BOOL CALLBACK
  225. RouteBoxDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  226. {
  227.     switch (msg)
  228.     {
  229.     case WM_INITDIALOG:
  230.         PopulateRouteListBox(hDlg);
  231.         return TRUE;
  232.     HANDLE_MSG(hDlg, WM_COMMAND, RBox_OnCommand);
  233.     }
  234.     return FALSE;
  235. }
  236. void RBox_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
  237. {
  238.     ADRPARM AdrParm = { 0 };
  239.     ULONG ulrectps = MAPI_TO;
  240.     LPSTR  lpszTitles = "Route To ";
  241.     UINT nIndex, nIndex1;
  242.     LPSPropValue lpspv = NULL;
  243.     LPROUTEDATA pRouteData = NULL;
  244.     HRESULT hr;
  245.     switch (id)
  246.     {
  247.     case IDC_ADDRLISTACTIVE:
  248.     case IDC_ADDRLISTOLD:
  249.             /*This is to disallow hitting "Remove" button when
  250.             there is something selected in the old address list*/
  251.         if(codeNotify == LBN_SETFOCUS)
  252.         {
  253.             if(id == IDC_ADDRLISTOLD)
  254.             {
  255.                 EnableWindow(GetDlgItem(hDlg, IDC_REMOVEADDR), FALSE);
  256.                 EnableWindow(GetDlgItem(hDlg, IDC_MOVEUP), FALSE);
  257.                 EnableWindow(GetDlgItem(hDlg, IDC_MOVEDOWN), FALSE);
  258.                 ListBox_SetCurSel(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), -1);
  259.             }
  260.             else /*must be IDC_ADDRLISTACTIVE*/
  261.             {
  262.                 EnableWindow(GetDlgItem(hDlg, IDC_REMOVEADDR), TRUE);
  263.                 ListBox_SetCurSel(GetDlgItem(hDlg, IDC_ADDRLISTOLD), -1);
  264.             }
  265.         }
  266.         if(IDC_ADDRLISTACTIVE == id && LBN_SELCHANGE == codeNotify)
  267.         {
  268.             ConfigMoveButtons(hDlg, hwndCtl);
  269.         }
  270.         /* Details */
  271.         if(codeNotify == LBN_DBLCLK)
  272.         {
  273.             LPSPropValue pvalDtls = NULL;
  274.             ULONG cVals = 0;
  275.             nIndex = (UINT)ListBox_GetCurSel(hwndCtl);
  276.             if (nIndex == LB_ERR)
  277.                 break;
  278.             nIndex1 = (UINT)ListBox_GetItemData(hwndCtl, nIndex);
  279.             if(nIndex1 == LB_ERR)
  280.             {
  281.                 DebugTrace("Client: error retrieving listbox item data");
  282.                 break;
  283.             }
  284.             pRouteData = (LPROUTEDATA) GetWindowLong(GetParent(hDlg), GWL_USERDATA);
  285.             Assert(pRouteData);
  286.             if(IDC_ADDRLISTACTIVE == id)
  287.             {
  288.                 Assert(nIndex1 < pRouteData->palAddrListActive->cEntries);
  289.                 pvalDtls = pRouteData->palAddrListActive->aEntries[nIndex1].rgPropVals;
  290.                 cVals = pRouteData->palAddrListActive->aEntries[nIndex1].cValues;
  291.             }
  292.             else if(IDC_ADDRLISTOLD == id)
  293.             {
  294.                 Assert(nIndex1 < pRouteData->palAddrListOld->cEntries);
  295.                 pvalDtls = pRouteData->palAddrListOld->aEntries[nIndex1].rgPropVals;
  296.                 cVals = pRouteData->palAddrListOld->aEntries[nIndex1].cValues;
  297.             }
  298.             else
  299.                 Assert(FALSE);
  300.             Assert(pvalDtls);
  301.             pvalDtls = PpropFindProp(pvalDtls, cVals, PR_ENTRYID);
  302.             Assert(pvalDtls);
  303.             if(pvalDtls)
  304.             {
  305.                 hr = pabAddrB->lpVtbl->Details(pabAddrB, (LPULONG) &hDlg, NULL,
  306.                                         NULL, pvalDtls->Value.bin.cb,
  307.                                         (LPENTRYID)pvalDtls->Value.bin.lpb, NULL,
  308.                                         NULL, NULL, DIALOG_MODAL);
  309.             }
  310.         }
  311.         return;
  312.     case IDC_MOVEDOWN:
  313.     case IDC_MOVEUP:
  314.         {
  315.             int nInd, nIndNew;
  316.             int nIndData, nIndDataNew;
  317. #ifdef DEBUG
  318.             int nTotal;
  319. #endif
  320.             char szStr[256];
  321.             ADRENTRY ae = {0};
  322.             HWND hLB = GetDlgItem(hDlg, IDC_ADDRLISTACTIVE);
  323.             Assert(hLB);
  324.             nInd = ListBox_GetCurSel(hLB);
  325.             if (nInd == LB_ERR)
  326.                 break;
  327. #ifdef DEBUG
  328.             Assert(nInd != 0 || id != IDC_MOVEUP);
  329.             nTotal = ListBox_GetCount(hLB);
  330.             if(nTotal != LB_ERR)
  331.                 Assert(nInd != nTotal-1 || id != IDC_MOVEDOWN);
  332. #endif
  333.             if(IDC_MOVEDOWN == id)
  334.                 nIndNew = nInd + 1;
  335.             else
  336.                 nIndNew = nInd - 1;
  337.             nIndData = ListBox_GetItemData(hLB, nInd);
  338.             if(nIndData == LB_ERR)
  339.             {
  340.                 DebugTrace("Client: error retrieving listbox item data");
  341.                 break;
  342.             }
  343.             nIndDataNew = ListBox_GetItemData(hLB, nIndNew);
  344.             if(nIndDataNew == LB_ERR)
  345.             {
  346.                 DebugTrace("Client: error retrieving listbox item data");
  347.                 break;
  348.             }
  349.             pRouteData = (LPROUTEDATA) GetWindowLong(GetParent(hDlg), GWL_USERDATA);
  350.             Assert(pRouteData);
  351.             ae = pRouteData->palAddrListActive->aEntries[nIndData];
  352.             pRouteData->palAddrListActive->aEntries[nIndData] =
  353.             pRouteData->palAddrListActive->aEntries[nIndDataNew];
  354.             pRouteData->palAddrListActive->aEntries[nIndDataNew] = ae;
  355.             /*PopulateRouteListBox(hDlg);*/
  356.             /*this works only because the two strings we swap are adjacent*/
  357.             ListBox_GetText(hLB, nInd, szStr);
  358.             ListBox_DeleteString(hLB, nInd);
  359.             ListBox_InsertString(hLB, nIndNew, szStr);
  360.             ListBox_SetItemData(hLB, nIndNew, nIndDataNew);
  361.             ListBox_SetItemData(hLB, nInd, nIndData);
  362.             ListBox_SetCurSel(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), nIndNew);
  363.             ConfigMoveButtons(hDlg, GetDlgItem(hDlg, IDC_ADDRLISTACTIVE));
  364.             break;
  365.         }
  366.     case IDC_ADDADDR:
  367.         Assert(pabAddrB != NULL);
  368.         memset(&AdrParm, 0, sizeof(AdrParm));
  369.         AdrParm.ulFlags = AB_SELECTONLY | DIALOG_MODAL;
  370.         AdrParm.lpszCaption = "Routing Slip";
  371.         AdrParm.lpszNewEntryTitle = "NEW ENTRY";
  372.         AdrParm.cDestFields = 1;
  373.         AdrParm.nDestFieldFocus = 0;
  374.         AdrParm.lppszDestTitles = &lpszTitles;
  375.         AdrParm.lpulDestComps =  &ulrectps ;
  376.         pRouteData = (LPROUTEDATA) GetWindowLong(GetParent(hDlg), GWL_USERDATA);
  377.         Assert(pRouteData);
  378.         hr = pabAddrB->lpVtbl->Address(pabAddrB, (LPULONG) &hDlg, &AdrParm, &pRouteData->palAddrListActive);
  379.         if(GetScode(hr)!= MAPI_E_USER_CANCEL)
  380.         {
  381.             PopulateRouteListBox(hDlg);
  382.             SetWindowText(GetDlgItem(hDlg, IDCANCEL), "Close");
  383.             SetFocus(GetDlgItem(hDlg, IDCANCEL));
  384.             ListBox_SetCurSel(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), 0);
  385.             ConfigMoveButtons(hDlg, GetDlgItem(hDlg, IDC_ADDRLISTACTIVE));
  386.         }
  387.         return;
  388.     case IDC_REMOVEADDR:
  389.         nIndex = (UINT)ListBox_GetCurSel(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE));
  390.         if (nIndex == LB_ERR)
  391.             break;
  392.         /*items position in ADRLIST is stored with the item in the listbox*/
  393.         nIndex1 = (UINT)ListBox_GetItemData(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), nIndex);
  394.         if(nIndex1 == LB_ERR)
  395.         {
  396.             DebugTrace("Client: error retrieving listbox item data");
  397.             break;
  398.         }
  399.         pRouteData = (LPROUTEDATA) GetWindowLong(GetParent(hDlg), GWL_USERDATA);
  400.         Assert(pRouteData);
  401.         /* Null out the removed item */
  402.         MAPIFreeBuffer(pRouteData->palAddrListActive->aEntries[nIndex1].rgPropVals);
  403.         pRouteData->palAddrListActive->aEntries[nIndex1].rgPropVals = NULL;
  404.         pRouteData->palAddrListActive->aEntries[nIndex1].cValues = 0;
  405.         ListBox_DeleteString(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), nIndex);
  406.         if(nIndex > 0)
  407.             --nIndex;
  408.         ListBox_SetCurSel(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), nIndex);
  409.         ConfigMoveButtons(hDlg, GetDlgItem(hDlg, IDC_ADDRLISTACTIVE));
  410.         SetWindowText(GetDlgItem(hDlg, IDCANCEL), "Close");
  411.         return;
  412.     case IDCANCEL:
  413.         EndDialog (hDlg, TRUE);
  414.         return;
  415.     default:
  416.         break;
  417.     }
  418. }
  419. void ConfigMoveButtons(HWND hDlg, HWND hLB)
  420. {
  421.     int nIndex;
  422.     int nTotal;
  423.     EnableWindow(GetDlgItem(hDlg, IDC_MOVEUP), FALSE);
  424.     EnableWindow(GetDlgItem(hDlg, IDC_MOVEDOWN), FALSE);
  425.     nIndex = (UINT)ListBox_GetCurSel(hLB);
  426.     if (nIndex == LB_ERR)
  427.         return;
  428.     nTotal = ListBox_GetCount(hLB);
  429.     if(nTotal == LB_ERR)
  430.         return;
  431.     if(nIndex)
  432.         EnableWindow(GetDlgItem(hDlg, IDC_MOVEUP), TRUE);
  433.     if(nIndex < nTotal-1)
  434.         EnableWindow(GetDlgItem(hDlg, IDC_MOVEDOWN), TRUE);
  435. }
  436. /*
  437.  *  Handles the Route Note dialog which is used for both composing
  438.  *  and reading routing messages.
  439.  *
  440.  *  If RotueNoteDlg is called to route an existing msg, a pointer to
  441.  *  the message is passed as a lParam to WM_INITDIALOG.
  442.  *
  443.  */
  444. BOOL CALLBACK
  445. RouteNoteDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  446. {
  447.     switch (msg)
  448.     {
  449.     HANDLE_MSG(hDlg, WM_INITDIALOG, RT_OnInitDialog);
  450.     HANDLE_MSG(hDlg, WM_COMMAND, RT_OnCommand);
  451.     default:
  452.         break;
  453.     }
  454.     return FALSE;
  455. }
  456. BOOL RT_OnInitDialog(HWND hDlg, HWND hwndFocus, LPARAM lParam)
  457. {
  458.     HRESULT hr;
  459.     ULONG cVals = 0;
  460.     LPSPropValue pvalProp = NULL;
  461.     LPSTREAM lpstreamBody = NULL;
  462.     STATSTG statstg = {0};
  463.     LPSTR lpszNoteText = NULL;
  464.     ULONG cb = 0;
  465.     LPMESSAGE pmsgRead = (LPMESSAGE)lParam;
  466.     LPROUTEDATA pRouteData = NULL;
  467.     LPMESSAGE pmsgRoute = NULL;
  468.     if(!MakeNewRouteMessage(pmsgRead, &pRouteData))
  469.     {
  470.         DebugTrace("Client: MakeNewRouteMessage failed (RT_OnInitDialog)");
  471.         goto err;
  472.     }
  473.     if (pmsgRead)
  474.     {
  475.         hr = pmsgRead->lpVtbl->SetReadFlag(pmsgRead, MAPI_DEFERRED_ERRORS);
  476.         /* RouteNote is being called to route  */
  477.         /*  a message in the Inbox.  So, we'll initialize the   */
  478.         /*  form with data from  pmsgRouteMsg */
  479.         pmsgRoute = pRouteData->pmsgRouteMsg;
  480.         Assert(pmsgRoute);
  481.         hr = pmsgRoute->lpVtbl->GetProps(pmsgRoute, (LPSPropTagArray)&tagaMsgProps, 0,
  482.                                                      &cVals, &pvalProp);
  483.         Assert(cVals == EMSGPROPDIM);
  484.         if(HR_SUCCEEDED(hr))
  485.         {
  486.             if(PROP_TYPE(pvalProp[EMSG_SUBJ].ulPropTag) == PT_ERROR)
  487.             {
  488.                 DebugTrace("Client: Unable to retrieve subject");
  489.                 /*goto err;*/
  490.             }
  491.             else
  492.             {
  493.                 SetDlgItemText(hDlg, IDC_RTSUBJECT, pvalProp[EMSG_SUBJ].Value.LPSZ);
  494.                 /* //$ */
  495.             }
  496.             if(PR_CONVERSATION_INDEX == pvalProp[EMSG_CONVIDX].ulPropTag)
  497.             {
  498.                 LPSPropValue pval = &pvalProp[EMSG_CONVIDX];
  499.                 pRouteData->cbConvIdx = pval->Value.bin.cb;
  500.                 if(MAPIAllocateBuffer(pRouteData->cbConvIdx, &pRouteData->lpbConvIdx))
  501.                 {
  502.                     DebugTrace("Client: MAPIAllocateBuffer failedrn");
  503.                     pRouteData->lpbConvIdx = NULL;
  504.                     pRouteData->cbConvIdx = 0;
  505.                 }
  506.                 else
  507.                 {
  508.                     CopyMemory(pRouteData->lpbConvIdx, pval->Value.bin.lpb, pRouteData->cbConvIdx);
  509.                 }
  510.             }
  511.             else
  512.             {
  513.                 pRouteData->lpbConvIdx = NULL;
  514.                 pRouteData->cbConvIdx = 0;
  515.             }
  516.             if(PROP_TYPE(pvalProp[EMSG_BODY].ulPropTag) == PT_ERROR)
  517.             {
  518.                 if(GetScode(pvalProp[EMSG_BODY].Value.l) == MAPI_E_NOT_ENOUGH_MEMORY)
  519.                 {
  520.                     hr = pmsgRoute->lpVtbl->OpenProperty(pmsgRoute, PR_BODY, &IID_IStream,
  521.                                                 STGM_READ, MAPI_DEFERRED_ERRORS,
  522.                                                 (LPUNKNOWN FAR *) &lpstreamBody);
  523.                     if(S_OK != GetScode(hr))
  524.                     {
  525.                         DebugTraceResult(OpenProperty, hr);
  526.                         goto err;
  527.                     }
  528.                     hr = lpstreamBody->lpVtbl->Stat(lpstreamBody, &statstg, STATFLAG_NONAME);
  529.                     if(S_OK != GetScode(hr))
  530.                     {
  531.                         DebugTrace("IStream::Stat failed");
  532.                         goto err;
  533.                     }
  534.                     Assert(statstg.cbSize.HighPart == 0);
  535.                     if(MAPIAllocateBuffer(statstg.cbSize.LowPart + 1, (LPVOID FAR *) &lpszNoteText))
  536.                     {
  537.                         goto err;
  538.                     }
  539.                     hr = lpstreamBody->lpVtbl->Read(lpstreamBody, lpszNoteText,
  540.                                                 statstg.cbSize.LowPart, &cb);
  541.                     if(S_OK != GetScode(hr))
  542.                     {
  543.                         DebugTrace("IStream::Read failed");
  544.                         goto err;
  545.                     }
  546.                     lpszNoteText[statstg.cbSize.LowPart] = '';
  547.                     SetDlgItemText(hDlg, IDC_RTNOTE, lpszNoteText);
  548.                     MAPIFreeBuffer(lpszNoteText);
  549.                     lpszNoteText = NULL;
  550.                     lpstreamBody->lpVtbl->Release(lpstreamBody);
  551.                     lpstreamBody = NULL;
  552.                 }
  553.                 else /* some other error (too bad) */
  554.                 {
  555.                     DebugTrace("Client: error reading body");
  556.                      /*//$goto err;*/
  557.                 }
  558.             }
  559.             else /* everything's fine */
  560.             {
  561.                 SetDlgItemText(hDlg, IDC_RTNOTE, pvalProp[EMSG_BODY].Value.LPSZ);
  562.             }
  563.         }
  564.         else  /* a real error*/
  565.         {
  566.             DebugTrace("Client: error reading body and subject");
  567.             goto err;
  568.         }
  569.     
  570.         if(pvalProp[EMSG_MSGFLAGS].ulPropTag == PR_MESSAGE_FLAGS)
  571.         {
  572.             if(pvalProp[EMSG_MSGFLAGS].Value.l & MSGFLAG_HASATTACH)
  573.             {
  574.                 PopulateAttachList(hDlg, pRouteData);
  575.             }
  576.         }
  577.         MAPIFreeBuffer(pvalProp);
  578.         pvalProp = NULL;
  579.         Assert(pRouteData->palAddrListOld || pRouteData->palAddrListActive);
  580.     }
  581.     else
  582.     {
  583.     /* if we are here it means we are creating a new message */
  584.         pRouteData->lpbConvIdx = NULL;
  585.         pRouteData->cbConvIdx = 0;
  586.     }
  587.     SetWindowLong(hDlg, GWL_USERDATA, (LONG) pRouteData);
  588.     UlRelease(pmsgRead);
  589.     return TRUE;
  590. err:
  591.     UlRelease(lpstreamBody);
  592.     MAPIFreeBuffer(pvalProp);
  593.     MAPIFreeBuffer(lpszNoteText);
  594.     DeInitRouteData(pRouteData);
  595.     UlRelease(pmsgRead);
  596.     MakeMessageBox(hDlg, 0, IDS_INIDIAG, NULL, MBS_ERROR);
  597.     EndDialog(hDlg, FALSE);
  598.     return TRUE;
  599. }
  600. void RT_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
  601. {
  602.     LONG cb, cLines;
  603.     ULONG nAttNum;
  604.     HRESULT hr;
  605.     LPSTR lpszSubject = NULL;
  606.     LPSTR lpszNoteText = NULL;
  607.     /* +1 for SentMailEID; +2 for conversation topic*/  
  608.     SPropValue spvProp[EMSGPROPDIM+2] = {0}; 
  609.     LPSTREAM lpstreamBody = NULL;
  610.     HCURSOR hcOld;
  611.     UINT nFstRecip;
  612.     LPROUTEDATA pRouteData = NULL;
  613.     LPMESSAGE pmsgRoute = NULL;
  614.     LPSPropProblemArray pProblems = NULL;
  615.     ULONG cbNewConvIdx = 0;
  616.     LPBYTE lpbNewConvIdx = NULL;
  617.     switch (id)
  618.         {
  619.         case IDC_RTATTACH:
  620.             if(!CreateNewAttachment(hDlg))
  621.             {
  622.                 DebugTrace("CreateNewAttachment failed");
  623.             }
  624.             return;
  625.         case IDC_RTDELATTACH:
  626.             pRouteData = (LPROUTEDATA)GetWindowLong(hDlg, GWL_USERDATA);
  627.             Assert(pRouteData);
  628.             cb = ListBox_GetCurSel(GetDlgItem(hDlg, IDC_RTATTACHLIST));
  629.             if(LB_ERR != cb)
  630.             {
  631.                 nAttNum = ListBox_GetItemData(GetDlgItem(hDlg, IDC_RTATTACHLIST), cb);
  632.                 if(LB_ERR == nAttNum)
  633.                 {
  634.                     DebugTrace("Client:GetItemData failed (routenote)");
  635.                     break;
  636.                 }
  637.                 hr = pRouteData->pmsgRouteMsg->lpVtbl->DeleteAttach(pRouteData->pmsgRouteMsg, nAttNum, 0,
  638.                                             NULL, 0);
  639.                 if(S_OK != GetScode(hr))
  640.                 {
  641.                     DebugTrace("Client: DeleteAttach failed");
  642.                     break;
  643.                 }
  644.                 ListBox_DeleteString(GetDlgItem(hDlg, IDC_RTATTACHLIST), cb);
  645.             }
  646.             break;
  647.         case IDC_RTATTACHLIST:
  648.             cb = ListBox_GetCurSel(hwndCtl);
  649.                 if(cb!=LB_ERR)
  650.                 {
  651.                     EnableWindow(GetDlgItem(hDlg, IDC_RTSAVEATTACH), TRUE);
  652.                     EnableWindow(GetDlgItem(hDlg, IDC_RTDELATTACH), TRUE);
  653.                 }
  654.                 else
  655.                 {
  656.                     EnableWindow(GetDlgItem(hDlg, IDC_RTSAVEATTACH), FALSE);
  657.                     EnableWindow(GetDlgItem(hDlg, IDC_RTDELATTACH), FALSE);
  658.                 }
  659.             if(codeNotify != LBN_DBLCLK)
  660.                 break;
  661.             /*fall through*/
  662.         case IDC_RTSAVEATTACH:
  663.             cb = ListBox_GetCurSel(GetDlgItem(hDlg, IDC_RTATTACHLIST));
  664.             if(LB_ERR != cb)
  665.             {
  666.                 SaveAttachment(hDlg, (UINT) cb);
  667.             }
  668.             break;
  669.         case IDC_RTEDITROUTESLIP:
  670.             DialogBox (hInst, "RouteSlipBox", hDlg, RouteBoxDlgProc);
  671.             break;
  672.         case IDC_RTROUTE:
  673.             pRouteData = (LPROUTEDATA)GetWindowLong(hDlg, GWL_USERDATA);
  674.             Assert(pRouteData);
  675.             pmsgRoute = pRouteData->pmsgRouteMsg;
  676.             Assert(pmsgRoute);
  677.             if(!pRouteData->palAddrListActive && pRouteData->palAddrListOld)
  678.             {
  679.                 MakeMessageBox(hDlg,0, IDS_LASTRECIP, NULL, MB_OK);
  680.                 break;
  681.             }
  682.             nFstRecip = FirstRecipient(pRouteData->palAddrListActive);
  683.             if((!pRouteData->palAddrListActive && !pRouteData->palAddrListOld) || !nFstRecip)
  684.             {
  685.                 MakeMessageBox(hDlg, 0, IDS_NORECIPS, NULL, MB_OK);
  686.                 break;
  687.             }
  688.             hcOld = SetCursor(hWaitCur);
  689.             if (Edit_GetModify(GetDlgItem(hDlg, IDC_RTSUBJECT)))
  690.             {
  691.                 cb = Edit_LineLength(GetDlgItem(hDlg, IDC_RTSUBJECT), 0);
  692.                 if (MAPIAllocateBuffer (cb + 1, (LPVOID far *) & lpszSubject))
  693.                     goto err;
  694.                 GetDlgItemText (hDlg, IDC_RTSUBJECT, lpszSubject, (int)cb+1);
  695.                 spvProp[EMSG_SUBJ].ulPropTag = PR_SUBJECT;
  696.                 spvProp[EMSG_SUBJ].Value.LPSZ = lpszSubject;
  697.             }
  698.             else
  699.             {
  700.                 spvProp[EMSG_SUBJ].ulPropTag = PR_NULL;
  701.             }
  702.             if (pRouteData->bNewMessage || Edit_GetModify(GetDlgItem(hDlg, IDC_RTNOTE)))
  703.             {
  704.                 cLines = Edit_GetLineCount(GetDlgItem(hDlg, IDC_RTNOTE));
  705.                 if (cLines)
  706.                 {
  707.                     /* Get the total number of bytes in the multi-line */
  708.                     cb = Edit_LineIndex(GetDlgItem(hDlg, IDC_RTNOTE),(cLines - 1));
  709.                     cb += Edit_LineLength(GetDlgItem(hDlg, IDC_RTNOTE), cb);
  710.                     /* The next line is to account for CR-LF pairs per line. */
  711.                     cb += cLines * 2;
  712.                     if (MAPIAllocateBuffer (cb + 1, (LPVOID FAR *) & lpszNoteText))
  713.                         goto err;
  714.                     /* Get the Note Text from the edit */
  715.                     GetDlgItemText (hDlg, IDC_RTNOTE, lpszNoteText, (int)cb);
  716.                     spvProp[EMSG_BODY].ulPropTag = PR_BODY;
  717.                     spvProp[EMSG_BODY].Value.LPSZ = lpszNoteText;
  718.                 }
  719.             }
  720.             else
  721.             {
  722.                 spvProp[EMSG_BODY].ulPropTag = PR_NULL;
  723.             }
  724.             /*We want a copy of the message in the "Sent Mail" folder*/
  725.             CopyMemory(&spvProp[EMSGPROPDIM], pvalSentMailEID, sizeof(SPropValue));
  726. #ifdef DEBUG
  727.             if(pRouteData->bNewMessage)
  728.             {
  729.                 Assert(pRouteData->cbConvIdx == 0);
  730.                 Assert(pRouteData->lpbConvIdx == NULL);
  731.             }
  732. #endif
  733.             if(!ScAddConversationIndex(pRouteData->cbConvIdx, pRouteData->lpbConvIdx,
  734.                                         &cbNewConvIdx, &lpbNewConvIdx))
  735.             {
  736.                 spvProp[EMSG_CONVIDX].ulPropTag = PR_CONVERSATION_INDEX;
  737.                 spvProp[EMSG_CONVIDX].Value.bin.cb = cbNewConvIdx;
  738.                 spvProp[EMSG_CONVIDX].Value.bin.lpb = lpbNewConvIdx;
  739.             }
  740.             else
  741.             {
  742.                 spvProp[EMSG_CONVIDX].ulPropTag = PR_NULL;
  743.             }
  744.             if(pRouteData->bNewMessage)
  745.             {
  746.                 spvProp[EMSGPROPDIM+1].ulPropTag = PR_CONVERSATION_TOPIC;
  747.                 if(PR_SUBJECT == spvProp[EMSG_SUBJ].ulPropTag)
  748.                 {
  749.                     spvProp[EMSGPROPDIM+1].Value.LPSZ = spvProp[EMSG_SUBJ].Value.LPSZ;
  750.                 }
  751.                 else
  752.                 {
  753.                     spvProp[EMSGPROPDIM+1].Value.LPSZ = "";
  754.                 }
  755.             }
  756.             else
  757.             {
  758.                 spvProp[EMSGPROPDIM+1].ulPropTag = PR_NULL;
  759.             }
  760.             spvProp[EMSG_MSGFLAGS].ulPropTag = PR_NULL;
  761.             
  762.             hr = pmsgRoute->lpVtbl->SetProps(pmsgRoute, EMSGPROPDIM+2, spvProp, &pProblems);
  763.             MAPIFreeBuffer(lpbNewConvIdx);
  764.             lpbNewConvIdx = NULL;
  765.             if(S_OK != GetScode(hr))
  766.             {
  767.                 DebugTrace("Client: SetProps failed (RouteNote)");
  768.                 goto err;
  769.             }
  770.             else
  771.             {
  772.                 if(pProblems)
  773.                 {   /* use nAttNum as an index for a sec */
  774.                     for(nAttNum = 0; nAttNum < pProblems->cProblem; ++nAttNum)
  775.                     {
  776.                         switch(pProblems->aProblem[nAttNum].ulPropTag)
  777.                         {
  778.                         case PR_SENTMAIL_ENTRYID:
  779.                             DebugTrace("Client: Error setting PR_SENTMAIL_ENTRYID");
  780.                             goto err;
  781.                         case PR_SUBJECT:
  782.                             DebugTrace("Client: Error settting PR_SUBJECT");
  783.                             goto err;
  784.                         case PR_BODY:
  785.                             if(MAPI_E_NOT_ENOUGH_MEMORY != pProblems->aProblem[nAttNum].scode)
  786.                             {
  787.                                 DebugTrace("Client: Error settting PR_BODY");
  788.                                 goto err;
  789.                             }
  790.                             else /* have to use IStream */
  791.                             {
  792.                                 hr = pmsgRoute->lpVtbl->OpenProperty(pmsgRoute, PR_BODY, &IID_IStream,
  793.                                                 STGM_READWRITE, MAPI_DEFERRED_ERRORS,
  794.                                                 (LPUNKNOWN FAR *) &lpstreamBody);
  795.                                 if(S_OK != GetScode(hr))
  796.                                 {
  797.                                     DebugTraceResult(OpenProperty, hr);
  798.                                     goto err;
  799.                                 }
  800.                                 hr = lpstreamBody->lpVtbl->Write(lpstreamBody, lpszNoteText, lstrlen(lpszNoteText), NULL);
  801.                                 if(S_OK != GetScode(hr))
  802.                                 {
  803.                                     DebugTrace("IStream::Write failed");
  804.                                     goto err;
  805.                                 }
  806.                             }
  807.                             break;
  808.                         }
  809.                     }
  810.                 }
  811.             }
  812.             DelRouteProps(pRouteData);
  813.             if(!SetRouteProps(pRouteData))
  814.             {
  815.                 DebugTrace("Client: SetRouteProps failed (RouteNote)");
  816.                 goto err;
  817.             }
  818.             if(!SetMessageClass(pRouteData->pmsgRouteMsg,  lpszSmplRTMsgClass))
  819.             {
  820.                 DebugTrace("Client: SetMessageClass failed");
  821.                 goto err;
  822.             }
  823.             cb = pRouteData->palAddrListActive->cEntries;
  824.             /* nFstRecip is the index of the first non NULL entry in the
  825.             palAddrListActive. So we pretend for a sec that palAddrListActive had
  826.             only one recipient to set a "TO" recipient in the pmsgRouteMsg */
  827.             pRouteData->palAddrListActive->cEntries = nFstRecip;
  828.             hr = pRouteData->pmsgRouteMsg->lpVtbl->ModifyRecipients(pRouteData->pmsgRouteMsg,
  829.                                         0, pRouteData->palAddrListActive);
  830.             pRouteData->palAddrListActive->cEntries = cb;
  831.             if(S_OK != GetScode(hr))
  832.             {
  833.                 DebugTrace("Client: ModifyRecipients faild (routenote)");
  834.                 goto err;
  835.             }
  836.             hr = pRouteData->pmsgRouteMsg->lpVtbl->SubmitMessage(pRouteData->pmsgRouteMsg, 0);
  837.             if(S_OK != GetScode(hr))
  838.             {
  839.                 MakeMessageBox(hDlg, GetScode(hr), IDS_SENDERROR, NULL, MBS_ERROR);
  840.                 goto err;
  841.             }
  842.             /*fall through*/
  843. err:
  844.         case IDCANCEL:
  845.             if(IDCANCEL == id)
  846.             {
  847.                 pRouteData = (LPROUTEDATA)GetWindowLong(hDlg, GWL_USERDATA);
  848.                 Assert(pRouteData);
  849.                 if(pRouteData->palAddrListActive||
  850.                     Edit_GetModify(GetDlgItem(hDlg, IDC_RTNOTE)) ||
  851.                     Edit_GetModify(GetDlgItem(hDlg, IDC_RTSUBJECT)))
  852.                     {
  853.                         if(MessageBox(hDlg, "Are you sure you want to close this form?",
  854.                         "?", MB_YESNO) == IDNO)  break;
  855.                     }
  856.             }
  857.             else
  858.             {
  859.                 SetCursor(hcOld);
  860.             }
  861.             MAPIFreeBuffer (lpszSubject);
  862.             MAPIFreeBuffer (lpszNoteText);
  863.             UlRelease(lpstreamBody);
  864.             lpstreamBody = NULL;
  865.             DeInitRouteData(pRouteData);
  866.             pRouteData = NULL;
  867.             EndDialog (hDlg, TRUE);
  868.             break;
  869.         default:
  870.             break;
  871.         }
  872. }
  873. /* 
  874. *   DeInitRouteData
  875. *
  876. *  releases pRouteData and everything that was in it
  877. */
  878. void DeInitRouteData(LPROUTEDATA pRouteData)
  879. {
  880.     if(!pRouteData) return;
  881.     FreePadrlist(pRouteData->palAddrListOld);
  882.     FreePadrlist(pRouteData->palAddrListActive);
  883.     UlRelease(pRouteData->pmsgRouteMsg);
  884.     UlRelease(pRouteData->ptblAttach);
  885.     MAPIFreeBuffer(pRouteData->lpbConvIdx);
  886.     MAPIFreeBuffer(pRouteData);
  887. }
  888. /* Returns a 1-based index of the first recipent.
  889.  returns 0 if all entries in the input address list are NULLs*/
  890. UINT FirstRecipient(LPADRLIST lpAL)
  891. {
  892.     UINT idx;
  893.     if(!lpAL || !lpAL->cEntries) return 0;
  894.     for(idx = 0; idx < lpAL->cEntries; ++idx)
  895.         if(lpAL->aEntries[idx].rgPropVals) return (idx+1);
  896.     return 0;
  897. }
  898. void PopulateRouteListBox(HWND hDlg)
  899. {
  900.     LPADRENTRY lpadrent;
  901.     LPSPropValue lpsprop;
  902.     LPSTR pStr = NULL;
  903.     LPROUTEDATA pRouteData = NULL;
  904.     UINT iadrentry = 0, ilbitem = 0;
  905.     UINT yOld = MINY, yActive = MINY;
  906.     UINT cOld;
  907.     UINT cActive;
  908.     RECT rect;
  909.     pRouteData = (LPROUTEDATA) GetWindowLong(GetParent(hDlg), GWL_USERDATA);
  910.     Assert(pRouteData);
  911.     if(!pRouteData->palAddrListOld && !pRouteData->palAddrListActive)
  912.         return;
  913.     /* some arithmetic to resize the listboxes.
  914.        Make the listbox that has more entries taller*/
  915.     if(pRouteData->palAddrListOld && pRouteData->palAddrListActive)
  916.     {
  917.         cOld = pRouteData->palAddrListOld->cEntries;
  918.         cActive = pRouteData->palAddrListActive->cEntries;
  919.         yOld = (UINT)LBLENGTH * cOld / (cOld + cActive);
  920.         yActive = (UINT)LBLENGTH - yOld;
  921.     }
  922.     else if(pRouteData->palAddrListOld)
  923.     {
  924.         yActive = 0;
  925.     }
  926.     else
  927.     {
  928.         yOld = 0;
  929.     }
  930.     if(yOld < MINY)
  931.     {
  932.         yOld = MINY;
  933.         yActive = LBLENGTH - MINY;
  934.     }
  935.     else if(yActive < MINY)
  936.     {
  937.         yActive = MINY;
  938.         yOld = LBLENGTH - MINY;
  939.     }
  940.     rect.left = LBX;
  941.     rect.top = OLDY;
  942.     rect.right = DELTAX;
  943.     rect.bottom = yOld;
  944.     MapDialogRect(hDlg, &rect);
  945.     SetWindowPos(GetDlgItem(hDlg, IDC_ADDRLISTOLD), 0,
  946.                 rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
  947.     rect.left = LBX;
  948.     rect.top = OLDY + yOld + DELTA;
  949.     rect.right = DELTAX;
  950.     rect.bottom = yActive;
  951.     MapDialogRect(hDlg, &rect);
  952.     SetWindowPos(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), 0,
  953.                 rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
  954.     ListBox_ResetContent(GetDlgItem(hDlg, IDC_ADDRLISTOLD));
  955.     ListBox_ResetContent(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE));
  956.     if(pRouteData->palAddrListOld)
  957.     {
  958.     for(iadrentry = 0, lpadrent = pRouteData->palAddrListOld->aEntries;
  959.          lpadrent < pRouteData->palAddrListOld->aEntries+pRouteData->palAddrListOld->cEntries;
  960.          ++lpadrent, ++iadrentry)
  961.     {
  962.         if(!lpadrent->rgPropVals) continue;
  963.         /* IAddrBook::Addres doesn't guarantee the order of the props.
  964.             So we have to loop through all of them */
  965.         for(lpsprop = lpadrent->rgPropVals;
  966.             lpsprop < lpadrent->rgPropVals + lpadrent->cValues; ++lpsprop)
  967.         {
  968.             if(lpsprop->ulPropTag ==  PR_DISPLAY_NAME)
  969.             {
  970.                 pStr =  lpsprop->Value.LPSZ;
  971.                 ilbitem = ListBox_AddString(GetDlgItem(hDlg, IDC_ADDRLISTOLD), pStr);
  972.                 if(LB_ERR != ilbitem)
  973.                     ListBox_SetItemData(GetDlgItem(hDlg, IDC_ADDRLISTOLD), ilbitem, iadrentry);
  974.                 break;
  975.             }
  976.         }
  977.     }
  978.     }
  979.     if(pRouteData->palAddrListActive)
  980.     {
  981.         for(iadrentry = 0, lpadrent = pRouteData->palAddrListActive->aEntries;
  982.              lpadrent < pRouteData->palAddrListActive->aEntries+pRouteData->palAddrListActive->cEntries;
  983.              ++lpadrent, ++iadrentry)
  984.         {
  985.             if(!lpadrent->rgPropVals) continue;
  986.             /* IAddrBook::Addres doesn't guarantee the order of the props.
  987.             So we have to loop through all of them */
  988.             for(lpsprop = lpadrent->rgPropVals;
  989.                 lpsprop < lpadrent->rgPropVals + lpadrent->cValues; ++lpsprop)
  990.             {
  991.                 if(lpsprop->ulPropTag ==  PR_DISPLAY_NAME)
  992.                 {
  993.                     pStr =  lpsprop->Value.LPSZ;
  994.                     ilbitem = ListBox_AddString(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), pStr);
  995.                     if(LB_ERR != ilbitem)    /* save the position of the entry in the addrlist for future refs*/
  996.                         ListBox_SetItemData(GetDlgItem(hDlg, IDC_ADDRLISTACTIVE), ilbitem, iadrentry);
  997.                     break;
  998.                 }
  999.             }
  1000.         }
  1001.     }
  1002. }
  1003. /* Get the index of the current recip and total number of recipients
  1004.  * from the routing slip of the message
  1005.  */
  1006. BOOL GetRouteIndices(LPROUTEDATA pRouteData)
  1007. {
  1008.     HRESULT hr;
  1009.     LPSPropTagArray lpsptProp = NULL;
  1010.     LPSPropValue lpspv = NULL ;
  1011.     ULONG cProps = 0;
  1012.     LPMESSAGE pmsg = NULL;
  1013.     MAPINAMEID nmidRTPR[2];
  1014.     MAPINAMEID *pnmidRTPR[2] = {&nmidRTPR[0], &nmidRTPR[1]};
  1015.     nmidRTPR[0].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1016.     nmidRTPR[0].ulKind = MNID_STRING;
  1017.     nmidRTPR[0].Kind.lpwstrName =   L"CURRENT_RT_RECIP";
  1018.     nmidRTPR[1].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1019.     nmidRTPR[1].ulKind = MNID_STRING;
  1020.     nmidRTPR[1].Kind.lpwstrName =   L"TOTAL_RT_RECIP";
  1021.     Assert(pRouteData);
  1022.     pmsg = pRouteData->pmsgRouteMsg;
  1023.     Assert(pmsg);
  1024.     hr = pmsg->lpVtbl->GetIDsFromNames(pmsg, 2, pnmidRTPR, 0, &lpsptProp);
  1025.     if(S_OK != GetScode(hr))
  1026.     {
  1027.         DebugTraceResult(GetIDsFromNames, hr);
  1028.         goto err;
  1029.     }
  1030.     lpsptProp->aulPropTag[0] = PROP_TAG(PT_LONG, PROP_ID(lpsptProp->aulPropTag[0]));
  1031.     lpsptProp->aulPropTag[1] = PROP_TAG(PT_LONG, PROP_ID(lpsptProp->aulPropTag[1]));
  1032.     /* save for later use in setrouteindices() */
  1033.     pRouteData->tagCurrent = lpsptProp->aulPropTag[0];
  1034.     pRouteData->tagTotal = lpsptProp->aulPropTag[1];
  1035.     hr = pmsg->lpVtbl->GetProps(pmsg, lpsptProp, 0, &cProps, &lpspv);
  1036.     if(S_OK != GetScode(hr))
  1037.     {
  1038.         DebugTraceResult(GetProps, hr);
  1039.         goto err;
  1040.     }
  1041.     Assert(lpspv);
  1042.     pRouteData->nCurrentRouteRecip = lpspv[0].Value.l;
  1043.     pRouteData->nTotalRouteRecip = lpspv[1].Value.l;
  1044. err:
  1045.     MAPIFreeBuffer(lpsptProp);
  1046.     MAPIFreeBuffer(lpspv);
  1047.     return !hr;
  1048. }
  1049. BOOL SetRouteIndices(LPROUTEDATA pRouteData)
  1050. {
  1051.     HRESULT hr;
  1052.     LPSPropTagArray lpsptProp = NULL;
  1053.     SPropValue spvRTProp[2];
  1054.     LPSPropProblemArray pProblems = NULL;
  1055.     MAPINAMEID nmidRTPR[2];
  1056.     MAPINAMEID *pnmidRTPR[2] = {&nmidRTPR[0], &nmidRTPR[1]};
  1057.     Assert(pRouteData);
  1058.     ZeroMemory(&spvRTProp, 2*sizeof(SPropValue));
  1059.     /* if this is a new message, get PropIDs */
  1060.     if(pRouteData->bNewMessage)
  1061.     {
  1062.         nmidRTPR[0].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1063.         nmidRTPR[0].ulKind = MNID_STRING;
  1064.         nmidRTPR[0].Kind.lpwstrName =   L"CURRENT_RT_RECIP";
  1065.         nmidRTPR[1].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1066.         nmidRTPR[1].ulKind = MNID_STRING;
  1067.         nmidRTPR[1].Kind.lpwstrName =   L"TOTAL_RT_RECIP";
  1068.         hr = pRouteData->pmsgRouteMsg->lpVtbl->GetIDsFromNames(pRouteData->pmsgRouteMsg, 2, pnmidRTPR, MAPI_CREATE, &lpsptProp);
  1069.         if(S_OK != GetScode(hr))
  1070.         {
  1071.             DebugTraceResult(GetIDsFromNames, hr);
  1072.             goto err;
  1073.         }
  1074.         lpsptProp->aulPropTag[0] = PROP_TAG(PT_LONG, PROP_ID(lpsptProp->aulPropTag[0]));
  1075.         lpsptProp->aulPropTag[1] = PROP_TAG(PT_LONG, PROP_ID(lpsptProp->aulPropTag[1]));
  1076.         spvRTProp[0].ulPropTag = lpsptProp->aulPropTag[0];
  1077.         spvRTProp[1].ulPropTag = lpsptProp->aulPropTag[1];
  1078.     }
  1079.     else /* if we created this msg from one in the inbox, we already have the PropIDs*/
  1080.     {
  1081.         spvRTProp[0].ulPropTag = pRouteData->tagCurrent;
  1082.         spvRTProp[1].ulPropTag = pRouteData->tagTotal;
  1083.     }
  1084.     spvRTProp[0].Value.l = pRouteData->nCurrentRouteRecip;
  1085.     spvRTProp[1].Value.l = pRouteData->nTotalRouteRecip;
  1086.     hr = pRouteData->pmsgRouteMsg->lpVtbl->SetProps(pRouteData->pmsgRouteMsg, 2, spvRTProp, &pProblems);
  1087.     if(S_OK != GetScode(hr))
  1088.     {
  1089.         if(pProblems)
  1090.         {
  1091.             DebugTraceProblems("Client: ", pProblems);
  1092.             MAPIFreeBuffer(pProblems);
  1093.             pProblems = NULL;
  1094.         }
  1095.         DebugTraceResult(SetProps, hr);
  1096.         goto err;
  1097.     }
  1098. err:
  1099.     MAPIFreeBuffer(lpsptProp);
  1100.     return !hr;
  1101. }
  1102. void InitRouteNameIDArray(ULONG iRecip, LPMAPINAMEID  lpPropNames)
  1103. {
  1104.     ULONG idx;
  1105.     Assert (lpPropNames);
  1106.     for(idx = 0; idx < ROUTEPROPSETDIM; ++idx)
  1107.     {
  1108.         lpPropNames[idx].lpguid = (LPGUID)lpguidA[idx];
  1109.         lpPropNames[idx].ulKind = MNID_ID;
  1110.         lpPropNames[idx].Kind.lID = iRecip;
  1111.     }
  1112. }
  1113. BOOL GetRoutePropTagArray(ULONG iRecip, LPMESSAGE   lpM, LPSPropTagArray FAR * lppspta)
  1114. {
  1115.     MAPINAMEID nmidA[ROUTEPROPSETDIM];
  1116.     LPMAPINAMEID  lppnmidA[5];
  1117.     HRESULT hr;
  1118.     ULONG *pulptPropTag = NULL;
  1119.     UINT ulidx = 0;
  1120.     Assert(lpM);
  1121.     /*First create the 5 prop names and get IDs for them*/
  1122.     for(ulidx = 0; ulidx < ROUTEPROPSETDIM; ++ulidx)
  1123.         lppnmidA[ulidx] = &nmidA[ulidx];
  1124.     InitRouteNameIDArray(iRecip, nmidA);
  1125.     hr = lpM->lpVtbl->GetIDsFromNames(lpM, ROUTEPROPSETDIM, lppnmidA,
  1126.                                         MAPI_CREATE, lppspta);
  1127.     if(S_OK != GetScode(hr))
  1128.     {
  1129.         DebugTraceResult(GetIDsFromNames, hr);
  1130.         return FALSE;
  1131.     }
  1132.     Assert((*lppspta)->cValues == ROUTEPROPSETDIM);
  1133.     /*Now add right prop types */
  1134.     ulidx = 0;
  1135.     for(pulptPropTag = (*lppspta)->aulPropTag;
  1136.         pulptPropTag < (*lppspta)->aulPropTag + ROUTEPROPSETDIM; ++pulptPropTag, ++ulidx)
  1137.     {
  1138.      *pulptPropTag =  PROP_TAG(ulRoutePropTypes[ulidx], PROP_ID(*pulptPropTag));
  1139.     }
  1140.     return TRUE;
  1141. }
  1142. /* the output PropTag array contains nTotalRecip * ROUTEPROPSETDIM + 1
  1143.  * prop tags. The last one is PR_NULL.
  1144.  */
  1145. BOOL GetRoutePropTagArrayFast(ULONG nTotalRecip, LPMESSAGE lpM, BOOL fCreate,
  1146.                                 LPSPropTagArray FAR * lppspta)
  1147. {
  1148.     LPMAPINAMEID pnmid = NULL;
  1149.     LPMAPINAMEID * ppnmid = NULL;
  1150.     HRESULT hr;
  1151.     ULONG *pulptPropTag = NULL;
  1152.     UINT ulidx = 0;
  1153.     /*//$ hack!!!  +1 is to save a spot for PR_RECIPIENT_TYPE */
  1154.     UINT nTotalProps = nTotalRecip * ROUTEPROPSETDIM + 1;
  1155.     
  1156.     Assert(lpM);
  1157.     if(hr = ResultFromScode(MAPIAllocateBuffer(nTotalProps * sizeof(MAPINAMEID),
  1158.                             (LPVOID FAR *)&pnmid)))
  1159.         return FALSE;
  1160.     ZeroMemory(pnmid, nTotalProps * sizeof(MAPINAMEID));
  1161.     if(hr = ResultFromScode(MAPIAllocateBuffer(nTotalProps * sizeof(LPMAPINAMEID),
  1162.                             (LPVOID FAR *)&ppnmid)))
  1163.         goto err;
  1164.     for(ulidx = 0; ulidx < nTotalProps; ++ulidx)
  1165.         ppnmid[ulidx] = &pnmid[ulidx];
  1166.     for(ulidx = 0; ulidx < nTotalRecip; ++ulidx )
  1167.         InitRouteNameIDArray(ulidx, &pnmid[ulidx * ROUTEPROPSETDIM]);
  1168.     //put someting reasonable in
  1169.     pnmid[nTotalProps-1].lpguid = (LPGUID)lpguidA[0];
  1170.     pnmid[nTotalProps-1].ulKind = MNID_ID;
  1171.     pnmid[nTotalProps-1].Kind.lID = 0;
  1172.     hr = lpM->lpVtbl->GetIDsFromNames(lpM, nTotalProps, ppnmid,
  1173.                         fCreate? MAPI_CREATE : 0, lppspta);
  1174.     if(hr) /* treat warnings as errors */
  1175.         goto err;
  1176.     Assert((*lppspta)->cValues == nTotalProps);
  1177.     
  1178.     ulidx = 0;
  1179.     for(pulptPropTag = (*lppspta)->aulPropTag;
  1180.         pulptPropTag < (*lppspta)->aulPropTag + nTotalProps - 1;
  1181.         ++pulptPropTag , ++ulidx)
  1182.     {
  1183.         *pulptPropTag = PROP_TAG(ulRoutePropTypes[ulidx % ROUTEPROPSETDIM],
  1184.                                 PROP_ID(*pulptPropTag));
  1185.     }
  1186.     *pulptPropTag = PR_NULL;
  1187.     
  1188. err:
  1189.     MAPIFreeBuffer(pnmid);
  1190.     MAPIFreeBuffer(ppnmid);
  1191.         
  1192.     DebugTraceResult(ROUTECLI_GetRoutePropTagArray, hr);
  1193.     return (hr? FALSE : TRUE);
  1194. }
  1195. BOOL OpenOutFolder(HWND hWnd, LPMAPIFOLDER FAR * lppF)
  1196. {
  1197.     LPMAPIFOLDER lpfOutF = NULL;
  1198.     HRESULT hr;
  1199.     LPSPropValue lpspvFEID = NULL;
  1200.     ULONG  ulObjType = 0;
  1201.     Assert(pmdb);
  1202.     *lppF = NULL;
  1203.     hr = HrGetOneProp((LPMAPIPROP) pmdb, PR_IPM_OUTBOX_ENTRYID, &lpspvFEID);
  1204.     if(hr)
  1205.     {
  1206.         DebugTrace("Client: HrGetOneProp failed (OpneOutFolder)");
  1207.         goto err;
  1208.     }
  1209.     Assert(lpspvFEID->ulPropTag == PR_IPM_OUTBOX_ENTRYID);
  1210.     hr = pmdb->lpVtbl->OpenEntry(pmdb, lpspvFEID->Value.bin.cb,
  1211.                         (LPENTRYID)lpspvFEID->Value.bin.lpb, NULL,
  1212.                         MAPI_MODIFY | MAPI_DEFERRED_ERRORS,
  1213.                         &ulObjType, (LPUNKNOWN FAR *) &lpfOutF);
  1214.     if(S_OK != GetScode(hr))
  1215.     {
  1216.         DebugTrace("Client: OpenEntry (OpenOutFolder)");
  1217.         goto err;
  1218.     }
  1219.     *lppF = lpfOutF;
  1220. err:
  1221.     MAPIFreeBuffer(lpspvFEID);
  1222.     if(hr)
  1223.         MakeMessageBox(hWnd, GetScode(hr), IDS_OPENOUTB, NULL, MBS_ERROR);
  1224.     return !hr;
  1225. }
  1226. BOOL CreateOutMessage(LPMESSAGE FAR * lpmM)
  1227. {
  1228.     LPMESSAGE lpmResM = NULL;
  1229.     HRESULT hr;
  1230.     Assert(pfldOutBox);
  1231.     hr = pfldOutBox->lpVtbl->CreateMessage(pfldOutBox, NULL, MAPI_DEFERRED_ERRORS,
  1232.                                             &lpmResM);
  1233.     if(S_OK != GetScode(hr)) return FALSE;
  1234.     *lpmM = lpmResM;
  1235.     return TRUE;
  1236. }
  1237. BOOL MakeNewRouteMessage(LPMESSAGE pmsgRead, LPROUTEDATA FAR * ppRouteData)
  1238. {
  1239.     HRESULT hr;
  1240.     LPROUTEDATA pRouteData = NULL;
  1241.     LPSPropProblemArray pProblems = NULL;
  1242.     if(MAPIAllocateBuffer(sizeof(ROUTEDATA), (LPVOID FAR *) &pRouteData))
  1243.     {
  1244.         return FALSE;
  1245.     }
  1246.     ZeroMemory(pRouteData, sizeof(ROUTEDATA));
  1247.     if(!CreateOutMessage(&pRouteData->pmsgRouteMsg))
  1248.     {
  1249.         goto err;
  1250.     }
  1251.     if(!pmsgRead)   /*if called  to create a new message*/
  1252.     {
  1253.         pRouteData->bNewMessage = TRUE;
  1254.         *ppRouteData = pRouteData;
  1255.         return TRUE;
  1256.     }
  1257.      pRouteData->bNewMessage = FALSE;
  1258.     /* include attachments*/
  1259.     sptExcludedProps.cValues = EXCLUDED_PROPS_ON_REPLY - 1;
  1260.     hr = pmsgRead->lpVtbl->CopyTo(pmsgRead, 0, NULL,
  1261.                                   (LPSPropTagArray)&sptExcludedProps,
  1262.                                   0, NULL, &IID_IMessage,
  1263.                                   pRouteData->pmsgRouteMsg, 0, &pProblems);
  1264.     if(HR_FAILED(hr))
  1265.     {
  1266.         if(pProblems)
  1267.         {
  1268.             DebugTraceProblems("Client: ", pProblems);
  1269.             MAPIFreeBuffer(pProblems);
  1270.             pProblems = NULL;
  1271.         }
  1272.         goto err;
  1273.     }
  1274.     if(!GetRouteIndices(pRouteData))
  1275.     {
  1276.         goto err;
  1277.     }
  1278.     if(!GetRouteAddrLists(pRouteData))
  1279.     {
  1280.         goto err;
  1281.     }
  1282.     *ppRouteData = pRouteData;
  1283.     return TRUE;
  1284. err:
  1285.     UlRelease(pRouteData->pmsgRouteMsg);
  1286.     MAPIFreeBuffer(pRouteData);
  1287.     *ppRouteData = NULL;
  1288.     return FALSE;
  1289. }
  1290. /*Assumes that members nCurrentRouteRecip and nTotalRouteRecip were succesfully
  1291.  *set. Initializes palAddrListActive and palAddrListOld.
  1292.  */
  1293. BOOL GetRouteAddrLists(LPROUTEDATA pRouteData)
  1294. {
  1295.     LPSPropTagArray lpspta = NULL;
  1296. //  SizedSPropTagArray((ROUTEPROPSETDIM + 1), sspta);
  1297.     LPADRLIST lpalOld = NULL;
  1298.     LPADRLIST lpalActive = NULL;
  1299.     ULONG cbal = 0;
  1300.     HRESULT hr;
  1301.     UINT ulidx, ulidx1;
  1302.     ULONG cActiveRecip ;
  1303.     LPMESSAGE pmsg;
  1304.     ULONG cvalAllProps = 0;
  1305.     LPSPropValue pvalAllProps = NULL;
  1306.     
  1307.     Assert(pRouteData);
  1308.     Assert(!pRouteData->palAddrListActive);
  1309.     Assert(!pRouteData->palAddrListOld);
  1310.     pmsg = pRouteData->pmsgRouteMsg;
  1311.     Assert(pmsg);
  1312.     
  1313.     if(!GetRoutePropTagArrayFast(pRouteData->nTotalRouteRecip,
  1314.                             pmsg,
  1315.                             FALSE,
  1316.                             &lpspta))
  1317.         goto err;
  1318.         
  1319.     /* hack!! the output PropTag array contains nTotalRecip * ROUTEPROPSETDIM + 1
  1320.      * prop tags. The last one is PR_NULL. We do this to reserve a spot for
  1321.      * PR_RECIPIENT_TYPE
  1322.      */
  1323.     hr = pmsg->lpVtbl->GetProps(pmsg, lpspta, 0, &cvalAllProps, &pvalAllProps);
  1324.     MAPIFreeBuffer(lpspta);
  1325.     lpspta=NULL;
  1326.     if(HR_FAILED(hr))
  1327.         goto err;
  1328.     Assert(cvalAllProps == pRouteData->nTotalRouteRecip * ROUTEPROPSETDIM + 1);
  1329.     //
  1330.     // In case somebody does not handle PR_NULL in GetProps
  1331.     //
  1332.     pvalAllProps[cvalAllProps - 1].ulPropTag = PR_NULL;
  1333.     
  1334.     cActiveRecip = pRouteData->nTotalRouteRecip - pRouteData->nCurrentRouteRecip;
  1335.     /*First do the recipients already routed to */
  1336.     cbal =  CbNewADRLIST(pRouteData->nCurrentRouteRecip);
  1337.     if (MAPIAllocateBuffer(cbal, &lpalOld))
  1338.         goto err;
  1339.     ZeroMemory(lpalOld, cbal);
  1340.     lpalOld->cEntries = pRouteData->nCurrentRouteRecip;
  1341.     for(ulidx = 0; ulidx < pRouteData->nCurrentRouteRecip; ++ulidx)
  1342.     {
  1343.         LPSPropValue pval = NULL;
  1344.         hr = ResultFromScode(ScDupPropset(ROUTEPROPSETDIM +1,
  1345.                                 &pvalAllProps[ulidx * ROUTEPROPSETDIM],
  1346.                                 MAPIAllocateBuffer,
  1347.                                 &pval));
  1348.         
  1349.         if(hr)
  1350.             goto err;
  1351.             
  1352.         lpalOld->aEntries[ulidx].rgPropVals = pval;
  1353.         lpalOld->aEntries[ulidx].cValues = ROUTEPROPSETDIM + 1;
  1354.             
  1355.         for(ulidx1 = 0; ulidx1 < ROUTEPROPSETDIM; ++ulidx1)
  1356.         {
  1357.             pval[ulidx1].ulPropTag = sptRouteProps.aulPropTag[ulidx1];
  1358.             pval[ulidx1].dwAlignPad = 0;
  1359.         }
  1360.         /*Have to set RECIPIENT_TYPE in order for IAddressBook::Address to show the
  1361.           recipient in one of its listboxes*/
  1362.         pval[ROUTEPROPSETDIM].ulPropTag = PR_RECIPIENT_TYPE;
  1363.         pval[ROUTEPROPSETDIM].dwAlignPad = 0;
  1364.         pval[ROUTEPROPSETDIM].Value.l = MAPI_TO;
  1365.     }
  1366.     
  1367.     if(cActiveRecip == 0)
  1368.     {
  1369.         pRouteData->palAddrListOld = lpalOld;
  1370.         pRouteData->palAddrListActive = NULL;
  1371.         goto ret;
  1372.     }
  1373.     /*Now the same for palAddrListActive*/
  1374.     cbal =  CbNewADRLIST(cActiveRecip);
  1375.     if (MAPIAllocateBuffer(cbal, &lpalActive))
  1376.         goto err;
  1377.     memset(lpalActive, 0, cbal);
  1378.     lpalActive->cEntries = cActiveRecip;
  1379.     for(ulidx = 0; ulidx < cActiveRecip; ++ulidx)
  1380.     {
  1381.         LPSPropValue pval = NULL;
  1382.         hr = ResultFromScode(ScDupPropset(ROUTEPROPSETDIM +1,
  1383.                             &pvalAllProps[(ulidx + pRouteData->nCurrentRouteRecip) *
  1384.                                                 ROUTEPROPSETDIM],
  1385.                                 MAPIAllocateBuffer,
  1386.                                 &pval));
  1387.         
  1388.         if(hr)
  1389.             goto err;
  1390.             
  1391.         lpalActive->aEntries[ulidx].rgPropVals = pval;
  1392.         lpalActive->aEntries[ulidx].cValues = ROUTEPROPSETDIM + 1;
  1393.             
  1394.         for(ulidx1 = 0; ulidx1 < ROUTEPROPSETDIM; ++ulidx1)
  1395.         {
  1396.             pval[ulidx1].ulPropTag = sptRouteProps.aulPropTag[ulidx1];
  1397.             pval[ulidx1].dwAlignPad = 0;
  1398.         }
  1399.         /*Have to set RECIPIENT_TYPE in order for IAddressBook::Address to show the
  1400.           recipient in one of its listboxes*/
  1401.         pval[ROUTEPROPSETDIM].ulPropTag = PR_RECIPIENT_TYPE;
  1402.         pval[ROUTEPROPSETDIM].dwAlignPad = 0;
  1403.         pval[ROUTEPROPSETDIM].Value.l = MAPI_TO;
  1404.     }
  1405.     pRouteData->palAddrListOld = lpalOld;
  1406.     pRouteData->palAddrListActive = lpalActive;
  1407. ret:
  1408.     MAPIFreeBuffer(pvalAllProps);
  1409.     return TRUE;
  1410. err:
  1411.     FreePadrlist(lpalOld);
  1412.     FreePadrlist(lpalActive);
  1413.     MAPIFreeBuffer(pvalAllProps);
  1414.     
  1415.     return FALSE;
  1416. }
  1417. /*deletes all the props corresponding to the entries in palAddrListActive*/
  1418. BOOL  DelRouteProps(LPROUTEDATA pRouteData)
  1419. {
  1420.     UINT ulidx;
  1421.     LPSPropTagArray lpsptaRouteTags = NULL;
  1422.     LPSPropProblemArray lpsppaProblems = NULL;
  1423.     HRESULT hr = hrSuccess;
  1424.     if(!pRouteData->palAddrListActive) return TRUE;
  1425.     Assert(pRouteData);
  1426.     Assert(pRouteData->pmsgRouteMsg);
  1427.     for(ulidx = pRouteData->nCurrentRouteRecip; ulidx < pRouteData->nTotalRouteRecip; ++ulidx)
  1428.     {
  1429.         if(!GetRoutePropTagArray(ulidx, pRouteData->pmsgRouteMsg, &lpsptaRouteTags))
  1430.         {
  1431.             /*
  1432.             //$ even if it gives an error still have to go through all of them*/
  1433.             continue;
  1434.         }
  1435.         hr = pRouteData->pmsgRouteMsg->lpVtbl->DeleteProps(pRouteData->pmsgRouteMsg, lpsptaRouteTags, &lpsppaProblems);
  1436.         /* even if it gives an error still have to go through all of them*/
  1437.         if(lpsppaProblems)
  1438.         {
  1439.             DebugTraceProblems("Client:", lpsppaProblems);
  1440.             MAPIFreeBuffer(lpsppaProblems);
  1441.             lpsppaProblems = NULL;
  1442.         }
  1443.         MAPIFreeBuffer(lpsptaRouteTags);
  1444.         lpsptaRouteTags = NULL;
  1445.     }
  1446.     return (S_OK == GetScode(hr));
  1447. }
  1448. BOOL SetRouteProps(LPROUTEDATA pRouteData)
  1449. {
  1450.     //SPropValue pspvRouteProps[ROUTEPROPSETDIM];
  1451.     LPSPropTagArray lpsptaRouteTags = NULL;
  1452.     ULONG cRouteRecip;
  1453.     LPADRENTRY lpae = NULL;
  1454.     LPSPropValue lpspv = NULL;
  1455.     UINT ulidx;
  1456.     LPSPropProblemArray lpsppaProblems = NULL;
  1457.     HRESULT hr;
  1458.     UINT cNewRecips = 0;
  1459.     LPSPropValue pvalAll = NULL;
  1460.     LPSPropValue pval = NULL;
  1461.     Assert(pRouteData);
  1462.     if(!pRouteData->palAddrListActive) return TRUE;
  1463.     cRouteRecip = pRouteData->nCurrentRouteRecip;
  1464.     if(!GetRoutePropTagArrayFast(
  1465.                 cRouteRecip + pRouteData->palAddrListActive->cEntries,
  1466.                 pRouteData->pmsgRouteMsg,
  1467.                 TRUE,
  1468.                 &lpsptaRouteTags))
  1469.     {
  1470.         hr = ResultFromScode(E_FAIL);
  1471.         goto err;
  1472.     }
  1473.     if(hr = MAPIAllocateBuffer(
  1474.                     pRouteData->palAddrListActive->cEntries * ROUTEPROPSETDIM *
  1475.                         sizeof(SPropValue), (LPVOID *) &pvalAll))
  1476.         goto err;
  1477.     ZeroMemory(pvalAll, pRouteData->palAddrListActive->cEntries *
  1478.                         ROUTEPROPSETDIM * sizeof(SPropValue));
  1479.     /* get required properties missing in AddrlistActive*/
  1480.     hr = pabAddrB->lpVtbl->PrepareRecips(pabAddrB, 0, (LPSPropTagArray)&sptRouteProps,
  1481.                                                         pRouteData->palAddrListActive);
  1482.     if(S_OK != GetScode(hr))
  1483.     {
  1484.         DebugTrace("Client: PrepareRecips failed");
  1485.         goto err;
  1486.     }
  1487.     
  1488.     for(lpae = pRouteData->palAddrListActive->aEntries,
  1489.             pval = pvalAll, cNewRecips = 0;
  1490.         lpae < pRouteData->palAddrListActive->aEntries +
  1491.                 pRouteData->palAddrListActive->cEntries;
  1492.             ++lpae )
  1493.     {
  1494.         if(!lpae->rgPropVals)
  1495.         {
  1496.             continue;
  1497.         }
  1498.         ++cNewRecips;
  1499.                 
  1500.         Assert(lpae->rgPropVals[ROUTEPROPSET_EMAIL_ADDRESS].ulPropTag == PR_EMAIL_ADDRESS);
  1501.         pval[ROUTEPROPSET_EMAIL_ADDRESS].Value.LPSZ =
  1502.             lpae->rgPropVals[ROUTEPROPSET_EMAIL_ADDRESS].Value.LPSZ;
  1503.         Assert(lpae->rgPropVals[ROUTEPROPSET_ADDRTYPE].ulPropTag == PR_ADDRTYPE);
  1504.         pval[ROUTEPROPSET_ADDRTYPE].Value.LPSZ =
  1505.             lpae->rgPropVals[ROUTEPROPSET_ADDRTYPE].Value.LPSZ;
  1506.         Assert(lpae->rgPropVals[ROUTEPROPSET_DISPLAY_NAME].ulPropTag == PR_DISPLAY_NAME);
  1507.         pval[ROUTEPROPSET_DISPLAY_NAME].Value.LPSZ =
  1508.             lpae->rgPropVals[ROUTEPROPSET_DISPLAY_NAME].Value.LPSZ;
  1509.         
  1510.         Assert(lpae->rgPropVals[ROUTEPROPSET_ENTRYID].ulPropTag == PR_ENTRYID);
  1511.         pval[ROUTEPROPSET_ENTRYID].Value =
  1512.             lpae->rgPropVals[ROUTEPROPSET_ENTRYID].Value;
  1513.         Assert(lpae->rgPropVals[ROUTEPROPSET_SEARCH_KEY].ulPropTag == PR_SEARCH_KEY);
  1514.         pval[ROUTEPROPSET_SEARCH_KEY].Value =
  1515.             lpae->rgPropVals[ROUTEPROPSET_SEARCH_KEY].Value;
  1516.         pval += ROUTEPROPSETDIM;
  1517.     }
  1518.     
  1519.     for(ulidx = cRouteRecip * ROUTEPROPSETDIM, pval = pvalAll;
  1520.          ulidx < (cRouteRecip + cNewRecips)*ROUTEPROPSETDIM;
  1521.          ++pval, ++ulidx)
  1522.     {
  1523.         pval->ulPropTag = lpsptaRouteTags->aulPropTag[ulidx];
  1524.     }
  1525.     hr = pRouteData->pmsgRouteMsg->lpVtbl->SetProps(
  1526.                                             pRouteData->pmsgRouteMsg,
  1527.                                             cNewRecips * ROUTEPROPSETDIM,
  1528.                                             pvalAll,
  1529.                                             &lpsppaProblems);
  1530.     if(S_OK != GetScode(hr))
  1531.     {
  1532.         
  1533.         DebugTraceResult(SetProps, hr);
  1534.         goto err;
  1535.     }
  1536.     if(lpsppaProblems)
  1537.     {
  1538.         DebugTraceProblems("Client: SetProps", lpsppaProblems);
  1539.         MAPIFreeBuffer(lpsppaProblems);
  1540.         lpsppaProblems = NULL;
  1541.     }
  1542.     MAPIFreeBuffer(lpsptaRouteTags);
  1543.     lpsptaRouteTags = NULL;
  1544.     pRouteData->nTotalRouteRecip = pRouteData->nCurrentRouteRecip + cNewRecips;
  1545.     ++(pRouteData->nCurrentRouteRecip);
  1546.     if(!SetRouteIndices(pRouteData))
  1547.     {
  1548.         hr = ResultFromScode(E_FAIL);
  1549.         goto err;
  1550.     }
  1551.     
  1552. err:
  1553.     MAPIFreeBuffer(lpsptaRouteTags);
  1554.     MAPIFreeBuffer(lpsppaProblems);
  1555.     MAPIFreeBuffer(pvalAll);
  1556.     return ( hr ? FALSE : TRUE);
  1557. }
  1558. BOOL SetMessageClass(LPMESSAGE lpM, LPSTR lpszClass)
  1559. {
  1560.     HRESULT hr;
  1561.     SPropValue spvProp;
  1562.     spvProp.ulPropTag = PR_MESSAGE_CLASS;
  1563.     spvProp.dwAlignPad = 0;
  1564.     spvProp.Value.LPSZ = lpszClass;
  1565.     Assert(lpM);
  1566.     hr = HrSetOneProp((LPMAPIPROP)lpM, &spvProp);
  1567.     if(hr)
  1568.     {
  1569.         DebugTrace("Client: HrSetOneProp failed (SetMessageClass)");
  1570.         return FALSE;
  1571.     }
  1572.     return TRUE;
  1573. }
  1574. /* this functions works correctly only for received (saved) msgs*/
  1575. /*BOOL HasAttachment(LPMESSAGE lpM)
  1576. {
  1577.     HRESULT hr;
  1578.     LPSPropValue lpspvProp = NULL;
  1579.     LONG lflags = 0;
  1580.     Assert(lpM);
  1581.     hr = HrGetOneProp((LPMAPIPROP) lpM, PR_MESSAGE_FLAGS, &lpspvProp);
  1582.     if(hr)
  1583.     {
  1584.         DebugTrace("Client: HrGetOneProp failed (hasattachment)");
  1585.         goto err;
  1586.     }
  1587.     lflags = lpspvProp->Value.l;
  1588. err:
  1589.     MAPIFreeBuffer(lpspvProp);
  1590.     return lflags & MSGFLAG_HASATTACH;
  1591. }*/
  1592. BOOL PopulateAttachList(HWND hDlg, LPROUTEDATA pRouteData)
  1593. {
  1594.     SizedSPropTagArray (1, sptAttachNum) =  {   1,  {PR_ATTACH_NUM}  };
  1595.     LPSRowSet lprsRows = NULL;
  1596.     LPATTACH lpAttach = NULL;
  1597.     HRESULT hr;
  1598.     UINT idx, lbidx;
  1599.     LPSPropValue lpProp = NULL;
  1600.     SPropValue spvPosProp = {0};
  1601.     spvPosProp.ulPropTag = PR_RENDERING_POSITION;
  1602.     spvPosProp.Value.l = -1;
  1603.     Assert(pRouteData);
  1604.     Assert(pRouteData->pmsgRouteMsg);
  1605.     hr = pRouteData->pmsgRouteMsg->lpVtbl->
  1606.             GetAttachmentTable(pRouteData->pmsgRouteMsg, 0,
  1607.                                 &pRouteData->ptblAttach);
  1608.     if(S_OK != hr)
  1609.     {
  1610.         DebugTrace("Client: GetAttachmentTable failed (PopulateAttachList)");
  1611.         goto err;
  1612.     }
  1613.     hr = HrQueryAllRows(pRouteData->ptblAttach, (LPSPropTagArray)&sptAttachNum, NULL,
  1614.                                         NULL, 0, &lprsRows);
  1615.     if(S_OK != hr)
  1616.     {
  1617.         DebugTrace("Client: QueryAllRows failed (PopulateAttachList)");
  1618.         goto err;
  1619.     }
  1620.     if(!lprsRows || !(lprsRows->cRows)) goto err;
  1621.     for(idx = 0; idx < lprsRows->cRows; ++idx)
  1622.     {
  1623.         Assert(lprsRows->aRow[idx].cValues == 1);
  1624.         Assert(lprsRows->aRow[idx].lpProps->ulPropTag == PR_ATTACH_NUM);
  1625.         hr = pRouteData->pmsgRouteMsg->lpVtbl->
  1626.             OpenAttach(pRouteData->pmsgRouteMsg,
  1627.                             lprsRows->aRow[idx].lpProps->Value.l,
  1628.                         NULL, MAPI_MODIFY | MAPI_DEFERRED_ERRORS, &lpAttach);
  1629.         if(S_OK != hr)
  1630.         {
  1631.             DebugTrace("Client: openattach failed (PopulateAttachList)");
  1632.             goto err;
  1633.         }
  1634.         hr = HrGetOneProp((LPMAPIPROP)lpAttach, PR_DISPLAY_NAME, &lpProp);
  1635.         if(hr)
  1636.         {
  1637.             DebugTrace("Client: HrGetOneProp failed (PopulateAttachList)");
  1638.             goto err;
  1639.         }
  1640.         lbidx = ListBox_AddString(GetDlgItem(hDlg, IDC_RTATTACHLIST), lpProp->Value.LPSZ);
  1641.         if(LB_ERR != lbidx)
  1642.         {
  1643.             ListBox_SetItemData(GetDlgItem(hDlg, IDC_RTATTACHLIST), lbidx,
  1644.                                     lprsRows->aRow[idx].lpProps->Value.l);
  1645.         }
  1646.         MAPIFreeBuffer(lpProp);
  1647.         lpProp = NULL;
  1648.         /* in received msgs attachment positions are not -1 any more.
  1649.             Set them to -1 again*/
  1650.         hr = HrSetOneProp((LPMAPIPROP)lpAttach, &spvPosProp);
  1651.         if(!hr)
  1652.         {
  1653.             hr = lpAttach->lpVtbl->SaveChanges(lpAttach, 0);
  1654.         }
  1655.         lpAttach->lpVtbl->Release(lpAttach);
  1656.         lpAttach = NULL;
  1657.     }
  1658. err:
  1659.     FreeProws(lprsRows);
  1660.     lprsRows = NULL;
  1661.     UlRelease(lpAttach);
  1662.     MAPIFreeBuffer(lpProp);
  1663.     return (S_OK == GetScode(hr));
  1664. }
  1665. BOOL CreateNewAttachment(HWND hDlg)
  1666. {
  1667.     OPENFILENAME ofn;
  1668.     char szFileName[MAX_PATH] = "";
  1669.     char szFilter[256];
  1670.     static char szFileTitle[16] = "";
  1671.     static char szDirName[256] = "";
  1672.     LPSTR lpszEndPath;
  1673.     UINT idx, lbidx;
  1674.     HRESULT hr;
  1675.     LPROUTEDATA pRouteData = NULL;
  1676.     enum { REND_POS, PATH_NAME, ATT_METHOD, DISP_NAME, ATT_FILENAME, ATT_DIM};
  1677.     SizedSPropTagArray(ATT_DIM , sptAttachTags) =
  1678.     { ATT_DIM,
  1679.         {   PR_RENDERING_POSITION, PR_ATTACH_PATHNAME,
  1680.             PR_ATTACH_METHOD, PR_DISPLAY_NAME, PR_ATTACH_FILENAME }
  1681.     };
  1682.     SPropValue spvAttachProps[ATT_DIM];
  1683.     LPATTACH lpAttach = NULL;
  1684.     ULONG ulAttachNum = 0;
  1685.     pRouteData = (LPROUTEDATA)GetWindowLong(hDlg, GWL_USERDATA);
  1686.     Assert(pRouteData);
  1687.     
  1688. #ifndef WIN16
  1689.     if (!szDirName[0])
  1690.         GetCurrentDirectory (255, (LPSTR) szDirName);
  1691.     else
  1692. #endif
  1693.         lstrcpy (szFileName, szFileTitle);
  1694.     if(!LoadString(hInst, IDS_FILTER, szFilter, sizeof(szFilter)))
  1695.     {
  1696.         DebugTrace("Client: failed to load a string");
  1697.         return FALSE;
  1698.     }
  1699.     for (idx = 0; szFilter[idx] != ''; idx++)
  1700.         if (szFilter[idx] == '|')
  1701.             szFilter[idx] = '';
  1702.     ofn.lStructSize = sizeof (OPENFILENAME);
  1703.     ofn.hwndOwner = 0;
  1704.     ofn.hInstance = 0;
  1705.     ofn.lpstrFilter = szFilter;
  1706.     ofn.lpstrCustomFilter = NULL;
  1707.     ofn.nMaxCustFilter = 0L;
  1708.     ofn.nFilterIndex = 1L;
  1709.     ofn.lpstrFile = szFileName;
  1710.     ofn.nMaxFile = 256;
  1711.     ofn.lpstrFileTitle = szFileTitle;
  1712.     ofn.nMaxFileTitle = 16;
  1713.     ofn.lpstrInitialDir = szDirName;
  1714.     ofn.lpstrTitle = "Attach";
  1715.     ofn.nFileOffset = 0;
  1716.     ofn.nFileExtension = 0;
  1717.     ofn.lpstrDefExt = NULL;
  1718.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
  1719.     if (!GetOpenFileName (&ofn))
  1720.         return FALSE;
  1721.     /* Save the directory for the next time we call this */
  1722.     lstrcpy (szDirName, szFileName);
  1723.     if (lpszEndPath = SzFindLastCh(szDirName, '\'))
  1724.         *(lpszEndPath) = '';
  1725.     hr = pRouteData->pmsgRouteMsg->lpVtbl->CreateAttach(pRouteData->pmsgRouteMsg,
  1726.                                  NULL, MAPI_DEFERRED_ERRORS, &ulAttachNum, &lpAttach);
  1727.     if(S_OK != GetScode(hr))
  1728.     {
  1729.         DebugTrace("Client: CreateAttach failed (CreateNewAttach)");
  1730.         return FALSE;
  1731.     }
  1732.     for(idx = 0; idx < ATT_DIM; ++idx)
  1733.     {
  1734.         spvAttachProps[idx].ulPropTag = sptAttachTags.aulPropTag[idx];
  1735.         spvAttachProps[idx].dwAlignPad = 0;
  1736.     }
  1737.     spvAttachProps[REND_POS].Value.l = -1;
  1738.     spvAttachProps[PATH_NAME].Value.LPSZ = szFileName;
  1739.     spvAttachProps[ATT_METHOD].Value.l = ATTACH_BY_REF_RESOLVE;
  1740.     /* ATTACH_BY_REF_RESOLVE means the spooler wiil reslove the attachment into ATTACH_BY_VALUE
  1741.         and place the attachment data in PR_ATTACH_DATA_BIN */
  1742.     spvAttachProps[DISP_NAME].Value.LPSZ = szFileTitle;
  1743.     spvAttachProps[ATT_FILENAME].Value.LPSZ = szFileTitle;
  1744.     hr = lpAttach->lpVtbl->SetProps(lpAttach, ATT_DIM, spvAttachProps, NULL);
  1745.     if(S_OK != GetScode(hr))
  1746.     {
  1747.         DebugTrace("Client: SetProp failed (createnewattachment)");
  1748.         goto err;
  1749.     }
  1750.     hr = lpAttach->lpVtbl->SaveChanges(lpAttach, MAPI_DEFERRED_ERRORS);
  1751.     if(S_OK != GetScode(hr))
  1752.     {
  1753.         DebugTrace("Client: SaveChanges failed (createnewattachment)");
  1754.         goto err;
  1755.     }
  1756.     lbidx = ListBox_AddString(GetDlgItem(hDlg, IDC_RTATTACHLIST), szFileTitle);
  1757.     if(LB_ERR != lbidx)
  1758.     {
  1759.         /*Store the attachment # with its name in the listbox*/
  1760.         ListBox_SetItemData(GetDlgItem(hDlg, IDC_RTATTACHLIST), lbidx,
  1761.                                     ulAttachNum);
  1762.     }
  1763. err:
  1764.     UlRelease(lpAttach);
  1765.     return (S_OK == GetScode(hr));
  1766. }
  1767. void SaveAttachment( HWND hDlg, UINT itemindx)
  1768. {
  1769.     OPENFILENAME ofn;
  1770.     char szFileName[256] = "";
  1771.     char szFilter[256];
  1772.     static char szFileTitle[16];
  1773.     static char szDirName[256] = "";
  1774.     LPSTR lpszEndPath;
  1775.     ULONG idx;
  1776.     HRESULT hr;
  1777.     LPSPropValue lpProp = NULL;
  1778.     LPATTACH lpAttach = NULL;
  1779.     LPSTREAM lpstrAtt=NULL, lpstrFile=NULL;
  1780.     STATSTG statstg = {0};
  1781.     ULONG ulAttachNum;
  1782.     LPROUTEDATA pRouteData = NULL;
  1783.     pRouteData = (LPROUTEDATA)GetWindowLong(hDlg, GWL_USERDATA);
  1784.     if(!pRouteData)
  1785.     {
  1786.         DebugTrace("Client: pRouteData == 0 (saveattachment)");
  1787.         goto err;
  1788.     }
  1789.     if (!szDirName[0])
  1790.         GetTempPath (sizeof(szDirName), szDirName);
  1791.     if(!LoadString(hInst, IDS_FILTER, szFilter, sizeof(szFilter)))
  1792.     {
  1793.         DebugTrace("Client: failed to load a string");
  1794.         goto err;
  1795.     }
  1796.     for (idx = 0; szFilter[idx] != ''; idx++)
  1797.         if (szFilter[idx] == '|')
  1798.             szFilter[idx] = '';
  1799.     ulAttachNum = ListBox_GetItemData(GetDlgItem(hDlg, IDC_RTATTACHLIST), itemindx);
  1800.     if(LB_ERR == ulAttachNum)
  1801.     {
  1802.         DebugTrace("Client: can't get attach num (saveattachment)");
  1803.         return;
  1804.     }
  1805.     hr = pRouteData->pmsgRouteMsg->lpVtbl->
  1806.             OpenAttach(pRouteData->pmsgRouteMsg, ulAttachNum, NULL,
  1807.                         MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS, &lpAttach);
  1808.     if(S_OK != GetScode(hr))
  1809.     {
  1810.         DebugTrace("Client: OpenAttach failed (saveattachment)");
  1811.         goto err;
  1812.     }
  1813.     hr = HrGetOneProp((LPMAPIPROP)lpAttach, PR_ATTACH_FILENAME, &lpProp);
  1814.     if(hr)
  1815.     {
  1816.         DebugTrace("Client: OpenAttach failed (saveattachment)");
  1817.         goto err;
  1818.     }
  1819.     lstrcpy (szFileName, lpProp->Value.LPSZ);
  1820.     MAPIFreeBuffer(lpProp);
  1821.     lpProp = NULL;
  1822.     ofn.lStructSize = sizeof (OPENFILENAME);
  1823.     ofn.hwndOwner = hDlg;
  1824.     ofn.hInstance = 0;
  1825.     ofn.lpstrFilter = szFilter;
  1826.     ofn.lpstrCustomFilter = NULL;
  1827.     ofn.nMaxCustFilter = 0L;
  1828.     ofn.nFilterIndex = 1L;
  1829.     ofn.lpstrFile = szFileName;
  1830.     ofn.nMaxFile = sizeof(szFileName);
  1831.     ofn.lpstrFileTitle = szFileTitle;
  1832.     ofn.nMaxFileTitle = sizeof(szFileTitle);
  1833.     ofn.lpstrInitialDir = szDirName;
  1834.     ofn.lpstrTitle = "Save Attachment";
  1835.     ofn.nFileOffset = 0;
  1836.     ofn.nFileExtension = 0;
  1837.     ofn.lpstrDefExt = NULL;
  1838.     ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
  1839.     if (!GetSaveFileName (&ofn))
  1840.         goto err;
  1841.     /* Save the directory for the next time we call this */
  1842.     lstrcpy (szDirName, szFileName);
  1843.     if (lpszEndPath = SzFindLastCh(szDirName, '\'))
  1844.         *(lpszEndPath) = '';
  1845.     hr = lpAttach->lpVtbl->OpenProperty (lpAttach, PR_ATTACH_DATA_BIN,
  1846.                                         (LPIID)&IID_IStream,
  1847.                                         0, MAPI_DEFERRED_ERRORS,
  1848.                                         (LPUNKNOWN *)&lpstrAtt);
  1849.     if(S_OK != GetScode(hr))
  1850.     {
  1851.         /*must be a new attachment*/
  1852.         hr = HrGetOneProp((LPMAPIPROP)lpAttach, PR_ATTACH_PATHNAME, &lpProp);
  1853.         if(hr)
  1854.         {
  1855.             DebugTrace("Client: PR_ATTACH_PATHNAME (saveattach)");
  1856.             goto err;
  1857.         }
  1858.         CopyFile(lpProp->Value.LPSZ, szFileName, TRUE);
  1859.         goto err;
  1860.     }
  1861.     hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
  1862.                             STGM_CREATE | STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  1863.                             szFileName, NULL, &lpstrFile);
  1864.     if(S_OK != GetScode(hr))
  1865.     {
  1866.         DebugTrace("Client: OpenStreamOnFile failed (saveattachment)");
  1867.         goto err;
  1868.     }
  1869.     lpstrAtt->lpVtbl->Stat(lpstrAtt, &statstg, STATFLAG_NONAME);
  1870.     hr = lpstrAtt->lpVtbl->CopyTo(lpstrAtt, lpstrFile, statstg.cbSize, NULL, NULL);
  1871.     if(S_OK != GetScode(hr))
  1872.     {
  1873.         DebugTrace("Client: CopyTo failed (saveattachment)");
  1874.         goto err;
  1875.     }
  1876. err:
  1877.     UlRelease(lpstrAtt);
  1878.     UlRelease(lpstrFile);
  1879.     UlRelease(lpAttach);
  1880.     MAPIFreeBuffer(lpProp);
  1881. }