XPSNDMSG.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:20k
源码类别:
Windows编程
开发平台:
Visual C++
- /*
- - X P S N D M S G . C
- -
- * Purpose:
- * Code to support the MAPI Transport SPI entry points for
- * message transmission.
- * This module contains the following SPI entry points:
- *
- * SubmitMessage()
- * EndMessage()
- *
- * Copyright 1992-1995 Microsoft Corporation. All Rights Reserved.
- */
- #include "xppch.h"
- HRESULT HrAddDeferred(LPXPL lpxpl, LPMESSAGE lpMsg, ULONG *lpulMsgRef);
- /*
- - XPL_SubmitMessage
- -
- * Purpose:
- * Called by the Spooler when it wishes to attempt transmission
- * of a message.
- *
- * Parameters:
- * ulFlags Flags from the Spooler. The only
- * flag defined in the MAPI 1.0 TSPI
- * is BEGIN_DEFERRED, and this transport
- * doesn't do deferred transmission.
- * lpMessage Pointer to message object that the
- * Spooler wants sent.
- * lpulMsgRef Pointer to where the transport should
- * store a unsigned long for use in
- * identifying TransportNotify() message
- * events. Initialized to 1 by the
- * Spooler. We use this to ID deferred
- * messages using DEFERRED_MSG_REF.
- * lpulReturnParm Used for several MAPI_E_XXX returns,
- * but this transport doesn't do any
- * of them.
- *
- * Returns:
- * (HRESULT) MAPI_E_BUSY if the Spooler calls
- * here again while we're busy, else
- * errors encountered if any.
- *
- * Operation:
- * For non peer-to-peer, "send" the message to our outbound directory.
- *
- * For peer-to-peer, use the ADRLIST builder HrBuildAdrList to attempt
- * transmission to each recipient and build both a sent ADRLIST and a
- * NDR ADRLIST. ModifyRecipients() on the Spooler message if there's
- * anyone in the sent ADRLIST. This tells the spooler which ones got
- * the mail. If there were any recipients in the NDR ADRLIST, we need
- * to StatusRecips() with that list, and we will need to
- * ModifyRecipients() again with them.
- *
- * For non peer-to-peer or p2p with NDR recipients, use the ADRLIST
- * builder HrBuildAdrList to make a ADRLIST with all of our unsent
- * recipients (for non p2p, delivery to all recipients consists of
- * putting a file into the outbound and for NDR cases, we just take
- * responsibility because we've already NDR'ed them) and
- * ModifyRecipients().
- */
- STDMETHODIMP
- XPL_SubmitMessage(LPXPL lpxpl,
- ULONG ulFlags,
- LPMESSAGE lpMessage,
- ULONG * lpulMsgRef,
- ULONG * lpulReturnParm)
- {
- LPTSTR lpszMyDir;
- HRESULT hResult = 0;
- SCODE sc = 0;
- BOOL fUpdatedStatus = FALSE;
- BOOL fPeer2Peer;
- LPSPropValue lpPropArray = NULL;
- LPMAPISUP lpMAPISup;
- ULONG cValues;
- LPSPropValue lpMsgProps = NULL;
- static const SizedSPropTagArray(2, sptMsgDefer) =
- {
- 2,
- {
- PR_SAMPLE_PER_MSG_DEFER,
- PR_SAMPLE_PER_RECIP_DEFER
- }
- };
- SPropValue spvRecipUnsent =
- {PR_RESPONSIBILITY, 0L, FALSE};
- SPropValue spvRecipDefer =
- {PR_SAMPLE_PER_RECIP_DEFER, 0L, TRUE};
- SRestriction rgsrOr[2];
- SRestriction rgsrAnd[2];
- SRestriction srExist;
- SRestriction srRecipUnsent;
- LPMAPITABLE lpTable = NULL;
- LPMYADRLIST lpMyAdrListDone = NULL;
- LPMYADRLIST lpMyAdrListNotDone = NULL;
- /* Simple re-entrancy test. Should never happen anyway. */
- if (lpxpl->ulTransportStatus & STATUS_OUTBOUND_ACTIVE)
- {
- hResult = ResultFromScode(MAPI_E_BUSY);
- DebugTrace("XPL_SubmitMessage reentrancy test failed.n");
- goto ret;
- }
- /* Signal that we're uploading. */
- lpxpl->ulTransportStatus |= STATUS_OUTBOUND_ACTIVE;
- hResult = HrUpdateTransportStatus(lpxpl, 0L);
- if (hResult)
- goto ret;
- fUpdatedStatus = TRUE;
- /* Session's OK, hook up some local references */
- sc = ScCopySessionProps(lpxpl, &lpPropArray, NULL);
- if (FAILED(sc))
- {
- hResult = ResultFromScode(sc);
- DebugTrace("ScCopySessionProps failed in SubmitMessage.n");
- goto ret;
- }
- lpMAPISup = lpxpl->lpMAPISup;
- fPeer2Peer = ((ArrayIndex(PR_SAMPLE_FLAGS, lpPropArray).Value.ul) & PR_SAMPLE_FLAG_PEER_TO_PEER) != 0;
- lpszMyDir = ArrayIndex(PR_SAMPLE_OUTBOUND_DIR, lpPropArray).Value.LPSZ;
- PrintfTransportLog(TEXT("Start Outbound: %s"),
- ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ);
- /* Reset the timer for SpoolerYield() */
- HrCheckSpoolerYield(lpMAPISup, TRUE);
- /* Check if we are to defer this message */
- hResult = lpMessage->lpVtbl->GetProps(lpMessage,
- (LPSPropTagArray) &sptMsgDefer, 0, /* ansi */
- &cValues, &lpMsgProps);
- if (HR_FAILED(hResult))
- {
- DebugTrace("Failed getting props on the message.n");
- goto ret;
- }
- /* We'll default fResendDeferred to TRUE unless we defer this msg */
- lpxpl->fResendDeferred = TRUE;
- /* If PR_SAMPLE_PER_MSG_DEFER exists and is TRUE, then we delete
- this property from the message, and add this message to our
- deferred list. The lpulMsgRef is set to the value assigned to
- the node in our list. When EndMessage is called we search for
- this Ref in to list. If found, we return END_DONT_RESEND,
- causing the spooler to defer the msg. */
- if (lpMsgProps->ulPropTag == PR_SAMPLE_PER_MSG_DEFER)
- {
- lpMessage->lpVtbl->DeleteProps(lpMessage,
- (LPSPropTagArray) &sptMsgDefer, NULL);
- lpMessage->lpVtbl->SaveChanges(lpMessage, KEEP_OPEN_READWRITE);
- if (lpMsgProps->Value.b == TRUE)
- {
- hResult = HrAddDeferred(lpxpl, lpMessage, lpulMsgRef);
- goto ret;
- }
- }
- /* Now, see if any Recipients have PR_SAMPLE_PER_RECIP_DEFER set to
- TRUE in the RecipientTable. If so, then slam a non-transmittable
- property into the message to indicate we've deferred this message
- for some recipients this time around. If this property already
- exists, then we know it has already been deferred and we should
- just go ahead and send to all un-handled recipients. */
- if (lpMsgProps[1].ulPropTag == PR_SAMPLE_PER_RECIP_DEFER)
- {
- lpMessage->lpVtbl->DeleteProps(lpMessage,
- (LPSPropTagArray) &sptMsgDefer, NULL);
- lpMessage->lpVtbl->SaveChanges(lpMessage, KEEP_OPEN_READWRITE);
- /* Initialize a restriction -- we'll need it soon. */
- srRecipUnsent.rt = RES_PROPERTY;
- srRecipUnsent.res.resProperty.relop = RELOP_EQ;
- srRecipUnsent.res.resProperty.ulPropTag = PR_RESPONSIBILITY;
- srRecipUnsent.res.resProperty.lpProp = &spvRecipUnsent;
- }
- else
- {
- SRestriction srRecipDefer;
- srRecipDefer.rt = RES_PROPERTY;
- srRecipDefer.res.resProperty.relop = RELOP_EQ;
- srRecipDefer.res.resProperty.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
- srRecipDefer.res.resProperty.lpProp = &spvRecipDefer;
- hResult = lpMessage->lpVtbl->GetRecipientTable(
- lpMessage, 0L, &lpTable);
- if (hResult)
- {
- DebugTrace("GetRecipientTable failed in SubmitMessage.n");
- goto ret;
- }
- hResult = lpTable->lpVtbl->FindRow(lpTable, &srRecipDefer,
- BOOKMARK_BEGINNING, 0);
- /* Check our .2 second timer! */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message delivery.n");
- goto ret;
- }
- if (GetScode(hResult) != MAPI_E_NOT_FOUND)
- {
- hResult = HrAddDeferred(lpxpl, lpMessage, lpulMsgRef);
- if (HR_FAILED(hResult))
- {
- DebugTrace("HrAddDeferred failed doing a per-recip deferral.n");
- goto ret;
- }
- }
- else
- {
- hResult = lpTable->lpVtbl->SeekRow(lpTable,
- BOOKMARK_BEGINNING, 0L, NULL);
- }
- /* Initialize a restriction -- we'll need it soon. */
- spvRecipDefer.Value.b = FALSE;
- srExist.rt = RES_EXIST;
- srExist.res.resExist.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
- rgsrOr[0].rt = RES_NOT;
- rgsrOr[0].res.resNot.lpRes = &srExist;
- rgsrOr[1].rt = RES_PROPERTY;
- rgsrOr[1].res.resProperty.relop = RELOP_EQ;
- rgsrOr[1].res.resProperty.ulPropTag = PR_SAMPLE_PER_RECIP_DEFER;
- rgsrOr[1].res.resProperty.lpProp = &spvRecipDefer;
- rgsrAnd[0].rt = RES_PROPERTY;
- rgsrAnd[0].res.resProperty.relop = RELOP_EQ;
- rgsrAnd[0].res.resProperty.ulPropTag = PR_RESPONSIBILITY;
- rgsrAnd[0].res.resProperty.lpProp = &spvRecipUnsent;
- rgsrAnd[1].rt = RES_OR;
- rgsrAnd[1].res.resOr.cRes = 2;
- rgsrAnd[1].res.resOr.lpRes = rgsrOr;
- srRecipUnsent.rt = RES_AND;
- srRecipUnsent.res.resAnd.cRes = 2;
- srRecipUnsent.res.resAnd.lpRes = rgsrAnd;
- }
- /* Check our .2 second timer before attempting to send */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message delivery.n");
- goto ret;
- }
- /* If not peer-to-peer, "send message" to our outbound directory. */
- if (!fPeer2Peer)
- {
- BOOL fSent;
- hResult = HrSendOneMessage(lpxpl, lpPropArray,
- lpMessage, 0, lpszMyDir, &fSent);
- if (hResult)
- {
- DebugTrace("Copying message to outbound failed.n");
- goto ret;
- }
- }
- /* If we are peer-to-peer, send to all our recipients. */
- else
- {
- /* Get the recipient table from the message if we haven't already */
- if (!lpTable)
- {
- hResult = lpMessage->lpVtbl->GetRecipientTable(
- lpMessage, 0L, &lpTable);
- if (hResult)
- {
- DebugTrace("GetRecipientTable failed in SubmitMessage.n");
- goto ret;
- }
- }
- /* Restrict to all unsent recipients */
- hResult = lpTable->lpVtbl->Restrict(lpTable, &srRecipUnsent, 0L);
- if (hResult)
- {
- DebugTrace("Restriction on recipient table failed in SubmitMessage.n");
- goto ret;
- }
- /* Check our .2 second timer! */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message delivery.n");
- goto ret;
- }
- /* Send to the recipients which we can reach, and build ADRLISTs of
- the sent and unsent recipients */
- hResult = HrBuildAdrList(lpxpl, lpPropArray, lpMessage, lpTable,
- TRUE, HrSendOneMessage, &lpMyAdrListDone, &lpMyAdrListNotDone);
- if (hResult)
- {
- DebugTrace("HrBuildAdrList failed in SubmitMessage.n");
- goto ret;
- }
- /* No error, do we have some recipients? If so, do the ModifyRecipients(). */
- if (lpMyAdrListDone)
- {
- hResult = lpMessage->lpVtbl->ModifyRecipients(lpMessage,
- MODRECIP_MODIFY, lpMyAdrListDone->lpAdrList);
- if (hResult)
- {
- DebugTrace("ModifyRecipients failed in SubmitMessage.n");
- goto ret;
- }
- /* Now we need to save changes on the message. */
- hResult = lpMessage->lpVtbl->SaveChanges(lpMessage,
- lpMyAdrListNotDone ? KEEP_OPEN_READWRITE : 0L);
- if (hResult)
- {
- DebugTrace("SaveChanges failed in SubmitMessage.n");
- goto ret;
- }
- }
- /* Check for unsent recipients. If there were any, we need to NDR
- them and (finally) mark them as taken. If there were not any,
- we're really finished and can just go and release the message. */
- if (!lpMyAdrListNotDone)
- goto ret;
- hResult = lpMAPISup->lpVtbl->StatusRecips(lpMAPISup,
- lpMessage, lpMyAdrListNotDone->lpAdrList);
- if (HR_FAILED(hResult))
- {
- DebugTrace("StatusRecips failed in SubmitMessage.n");
- goto ret;
- }
- /* StatusRecips killed the ADRLIST so zero out our pointer. */
- lpMyAdrListNotDone->lpAdrList = NULL;
- /* Get rid of the MYADRLISTs. */
- FreeMyAdrList(lpxpl, lpMyAdrListDone);
- FreeMyAdrList(lpxpl, lpMyAdrListNotDone);
- lpMyAdrListDone = lpMyAdrListNotDone = NULL;
- /* Free the recipient table. */
- lpTable->lpVtbl->Release(lpTable);
- lpTable = NULL;
- }
- /* Check our .2 second timer after attempting to send */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message delivery.n");
- goto ret;
- }
- /* At this point we have either:
- a) If not peer-to-peer, made a single container file in
- the outbound directory
- b) If peer-to-peer, created a container file in every
- inbound directory we were able to reach (but not all
- of them) -- and have NDR'ed the ones we could not reach
- All that remains to do is to mark all unsent recipients as
- handled, since in the non-peer case the creation of the
- container suffices as "handling" and in the peer case the
- NDR message also does this.
- */
- hResult = lpMessage->lpVtbl->GetRecipientTable(lpMessage, 0L, &lpTable);
- if (hResult)
- {
- DebugTrace("Second GetRecipientTable failed in SubmitMessage.n");
- goto ret;
- }
- /* Restrict the recipient table to the remaining unsent */
- hResult = lpTable->lpVtbl->Restrict(lpTable, &srRecipUnsent, 0L);
- if (hResult)
- {
- DebugTrace("Restriction on recipient table failed.n");
- goto ret;
- }
- /* Build the ADRLIST of the unsent recipients */
- hResult = HrBuildAdrList(lpxpl, lpPropArray, lpMessage, lpTable,
- TRUE, NULL, &lpMyAdrListDone, &lpMyAdrListNotDone);
- if (hResult)
- {
- DebugTrace("HrBuildAdrList failed in SubmitMessage.n");
- goto ret;
- }
- Assert(!lpMyAdrListNotDone);
- /* No error, do we have some recipients? If so, do the ModifyRecipients(). */
- if (lpMyAdrListDone)
- {
- hResult = lpMessage->lpVtbl->ModifyRecipients(lpMessage,
- MODRECIP_MODIFY, lpMyAdrListDone->lpAdrList);
- if (hResult)
- {
- DebugTrace("ModifyRecipients failed in SubmitMessage.n");
- goto ret;
- }
- }
- /* Release the table, we're finished with it */
- UlRelease(lpTable);
- lpTable = NULL;
- /* With the recipient table work done, save changes again. */
- hResult = lpMessage->lpVtbl->SaveChanges(lpMessage, 0L);
- if (hResult)
- {
- DebugTrace("SaveChanges failed in SubmitMessage.n");
- goto ret;
- }
- PrintfTransportLog(TEXT("End Outbound: %s"),
- ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ);
- ret:
- /* Free-Up Memory */
- lpxpl->FreeBuffer(lpPropArray);
- lpxpl->FreeBuffer(lpMsgProps);
- /* Get rid of any MYADRLISTs. */
- FreeMyAdrList(lpxpl, lpMyAdrListDone);
- FreeMyAdrList(lpxpl, lpMyAdrListNotDone);
- /* Release any open table */
- UlRelease(lpTable);
- /* Release the spooler's message if need be */
- UlRelease(lpMessage);
- /* Reset upload status if set. If this errors, use the error only
- if no other error had occurred here. */
- if (fUpdatedStatus)
- {
- lpxpl->ulTransportStatus &= ~STATUS_OUTBOUND_ACTIVE;
- (void)HrUpdateTransportStatus(lpxpl, 0L);
- }
- DebugTraceResult(XPL_SubmitMessage, hResult);
- return hResult;
- }
- /*
- - XPL_EndMessage
- -
- * Purpose:
- * Called by the Spooler to complete transmission of a message.
- *
- * Parameters:
- * ulMsgRef Opaque identifier from SubmitMessage
- * lpulFlags Pointer to where the transport should
- * store special flags on return. This
- * Transport doesn't use any.
- *
- * Returns:
- * (HRESULT) Success.
- *
- * Operation:
- * Clears unsigned long status, and returns success.
- */
- STDMETHODIMP
- XPL_EndMessage(LPXPL lpxpl, ULONG ulMsgRef, ULONG * lpulFlags)
- {
- LPDEFMSG lpDefMsg;
- Assert(!IsBadWritePtr(lpulFlags, sizeof(ULONG)));
- *lpulFlags = 0L;
- /* If the ulMsgRef is non zero, look for it in the deferred
- list. If found, return END_DONT_RESEND to the Spooler. */
- if (ulMsgRef)
- {
- lpDefMsg = lpxpl->lpDeferredList;
- while (lpDefMsg)
- {
- if (lpDefMsg->ulMsgRef == ulMsgRef)
- {
- *lpulFlags = END_DONT_RESEND;
- break;
- }
- }
- }
- return hrSuccess;
- }
- /*
- - HrAddDeferred
- -
- * Purpose:
- * Adds the EntryID and ulMsgRef of a message we are deferring
- * to our list of deferred message.
- *
- * Parameters:
- * lpxpl Transport session
- * lpMsg The message we wish to defer
- * lpulMsgRef Receives the reference we assign to this message
- *
- * Returns:
- * hResult Indicating Success/Failure
- */
- HRESULT
- HrAddDeferred(LPXPL lpxpl, LPMESSAGE lpMsg, ULONG *lpulMsgRef)
- {
- HRESULT hResult;
- SCODE sc;
- LPDEFMSG lpDefMsg = NULL;
- ULONG cVals;
- LPSPropValue lpEIDProp = NULL;
- static SPropTagArray spta = {1, {PR_ENTRYID}};
- /* Allocate a new DefMsg node */
- sc = lpxpl->AllocateBuffer(sizeof(DEFMSG), (LPVOID *)&lpDefMsg);
- if (FAILED(sc))
- {
- hResult = ResultFromScode(sc);
- DebugTrace("Allocation failed in HrAddDeferred.n");
- goto ret;
- }
- /* Get the EntryID of the message we are deferring */
- hResult = lpMsg->lpVtbl->GetProps(lpMsg, &spta, 0, &cVals, &lpEIDProp);
- if (HR_FAILED(hResult))
- {
- DebugTrace("GetProps failed in HrAddDeferred.n");
- goto ret;
- }
- Assert(cVals == 1);
- Assert(lpEIDProp);
- Assert(lpEIDProp->ulPropTag == PR_ENTRYID);
- /* We'll make our own copy of the EntryID */
- sc = lpxpl->AllocateMore(lpEIDProp->Value.bin.cb, (LPVOID)lpDefMsg,
- (LPVOID *)&(lpDefMsg->sbinEIDDef.lpb));
- if (FAILED(sc))
- {
- hResult = ResultFromScode(sc);
- DebugTrace("Allocation failed in HrAddDeferred.n");
- goto ret;
- }
- /* Fill in this new node and add it to the list */
- lpDefMsg->sbinEIDDef.cb = lpEIDProp->Value.bin.cb;
- memcpy(lpDefMsg->sbinEIDDef.lpb, lpEIDProp->Value.bin.lpb,
- (UINT)lpDefMsg->sbinEIDDef.cb);
- lpDefMsg->ulMsgRef = ++lpxpl->ulDeferredMsgRef;
- lpDefMsg->lpNext = lpxpl->lpDeferredList;
- lpxpl->lpDeferredList = lpDefMsg;
- lpxpl->fResendDeferred = FALSE;
- *lpulMsgRef = lpDefMsg->ulMsgRef;
- ret:
- if (HR_FAILED(hResult))
- lpxpl->FreeBuffer(lpDefMsg);
- lpxpl->FreeBuffer(lpEIDProp);
- DebugTraceResult(HrAddDeferred, hResult);
- return hResult;
- }