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

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