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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  -  X P S T A T U S . C
  3.  -
  4.  *  Purpose:
  5.  *      Sample transport provider status interface code.  This module
  6.  *      contains the following Transport SPI entry points:
  7.  *
  8.  *          OpenStatusEntry()
  9.  *
  10.  *      The Status Object methods implemented in this module are:
  11.  *
  12.  *          QueryInterface,
  13.  *          AddRef,
  14.  *          Release,
  15.  *          GetLastError,
  16.  *          GetProps,
  17.  *          GetPropList,
  18.  *          SettingsDialog,
  19.  *          FlushQueues,
  20.  *
  21.  *      Additional support functions found here:
  22.  *
  23.  *          HrBuildTransportStatus
  24.  *          HrUpdateTransportStatus
  25.  *          NewSOB
  26.  *          HrLoadStatusString
  27.  *          MapScodeSz
  28.  *
  29.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  30.  */
  31. //$BUG  Invalid flags should return MAPI_E_UNKNOWN_FLAGS!
  32. #include "xppch.h"
  33. #include "xpresrc.h"
  34. #define MAX_STRING          8192
  35. #define MAX_RESRC_STRING    256
  36. /* Declared in xpbase.c */
  37. extern sptLogonArray;
  38. /*  SOB IMAPIProp jump table */
  39. SOB_Vtbl vtblSOB =
  40. {
  41.     SOB_QueryInterface,
  42.     SOB_AddRef,
  43.     SOB_Release,
  44.     SOB_GetLastError,
  45.     SOB_SaveChanges,
  46.     SOB_GetProps,
  47.     SOB_GetPropList,
  48.     SOB_OpenProperty,
  49.     SOB_SetProps,
  50.     SOB_DeleteProps,
  51.     SOB_CopyTo,
  52.     SOB_CopyProps,
  53.     SOB_GetNamesFromIDs,
  54.     SOB_GetIDsFromNames,
  55.     SOB_ValidateState,
  56.     SOB_SettingsDialog,
  57.     SOB_ChangePassword,
  58.     SOB_FlushQueues,
  59. };
  60. /*  Static properties. In this case the array of Property Tags available
  61.     from the Status object if opened.  The PR_RESOURCE_PATH must be last
  62.     because we will not tell the client about this property if it isn't
  63.     set in the Logon dialog.  Being last makes GetPropList() easier to do. */
  64. /* Number of columns in Status row. */
  65. #define NUM_STATUS_ROW_PROPS 10
  66. const static SizedSPropTagArray(NUM_STATUS_ROW_PROPS, sptaStatusRow) =
  67. {
  68.     NUM_STATUS_ROW_PROPS,
  69.     {
  70.         PR_RESOURCE_METHODS,
  71.         PR_PROVIDER_DISPLAY,
  72.         PR_DISPLAY_NAME,
  73.         PR_IDENTITY_DISPLAY,
  74.         PR_IDENTITY_ENTRYID,
  75.         PR_IDENTITY_SEARCH_KEY,
  76.         PR_STATUS_CODE,
  77.         PR_STATUS_STRING,
  78.         PR_OBJECT_TYPE,
  79.         PR_RESOURCE_PATH
  80.     }
  81. };
  82. /* List of IID's we support on open/query */
  83. #define N_IID 3
  84. static const LPIID lpStatusFamilyIID[N_IID] =
  85. {
  86.     (LPIID) &IID_IUnknown,      /* IUnknown is everyone's parent */
  87.     (LPIID) &IID_IMAPIProp,     /* IMAPIProp follows from this   */
  88.     (LPIID) &IID_IMAPIStatus    /* My actual interface ID        */
  89. };
  90. /* Local code */
  91. static HRESULT NewSOB(LPCIID lpInterface,
  92.     ULONG ulOpenFlags,
  93.     LPXPL lpxpl,
  94.     ULONG * lpulObjType,
  95.     LPSOB * lppSOB);
  96. static HRESULT HrLoadStatusString(LPXPL lpxpl,
  97.     LPVOID lpvParent,
  98.     LPTSTR * lppsz);
  99. /*
  100.  -  HrBuildTransportStatus
  101.  -
  102.  *  Purpose:
  103.  *      Called by TransportLogon to build the Status Table entry for the
  104.  *      Sample Transport Provider.
  105.  *
  106.  *  Parameters:
  107.  *      lpxpl               The current session structure.
  108.  *      ulFlags             0 or STATUSROW_UPDATE
  109.  *
  110.  *  Returns:
  111.  *      (HRESULT)           Errors encountered if any.
  112.  *      (Status Row)        Contains properties from session
  113.  *
  114.  *  Operation:
  115.  *      This one's relatively simple: build a property value array based on
  116.  *      data in the session structure, and call (*lpMAPISup)->ModifyStatusRow
  117.  *      to register the row in the table.
  118.  */
  119. HRESULT
  120. HrBuildTransportStatus(LPXPL lpxpl, ULONG ulFlags)
  121. {
  122.     SCODE sc = 0;
  123.     LPSPropValue lpPropArray = NULL;
  124.     LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
  125.     LPSPropValue pPropValT;
  126.     LPVOID lpvT;
  127.     LPVOID lpvT1;
  128.     LPVOID lpvT2;
  129.     LPTSTR lpszStatus = NULL;
  130.     ULONG ulT;
  131.     /*  Allocate initial property array now. */
  132.     sc = lpxpl->AllocateBuffer(sizeof(SPropValue) * (NUM_STATUS_ROW_PROPS - 1), (LPVOID *) &lpPropArray);
  133.     if (sc)
  134.     {
  135.         DebugTraceSc(Status Row Allocation, sc);
  136.         goto ret;
  137.     }
  138.     /*  Store the properties into the status row */
  139.     pPropValT = lpPropArray;
  140.     /*  1. Transport's Display Name. */
  141.     pPropValT->ulPropTag = PR_PROVIDER_DISPLAY;
  142.     pPropValT->Value.LPSZ = (LPTSTR) MYDISPLAYNAME;
  143.     pPropValT++;
  144.     /*  2. Extra methods on status object */
  145.     pPropValT->ulPropTag = PR_RESOURCE_METHODS;
  146.     pPropValT->Value.ul = lpxpl->ulResourceMethods;
  147.     pPropValT++;
  148.     /*  3. Display Name associated with session. Use email address. */
  149.     lpvT1 = ArrayIndex (PR_SAMPLE_DISPLAY_NAME, lpxpl->lpPropArray).Value.LPSZ;
  150.     lpvT2 = ArrayIndex (PR_SAMPLE_EMAIL_ADDRESS, lpxpl->lpPropArray).Value.LPSZ;
  151.     ulT = (lstrlen((LPCTSTR) lpvT1)+lstrlen((LPCTSTR) lpvT2)+4)*sizeof (TCHAR);
  152.     sc = lpxpl->AllocateMore(ulT, (LPVOID) lpPropArray, &lpvT);
  153.     if (sc)
  154.     {
  155.         DebugTraceSc(Session Display Name allocation, sc);
  156.         goto ret;
  157.     }
  158.     wsprintf((LPTSTR) lpvT, TEXT("%s [%s]"), (LPTSTR) lpvT1, (LPTSTR) lpvT2);
  159.     pPropValT->ulPropTag = PR_DISPLAY_NAME;
  160.     pPropValT->Value.LPSZ = (LPTSTR) lpvT;
  161.     pPropValT++;
  162.     /*  4. User's Display Name. */
  163.     Assert(lpxpl->lpMyIDArray);
  164.     *pPropValT = lpxpl->lpMyIDArray[1];
  165.     Assert(pPropValT->ulPropTag == PR_SENDER_NAME);
  166.     Assert(!IsBadStringPtr(pPropValT->Value.LPSZ, MAX_STRING));
  167.     pPropValT->ulPropTag = PR_IDENTITY_DISPLAY;
  168.     pPropValT++;
  169.     /*  5. User Entry-ID. */
  170.     Assert(lpxpl->lpMyIDArray);
  171.     *pPropValT = lpxpl->lpMyIDArray[0];
  172.     Assert(pPropValT->ulPropTag == PR_SENDER_ENTRYID);
  173.     Assert(pPropValT->Value.bin.cb);
  174.     Assert(!IsBadReadPtr(pPropValT->Value.bin.lpb, (UINT) pPropValT->Value.bin.cb));
  175.     pPropValT->ulPropTag = PR_IDENTITY_ENTRYID;
  176.     pPropValT++;
  177.     /*  6. User Search Key. */
  178.     Assert(lpxpl->lpMyIDArray);
  179.     *pPropValT = lpxpl->lpMyIDArray[2];
  180.     Assert(pPropValT->ulPropTag == PR_SENDER_SEARCH_KEY);
  181.     Assert(pPropValT->Value.bin.cb);
  182.     Assert(!IsBadReadPtr(pPropValT->Value.bin.lpb, (UINT) pPropValT->Value.bin.cb));
  183.     pPropValT->ulPropTag = PR_IDENTITY_SEARCH_KEY;
  184.     pPropValT++;
  185.     /*  7. Code. Online/Offline, Send/Receive, Uploading/Downloading. */
  186.     pPropValT->ulPropTag = PR_STATUS_CODE;
  187.     pPropValT->Value.ul = lpxpl->ulTransportStatus;
  188.     pPropValT++;
  189.     /*  8. Status String based on Status Code. */
  190.     if (HrLoadStatusString(lpxpl, lpPropArray, &lpszStatus))
  191.     {
  192.         pPropValT->ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_STATUS_STRING));
  193.         pPropValT->Value.err = MAPI_E_NOT_FOUND;
  194.     }
  195.     else
  196.     {
  197.         pPropValT->ulPropTag = PR_STATUS_STRING;
  198.         pPropValT->Value.LPSZ = lpszStatus;
  199.     }
  200.     pPropValT++;
  201.     /*  9. Resource Path == WGAP Directory. */
  202.     lpvT = (LPVOID) ArrayIndex(PR_SAMPLE_DIRECTORY, lpxpl->lpPropArray).Value.LPSZ;
  203.     if (lstrlen((LPCTSTR) lpvT))
  204.     {
  205.         pPropValT->ulPropTag = PR_RESOURCE_PATH;
  206.         pPropValT->Value.LPSZ = (LPTSTR) lpvT;
  207.         pPropValT++;
  208.     }
  209.     /*  Status Row is built. Register it. */
  210.     sc = GetScode(lpMAPISup->lpVtbl->ModifyStatusRow(lpMAPISup,
  211.             (pPropValT - lpPropArray), lpPropArray, ulFlags));
  212.     if (FAILED(sc))
  213.         DebugTrace("ModifyStatusRow failed.n");
  214. ret:
  215.     /*  Free the allocated memory */
  216.     lpxpl->FreeBuffer(lpPropArray);
  217.     DebugTraceSc(HrBuildTransportStatus, sc);
  218.     return ResultFromScode(sc);
  219. }
  220. /*
  221.  -  HrUpdateTransportStatus
  222.  -
  223.  *  Purpose:
  224.  *      Called by Transport code to update the PR_STATUS_CODE property in the
  225.  *      Status Table row for the Sample Transport Provider.
  226.  *
  227.  *  Parameters:
  228.  *      lpxpl               The current session structure.
  229.  *      ulFlags             Flags. Not currently used.
  230.  *
  231.  *  Returns:
  232.  *      (HRESULT)           Errors encountered if any.
  233.  *      (Status Row)        PR_STATUS_CODE and PR_STATUS_STRING updated
  234.  *
  235.  *  Operation:
  236.  *      Transport should already have updated lpxpl->ulTransportStatus
  237.  *      before calling here.  So all this routine does is construct a
  238.  *      notification structure for a status object modification and call
  239.  *      (*lpMAPISup)->ModifyStatusRow() to update the table.  If there is a
  240.  *      string available in the StringTable, then our cProps goes to 2 and
  241.  *      we assign the string to the 2nd element of rgProps.
  242.  */
  243. HRESULT
  244. HrUpdateTransportStatus(LPXPL lpxpl, ULONG ulFlags)
  245. {
  246.     HRESULT hResult;
  247.     ULONG cProps = 2;
  248.     SPropValue rgProps[2];
  249.     LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
  250.     LPTSTR lpszStatus = NULL;
  251.     /*  Store the new Transport Provider Status Code. */
  252.     rgProps[0].ulPropTag = PR_STATUS_CODE;
  253.     rgProps[0].Value.ul = lpxpl->ulTransportStatus;
  254.     /* Set the Status String according to ulStatus */
  255.     if (HrLoadStatusString(lpxpl, NULL, &lpszStatus))
  256.     {
  257.         rgProps[1].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_STATUS_STRING));
  258.         rgProps[1].Value.err = MAPI_E_NOT_FOUND;
  259.     }
  260.     else
  261.     {
  262.         rgProps[1].ulPropTag = PR_STATUS_STRING;
  263.         rgProps[1].Value.LPSZ = lpszStatus;
  264.     }
  265.     /*  OK. Notify the Spooler. It will tell MAPI. */
  266.     hResult = lpMAPISup->lpVtbl->ModifyStatusRow(lpMAPISup,
  267.             cProps, rgProps, STATUSROW_UPDATE);
  268.     lpxpl->FreeBuffer(lpszStatus);
  269.     
  270.     DebugTraceResult(ModifyStatusRow, hResult);
  271.     return hResult;
  272. }
  273. /*
  274.  -  OpenStatusEntry
  275.  -
  276.  *  Purpose:
  277.  *      Called by Spooler to service client OpenEntry request.
  278.  *
  279.  *  Parameters:
  280.  *      lpiid               Interface identifier.
  281.  *      ulFlags             Open flags. The only doc'ed flag
  282.  *                          is MAPI_MODIFY, which we don't support.
  283.  *      lpulObjType         Pointer to a unsigned long into which
  284.  *                          we are to store the type of the
  285.  *                          object we've just opened.
  286.  *      lppEntry            Points to a variable into which we
  287.  *                          may store the object pointer.
  288.  *
  289.  *  Returns:
  290.  *      (HRESULT)           E_INVALIDARG if the session
  291.  *                          pointer isn't valid, or any other
  292.  *                          parameter not to our liking,
  293.  *                          or any other errors we encounter.
  294.  *      *lpulObjType        MAPI_STATUS if we open the entry,
  295.  *                          unchanged if not
  296.  *      *lppEntry           Pointer to object if we open the
  297.  *                          entry, unchanged if not
  298.  *
  299.  *  Operation:
  300.  *      Validate parameters. Call NewSOB() to create the object, returning
  301.  *      object type and object pointer into user-supplied locations.
  302.  */
  303. STDMETHODIMP
  304. XPL_OpenStatusEntry(LPXPL lpxpl,
  305.     LPCIID lpiid,
  306.     ULONG ulFlags,
  307.     ULONG * lpulObjType,
  308.     LPMAPISTATUS * lppEntry)
  309. {
  310.     HRESULT hResult;
  311. #ifndef MAC
  312.     LPXPP lpxpp;
  313. #endif
  314.     /* Need to do weak session validation to do this */
  315.     if (IsBadWritePtr(lpxpl, sizeof(XPL)) ||
  316.         IsBadWritePtr((lpxpp = lpxpl->lpxppParent), sizeof(XPP)) ||
  317.         (lpiid != NULL && IsBadReadPtr(lpiid, sizeof(IID))) ||
  318.         (IsBadWritePtr(lpulObjType, sizeof(ULONG))) ||
  319.         (IsBadWritePtr(lppEntry, sizeof(LPMAPISTATUS))))
  320.     {
  321.         DebugTraceSc(OpenStatusEntry, E_INVALIDARG);
  322.         return ResultFromScode(E_INVALIDARG);
  323.     }
  324.     /* Get the Critical Section */
  325.     EnterCriticalSection(&lpxpp->csTransport);
  326.     /*  Validate the user's parameters always */
  327.     /*  Invalid parameter checking: 1) make sure the passed session
  328.         is still valid; 2) lpiid should either be null or point
  329.         to a piece of memory at least the size of a iid; 3) lpulObjType
  330.         must point to a writable piece of memory the size of a ulong;
  331.         4) lppEntry must point to enough writable memory to store a
  332.         LPMAPISTATUS. */
  333.     if (!FIsValidSession(lpxpl))
  334.     {
  335.         hResult = ResultFromScode(E_INVALIDARG);
  336.         DebugTrace("Invalid Logon object.n");
  337.         goto ret;
  338.     }
  339.     /*  We don't support MAPI_MODIFY and no other flags are spec'ed. */
  340.     if (ulFlags & ~MAPI_MODIFY)
  341.     {
  342.         hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  343.         DebugTrace("Unknown Flags.n");
  344.         goto ret;
  345.     }
  346.     if (ulFlags & MAPI_MODIFY)
  347.     {
  348.         hResult = ResultFromScode(MAPI_E_NO_ACCESS);
  349.         DebugTrace("XP Support Object doesn't support Modify access.n");
  350.         goto ret;
  351.     }
  352.     /*  The argument list looks good to us. Now, if we already have opened
  353.         a status object on this logon context, we'll just use QueryInterface
  354.         to get a new copy of the object... */
  355.     if (lpxpl->lpXPStatus)
  356.     {
  357.         hResult = lpxpl->lpXPStatus->lpVtbl->QueryInterface(lpxpl->lpXPStatus,
  358.                 (lpiid ? lpiid : &IID_IMAPIStatus), lppEntry);
  359.                 
  360.         if (HR_FAILED(hResult))
  361.             DebugTrace("QueryInterface failed.n");
  362.         else
  363.             *lpulObjType = MAPI_STATUS;
  364.     }
  365.     else
  366.     {
  367.         /*  Or if we don't already have an object, create it, saving a
  368.             copy in the logon context. */
  369.         hResult = NewSOB(lpiid, ulFlags, lpxpl, 
  370.                 lpulObjType, (LPSOB *) lppEntry);
  371.                 
  372.         if (HR_FAILED(hResult))
  373.             DebugTrace("NewSOB failed.n");
  374.         else
  375.             lpxpl->lpXPStatus = *lppEntry;
  376.     }
  377. ret:
  378.     /*  Release the critical section. */
  379.     LeaveCriticalSection(&lpxpp->csTransport);
  380.     /*  Errors returned from this routine are always in sc. So if
  381.         sc is zero we return 0. If it's nonzero we return a hResult
  382.         built here from sc. */
  383.     DebugTraceResult(OpenStatusEntry, hResult);
  384.     return hResult;
  385. }
  386. /*
  387.  -  NewSOB
  388.  -
  389.  *  Purpose:
  390.  *      Called from OpenStatusEntry to create a Status Object.
  391.  *
  392.  *  Parameters:
  393.  *      lpInterface         If non-null must be IID_IMAPIStatus
  394.  *      ulOpenFlags         Open flags. The only doc'ed flag
  395.  *                          is MAPI_MODIFY, which we don't support.
  396.  *      lpxpl               The handle of the session for which
  397.  *                          we want to open a Status object. In
  398.  *                          Spooler context, a pointer to the
  399.  *                          session data structure.
  400.  *      lpulObjType         Pointer to a unsigned long into which
  401.  *                          we are to store the type of the
  402.  *                          object we've just opened.
  403.  *      lppSOB              Points to a variable into which we
  404.  *                          may store the object pointer.
  405.  *
  406.  * Returns:
  407.  *      (HRESULT)           MAPI_E_NO_SUPPORT if an
  408.  *                          interface is specified, or any
  409.  *                          other errors we encounter.
  410.  *      *lpulObjType        MAPI_STATUS if we open the entry,
  411.  *                          unchanged if not
  412.  *      *lppEntry           Pointer to object if we open the
  413.  *                          entry, unchanged if not
  414.  *
  415.  *  Operation:
  416.  *      Allocates the memory for the object, initializes its data
  417.  *      members, plugs in the jump table and returns the appropriate
  418.  *      stuff to the caller.
  419.  */
  420. static HRESULT
  421. NewSOB(LPCIID lpInterface,
  422.     ULONG ulOpenFlags,
  423.     LPXPL lpxpl,
  424.     ULONG * lpulObjType,
  425.     LPSOB * lppSOB)
  426. {
  427.     SCODE sc;
  428.     LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
  429.     LPSOB lpSOB = NULL;
  430.     ULONG i;
  431.     *lpulObjType = 0;
  432.     *lppSOB = NULL;
  433.     /*  Make sure no interface (or ours) was specified. */
  434.     if (lpInterface)
  435.     {
  436.         for (i = 0; i < N_IID; i++)
  437.         {
  438.             if (!memcmp(lpInterface, lpStatusFamilyIID[i], sizeof(IID)))
  439.                 break;
  440.         }
  441.         if (i == N_IID)
  442.         {
  443.             DebugTraceSc(NewSOB, E_INVALIDARG);
  444.             return ResultFromScode(E_INVALIDARG);
  445.         }
  446.     }
  447.     /*  Allocate space for the SOB structure */
  448.     sc = lpxpl->AllocateBuffer(sizeof(SOB), (LPVOID *) &lpSOB);
  449.     if (sc)
  450.     {
  451.         DebugTrace("Allocation of Status Object failed.n");
  452.         return ResultFromScode(sc);
  453.     }
  454.     /*  Fill in the data members and the jump table. */
  455.     lpSOB->lpVtbl = &vtblSOB;
  456.     lpSOB->lcInit = 1;
  457.     lpSOB->lpsobMyAddress = lpSOB;
  458.     lpSOB->hrLastError = 0;
  459.     lpSOB->ulOpenFlags = ulOpenFlags;
  460.     lpSOB->AllocateBuffer = lpxpl->AllocateBuffer;
  461.     lpSOB->AllocateMore = lpxpl->AllocateMore;
  462.     lpSOB->FreeBuffer = lpxpl->FreeBuffer;
  463.     lpSOB->lpMAPISup = lpMAPISup;
  464.     lpSOB->lpxpl = lpxpl;
  465.     /*  Return the newly constructed object to the caller. */
  466.     *lpulObjType = MAPI_STATUS;
  467.     *lppSOB = lpSOB;
  468.     return 0;
  469. }
  470. /*
  471.  -  HrLoadStatusString
  472.  -
  473.  *  Purpose:
  474.  *      Retrieves a Status String from the resource StringTable
  475.  *      based on ulStatus code passed in.
  476.  *
  477.  *  Parameters:
  478.  *      lpxpl               The Transport Logon session
  479.  *      lpvParent           If non-null we chain the memory to this block
  480.  *      lppsz               Place to copy Status String to.
  481.  *
  482.  * Returns:
  483.  *      hr                  Indicating Success/Failure
  484.  *
  485.  */
  486. static HRESULT
  487. HrLoadStatusString(LPXPL lpxpl, LPVOID lpvParent, LPTSTR *lppsz)
  488. {
  489.     SCODE sc = S_OK;
  490.     UINT ids;
  491.     ULONG cb;
  492.     ULONG ulStatus = lpxpl->ulTransportStatus;
  493.     TCHAR szStatus[MAX_RESRC_STRING];
  494.     /* Determine the IDS of the status.  Since the status' are bit fields
  495.        of ulStatus, we apply this hierarcy to determine the correct string. */
  496.     
  497.     if (ulStatus & STATUS_INBOUND_ACTIVE)
  498.         ids = IDS_STATUS_UPLOADING;
  499.     else if (ulStatus & STATUS_OUTBOUND_ACTIVE)
  500.         ids = IDS_STATUS_DOWNLOADING;
  501.     else if (ulStatus & STATUS_INBOUND_FLUSH)
  502.         ids = IDS_STATUS_INFLUSHING;
  503.     else if (ulStatus & STATUS_OUTBOUND_FLUSH)
  504.         ids = IDS_STATUS_OUTFLUSHING;
  505.     else if ((ulStatus & STATUS_AVAILABLE) &&
  506.             ((ulStatus & STATUS_INBOUND_ENABLED) ||
  507.             (ulStatus & STATUS_OUTBOUND_ENABLED)))
  508.         ids = IDS_STATUS_ONLINE;
  509.     else if (ulStatus & STATUS_AVAILABLE)
  510.         ids = IDS_STATUS_AVAILABLE;
  511.     else
  512.         ids = IDS_STATUS_OFFLINE;
  513.     /* Attempt to load the resource into our automatic variable. */
  514.     
  515.     cb = LoadString(lpxpl->lpxppParent->hInst, ids, szStatus, MAX_RESRC_STRING);
  516.     
  517.     if (!cb)
  518.     {
  519.         sc = MAPI_E_CALL_FAILED;
  520.         DebugTrace("LoadString failed in HrLoadStatusString.n");
  521.         goto ret;
  522.     }
  523.     /* We'll get the exact size of the string and put it on the heap.
  524.        The caller had the luxury of specifying a parent block to chain
  525.        this allocation to. */
  526.     
  527.     cb = (cb + 1) * sizeof(TCHAR);
  528.     if (lpvParent)  
  529.         sc = lpxpl->AllocateMore(cb, lpvParent, (LPVOID *)lppsz);
  530.     else    
  531.         sc = lpxpl->AllocateBuffer(cb, (LPVOID *)lppsz);
  532.     
  533.     if (FAILED(sc))
  534.     {
  535.         DebugTrace("Allocation failed in HrLoadStatusString.n");
  536.         goto ret;
  537.     }
  538.     
  539.     lstrcpy(*lppsz, szStatus);
  540. ret:
  541.     DebugTraceSc(HrLoadStatusString, sc);
  542.     return ResultFromScode(sc);
  543. }
  544. /*
  545.  -  IMAPISTATUS::QueryInterface
  546.  -
  547.  *  Purpose:
  548.  *      Standard IUnknown method.
  549.  *
  550.  *  Parameters:
  551.  *      lpObject            Pointer to object
  552.  *      lpiid               New interface to Query to
  553.  *      lppNewObj           Where to store pointer to new object
  554.  *
  555.  *  Returns:
  556.  *      (SCODE)             E_INVALIDARG if the input object
  557.  *                          doesn't look like a SOB, if the
  558.  *                          IID isn't readable or lppNewObj
  559.  *                          isn't writable; E_NOINTERFACE
  560.  *                          if we don't know the IID.
  561.  *
  562.  *  Operation:
  563.  *      Validate parameters. See if the caller wants IUnknown, IMAPIProp or
  564.  *      IStatus. If so, increment the usage count and return a new object.
  565.  */
  566. STDMETHODIMP
  567. SOB_QueryInterface(LPSOB lpSOB,
  568.     REFIID lpiid,
  569.     LPVOID * lppNewObj)
  570. {
  571.     ULONG i;
  572.     /*  Validate the parameters: 1) Does it seem to be an object?
  573.         2) is the refcount nonzero? 3) Is there enough there for
  574.         an interface ID? 4) Is there enough there for a new object? */
  575.     if ((IsBadWritePtr(lpSOB, sizeof(SOB))) ||
  576.         (lpSOB->lcInit == 0) ||
  577.         (lpSOB->lpsobMyAddress != lpSOB) ||
  578.         (IsBadReadPtr(lpiid, sizeof(IID))) ||
  579.         (IsBadWritePtr(lppNewObj, sizeof(LPSOB))))
  580.     {
  581.         DebugTraceSc(SOB_QueryInterface, E_INVALIDARG);
  582.         return ResultFromScode(E_INVALIDARG);
  583.     }
  584.     /*  See if the requested interface is one of ours */
  585.     for (i = 0; i < N_IID; i++)
  586.     {
  587.         if (!memcmp(lpiid, lpStatusFamilyIID[i], sizeof(IID)))
  588.             break;
  589.     }
  590.     /*  If we didn't find the interface, get out now. */
  591.     if (i == N_IID)
  592.     {
  593.         /* OLE requires zeroing [out] parameters */
  594.         *lppNewObj = NULL;
  595.         DebugTraceSc(SOB_QueryInterface, E_NOINTERFACE);
  596.         return ResultFromScode(E_NOINTERFACE);
  597.     }
  598.     /*  We'll do this one. Bump the usage count and return a new pointer. */
  599.     ++lpSOB->lcInit;
  600.     *lppNewObj = lpSOB;
  601.     return hrSuccess;
  602. }
  603. /*
  604.  -  IMAPISTATUS::AddRef
  605.  -
  606.  *  Purpose:
  607.  *      Increment reference count if nonzero.
  608.  *
  609.  *  Parameters:
  610.  *      lpObject            Pointer to object (should be SOB)
  611.  *
  612.  *  Returns:
  613.  *      (ULONG)             Current reference count or zero if
  614.  *                          it doesn't seem to be SOB.
  615.  *
  616.  *  Operation:
  617.  *      Make sure it looks like a SOB, and if so, bump the reference count
  618.  *      and return the result to the caller.
  619.  */
  620. STDMETHODIMP_(ULONG)
  621. SOB_AddRef(LPSOB lpSOB)
  622. {
  623.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  624.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  625.         lpSOB->lcInit == 0 ||
  626.         lpSOB->lpsobMyAddress != lpSOB)
  627.         return 0;
  628.     return ++lpSOB->lcInit;
  629. }
  630. /*
  631.  -  IMAPISTATUS::Release
  632.  -
  633.  *  Purpose:
  634.  *      Decrement lcInit. If it's zero, release the object.
  635.  *
  636.  *  Parameters:
  637.  *      lpObject            Pointer to object (should be SOB)
  638.  *
  639.  *  Returns:
  640.  *      (ULONG)             Current reference count or zero if
  641.  *                          it doesn't seem to be SOB.
  642.  *
  643.  *  Operation:
  644.  *      Make sure it looks like a SOB, and if so, decrement the reference
  645.  *      count. If the count is now zero, deallocate the object.
  646.  *      Return the reference count to the caller.
  647.  */
  648. STDMETHODIMP_(ULONG)
  649. SOB_Release(LPSOB lpSOB)
  650. {
  651.     /*  If it doesn't seem to be an object or refcount is zero, return zero */
  652.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  653.         lpSOB->lcInit == 0 ||
  654.         lpSOB->lpsobMyAddress != lpSOB)
  655.         return 0;
  656.     --lpSOB->lcInit;
  657.     if (lpSOB->lcInit == 0)
  658.     {
  659.         DebugTrace("SOB::Release() freeing SOB.n");
  660.         /* Unlink the status object from the logon object */
  661.         if (FIsValidSession(lpSOB->lpxpl))
  662.             lpSOB->lpxpl->lpXPStatus = NULL;
  663.         lpSOB->lpVtbl = NULL;
  664.         (*lpSOB->FreeBuffer) (lpSOB);
  665.         return 0;
  666.     }
  667.     return lpSOB->lcInit;
  668. }
  669. /*
  670.  -  IMAPISTATUS::GetLastError
  671.  -
  672.  *  Purpose:
  673.  *      Returns a string associated with the last HRESULT returned
  674.  *      by the SOB object.
  675.  *
  676.  *  Parameters:
  677.  *      lpObject            Pointer to object (should be SOB)
  678.  *      hError              HRESULT that caller is interested in
  679.  *      ulFlags             Ignored.
  680.  *      lppszMessage        Pointer to where message pointer should
  681.  *                          be copied.
  682.  *
  683.  *  Returns:
  684.  *      (HRESULT)           E_INVALIDARG if object doesn't look
  685.  *                          like a SOB or if any parameters look
  686.  *                          bad; other errors if any; 0 if successful.
  687.  *      *lppszMessage       Pointer to error message if any, else NULL
  688.  *
  689.  *  Operation:
  690.  *      Confirm the parameters. Compare the HRESULT to our last saved one. If
  691.  *      they match, copy the string into a new buffer and store the pointer
  692.  *      into the location provided by the caller.
  693.  */
  694. STDMETHODIMP
  695. SOB_GetLastError(LPSOB lpSOB,
  696.     HRESULT hError,
  697.     ULONG ulFlags,
  698.     LPMAPIERROR * lppMapiError )
  699. {
  700.     HRESULT hResult = hrSuccess;
  701.     SCODE   sc;
  702.     LPTSTR  pszMessage  = NULL;
  703.     /*  Validate the object and return pointer */
  704.     *lppMapiError = NULL;
  705.     
  706.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  707.         (lpSOB->lcInit == 0) ||
  708.         (lpSOB->lpsobMyAddress != lpSOB) ||
  709.         (IsBadWritePtr(lppMapiError, sizeof(LPMAPIERROR))))
  710.     {
  711.         DebugTraceSc(SOB_GetLastError, E_INVALIDARG);
  712.         return ResultFromScode(E_INVALIDARG);
  713.     }
  714.     if ( ulFlags & ~MAPI_UNICODE )
  715.     {
  716.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  717.     }
  718.     
  719.     if ( ulFlags & MAPI_UNICODE )
  720.     {
  721.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  722.     }
  723.     
  724.     /*  See if we have the message the caller wants. If so,
  725.         make a copy and pass it back. */
  726.     if ((hError != 0) && (hError == lpSOB->hrLastError))
  727.     {
  728.         sc = lpSOB->AllocateBuffer( sizeof( MAPIERROR ), lppMapiError );
  729.         if ( FAILED( sc ) )
  730.         {
  731.             hResult = ResultFromScode( sc );
  732.             goto ret;
  733.         }
  734.         
  735.         memset( *lppMapiError, 0, sizeof( MAPIERROR ) );
  736.         
  737.         (*lppMapiError)->ulVersion = MAPI_ERROR_VERSION;    
  738.     
  739.         hResult = MapScodeSz(GetScode(hError), lpSOB->lpxpl, &pszMessage);
  740.         if ( HR_FAILED( hResult ) )
  741.             goto ret;
  742.         
  743.         sc = lpSOB->AllocateMore( Cbtszsize( pszMessage ), *lppMapiError, 
  744.                 &(*lppMapiError)->lpszError );
  745.         if ( FAILED( sc ) )     
  746.         {
  747.             hResult = ResultFromScode( sc );
  748.             goto ret;
  749.         }
  750.         
  751.         lstrcpy( (*lppMapiError)->lpszError, pszMessage );
  752.     }
  753. ret:
  754.     if ( hResult )
  755.     {
  756.         lpSOB->FreeBuffer( *lppMapiError );
  757.         *lppMapiError = NULL;
  758.     }
  759.         
  760.     lpSOB->FreeBuffer( pszMessage );
  761.     return hResult;
  762. }
  763. /*
  764.  -  IMAPISTATUS::GetProps
  765.  -
  766.  *  Purpose:
  767.  *      Returns the properties listed in the lpPropTagArray.
  768.  *
  769.  *  Parameters:
  770.  *      lpObject            Pointer to object (should be SOB)
  771.  *      lpPropTagArray      List of tags for which values are desired
  772.  *      ulFlags             UNICODE / String8
  773.  *      lpcValues           Pointer: where to store count of values
  774.  *      lppPropArray        Pointer: where to store pointer to values
  775.  *
  776.  *  Returns:
  777.  *      (HRESULT)           E_INVALIDARG if object doesn't look like
  778.  *                          a SOB or if any of the parameters look
  779.  *                          bad; other errors if any; 0 if successful.
  780.  *      *lpcValues          Contains a property count if successful
  781.  *      *lppPropArray       Undefined if not successful; NULL if
  782.  *                          no properties; points to array of
  783.  *                          properties if any.
  784.  *
  785.  *  Operation:
  786.  *      Confirm the parameters. If lpPropTagArray is NULL, use our canned
  787.  *      property list.
  788.  *      Walk through the list, and give the caller any properties in the
  789.  *      list which we can provide. Return count in *lpcValues and pointer to
  790.  *      the array in *lppPropArray.
  791.  */
  792. STDMETHODIMP
  793. SOB_GetProps(LPSOB lpSOB,
  794.     LPSPropTagArray lpPropTagArray,
  795.     ULONG ulFlags,
  796.     ULONG * lpcValues,
  797.     LPSPropValue * lppPropArray)
  798. {
  799.     SCODE sc = 0;
  800.     HRESULT hResult = 0;
  801.     ULONG ulT = 0;
  802.     LPXPL lpxpl = NULL;
  803.     HINSTANCE hInst;
  804.     LPSPropValue lpPropArray = NULL;
  805.     LPSPropValue lpMyIDArray = NULL;
  806.     LPSPropTagArray lpspta = NULL;
  807.     ULONG cb;
  808.     LPTSTR lpsz;
  809.     LPSPropValue lpPropT;
  810.     BOOL fGotMemErrors = FALSE;
  811.     BOOL fMyPTA = TRUE;
  812.     BOOL fNoResourcePath = FALSE;
  813.     /*  Validate the object and the return pointers */
  814.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  815.         lpSOB->lcInit == 0 ||
  816.         lpSOB->lpsobMyAddress != lpSOB)
  817.     {
  818.         hResult = ResultFromScode(E_INVALIDARG);
  819.         goto ret;
  820.     }
  821.     /* Validate the Flags */
  822.     
  823.     if ( ulFlags & ~(MAPI_UNICODE) )
  824.     {
  825.         hResult = ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  826.         goto ret;
  827.     }
  828.     
  829.     if ( ulFlags & MAPI_UNICODE )
  830.     {
  831.         hResult = ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  832.         goto ret;
  833.     }
  834.     
  835.     /*  Validate the return pointers */
  836.     if ((IsBadWritePtr(lpcValues, sizeof(ULONG))) ||
  837.         (IsBadWritePtr(lppPropArray, sizeof(LPSPropValue))))
  838.     {
  839.         hResult = ResultFromScode(E_INVALIDARG);
  840.         goto ret;
  841.     }
  842.     /*  Validate the passed property tag array if any */
  843.     if (lpPropTagArray)
  844.     {
  845.         if ((IsBadReadPtr(lpPropTagArray, CbNewSPropTagArray(0))) ||
  846.             (lpPropTagArray->cValues == 0) ||
  847.             (IsBadReadPtr(&lpPropTagArray->aulPropTag[0],
  848.                     (UINT) (lpPropTagArray->cValues * sizeof(ULONG)))))
  849.         {
  850.             hResult = ResultFromScode(E_INVALIDARG);
  851.             goto ret;
  852.         }
  853.         fMyPTA = FALSE;
  854.         lpspta = lpPropTagArray;
  855.     }
  856.     else
  857.     {
  858.         /*  An array wasn't passed. Use ours. */
  859.         lpspta = (LPSPropTagArray) &sptaStatusRow;
  860.     }
  861.     /*  Parameters have passed muster. Create the property array. */
  862.     lpxpl = lpSOB->lpxpl;
  863.     hInst = lpxpl->lpxppParent->hInst;
  864.     sc = ScCopySessionProps(lpxpl, &lpPropArray, &lpMyIDArray);
  865.     if (FAILED(sc))
  866.         goto ret;
  867.     sc = (*lpSOB->AllocateBuffer) (sizeof(SPropValue) * (lpspta->cValues), (LPVOID *) lppPropArray);
  868.     if (sc)
  869.     {
  870.         hResult = ResultFromScode(sc);
  871.         lpSOB->hrLastError = hResult;
  872.         goto ret;
  873.     }
  874.     /*  Count will always equal input number since we'll either get a
  875.         property value or a PT_ERROR. */
  876.     for (ulT = 0; ulT < lpspta->cValues; ulT++)
  877.     {
  878.         switch (lpspta->aulPropTag[ulT])
  879.         {
  880.         case PR_RESOURCE_METHODS:
  881.             (*lppPropArray)[ulT].ulPropTag = PR_RESOURCE_METHODS;
  882.             (*lppPropArray)[ulT].Value.ul = lpxpl->ulResourceMethods;
  883.             break;
  884.         case PR_PROVIDER_DISPLAY:
  885.             (*lppPropArray)[ulT].ulPropTag = PR_PROVIDER_DISPLAY;
  886.             (*lppPropArray)[ulT].Value.LPSZ = (LPTSTR)MYDISPLAYNAME;
  887.             break;
  888.         case PR_DISPLAY_NAME:
  889.             lpsz = ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ;
  890.             cb = sizeof(TCHAR) * (lstrlen(lpsz) + 1);
  891.             sc = lpSOB->AllocateMore(cb, (LPVOID) *lppPropArray,
  892.                     (LPVOID *) &((*lppPropArray)[ulT].Value.LPSZ));
  893.                 
  894.             if (sc)
  895.             {
  896.                 fGotMemErrors = TRUE;
  897.                 (*lppPropArray)[ulT].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpspta->aulPropTag[ulT]));
  898.                 (*lppPropArray)[ulT].Value.err = sc;
  899.             }
  900.             else
  901.             {
  902.                 (*lppPropArray)[ulT].ulPropTag = PR_DISPLAY_NAME;
  903.                 lstrcpy((*lppPropArray)[ulT].Value.LPSZ, lpsz);
  904.             }
  905.             break;
  906.         case PR_IDENTITY_DISPLAY:
  907.             lpPropT = &(lpMyIDArray[1]);
  908.             Assert(lpPropT);
  909.             Assert(lpPropT->ulPropTag == PR_SENDER_NAME);
  910.             cb = sizeof(TCHAR) * (lstrlen(lpPropT->Value.LPSZ) + 1);
  911.             sc = lpSOB->AllocateMore(cb, (LPVOID) * lppPropArray,
  912.                     (LPVOID *) &((*lppPropArray)[ulT].Value.LPSZ));
  913.             if (sc)
  914.             {
  915.                 fGotMemErrors = TRUE;
  916.                 (*lppPropArray)[ulT].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpspta->aulPropTag[ulT]));
  917.                 (*lppPropArray)[ulT].Value.err = sc;
  918.             }
  919.             else
  920.             {
  921.                 (*lppPropArray)[ulT].ulPropTag = PR_IDENTITY_DISPLAY;
  922.                 lstrcpy((*lppPropArray)[ulT].Value.LPSZ, lpPropT->Value.LPSZ);
  923.             }
  924.             break;
  925.         case PR_IDENTITY_ENTRYID:
  926.             lpPropT = &(lpMyIDArray[0]);
  927.             Assert(lpPropT);
  928.             Assert(lpPropT->ulPropTag == PR_SENDER_ENTRYID);
  929.             cb = lpPropT->Value.bin.cb;
  930.             Assert(cb);
  931.             Assert(!IsBadReadPtr(lpPropT->Value.bin.lpb, (UINT)cb));
  932.             sc = lpSOB->AllocateMore(cb, (LPVOID) *lppPropArray,
  933.                     (LPVOID *) &((*lppPropArray)[ulT].Value.bin.lpb));
  934.                     
  935.             if (sc)
  936.             {
  937.                 fGotMemErrors = TRUE;
  938.                 (*lppPropArray)[ulT].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpspta->aulPropTag[ulT]));
  939.                 (*lppPropArray)[ulT].Value.err = sc;
  940.             }
  941.             else
  942.             {
  943.                 (*lppPropArray)[ulT].ulPropTag = PR_IDENTITY_ENTRYID;
  944.                 (*lppPropArray)[ulT].Value.bin.cb = cb;
  945.                 if (cb)
  946.                     memcpy((*lppPropArray)[ulT].Value.bin.lpb,
  947.                             lpPropT->Value.bin.lpb, (UINT)cb);
  948.             }
  949.             break;
  950.         case PR_IDENTITY_SEARCH_KEY:
  951.             lpPropT = &(lpMyIDArray[2]);
  952.             Assert(lpPropT);
  953.             Assert(lpPropT->ulPropTag == PR_SENDER_SEARCH_KEY);
  954.             cb = lpPropT->Value.bin.cb;
  955.             Assert(cb);
  956.             Assert(!IsBadReadPtr(lpPropT->Value.bin.lpb, (UINT)cb));
  957.             sc = lpSOB->AllocateMore(cb, (LPVOID) *lppPropArray,
  958.                     (LPVOID *) &((*lppPropArray)[ulT].Value.bin.lpb));
  959.                     
  960.             if (sc)
  961.             {
  962.                 fGotMemErrors = TRUE;
  963.                 (*lppPropArray)[ulT].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpspta->aulPropTag[ulT]));
  964.                 (*lppPropArray)[ulT].Value.err = sc;
  965.             }
  966.             else
  967.             {
  968.                 (*lppPropArray)[ulT].ulPropTag = PR_IDENTITY_SEARCH_KEY;
  969.                 (*lppPropArray)[ulT].Value.bin.cb = cb;
  970.                 if (cb)
  971.                     memcpy((*lppPropArray)[ulT].Value.bin.lpb,
  972.                             lpPropT->Value.bin.lpb, (UINT)cb);
  973.             }
  974.             break;
  975.         case PR_STATUS_CODE:
  976.             (*lppPropArray)[ulT].ulPropTag = PR_STATUS_CODE;
  977.             (*lppPropArray)[ulT].Value.ul = lpxpl->ulTransportStatus;
  978.             break;
  979.         case PR_STATUS_STRING:
  980.             lpsz = NULL;
  981.             if (sc = GetScode(HrLoadStatusString(lpxpl, *lppPropArray, &lpsz)))
  982.             {
  983.                 fGotMemErrors = TRUE;
  984.                 (*lppPropArray)[ulT].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpspta->aulPropTag[ulT]));
  985.                 (*lppPropArray)[ulT].Value.err = sc;
  986.             }
  987.             else
  988.             {
  989.                 (*lppPropArray)[ulT].ulPropTag = PR_STATUS_STRING;
  990.                 (*lppPropArray)[ulT].Value.LPSZ = lpsz;
  991.             }
  992.             break;
  993.         case PR_RESOURCE_PATH:
  994.             lpsz = (LPVOID) ArrayIndex(PR_SAMPLE_DIRECTORY, lpPropArray).Value.LPSZ;
  995.             Assert(lpsz);
  996.             cb = (lstrlen(lpsz) + 1) * sizeof(TCHAR);
  997.             if (cb == sizeof(TCHAR))
  998.             {
  999.                 if (fMyPTA)
  1000.                 {
  1001.                     fNoResourcePath = TRUE;
  1002.                 }
  1003.                 else
  1004.                 {
  1005.                     (*lppPropArray)[ulT].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_RESOURCE_PATH));
  1006.                     (*lppPropArray)[ulT].Value.err = MAPI_E_NOT_FOUND;
  1007.                 }
  1008.                 break;
  1009.             }
  1010.             sc = (*lpSOB->AllocateMore) (cb, (LPVOID) * lppPropArray, (LPVOID *) &((*lppPropArray)[ulT].Value.LPSZ));
  1011.             if (sc)
  1012.             {
  1013.                 fGotMemErrors = TRUE;
  1014.                 (*lppPropArray)[ulT].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_RESOURCE_PATH));
  1015.                 (*lppPropArray)[ulT].Value.err = sc;
  1016.             }
  1017.             else
  1018.             {
  1019.                 (*lppPropArray)[ulT].ulPropTag = PR_RESOURCE_PATH;
  1020.                 lstrcpy((*lppPropArray)[ulT].Value.LPSZ, lpsz);
  1021.             }
  1022.             break;
  1023.         case PR_OBJECT_TYPE:
  1024.             (*lppPropArray)[ulT].ulPropTag = PR_OBJECT_TYPE;
  1025.             (*lppPropArray)[ulT].Value.ul = MAPI_STATUS;
  1026.             break;
  1027.         default:
  1028.             (*lppPropArray)[ulT].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpspta->aulPropTag[ulT]));
  1029.             (*lppPropArray)[ulT].Value.err = MAPI_E_NOT_FOUND;
  1030.             hResult = ResultFromScode(MAPI_W_ERRORS_RETURNED);
  1031.             lpSOB->hrLastError = hResult;
  1032.             break;
  1033.         }
  1034.     }
  1035.     /*  Store number of properties we're returning, i.e., the number
  1036.         asked for (with possible errors). */
  1037.     if (fMyPTA && fNoResourcePath)
  1038.         *lpcValues = lpspta->cValues - 1;
  1039.     else    
  1040.         *lpcValues = lpspta->cValues;
  1041.     if (fGotMemErrors)
  1042.     {
  1043.         hResult = ResultFromScode(MAPI_W_ERRORS_RETURNED);
  1044.         lpSOB->hrLastError = hResult;
  1045.     }
  1046. ret:
  1047.     if(lpxpl)
  1048.     {
  1049.         lpxpl->FreeBuffer(lpPropArray);
  1050.         lpxpl->FreeBuffer(lpMyIDArray);
  1051.     }
  1052.     DebugTraceResult(SOB_GetProps, hResult);
  1053.     return hResult;
  1054. }
  1055. /*
  1056.  -  IMAPISTATUS::GetPropList
  1057.  -
  1058.  *  Purpose:
  1059.  *
  1060.  *  Parameters:
  1061.  *      lpObject            Pointer to object (should be SOB)
  1062.  *      ulFlags             UNICODE / String8
  1063.  *      lppPropTagArray     Pointer: where to store pointer to tags
  1064.  *
  1065.  *  Returns:
  1066.  *      (HRESULT)           E_INVALIDARG if object doesn't look like a
  1067.  *                          SOB or if any of the parameters look bad;
  1068.  *                          other errors if any; 0 if successful.
  1069.  *      *lppPropArray       Undefined if not successful; points to
  1070.  *                          array of property tags otherwise.
  1071.  *
  1072.  *  Operation:
  1073.  *      Validate parameters; Create enough memory for out property tag list,
  1074.  *      copy the list into it and do so. Return the new list into the caller's
  1075.  *      pointer.
  1076.  */
  1077. STDMETHODIMP
  1078. SOB_GetPropList(LPSOB lpSOB,
  1079.     ULONG ulFlags,
  1080.     LPSPropTagArray * lppPropTagArray)
  1081. {
  1082.     SCODE sc;
  1083.     HRESULT hResult = 0;
  1084.     LPXPL lpxpl;
  1085.     ULONG ulArraySize;
  1086.     ULONG cActualProps;
  1087.     /* Validate the Flags */
  1088.     
  1089.     if ( ulFlags & ~(MAPI_UNICODE) )
  1090.     {
  1091.         hResult = ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  1092.         goto ret;
  1093.     }
  1094.     
  1095.     if ( ulFlags & MAPI_UNICODE )
  1096.     {
  1097.         hResult = ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  1098.         goto ret;
  1099.     }
  1100.     
  1101.     /*  Validate the object and the return pointers */
  1102.     if ((IsBadWritePtr(lpSOB, sizeof(SOB))) ||
  1103.         (lpSOB->lcInit == 0) ||
  1104.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1105.         (IsBadWritePtr(lppPropTagArray, sizeof(LPSPropTagArray))))
  1106.     {
  1107.         hResult = ResultFromScode(E_INVALIDARG);
  1108.         goto ret;
  1109.     }
  1110.     lpxpl = lpSOB->lpxpl;
  1111.     /* If WGAP Directory is empty, don't tell them about this property. */
  1112.     cActualProps = sptaStatusRow.cValues;
  1113.     if (lstrlen((LPTSTR) ArrayIndex(PR_SAMPLE_DIRECTORY, lpxpl->lpPropArray).Value.LPSZ))
  1114.         ulArraySize = CbNewSPropTagArray(sptaStatusRow.cValues);
  1115.     else
  1116.     {
  1117.         /* Adjust for removing a prop tag */
  1118.         cActualProps--;
  1119.         ulArraySize = CbNewSPropTagArray(sptaStatusRow.cValues - 1);
  1120.     }
  1121.     /*  Allocate the required amount of memory */
  1122.     sc = (*lpSOB->AllocateBuffer) (ulArraySize, (LPVOID *) lppPropTagArray);
  1123.     if (sc)
  1124.     {
  1125.         hResult = ResultFromScode(sc);
  1126.         lpSOB->hrLastError = hResult;
  1127.         goto ret;
  1128.     }
  1129.     /*  Copy the contents of our canned property tag array into the buffer */
  1130.     if (ulArraySize)
  1131.     {
  1132.         memcpy(*lppPropTagArray, &sptaStatusRow, (size_t) ulArraySize);
  1133.         (*lppPropTagArray)->cValues = cActualProps;
  1134.     }
  1135. ret:
  1136.     DebugTraceResult(SOB_GetPropList, hResult);
  1137.     return hResult;
  1138. }
  1139. /*
  1140.  -  SOB_SettingsDialog
  1141.  -
  1142.  *  Purpose:
  1143.  *      This routine will invoke the Transports Logon dialog to allow
  1144.  *      the user to change the Logon properties.  The lpPropArray on the
  1145.  *      current session will be updated.
  1146.  *
  1147.  *  Parameters:
  1148.  *      lpSOB               The status object for this transport session
  1149.  *      ulUIParam           The HWnd of the caller (may be null)
  1150.  *      ulFlags             If UI_READONLY will not update the lpPropArray
  1151.  *
  1152.  *  Returns:
  1153.  *      hResult             Indicating success/failure.
  1154.  *
  1155.  *  Operation:
  1156.  *
  1157.  */
  1158. STDMETHODIMP
  1159. SOB_SettingsDialog(LPSOB lpSOB,
  1160.     ULONG ulUIParam,
  1161.     ULONG ulFlags)
  1162. {
  1163.     HRESULT hResult = hrSuccess;
  1164.     SCODE sc = S_OK;
  1165.     LPSPropValue lpMyIDArray = NULL;
  1166.     LPVOID lpvT, lpvT2;
  1167.     ULONG ulCount = MAX_LOGON_PROPERTIES - TEMP_LOGON_PROPERTIES;
  1168.     ULONG ulT;
  1169.     LPXPL lpxpl = lpSOB->lpxpl;
  1170.     LPSPropValue lpPropArray = NULL;
  1171.     LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
  1172.     LPPROFSECT lpProfileObj = NULL;
  1173.     XPDLG XPDialog;
  1174.     BOOL fNeedUI = TRUE;
  1175.     BOOL fInCS = FALSE;
  1176.     if ((IsBadReadPtr(lpSOB, sizeof(SOB))) ||
  1177.         (lpSOB->lcInit == 0) ||
  1178.         (lpSOB->lpsobMyAddress != lpSOB))
  1179.     {
  1180.         hResult = ResultFromScode(E_INVALIDARG);
  1181.         goto ret;
  1182.     }
  1183.     if (ulFlags & ~UI_READONLY)
  1184.     {
  1185.         hResult = ResultFromScode(E_INVALIDARG);
  1186.         goto ret;
  1187.     }
  1188.     /* Get the Critical Section */
  1189.     EnterCriticalSection(&(lpxpl->lpxppParent->csTransport));
  1190.     fInCS = TRUE;
  1191.     sc = ScCopySessionProps(lpxpl, &lpPropArray, NULL);
  1192.     if (FAILED(sc))
  1193.         goto ret;
  1194.     /* Fill in the logon UI structure */
  1195.     XPDialog.hInst = lpxpl->lpxppParent->hInst;
  1196.     XPDialog.hwnd = (HWND) ulUIParam;
  1197.     XPDialog.lppPropArray = &lpPropArray;
  1198.     XPDialog.lpPTArray = (LPSPropTagArray) &sptLogonArray;
  1199.     XPDialog.AllocateBuffer = lpxpl->AllocateBuffer;
  1200.     XPDialog.AllocateMore = lpxpl->AllocateMore;
  1201.     XPDialog.FreeBuffer = lpxpl->FreeBuffer;
  1202.     XPDialog.lpMalloc = lpxpl->lpxppParent->lpMalloc;
  1203.     XPDialog.lpMAPISup = lpxpl->lpMAPISup;
  1204.     XPDialog.fLogon = FALSE;
  1205.     XPDialog.ulFlags = ulFlags;
  1206.     while (fNeedUI)
  1207.     {
  1208.         sc = ScDoLogonDlg(&XPDialog);
  1209.         if (FAILED(sc))
  1210.         {
  1211.             DebugTraceSc(Logon UI activation, sc);
  1212.             goto ret;
  1213.         }
  1214.         if (lpPropArray)
  1215.         {
  1216.             /* Got a prop array, make sure everything in it is good */
  1217.             for (ulT = 0; ulT < ulCount; ulT++)
  1218.             {
  1219.                 if (PROP_TYPE((lpPropArray)[ulT].ulPropTag) == PT_ERROR)
  1220.                 {
  1221.                     DebugTrace("Property %x not available.n", PROP_ID((lpPropArray)[ulT].ulPropTag));
  1222.                     sc = MAPI_E_NO_ACCESS;
  1223.                 }
  1224.             }
  1225.         }
  1226.         else
  1227.             sc = MAPI_E_NO_ACCESS;
  1228.         if (sc)
  1229.         {
  1230.             DebugTraceSc(Logon UI returning, sc);
  1231.             goto ret;
  1232.         }
  1233.         /* Do some simple validation of the Logon Props */
  1234.         sc = ScCheckLogonProps(&XPDialog, TRUE);
  1235.         if (sc == MAPI_E_USER_CANCEL)
  1236.             goto ret;
  1237.         else if (sc == MAPI_E_INVALID_PARAMETER)
  1238.             continue;
  1239.         else
  1240.             fNeedUI = FALSE;
  1241.         /* If we get here, everything is fine and we can proceed. But first
  1242.            we should write the properties out if the user is willing. */
  1243.         ulT = ArrayIndex(PR_SAMPLE_FLAGS, lpPropArray).Value.ul;
  1244.         if ((ulT & PR_SAMPLE_FLAG_SAVE_DATA))
  1245.         {
  1246.             /* Try to open our profile. */
  1247.             hResult = lpMAPISup->lpVtbl->OpenProfileSection(lpMAPISup,
  1248.                 (LPMAPIUID) NULL, MAPI_MODIFY, &lpProfileObj);
  1249.             if (HR_FAILED(hResult))
  1250.             {
  1251.               DebugTraceResult(MAPISUP: :OpenProfileSection, hResult);
  1252.                 goto ret;
  1253.             }
  1254.             hResult = lpProfileObj->lpVtbl->SetProps(lpProfileObj,
  1255.                 ulCount, lpPropArray, NULL);
  1256.             if (HR_FAILED(hResult))
  1257.             {
  1258.               DebugTraceResult(PROFSECT: :SetProps, hResult);
  1259.                 goto ret;
  1260.             }
  1261.         }
  1262.     }
  1263.     /* Allocate initial property array for transport ID. */
  1264.     sc = (*lpxpl->AllocateBuffer) (sizeof(SPropValue) * NUM_SENDER_PROPS,
  1265.         (LPVOID *) &lpMyIDArray);
  1266.     if (sc)
  1267.     {
  1268.         DebugTraceSc(Sender ID property array allocation, sc);
  1269.         goto ret;
  1270.     }
  1271.     memset(lpMyIDArray, 0, sizeof(SPropValue) * NUM_SENDER_PROPS);
  1272.     /* Create the One-Off directly into the property value structure. */
  1273.     lpMyIDArray[0].ulPropTag = PR_SENDER_ENTRYID;
  1274.     hResult = lpMAPISup->lpVtbl->CreateOneOff(lpMAPISup,
  1275.         ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ,
  1276.         ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ,
  1277.         ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ,
  1278.         fMapiUnicode,
  1279.         &lpMyIDArray[0].Value.bin.cb,
  1280.         (LPENTRYID *) &lpMyIDArray[0].Value.bin.lpb);
  1281.     if (hResult)
  1282.     {
  1283.       DebugTraceResult(MAPISUP: :CreateOneOff, hResult);
  1284.         lpMyIDArray[0].Value.bin.lpb = NULL;
  1285.         goto ret;
  1286.     }
  1287.     /* Create the PR_SENDER_NAME property value. */
  1288.     lpvT2 = ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ;
  1289.     ulT = lstrlen((LPCTSTR) lpvT2) + 1;
  1290.     sc = (*lpxpl->AllocateMore) (ulT, (LPVOID) lpMyIDArray,
  1291.         (LPVOID *) &lpvT);
  1292.     if (sc)
  1293.     {
  1294.         DebugTraceSc(User Display Name allocation, sc);
  1295.         goto ret;
  1296.     }
  1297.     lstrcpy((LPTSTR) lpvT, (LPCTSTR) lpvT2);
  1298.     lpMyIDArray[1].ulPropTag = PR_SENDER_NAME;
  1299.     lpMyIDArray[1].Value.LPSZ = (LPTSTR) lpvT;
  1300.     /* Create the PR_SENDER_SEARCH_KEY value. */
  1301.     lpMyIDArray[2].ulPropTag = PR_SENDER_SEARCH_KEY;
  1302.     /* Size of property = type plus colon plus address plus null. */
  1303.     ulT = 2 + lstrlen(ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ) +
  1304.         lstrlen(ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ);
  1305.     sc = (*lpxpl->AllocateMore) (ulT, (LPVOID) lpMyIDArray,
  1306.         (LPVOID *) &lpvT);
  1307.     if (sc)
  1308.     {
  1309.         DebugTraceSc(User Search Key allocation, sc);
  1310.         goto ret;
  1311.     }
  1312.     /* PR_SENDER_SEARCH_KEY is "TYPE:ADDRESS" folded to uppercase. */
  1313.     wsprintf((LPTSTR) lpvT, TEXT("%s:%s"),
  1314.         (ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ),
  1315.         (ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ));
  1316.     CharUpperBuff((LPTSTR) lpvT, (UINT)-- ulT);
  1317.     lpMyIDArray[2].Value.bin.cb = sizeof(TCHAR) * (1 + lstrlen((LPTSTR) lpvT));
  1318.     lpMyIDArray[2].Value.bin.lpb = lpvT;
  1319.     /* Replace the original PropArray with the new one. */
  1320.     lpxpl->FreeBuffer(lpxpl->lpPropArray);
  1321.     lpxpl->lpPropArray = lpPropArray;
  1322.     /* Now, free the original User Display Name and Entry-ID */
  1323.     if (lpxpl->lpMyIDArray)
  1324.     {
  1325.         (*lpxpl->FreeBuffer) (lpxpl->lpMyIDArray[0].Value.bin.lpb);
  1326.         (*lpxpl->FreeBuffer) (lpxpl->lpMyIDArray);
  1327.     }
  1328.     lpxpl->lpMyIDArray = lpMyIDArray;
  1329.     hResult = HrBuildTransportStatus(lpxpl, STATUSROW_UPDATE);
  1330. ret:
  1331.     /* Release the Critical Section. */
  1332.     if (fInCS)
  1333.         LeaveCriticalSection(&(lpxpl->lpxppParent->csTransport));
  1334.     UlRelease(lpProfileObj);
  1335.     if (lpPropArray && (lpxpl->lpPropArray != lpPropArray))
  1336.         lpxpl->FreeBuffer(lpPropArray);
  1337.     if (lpMyIDArray && (lpxpl->lpMyIDArray != lpMyIDArray))
  1338.     {
  1339.         (*lpxpl->FreeBuffer) (lpMyIDArray[0].Value.bin.lpb);
  1340.         (*lpxpl->FreeBuffer) (lpMyIDArray);
  1341.     }
  1342.     if (!hResult && sc)
  1343.         hResult = ResultFromScode(sc);
  1344.     DebugTraceResult(SOB_SettingsDialog, hResult);
  1345.     return hResult;
  1346. }
  1347. /*
  1348.  -  SOB_FlushQueues
  1349.  -
  1350.  *  Purpose:
  1351.  *      Logon object method used by Spooler if FlushQueues is called on
  1352.  *      the spooler status object.
  1353.  *
  1354.  *  Parameters:
  1355.  *      lpSOB               This pointer for Status Object
  1356.  *      ulUIParam           Window handle
  1357.  *      cbTargetTransport   Count of bytes in Entryid. Zero.
  1358.  *      lpTargetTransport   Entryid of transport. NULL.
  1359.  *      ulFlags
  1360.  *
  1361.  *  Returns:
  1362.  *      (HRESULT)           E_INVALIDARG if object doesn't
  1363.  *                          look like a XPL; MAPI_E_NO_SUPPORT
  1364.  *                          otherwise.
  1365.  *
  1366.  *  Operation:
  1367.  *      Validate the object pointer.
  1368.  */
  1369. STDMETHODIMP
  1370. SOB_FlushQueues(LPSOB lpSOB,
  1371.     ULONG ulUIParam,
  1372.     ULONG cbTargetTransport,
  1373.     LPENTRYID lpTargetTransport,
  1374.     ULONG ulFlags)
  1375. {
  1376.     HRESULT hResult;
  1377.     if ((IsBadReadPtr(lpSOB, sizeof(SOB))) ||
  1378.         (lpSOB->lcInit == 0) ||
  1379.         (lpSOB->lpsobMyAddress != lpSOB))
  1380.     {
  1381.         return ResultFromScode(E_INVALIDARG);
  1382.     }
  1383.     if (ulFlags & FLUSH_UPLOAD)
  1384.         lpSOB->lpxpl->ulTransportStatus |= STATUS_OUTBOUND_FLUSH;
  1385.     if (ulFlags & FLUSH_DOWNLOAD)
  1386.         lpSOB->lpxpl->ulTransportStatus |= STATUS_INBOUND_FLUSH;
  1387.     hResult = HrUpdateTransportStatus(lpSOB->lpxpl, 0L);
  1388.     return hResult;
  1389. }
  1390. /*
  1391.  -  Unimplemented functions. Stubbed to give access or NYI.
  1392.  -
  1393.  */
  1394. STDMETHODIMP
  1395. SOB_SaveChanges(LPSOB lpSOB,
  1396.     ULONG ulFlags)
  1397. {
  1398.     /*  Do parameter validation */
  1399.     if (IsBadReadPtr(lpSOB, sizeof(SOB)) ||
  1400.         (lpSOB->lcInit == 0) ||
  1401.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1402.         (ulFlags & ~(KEEP_OPEN_READWRITE | KEEP_OPEN_READONLY | FORCE_SAVE)))
  1403.     {
  1404.         DebugTraceSc(SOB_SaveChanges, E_INVALIDARG);
  1405.         return ResultFromScode(E_INVALIDARG);
  1406.     }
  1407.     
  1408.     DebugTraceSc(SOB_SaveChanges, MAPI_E_NO_ACCESS);
  1409.     return (ResultFromScode(MAPI_E_NO_ACCESS));
  1410. }
  1411. STDMETHODIMP
  1412. SOB_OpenProperty(LPSOB lpSOB,
  1413.     ULONG ulPropTag,
  1414.     LPCIID lpiid,
  1415.     ULONG ulInterfaceOptions,
  1416.     ULONG ulFlags,
  1417.     LPUNKNOWN * lppUnk)
  1418. {
  1419.     /*  Do parameter validation */
  1420.     if (IsBadReadPtr(lpSOB, sizeof(SOB)) ||
  1421.         (lpSOB->lcInit == 0) ||
  1422.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1423.         (!lpiid || IsBadReadPtr(lpiid, sizeof(IID))) ||
  1424.         (ulFlags & ~(MAPI_CREATE | MAPI_MODIFY | MAPI_DEFERRED_ERRORS)) ||
  1425.         (!lppUnk || IsBadWritePtr(lppUnk, sizeof(LPVOID))))
  1426.     {
  1427.         DebugTraceSc(SOB_OpenProperty, E_INVALIDARG);
  1428.         return ResultFromScode(E_INVALIDARG);
  1429.     }
  1430.     
  1431.     if ( ulInterfaceOptions & ~(MAPI_UNICODE) )
  1432.     {
  1433.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  1434.     }
  1435.     
  1436.     if ( ulInterfaceOptions & MAPI_UNICODE )
  1437.     {
  1438.         return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
  1439.     }
  1440.     
  1441.     DebugTraceSc(SOB_OpenProperty, MAPI_E_NO_SUPPORT);
  1442.     return (ResultFromScode(MAPI_E_NO_SUPPORT));
  1443. }
  1444. STDMETHODIMP
  1445. SOB_SetProps(LPSOB lpSOB,
  1446.     ULONG cValues,
  1447.     LPSPropValue lpPropArray,
  1448.     LPSPropProblemArray * lppProblems)
  1449. {
  1450.     /*  Do parameter validation */
  1451.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  1452.         (lpSOB->lcInit == 0) ||
  1453.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1454.         (cValues && IsBadReadPtr(lpPropArray, (UINT)cValues*sizeof(SPropValue))) ||
  1455.         (IsBadWritePtr(lppProblems, sizeof(LPSPropProblemArray))))
  1456.     {
  1457.         DebugTraceSc(SOB_SetProps, E_INVALIDARG);
  1458.         return ResultFromScode(E_INVALIDARG);
  1459.     }
  1460.     DebugTraceSc(SOB_SetProps, MAPI_E_NO_ACCESS);
  1461.     return (ResultFromScode(MAPI_E_NO_ACCESS));
  1462. }
  1463. STDMETHODIMP
  1464. SOB_DeleteProps(LPSOB lpSOB,
  1465.     LPSPropTagArray lpPropTagArray,
  1466.     LPSPropProblemArray * lppProblems)
  1467. {
  1468.     /*  Do parameter validation */
  1469.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  1470.         (lpSOB->lcInit == 0) ||
  1471.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1472.         (!lpPropTagArray) ||
  1473.         (IsBadReadPtr(lpPropTagArray, (UINT)lpPropTagArray->cValues*sizeof(ULONG))) ||
  1474.         (IsBadWritePtr(lppProblems, sizeof(LPSPropProblemArray))))
  1475.     {
  1476.         DebugTraceSc(SOB_DeleteProps, E_INVALIDARG);
  1477.         return ResultFromScode(E_INVALIDARG);
  1478.     }
  1479.     DebugTraceSc(SOB_DeleteProps, MAPI_E_NO_ACCESS);
  1480.     return (ResultFromScode(MAPI_E_NO_ACCESS));
  1481. }
  1482. STDMETHODIMP
  1483. SOB_CopyTo(LPSOB lpSOB,
  1484.     ULONG ciidExclude,
  1485.     LPCIID rgiidExclude,
  1486.     LPSPropTagArray lpExcludeProps,
  1487.     ULONG ulUIParam,
  1488.     LPMAPIPROGRESS lpProgress,
  1489.     LPCIID lpInterface,
  1490.     LPVOID lpDestObj,
  1491.     ULONG ulFlags,
  1492.     LPSPropProblemArray * lppProblems)
  1493. {
  1494.     /*  Do parameter validation */
  1495.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  1496.         (lpSOB->lcInit == 0) ||
  1497.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1498.         (ciidExclude && (!rgiidExclude || IsBadReadPtr(rgiidExclude, (UINT)ciidExclude*sizeof(IID)))) ||
  1499.         (lpExcludeProps && IsBadReadPtr(lpExcludeProps, (UINT)lpExcludeProps->cValues*sizeof(ULONG))) ||
  1500.         (lpProgress && IsBadReadPtr(lpProgress, sizeof(LPMAPIPROGRESS))) ||
  1501.         (!lpInterface || IsBadReadPtr(lpInterface, sizeof(IID))) ||
  1502.         (IsBadReadPtr(lpDestObj, sizeof(LPVOID))) ||
  1503.         (ulFlags & ~(MAPI_MOVE | MAPI_NOREPLACE | MAPI_DIALOG | MAPI_DECLINE_OK)) ||
  1504.         (IsBadWritePtr(lppProblems, sizeof(LPSPropProblemArray))))
  1505.     {
  1506.         DebugTraceSc(SOB_CopyTo, E_INVALIDARG);
  1507.         return ResultFromScode(E_INVALIDARG);
  1508.     }
  1509.     DebugTraceSc(SOB_CopyTo, MAPI_E_NO_SUPPORT);
  1510.     return (ResultFromScode(MAPI_E_NO_SUPPORT));
  1511. }
  1512. STDMETHODIMP
  1513. SOB_CopyProps(LPSOB lpSOB,
  1514.     LPSPropTagArray lpIncludeProps,
  1515.     ULONG ulUIParam,
  1516.     LPMAPIPROGRESS lpProgress,
  1517.     LPCIID lpInterface,
  1518.     LPVOID lpDestObj,
  1519.     ULONG ulFlags,
  1520.     LPSPropProblemArray * lppProblems)
  1521. {
  1522.     /*  Do parameter validation */
  1523.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  1524.         (lpSOB->lcInit == 0) ||
  1525.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1526.         (lpIncludeProps && IsBadReadPtr(lpIncludeProps, (UINT)lpIncludeProps->cValues*sizeof(ULONG))) ||
  1527.         (lpProgress && IsBadReadPtr(lpProgress, sizeof(LPMAPIPROGRESS))) ||
  1528.         (!lpInterface || IsBadReadPtr(lpInterface, sizeof(IID))) ||
  1529.         (IsBadReadPtr(lpDestObj, sizeof(LPVOID))) ||
  1530.         (ulFlags & ~(MAPI_MOVE | MAPI_NOREPLACE | MAPI_DIALOG | MAPI_DECLINE_OK)) ||
  1531.         (IsBadWritePtr(lppProblems, sizeof(LPSPropProblemArray))))
  1532.     {
  1533.         DebugTraceSc(SOB_CopyProps, E_INVALIDARG);
  1534.         return ResultFromScode(E_INVALIDARG);
  1535.     }
  1536.     DebugTraceSc(SOB_CopyProps, MAPI_E_NO_SUPPORT);
  1537.     return (ResultFromScode(MAPI_E_NO_SUPPORT));
  1538. }
  1539. STDMETHODIMP
  1540. SOB_GetNamesFromIDs(LPSOB lpSOB,
  1541.     LPSPropTagArray * lppPropTags,
  1542.     LPGUID lpPropSet,
  1543.     ULONG ulFlags,
  1544.     ULONG * lpcPropNames,
  1545.     LPMAPINAMEID * * lpppPropNames)
  1546. {
  1547.     /*  Do parameter validation */
  1548.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  1549.         (lpSOB->lcInit == 0) ||
  1550.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1551.         (IsBadReadPtr(lppPropTags, sizeof(LPSPropTagArray))) ||
  1552.         (IsBadReadPtr(lpPropSet, sizeof(GUID))) ||
  1553.         (IsBadWritePtr(lpcPropNames, sizeof(ULONG))) ||
  1554.         (IsBadWritePtr(lpppPropNames, sizeof(LPVOID))))
  1555.     {
  1556.         DebugTraceSc(SOB_GetNamesFromIDs, E_INVALIDARG);
  1557.         return ResultFromScode(E_INVALIDARG);
  1558.     }
  1559.     DebugTraceSc(SOB_GetNamesFromIDs, MAPI_E_NO_SUPPORT);
  1560.     return (ResultFromScode(MAPI_E_NO_SUPPORT));
  1561. }
  1562. STDMETHODIMP
  1563. SOB_GetIDsFromNames(LPSOB lpSOB,
  1564.     ULONG cPropNames,
  1565.     LPMAPINAMEID * lppPropNames,
  1566.     ULONG ulFlags,
  1567.     LPSPropTagArray * lppPropTags)
  1568. {
  1569.     /*  Do parameter validation */
  1570.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  1571.         (lpSOB->lcInit == 0) ||
  1572.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1573.         (!lppPropNames || IsBadReadPtr(lppPropNames, (UINT)cPropNames*sizeof(LPMAPINAMEID))) ||
  1574.         (IsBadReadPtr(lppPropTags, sizeof(LPSPropTagArray))))
  1575.     {
  1576.         DebugTraceSc(SOB_GetIDsFromNames, E_INVALIDARG);
  1577.         return ResultFromScode(E_INVALIDARG);
  1578.     }
  1579.     DebugTraceSc(SOB_GetIDsFromNames, MAPI_E_NO_SUPPORT);
  1580.     return (ResultFromScode(MAPI_E_NO_SUPPORT));
  1581. }
  1582. STDMETHODIMP
  1583. SOB_ChangePassword(LPSOB lpSOB,
  1584.     LPTSTR lpOldPass,
  1585.     LPTSTR lpNewPass,
  1586.     ULONG ulFlags)
  1587. {
  1588.     /*  Do parameter validation */
  1589.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  1590.         (lpSOB->lcInit == 0) ||
  1591.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1592.         (IsBadStringPtr(lpOldPass, MAX_STRING)) ||
  1593.         (IsBadStringPtr(lpNewPass, MAX_STRING)) ||
  1594.         (ulFlags & ~MAPI_UNICODE))
  1595.     {
  1596.         DebugTraceSc(SOB_ChangePassword, E_INVALIDARG);
  1597.         return ResultFromScode(E_INVALIDARG);
  1598.     }
  1599.     
  1600.     if ( ulFlags & MAPI_UNICODE )
  1601.     {
  1602.         DebugTraceSc(SOB_ChangePassword, MAPI_E_BAD_CHARWIDTH);
  1603.         return ResultFromScode( MAPI_E_BAD_CHARWIDTH );
  1604.     }
  1605.               
  1606.     DebugTraceSc(SOB_ChangePassword, MAPI_E_NO_SUPPORT);
  1607.     return (ResultFromScode(MAPI_E_NO_SUPPORT));
  1608. }
  1609. STDMETHODIMP
  1610. SOB_ValidateState(LPSOB lpSOB,
  1611.     ULONG ulUIParam,
  1612.     ULONG ulFlags)
  1613. {
  1614.     ULONG ulFlagMask =  REFRESH_XP_HEADER_CACHE | 
  1615.                         PROCESS_XP_HEADER_CACHE | 
  1616.                         FORCE_XP_CONNECT | 
  1617.                         FORCE_XP_DISCONNECT | 
  1618.                         SUPPRESS_UI;
  1619.                         
  1620.     /*  Do parameter validation */
  1621.     if (IsBadWritePtr(lpSOB, sizeof(SOB)) ||
  1622.         (lpSOB->lcInit == 0) ||
  1623.         (lpSOB->lpsobMyAddress != lpSOB) ||
  1624.         (ulFlags & (~(ulFlagMask))))
  1625.     {
  1626.         DebugTraceSc(SOB_ValidateState, E_INVALIDARG);
  1627.         return ResultFromScode(E_INVALIDARG);
  1628.     }
  1629.     DebugTraceSc(SOB_ValidateState, MAPI_E_NO_SUPPORT);
  1630.     return (ResultFromScode(MAPI_E_NO_SUPPORT));
  1631. }
  1632. /* The following array maps a string identifier (IDS) to status code  */
  1633. /* (SCODE).  The order of SCODEs in the array has an external         */
  1634. /* dependency:  the order of elements in the array is dictated by     */
  1635. /* the IDS definitions in xpresrc.h.  This implicit association must  */
  1636. /* be maintained for the strings associated with string identifiers   */
  1637. /* to make sense.  Thus, if either this structure or the rc.h defines */
  1638. /* changes, the other must change to match it.                        */
  1639. SCODE mpIdsScode[] =
  1640. {
  1641.     SUCCESS_SUCCESS,
  1642.     MAPI_E_BUSY,
  1643.     MAPI_E_CALL_FAILED,
  1644.     MAPI_E_INVALID_PARAMETER,
  1645.     MAPI_E_NO_ACCESS,
  1646.     MAPI_E_NO_SUPPORT,
  1647.     MAPI_E_NOT_FOUND,
  1648.     MAPI_E_UNKNOWN_FLAGS,
  1649.     MAPI_E_VERSION,
  1650.     MAPI_E_NOT_ENOUGH_MEMORY,
  1651.     MAPI_W_ERRORS_RETURNED
  1652. };
  1653. /*
  1654.  *  MapScodeSz
  1655.  *
  1656.  *  Purpose:
  1657.  *      Look up an SCODE in a mapping of IDS <-> SCODE to find its
  1658.  *      associated informational string and return it (with memory
  1659.  *      allocated by this function) to the caller.
  1660.  *
  1661.  *  Arguments:
  1662.  *      sc          The SCODE to look up.
  1663.  *      lpxpl       Pointer to the Transport Logon object
  1664.  *      lppszError  Location in which to place an address to a
  1665.  *                  newly allocated buffer containing the
  1666.  *                  informational string associated with scArg.
  1667.  *
  1668.  *  Returns:
  1669.  *      HRESULT
  1670.  *
  1671.  *  Errors:
  1672.  *      MAPI_E_NO_MEMORY    Could not allocate space for
  1673.  *                          the return string.
  1674.  */
  1675. HRESULT
  1676. MapScodeSz(SCODE scArg, LPXPL lpxpl, LPTSTR * lppszError)
  1677. {
  1678.     HRESULT hr = hrSuccess;
  1679.     SCODE sc = SUCCESS_SUCCESS;
  1680.     ULONG cb;
  1681.     UINT ui;
  1682.     UINT ids;
  1683.     UINT uiMax = sizeof mpIdsScode / sizeof mpIdsScode[0];
  1684.     TCHAR rgch[512];
  1685.     if (!lppszError || IsBadWritePtr(lppszError, sizeof(LPVOID)))
  1686.     {
  1687.         DebugTrace("Bad lppszError in MapScodeSzn");
  1688.         return ResultFromScode(E_INVALIDARG);
  1689.     }
  1690.     
  1691.     *lppszError = NULL;
  1692.     /* Linear search in mpIdsScode for sc. */
  1693.     for (ui = 0; ui < uiMax; ui++)
  1694.         if (mpIdsScode[ui] == scArg)
  1695.             break;
  1696.     if (ui == uiMax)
  1697.         ids = IDS_UNKNOWN_ERROR;
  1698.     else
  1699.         ids = ui + LIB_ERRORS;
  1700.     if (!LoadString(lpxpl->lpxppParent->hInst, ids, rgch, sizeof(rgch)))
  1701.     {
  1702.         hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1703.         DebugTraceResult(LoadString failed in MapScodeSz, hr);
  1704.         goto ret;
  1705.     }
  1706.     /* Allocate memory for return variable and set it */
  1707.     cb = (lstrlen(rgch) + 1) * sizeof(TCHAR);
  1708.     sc = lpxpl->AllocateBuffer(cb, (LPVOID *) lppszError);
  1709.     if (sc != SUCCESS_SUCCESS)
  1710.     {
  1711.         hr = ResultFromScode(sc);
  1712.         DebugTraceResult(AllocateBuffer failed in MapScodeSz, hr);
  1713.         goto ret;
  1714.     }
  1715.     lstrcpy(*lppszError, rgch);
  1716. ret:
  1717.     DebugTraceResult(MapScodeSz, hr);
  1718.     return hr;
  1719. }