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 / xpsndmsg.c < prev    next >
C/C++ Source or Header  |  1996-04-11  |  20KB  |  672 lines

  1. /*
  2.  -  X P S N D M S G . C
  3.  -
  4.  *  Purpose:
  5.  *      Code to support the MAPI Transport SPI entry points for
  6.  *      message transmission.
  7.  *      This module contains the following SPI entry points:
  8.  *
  9.  *          SubmitMessage()
  10.  *          EndMessage()
  11.  *
  12.  *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved.
  13.  */
  14.  
  15. #include "xppch.h"
  16.  
  17.  
  18. HRESULT HrAddDeferred(LPXPL lpxpl, LPMESSAGE lpMsg, ULONG *lpulMsgRef);
  19.  
  20.  
  21. /*
  22.  -  XPL_SubmitMessage
  23.  -
  24.  *  Purpose:
  25.  *      Called by the Spooler when it wishes to attempt transmission
  26.  *      of a message.
  27.  *
  28.  *  Parameters:
  29.  *      ulFlags             Flags from the Spooler. The only
  30.  *                          flag defined in the MAPI 1.0 TSPI
  31.  *                          is BEGIN_DEFERRED, and this transport
  32.  *                          doesn't do deferred transmission.
  33.  *      lpMessage           Pointer to message object that the
  34.  *                          Spooler wants sent.
  35.  *      lpulMsgRef          Pointer to where the transport should
  36.  *                          store a unsigned long for use in
  37.  *                          identifying TransportNotify() message
  38.  *                          events. Initialized to 1 by the
  39.  *                          Spooler. We use this to ID deferred
  40.  *                          messages using DEFERRED_MSG_REF.
  41.  *      lpulReturnParm      Used for several MAPI_E_XXX returns,
  42.  *                          but this transport doesn't do any
  43.  *                          of them.
  44.  *
  45.  *  Returns:
  46.  *      (HRESULT)           MAPI_E_BUSY if the Spooler calls
  47.  *                          here again while we're busy, else
  48.  *                          errors encountered if any.
  49.  *
  50.  *  Operation:
  51.  *      For non peer-to-peer, "send" the message to our outbound directory.
  52.  *
  53.  *      For peer-to-peer, use the ADRLIST builder HrBuildAdrList to attempt
  54.  *      transmission to each recipient and build both a sent ADRLIST and a
  55.  *      NDR ADRLIST. ModifyRecipients() on the Spooler message if there's
  56.  *      anyone in the sent ADRLIST. This tells the spooler which ones got
  57.  *      the mail.  If there were any recipients in the NDR ADRLIST, we need
  58.  *      to StatusRecips() with that list, and we will need to
  59.  *      ModifyRecipients() again with them.
  60.  *
  61.  *      For non peer-to-peer or p2p with NDR recipients, use the ADRLIST
  62.  *      builder HrBuildAdrList to make a ADRLIST with all of our unsent
  63.  *      recipients (for non p2p, delivery to all recipients consists of
  64.  *      putting a file into the outbound and for NDR cases, we just take
  65.  *      responsibility because we've already NDR'ed them) and
  66.  *      ModifyRecipients().
  67.  */
  68.  
  69. STDMETHODIMP
  70. XPL_SubmitMessage(LPXPL lpxpl,
  71.     ULONG ulFlags,
  72.     LPMESSAGE lpMessage,
  73.     ULONG * lpulMsgRef,
  74.     ULONG * lpulReturnParm)
  75. {
  76.     LPTSTR lpszMyDir;
  77.     HRESULT hResult = 0;
  78.     SCODE sc = 0;
  79.     BOOL fUpdatedStatus = FALSE;
  80.     BOOL fPeer2Peer;
  81.  
  82.     LPSPropValue lpPropArray = NULL;
  83.     LPMAPISUP lpMAPISup;
  84.  
  85.     ULONG cValues;
  86.     LPSPropValue lpMsgProps = NULL;
  87.  
  88.     static const SizedSPropTagArray(2, sptMsgDefer) =
  89.     {
  90.         2,
  91.         {
  92.             PR_SAMPLE_PER_MSG_DEFER,
  93.             PR_SAMPLE_PER_RECIP_DEFER
  94.         }
  95.     };
  96.  
  97.     SPropValue spvRecipUnsent =
  98.     {PR_RESPONSIBILITY, 0L, FALSE};
  99.     SPropValue spvRecipDefer =
  100.     {PR_SAMPLE_PER_RECIP_DEFER, 0L, TRUE};
  101.     SRestriction rgsrOr[2];
  102.     SRestriction rgsrAnd[2];
  103.     SRestriction srExist;
  104.     SRestriction srRecipUnsent;
  105.  
  106.     LPMAPITABLE lpTable = NULL;
  107.     LPMYADRLIST lpMyAdrListDone = NULL;
  108.     LPMYADRLIST lpMyAdrListNotDone = NULL;
  109.  
  110.     /* Simple re-entrancy test. Should never happen anyway. */
  111.  
  112.     if (lpxpl->ulTransportStatus & STATUS_OUTBOUND_ACTIVE)
  113.     {
  114.         hResult = ResultFromScode(MAPI_E_BUSY);
  115.         DebugTrace("XPL_SubmitMessage reentrancy test failed.\n");
  116.         goto ret;
  117.     }
  118.  
  119.     /* Signal that we're uploading. */
  120.  
  121.     lpxpl->ulTransportStatus |= STATUS_OUTBOUND_ACTIVE;
  122.     hResult = HrUpdateTransportStatus(lpxpl, 0L);
  123.     if (hResult)
  124.         goto ret;
  125.     fUpdatedStatus = TRUE;
  126.  
  127.     /*  Session's OK, hook up some local references */
  128.  
  129.     sc = ScCopySessionProps(lpxpl, &lpPropArray, NULL);
  130.  
  131.     if (FAILED(sc))
  132.     {
  133.         hResult = ResultFromScode(sc);
  134.         DebugTrace("ScCopySessionProps failed in SubmitMessage.\n");
  135.         goto ret;
  136.     }
  137.  
  138.     lpMAPISup = lpxpl->lpMAPISup;
  139.     fPeer2Peer = ((ArrayIndex(PR_SAMPLE_FLAGS, lpPropArray).Value.ul) & PR_SAMPLE_FLAG_PEER_TO_PEER) != 0;
  140.     lpszMyDir = ArrayIndex(PR_SAMPLE_OUTBOUND_DIR, lpPropArray).Value.LPSZ;
  141.  
  142.     PrintfTransportLog(TEXT("Start Outbound: %s"),
  143.         ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ);
  144.  
  145.     /* Reset the timer for SpoolerYield() */
  146.  
  147.     HrCheckSpoolerYield(lpMAPISup, TRUE);
  148.  
  149.     /* Check if we are to defer this message */
  150.  
  151.     hResult = lpMessage->lpVtbl->GetProps(lpMessage,
  152.         (LPSPropTagArray) &sptMsgDefer, 0, /* ansi */
  153.         &cValues, &lpMsgProps);
  154.  
  155.     if (HR_FAILED(hResult))
  156.     {
  157.         DebugTrace("Failed getting props on the message.\n");
  158.         goto ret;
  159.     }
  160.  
  161.     /* We'll default fResendDeferred to TRUE unless we defer this msg */
  162.  
  163.     lpxpl->fResendDeferred = TRUE;
  164.  
  165.     /* If PR_SAMPLE_PER_MSG_DEFER exists and is TRUE, then we delete
  166.        this property from the message, and add this message to our
  167.        deferred list.  The lpulMsgRef is set to the value assigned to
  168.        the node in our list.  When EndMessage is called we search for
  169.        this Ref in to list.  If found, we return END_DONT_RESEND,
  170.        causing the spooler to defer the msg. */
  171.  
  172.     if (lpMsgProps->ulPropTag == PR_SAMPLE_PER_MSG_DEFER)
  173.     {
  174.         lpMessage->lpVtbl->DeleteProps(lpMessage,
  175.             (LPSPropTagArray) &sptMsgDefer, NULL);
  176.  
  177.         lpMessage->lpVtbl->SaveChanges(lpMessage, KEEP_OPEN_READWRITE);
  178.  
  179.         if (lpMsgProps->Value.b == TRUE)
  180.         {
  181.             hResult = HrAddDeferred(lpxpl, lpMessage, lpulMsgRef);
  182.             goto ret;
  183.         }
  184.     }
  185.  
  186.     /* Now, see if any Recipients have PR_SAMPLE_PER_RECIP_DEFER set to
  187.        TRUE in the RecipientTable.  If so, then slam a non-transmittable
  188.        property into the message to indicate we've deferred this message
  189.        for some recipients this time around.  If this property already
  190.        exists, then we know it has already been deferred and we should
  191.        just go ahead and send to all un-handled recipients.              */
  192.  
  193.     if (lpMsgProps[1].ulPropTag == PR_SAMPLE_PER_RECIP_DEFER)
  194.     {
  195.         lpMessage->lpVtbl->DeleteProps(lpMessage,
  196.             (LPSPropTagArray) &sptMsgDefer, NULL);
  197.  
  198.         lpMessage->lpVtbl->SaveChanges(lpMessage, KEEP_OPEN_READWRITE);
  199.  
  200.         /*  Initialize a restriction -- we'll need it soon. */
  201.  
  202.         srRecipUnsent.rt = RES_PROPERTY;
  203.         srRecipUnsent.res.resProperty.relop = RELOP_EQ;
  204.         srRecipUnsent.res.resProperty.ulPropTag = PR_RESPONSIBILITY;
  205.         srRecipUnsent.res.resProperty.lpProp = &spvRecipUnsent;
  206.     }
  207.     else
  208.     {
  209.         SRestriction srRecipDefer;
  210.  
  211.         srRecipDefer.rt = RES_PROPERTY;
  212.         srRecipDefer.res.resProperty.relop = RELOP_EQ;
  213.         srRecipDefer.res.resProperty.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
  214.         srRecipDefer.res.resProperty.lpProp = &spvRecipDefer;
  215.  
  216.         hResult = lpMessage->lpVtbl->GetRecipientTable(
  217.             lpMessage, 0L, &lpTable);
  218.  
  219.         if (hResult)
  220.         {
  221.             DebugTrace("GetRecipientTable failed in SubmitMessage.\n");
  222.             goto ret;
  223.         }
  224.  
  225.         hResult = lpTable->lpVtbl->FindRow(lpTable, &srRecipDefer,
  226.             BOOKMARK_BEGINNING, 0);
  227.  
  228.         /* Check our .2 second timer! */
  229.  
  230.         sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
  231.  
  232.         if (sc == MAPI_W_CANCEL_MESSAGE)
  233.         {
  234.             DebugTrace("Cancelling message delivery.\n");
  235.             goto ret;
  236.         }
  237.  
  238.         if (GetScode(hResult) != MAPI_E_NOT_FOUND)
  239.         {
  240.             hResult = HrAddDeferred(lpxpl, lpMessage, lpulMsgRef);
  241.  
  242.             if (HR_FAILED(hResult))
  243.             {
  244.                 DebugTrace("HrAddDeferred failed doing a per-recip deferral.\n");
  245.                 goto ret;
  246.             }
  247.         }
  248.         else
  249.         {
  250.             hResult = lpTable->lpVtbl->SeekRow(lpTable,
  251.                 BOOKMARK_BEGINNING, 0L, NULL);
  252.         }
  253.  
  254.         /*  Initialize a restriction -- we'll need it soon. */
  255.  
  256.         spvRecipDefer.Value.b = FALSE;
  257.  
  258.         srExist.rt = RES_EXIST;
  259.         srExist.res.resExist.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
  260.  
  261.         rgsrOr[0].rt = RES_NOT;
  262.         rgsrOr[0].res.resNot.lpRes = &srExist;
  263.  
  264.         rgsrOr[1].rt = RES_PROPERTY;
  265.         rgsrOr[1].res.resProperty.relop = RELOP_EQ;
  266.         rgsrOr[1].res.resProperty.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
  267.         rgsrOr[1].res.resProperty.lpProp = &spvRecipDefer;
  268.  
  269.         rgsrAnd[0].rt = RES_PROPERTY;
  270.         rgsrAnd[0].res.resProperty.relop = RELOP_EQ;
  271.         rgsrAnd[0].res.resProperty.ulPropTag = PR_RESPONSIBILITY;
  272.         rgsrAnd[0].res.resProperty.lpProp = &spvRecipUnsent;
  273.  
  274.         rgsrAnd[1].rt = RES_OR;
  275.         rgsrAnd[1].res.resOr.cRes = 2;
  276.         rgsrAnd[1].res.resOr.lpRes = rgsrOr;
  277.  
  278.         srRecipUnsent.rt = RES_AND;
  279.         srRecipUnsent.res.resAnd.cRes = 2;
  280.         srRecipUnsent.res.resAnd.lpRes = rgsrAnd;
  281.     }
  282.  
  283.     /* Check our .2 second timer before attempting to send */
  284.  
  285.     sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
  286.  
  287.     if (sc == MAPI_W_CANCEL_MESSAGE)
  288.     {
  289.         DebugTrace("Cancelling message delivery.\n");
  290.         goto ret;
  291.     }
  292.  
  293.     /*  If not peer-to-peer, "send message" to our outbound directory. */
  294.  
  295.     if (!fPeer2Peer)
  296.     {
  297.         BOOL fSent;
  298.  
  299.         hResult = HrSendOneMessage(lpxpl, lpPropArray,
  300.                 lpMessage, 0, lpszMyDir, &fSent);
  301.  
  302.         if (hResult)
  303.         {
  304.             DebugTrace("Copying message to outbound failed.\n");
  305.             goto ret;
  306.         }
  307.     }
  308.  
  309.     /*  If we are peer-to-peer, send to all our recipients. */
  310.  
  311.     else
  312.     {
  313.         /*  Get the recipient table from the message if we haven't already */
  314.  
  315.         if (!lpTable)
  316.         {
  317.             hResult = lpMessage->lpVtbl->GetRecipientTable(
  318.                 lpMessage, 0L, &lpTable);
  319.  
  320.             if (hResult)
  321.             {
  322.                 DebugTrace("GetRecipientTable failed in SubmitMessage.\n");
  323.                 goto ret;
  324.             }
  325.         }
  326.  
  327.         /*  Restrict to all unsent recipients */
  328.  
  329.         hResult = lpTable->lpVtbl->Restrict(lpTable, &srRecipUnsent, 0L);
  330.  
  331.         if (hResult)
  332.         {
  333.             DebugTrace("Restriction on recipient table  failed in SubmitMessage.\n");
  334.             goto ret;
  335.         }
  336.  
  337.         /* Check our .2 second timer! */
  338.  
  339.         sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
  340.  
  341.         if (sc == MAPI_W_CANCEL_MESSAGE)
  342.         {
  343.             DebugTrace("Cancelling message delivery.\n");
  344.             goto ret;
  345.         }
  346.  
  347.         /*  Send to the recipients which we can reach, and build ADRLISTs of
  348.             the sent and unsent recipients */
  349.  
  350.         hResult = HrBuildAdrList(lpxpl, lpPropArray, lpMessage, lpTable,
  351.                 TRUE, HrSendOneMessage, &lpMyAdrListDone, &lpMyAdrListNotDone);
  352.  
  353.         if (hResult)
  354.         {
  355.             DebugTrace("HrBuildAdrList failed in SubmitMessage.\n");
  356.             goto ret;
  357.         }
  358.  
  359.         /*  No error, do we have some recipients? If so, do the ModifyRecipients(). */
  360.  
  361.         if (lpMyAdrListDone)
  362.         {
  363.             hResult = lpMessage->lpVtbl->ModifyRecipients(lpMessage,
  364.                     MODRECIP_MODIFY, lpMyAdrListDone->lpAdrList);
  365.  
  366.             if (hResult)
  367.             {
  368.                 DebugTrace("ModifyRecipients failed in SubmitMessage.\n");
  369.                 goto ret;
  370.             }
  371.  
  372.             /* Now we need to save changes on the message. */
  373.  
  374.             hResult = lpMessage->lpVtbl->SaveChanges(lpMessage,
  375.                     lpMyAdrListNotDone ? KEEP_OPEN_READWRITE : 0L);
  376.  
  377.             if (hResult)
  378.             {
  379.                 DebugTrace("SaveChanges failed in SubmitMessage.\n");
  380.                 goto ret;
  381.             }
  382.         }
  383.  
  384.         /*  Check for unsent recipients. If there were any, we need to NDR
  385.             them and (finally) mark them as taken. If there were not any,
  386.             we're really finished and can just go and release the message. */
  387.  
  388.         if (!lpMyAdrListNotDone)
  389.             goto ret;
  390.  
  391.         hResult = lpMAPISup->lpVtbl->StatusRecips(lpMAPISup,
  392.                 lpMessage, lpMyAdrListNotDone->lpAdrList);
  393.  
  394.         if (HR_FAILED(hResult))
  395.         {
  396.             DebugTrace("StatusRecips failed in SubmitMessage.\n");
  397.             goto ret;
  398.         }
  399.  
  400.         /*  StatusRecips killed the ADRLIST so zero out our pointer. */
  401.  
  402.         lpMyAdrListNotDone->lpAdrList = NULL;
  403.  
  404.         /* Get rid of the MYADRLISTs. */
  405.  
  406.         FreeMyAdrList(lpxpl, lpMyAdrListDone);
  407.         FreeMyAdrList(lpxpl, lpMyAdrListNotDone);
  408.  
  409.         lpMyAdrListDone = lpMyAdrListNotDone = NULL;
  410.  
  411.         /*  Free the recipient table. */
  412.  
  413.         lpTable->lpVtbl->Release(lpTable);
  414.         lpTable = NULL;
  415.     }
  416.  
  417.     /* Check our .2 second timer after attempting to send */
  418.  
  419.     sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
  420.  
  421.     if (sc == MAPI_W_CANCEL_MESSAGE)
  422.     {
  423.         DebugTrace("Cancelling message delivery.\n");
  424.         goto ret;
  425.     }
  426.  
  427.     /*  At this point we have either:
  428.  
  429.         a)  If not peer-to-peer, made a single container file in
  430.             the outbound directory
  431.         b)  If peer-to-peer, created a container file in every
  432.             inbound directory we were able to reach (but not all
  433.             of them) -- and have NDR'ed the ones we could not reach
  434.  
  435.         All that remains to do is to mark all unsent recipients as
  436.         handled, since in the non-peer case the creation of the
  437.         container suffices as "handling" and in the peer case the
  438.         NDR message also does this.
  439.     */
  440.  
  441.     hResult = lpMessage->lpVtbl->GetRecipientTable(lpMessage, 0L, &lpTable);
  442.  
  443.     if (hResult)
  444.     {
  445.         DebugTrace("Second GetRecipientTable failed in SubmitMessage.\n");
  446.         goto ret;
  447.     }
  448.  
  449.     /*  Restrict the recipient table to the remaining unsent */
  450.  
  451.     hResult = lpTable->lpVtbl->Restrict(lpTable, &srRecipUnsent, 0L);
  452.  
  453.     if (hResult)
  454.     {
  455.         DebugTrace("Restriction on recipient table failed.\n");
  456.         goto ret;
  457.     }
  458.  
  459.     /*  Build the ADRLIST of the unsent recipients */
  460.  
  461.     hResult = HrBuildAdrList(lpxpl, lpPropArray, lpMessage, lpTable,
  462.             TRUE, NULL,  &lpMyAdrListDone, &lpMyAdrListNotDone);
  463.  
  464.     if (hResult)
  465.     {
  466.         DebugTrace("HrBuildAdrList failed in SubmitMessage.\n");
  467.         goto ret;
  468.     }
  469.  
  470.     Assert(!lpMyAdrListNotDone);
  471.  
  472.     /*  No error, do we have some recipients? If so, do the ModifyRecipients(). */
  473.  
  474.     if (lpMyAdrListDone)
  475.     {
  476.         hResult = lpMessage->lpVtbl->ModifyRecipients(lpMessage,
  477.                 MODRECIP_MODIFY, lpMyAdrListDone->lpAdrList);
  478.  
  479.         if (hResult)
  480.         {
  481.             DebugTrace("ModifyRecipients failed in SubmitMessage.\n");
  482.             goto ret;
  483.         }
  484.     }
  485.  
  486.     /*  Release the table, we're finished with it */
  487.  
  488.     UlRelease(lpTable);
  489.     lpTable = NULL;
  490.  
  491.     /* With the recipient table work done, save changes again. */
  492.  
  493.     hResult = lpMessage->lpVtbl->SaveChanges(lpMessage, 0L);
  494.  
  495.     if (hResult)
  496.     {
  497.         DebugTrace("SaveChanges failed in SubmitMessage.\n");
  498.         goto ret;
  499.     }
  500.  
  501.     PrintfTransportLog(TEXT("End Outbound: %s"),
  502.         ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ);
  503.  
  504. ret:
  505.     /* Free-Up Memory */
  506.  
  507.     lpxpl->FreeBuffer(lpPropArray);
  508.     lpxpl->FreeBuffer(lpMsgProps);
  509.  
  510.     /* Get rid of any MYADRLISTs. */
  511.  
  512.     FreeMyAdrList(lpxpl, lpMyAdrListDone);
  513.     FreeMyAdrList(lpxpl, lpMyAdrListNotDone);
  514.  
  515.     /* Release any open table */
  516.  
  517.     UlRelease(lpTable);
  518.  
  519.     /* Release the spooler's message if need be */
  520.  
  521.     UlRelease(lpMessage);
  522.  
  523.     /* Reset upload status if set. If this errors, use the error only
  524.        if no other error had occurred here. */
  525.  
  526.     if (fUpdatedStatus)
  527.     {
  528.         lpxpl->ulTransportStatus &= ~STATUS_OUTBOUND_ACTIVE;
  529.         (void)HrUpdateTransportStatus(lpxpl, 0L);
  530.     }
  531.  
  532.     DebugTraceResult(XPL_SubmitMessage, hResult);
  533.     return hResult;
  534.  
  535. }
  536.  
  537. /*
  538.  -  XPL_EndMessage
  539.  -
  540.  *  Purpose:
  541.  *      Called by the Spooler to complete transmission of a message.
  542.  *
  543.  *  Parameters:
  544.  *      ulMsgRef            Opaque identifier from SubmitMessage
  545.  *      lpulFlags           Pointer to where the transport should
  546.  *                          store special flags on return. This
  547.  *                          Transport doesn't use any.
  548.  *
  549.  *  Returns:
  550.  *      (HRESULT)           Success.
  551.  *
  552.  *  Operation:
  553.  *      Clears unsigned long status, and returns success.
  554.  */
  555.  
  556. STDMETHODIMP
  557. XPL_EndMessage(LPXPL lpxpl, ULONG ulMsgRef, ULONG * lpulFlags)
  558. {
  559.     LPDEFMSG lpDefMsg;
  560.  
  561.     Assert(!IsBadWritePtr(lpulFlags, sizeof(ULONG)));
  562.  
  563.     *lpulFlags = 0L;
  564.  
  565.     /* If the ulMsgRef is non zero, look for it in the deferred
  566.        list.  If found, return END_DONT_RESEND to the Spooler.  */
  567.  
  568.     if (ulMsgRef)
  569.     {
  570.         lpDefMsg = lpxpl->lpDeferredList;
  571.  
  572.         while (lpDefMsg)
  573.         {
  574.             if (lpDefMsg->ulMsgRef == ulMsgRef)
  575.             {
  576.                 *lpulFlags = END_DONT_RESEND;
  577.                 break;
  578.             }
  579.         }
  580.     }
  581.  
  582.     return hrSuccess;
  583. }
  584.  
  585.  
  586. /*
  587.  -  HrAddDeferred
  588.  -
  589.  *  Purpose:
  590.  *      Adds the EntryID and ulMsgRef of a message we are deferring
  591.  *      to our list of deferred message.
  592.  *
  593.  *  Parameters:
  594.  *      lpxpl           Transport session
  595.  *      lpMsg           The message we wish to defer
  596.  *      lpulMsgRef      Receives the reference we assign to this message
  597.  *
  598.  *  Returns:
  599.  *      hResult         Indicating Success/Failure
  600.  */
  601.  
  602. HRESULT
  603. HrAddDeferred(LPXPL lpxpl, LPMESSAGE lpMsg, ULONG *lpulMsgRef)
  604. {
  605.     HRESULT hResult;
  606.     SCODE sc;
  607.     LPDEFMSG lpDefMsg = NULL;
  608.     ULONG cVals;
  609.     LPSPropValue lpEIDProp = NULL;
  610.     static SPropTagArray spta = {1, {PR_ENTRYID}};
  611.  
  612.     /* Allocate a new DefMsg node */
  613.  
  614.     sc = lpxpl->AllocateBuffer(sizeof(DEFMSG), (LPVOID *)&lpDefMsg);
  615.  
  616.     if (FAILED(sc))
  617.     {
  618.         hResult = ResultFromScode(sc);
  619.         DebugTrace("Allocation failed in HrAddDeferred.\n");
  620.         goto ret;
  621.     }
  622.  
  623.     /* Get the EntryID of the message we are deferring */
  624.  
  625.     hResult = lpMsg->lpVtbl->GetProps(lpMsg, &spta, 0, &cVals, &lpEIDProp);
  626.  
  627.     if (HR_FAILED(hResult))
  628.     {
  629.         DebugTrace("GetProps failed in HrAddDeferred.\n");
  630.         goto ret;
  631.     }
  632.  
  633.     Assert(cVals == 1);
  634.     Assert(lpEIDProp);
  635.     Assert(lpEIDProp->ulPropTag == PR_ENTRYID);
  636.  
  637.     /* We'll make our own copy of the EntryID */
  638.  
  639.     sc = lpxpl->AllocateMore(lpEIDProp->Value.bin.cb, (LPVOID)lpDefMsg,
  640.             (LPVOID *)&(lpDefMsg->sbinEIDDef.lpb));
  641.  
  642.     if (FAILED(sc))
  643.     {
  644.         hResult = ResultFromScode(sc);
  645.         DebugTrace("Allocation failed in HrAddDeferred.\n");
  646.         goto ret;
  647.     }
  648.  
  649.     /* Fill in this new node and add it to the list */
  650.  
  651.     lpDefMsg->sbinEIDDef.cb = lpEIDProp->Value.bin.cb;
  652.     memcpy(lpDefMsg->sbinEIDDef.lpb, lpEIDProp->Value.bin.lpb,
  653.             (UINT)lpDefMsg->sbinEIDDef.cb);
  654.  
  655.     lpDefMsg->ulMsgRef = ++lpxpl->ulDeferredMsgRef;
  656.     lpDefMsg->lpNext = lpxpl->lpDeferredList;
  657.     lpxpl->lpDeferredList = lpDefMsg;
  658.  
  659.     lpxpl->fResendDeferred = FALSE;
  660.  
  661.     *lpulMsgRef = lpDefMsg->ulMsgRef;
  662.  
  663. ret:
  664.     if (HR_FAILED(hResult))
  665.         lpxpl->FreeBuffer(lpDefMsg);
  666.  
  667.     lpxpl->FreeBuffer(lpEIDProp);
  668.  
  669.     DebugTraceResult(HrAddDeferred, hResult);
  670.     return hResult;
  671. }
  672.