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 / peer.xp / xpstatus.c < prev    next >
C/C++ Source or Header  |  1996-04-11  |  61KB  |  2,045 lines

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