XPQUEUE.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:54k
源码类别:
Windows编程
开发平台:
Visual C++
- /*
- - X P Q U E U E . C
- -
- * Purpose:
- * Code to support the background queueing mechanism for the Sample
- * Transport Provider.
- * This module contains the following SPI entry points:
- *
- * Idle()
- *
- * Additional support functions found here:
- *
- * HrBuildAdrList()
- * HrSendOneMessage()
- * HrIMsgToTextMsg()
- * HrPrepareRecipientTable()
- * HrCrackSenderEID()
- * FPropIndex()
- * FormatFileTime()
- * FreeMyAdrList()
- * ScLoadTnef()
- *
- * Also present in this module is the transmit list management code and
- * all the recipient list manipulation logic.
- *
- * Copyright 1992-1995 Microsoft Corporation. All Rights Reserved.
- */
- #include "xppch.h"
- #include <tnef.h>
- #include "xpsof.h"
- #include "xptxtmsg.h"
- #include "xpresrc.h"
- BOOL FIsTextizedProp(ULONG ulPropTag);
- /* Generic BAD_VALUE for use in comparisons below */
- #define BAD_VALUE (0xFFFFFFFF)
- /*
- - lpxpl->lpVtbl->Idle
- -
- * Purpose:
- * Called by the Spooler periodically in its idle loop.
- *
- * The Transport will determine if there's any incoming mail for the
- * Spooler and will TransportNotify (NOTIFY_NEWMAIL) if so.
- *
- * Parameters:
- * ulFlags Flags. None are currently defined.
- *
- * Returns:
- * (HRESULT) Errors encountered if any.
- *
- * Operation:
- * If inbound operation is currently enabled, call the Poll() entry point
- * to see if there's anything there. If we find something with Poll(), then
- * SpoolerNotify(NOTIFY_NEWMAIL).
- */
- STDMETHODIMP
- XPL_Idle(LPXPL lpxpl, ULONG ulFlags)
- {
- HRESULT hResult = 0;
- LPDEFMSG lpDefMsg;
- /* Incoming messages? */
- if (lpxpl->ulTransportStatus & STATUS_INBOUND_ENABLED)
- {
- ULONG ulT = 0;
- if ((hResult = XPL_Poll(lpxpl, &ulT)) != 0)
- goto ret;
- if (ulT != 0)
- {
- /* SpoolerNotify() could theoretically return a nonzero
- HRESULT, but it's much easier and unambiguous to ignore
- that possibility and field Spooler errors elsewhere. */
- (void)lpxpl->lpMAPISup->lpVtbl->SpoolerNotify(lpxpl->lpMAPISup, NOTIFY_NEWMAIL, NULL);
- }
- }
- if (lpxpl->fResendDeferred)
- {
- while (lpxpl->lpDeferredList)
- {
- lpDefMsg = lpxpl->lpDeferredList;
- lpxpl->lpDeferredList = lpDefMsg->lpNext;
- lpxpl->lpMAPISup->lpVtbl->SpoolerNotify(lpxpl->lpMAPISup,
- NOTIFY_SENTDEFERRED, &(lpDefMsg->sbinEIDDef));
- lpxpl->FreeBuffer(lpDefMsg);
- }
- lpxpl->fResendDeferred = FALSE;
- }
- ret:
- DebugTraceResult(XPL_Idle, hResult);
- return hResult;
- }
- /*
- - HrBuildAdrList
- -
- * Called by outbound and inbound logic.
- *
- * Traverses a restricted recipient table and collates the rows into
- * a "done" adrlist structure and a "not done" adrlist structure. The
- * only distinction between done and not done is the result of a call
- * to an optional function to attempt to send the open message to
- * a particular recipient.
- *
- * Obviously, if the callback isn't specified, the "done" adrlist will
- * contain all recipients that matched the restriction.
- *
- * Parameters:
- * lpxpl Session in which we're executing
- * lpMessage Message containing the recipient table
- * lpTable Recipient table
- * fSetResponsibility TRUE/FALSE = Set/Clear PR_RESPONSIBILITY
- * in good list (clear bad list always)
- * lpfnCallBack Routine to call when trying to send
- * lppMyAdrListGood Where to store the list of done recips
- * lppMyAdrListBad Where to store the list of not done
- *
- * Returns:
- * (HRESULT) Errors encountered if any.
- *
- *
- * Operation:
- * This routine builds a pair of MYADRLISTS from the (restricted)
- * table which is passed to it.
- *
- * Do a SetColumns so we know where to find PR_EMAIL_ADDRESS, PR_ROWID
- * and other necessary columns. Included in the SetColumns is
- * PR_REPORT_TEXT as a placeholder for NDR information.
- *
- * Then, until we run out of data,
- *
- * 1) QueryRows on the input table
- * 2) For each row:
- * a) If lpfnCallBack and PR_EMAIL_ADDRESS, invoke callback.
- * b) If callback wasn't defined or if successful, add row to
- * "good" list, else add to "bad" list with NDR reason
- * 3) Free RowSet
- *
- * The caller can tell if any recipients remain by whether the
- * "not done" set contains any elements.
- *
- * The "not done" set will set PR_RESPONSIBILITY to FALSE if the caller
- * wants "done" recipients set,
- */
- HRESULT
- HrBuildAdrList(LPXPL lpxpl,
- LPSPropValue lpPropArray,
- LPMESSAGE lpMessage,
- LPMAPITABLE lpTable,
- BOOL fSetResponsibility,
- LPMYCALLBACK lpfnCallBack,
- LPMYADRLIST FAR * lppMyAdrListGood,
- LPMYADRLIST FAR * lppMyAdrListBad)
- {
- HRESULT hResult = hrSuccess;
- SCODE sc = S_OK;
- LPVOID lpvT;
- TCHAR rgchBuffer[512];
- LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
- LPSRowSet lpRow = NULL;
- LPMYADRLIST lpDone = NULL;
- LPMYADRLIST lpNotDone = NULL;
- LPSPropTagArray lpsptT = NULL;
- LPMYADRLIST FAR *lppMyAdrList;
- LPSPropTagArray lpsptNew;
- LPSPropValue lpspvT;
- ULONG ulT;
- ULONG ulNew;
- ULONG ulRow;
- /* These are the columns I need to have in the recipient table,
- even if all I get is a placeholder. If you need to add any,
- bump the definition of NUM_REQUIRED_COLS, add new defines
- for the new columns, and add the new column proptags to the
- switch below. If the property isn't necessarily going to be
- in the table, use the PR_NULL trick you see below for the
- PR_REPORT_TEXT property. */
- enum enumColumns
- {
- COLUMN_PR_ROWID,
- COLUMN_PR_EMAIL_ADDRESS,
- COLUMN_PR_RESPONSIBILITY,
- COLUMN_PR_REPORT_TEXT,
- COLUMN_PR_RECIPIENT_TYPE,
- NUM_REQUIRED_COLS
- };
- Assert(lppMyAdrListGood);
- Assert(lppMyAdrListBad);
- /*
- Arrange the columns so that we'll have the recipient properties
- we really want.
- So as not to lose any recipient properties, we need to do it in
- this fashion:
- 1) QueryColumns() on the input table
- 2) Build a new column set based on the properties we care
- about plus all other properties of the input table
- 3) SetColumns() on the input table
- The properties we care about are the following:
- 1) PR_ROWID
- 2) PR_EMAIL_ADDRESS
- 3) PR_RESPONSIBILITY */
- /* Get the complete column set */
- hResult = lpTable->lpVtbl->QueryColumns(lpTable, TBL_ALL_COLUMNS, &lpsptT);
- if (hResult)
- {
- DebugTrace("QueryColumns failed.n");
- goto ret;
- }
- /* Gotta have a PR_ROWID. That guarantees at least one column! */
- Assert(lpsptT->cValues >= 1);
- /* Allocate a new column set, linked to the old one for cleanup */
- ulT = CbNewSPropTagArray(NUM_REQUIRED_COLS + lpsptT->cValues);
- sc = (*lpxpl->AllocateMore) (ulT, (LPVOID) lpsptT, (LPVOID) &lpsptNew);
- if (sc)
- {
- hResult = ResultFromScode(sc);
- DebugTrace("New column set allocation failed.n");
- goto ret;
- }
- /* Fill in the new column set, required fields first in our order. */
- lpsptNew->aulPropTag[COLUMN_PR_ROWID] = PR_ROWID;
- lpsptNew->aulPropTag[COLUMN_PR_EMAIL_ADDRESS] = PR_EMAIL_ADDRESS;
- lpsptNew->aulPropTag[COLUMN_PR_RESPONSIBILITY] = PR_RESPONSIBILITY;
- lpsptNew->aulPropTag[COLUMN_PR_REPORT_TEXT] = PR_NULL;
- lpsptNew->aulPropTag[COLUMN_PR_RECIPIENT_TYPE] = PR_RECIPIENT_TYPE;
- ulNew = NUM_REQUIRED_COLS;
- for (ulT = 0; ulT < lpsptT->cValues; ulT++)
- {
- switch (lpsptT->aulPropTag[ulT])
- {
- case PR_REPORT_TEXT:
- lpsptNew->aulPropTag[COLUMN_PR_REPORT_TEXT] = PR_REPORT_TEXT;
- break;
- case PR_ROWID:
- case PR_EMAIL_ADDRESS:
- case PR_RESPONSIBILITY:
- case PR_RECIPIENT_TYPE:
- break;
- default:
- lpsptNew->aulPropTag[ulNew++] = lpsptT->aulPropTag[ulT];
- break;
- }
- }
- lpsptNew->cValues = ulNew;
- /* Set the new columns */
- hResult = lpTable->lpVtbl->SetColumns(lpTable, lpsptNew, 0L);
- if (hResult)
- {
- DebugTrace("SetColumns failed.n");
- goto ret;
- }
- /* Free both old and new PropTagArrays. */
- (*lpxpl->FreeBuffer) ((LPVOID) lpsptT);
- lpsptT = NULL;
- /* Build two big ADRLISTs from this table. Do minimal allocations so
- that all the reallocation code will be properly exercised. We can
- optimize later when we've tested.
- The obvious underlying assumption of this code is that it's
- possible to get the entire recipient list into memory at once. */
- #ifdef DEBUG
- #define GROW_SIZE 1 /* How much we'll add on every reallocation. */
- #define QUERY_SIZE 1 /* How much we'll try for on query rows */
- #else
- #define GROW_SIZE 20
- #define QUERY_SIZE 20
- #endif
- for (;;)
- {
- /* Get some rows from the recipient table. */
- hResult = lpTable->lpVtbl->QueryRows(lpTable, QUERY_SIZE, 0L, &lpRow);
- if (hResult)
- {
- DebugTrace("QueryRows failed.n");
- goto ret;
- }
- /* Are we finished getting rows? */
- if (!lpRow || !(lpRow->cRows))
- {
- /* Free the row if any */
- (*lpxpl->FreeBuffer) ((LPVOID) lpRow);
- lpRow = NULL;
- /* We're finished now, break out of the (for (;;)) loop. */
- break;
- }
- /* Work our way through the RowSet */
- for (ulRow = 0; ulRow < lpRow->cRows; ulRow++)
- {
- BOOL fDone = TRUE;
- Assert(lpRow->aRow[ulRow].cValues);
- Assert(lpRow->aRow[ulRow].lpProps);
- lpspvT = lpRow->aRow[ulRow].lpProps;
- /* Check our .2 second timer before processing each row. */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message delivery.n");
- goto ret;
- }
- /* See if we need to do the callback. If so, make the call now */
- if (lpfnCallBack)
- {
- Assert(lpspvT[COLUMN_PR_EMAIL_ADDRESS].ulPropTag == PR_EMAIL_ADDRESS);
- Assert(lpspvT[COLUMN_PR_RECIPIENT_TYPE].ulPropTag == PR_RECIPIENT_TYPE);
- hResult = lpfnCallBack(lpxpl,
- lpPropArray,
- lpMessage,
- lpspvT[COLUMN_PR_RECIPIENT_TYPE].Value.ul,
- lpspvT[COLUMN_PR_EMAIL_ADDRESS].Value.LPSZ,
- &fDone);
- if (hResult)
- {
- DebugTrace("IGNORE: Callback function failed.n");
- hResult = hrSuccess;
- }
- }
- /* Set the PR_RESPONSIBILITY flag to its indicated new state. */
- Assert(lpRow->aRow[ulRow].cValues > COLUMN_PR_RESPONSIBILITY);
- /* Make the appropriate change to PR_RESPONSIBILITY. If we're
- setting it, just do it into whatever column we've set;
- is pointing at, Prop Tag and Value. If we're clearing it,
- we only need to do anything if there was a discrete column,
- and all that's needed is to set the Prop Tag to PR_NULL. */
- if (fSetResponsibility)
- {
- lpspvT[COLUMN_PR_RESPONSIBILITY].ulPropTag = PR_RESPONSIBILITY;
- lpspvT[COLUMN_PR_RESPONSIBILITY].Value.b = fDone;
- }
- else
- {
- /* We want to clear the flag */
- lpspvT[COLUMN_PR_RESPONSIBILITY].ulPropTag = PR_NULL;
- }
- /* PR_NULL the PR_ROWID column if this will be a "bad" recipient, also
- adding NDR information to the row (in a column we set earlier) */
- if (!fDone)
- {
- TCHAR szReportText[512];
- lpspvT[COLUMN_PR_ROWID].ulPropTag = PR_NULL;
- /* The Spooler will default to a NDR report and will fill in all
- required properties in the StatusRecips call. The only thing
- we need to do is to fill in a specific per-recipient text
- description of the problem (it defaults too but it's good
- to have real info from the horse's mouth) */
- LoadString(lpxpl->lpxppParent->hInst, IDS_REPORT_TEXT_MSG,
- szReportText, sizeof(szReportText));
- wsprintf(rgchBuffer, "%s%s", szReportText,
- lpspvT[COLUMN_PR_EMAIL_ADDRESS].Value.LPSZ);
- ulT = Cbtszsize(rgchBuffer);
- sc = lpxpl->AllocateMore(ulT, lpspvT, &lpvT);
- if (sc)
- {
- hResult = ResultFromScode(sc);
- DebugTrace("NDR text allocation failed.n");
- goto ret;
- }
- /* Memory allocated, copy the formatted string and hook it into
- the pre-allocated column. */
- lstrcpy((LPTSTR) lpvT, rgchBuffer);
- lpspvT[COLUMN_PR_REPORT_TEXT].ulPropTag = PR_REPORT_TEXT;
- lpspvT[COLUMN_PR_REPORT_TEXT].Value.LPSZ = (LPTSTR) lpvT;
- }
- /* Now point ourselves at one of the two LPMYADRLIST pointers */
- lppMyAdrList = (fDone ? &lpDone : &lpNotDone);
- /* If we didn't already have a LPMYADRLIST, allocate one now. */
- if (*lppMyAdrList == NULL)
- {
- /* Allocate an initial MYADRLIST structure. Then allocate
- enough memory for (GROW_SIZE) ADRENTRYs and store
- it into the structure. Initialize the members. */
- sc = (*lpxpl->AllocateBuffer) (sizeof(MYADRLIST), &lpvT);
- if (sc)
- {
- hResult = ResultFromScode(sc);
- DebugTrace("Initial MYADRLIST allocation failed.n");
- goto ret;
- }
- /* Hook up the MYADRLIST with no entries. */
- *lppMyAdrList = (LPMYADRLIST) lpvT;
- (*lppMyAdrList)->cMaxEntries = 0;
- (*lppMyAdrList)->lpAdrList = NULL;
- /* Now allocate a ADRLIST with GROW_SIZE entries in it. */
- sc = (*lpxpl->AllocateBuffer) (CbNewADRLIST(GROW_SIZE), &lpvT);
- if (sc)
- {
- hResult = ResultFromScode(sc);
- DebugTrace("Initial ADRLIST allocation failed.n");
- goto ret;
- }
- /* Now hook up this ADRLIST into the MYADRLIST. */
- (*lppMyAdrList)->lpAdrList = (LPADRLIST) lpvT;
- (*lppMyAdrList)->cMaxEntries = GROW_SIZE;
- (*lppMyAdrList)->lpAdrList->cEntries = 0;
- }
- /* Make sure that the selected MYADRLIST has room for another row */
- ulT = (*lppMyAdrList)->lpAdrList->cEntries + 1;
- Assert(ulT <= (*lppMyAdrList)->cMaxEntries + 1);
- if (ulT > (*lppMyAdrList)->cMaxEntries)
- {
- LPADRLIST lpAdrListT;
- /* Not enough space, we need to create a new ADRLIST. */
- ulT = CbNewADRLIST((*lppMyAdrList)->cMaxEntries + GROW_SIZE);
- sc = (*lpxpl->AllocateBuffer) (ulT, &lpvT);
- if (sc)
- {
- hResult = ResultFromScode(sc);
- DebugTrace("Reallocation of ADRLIST failed.n");
- goto ret;
- }
- /* Got it, now copy the data from the old one */
- lpAdrListT = (LPADRLIST) lpvT;
- ulT = CbNewADRLIST((*lppMyAdrList)->cMaxEntries);
- if (ulT)
- memcpy(lpAdrListT, (*lppMyAdrList)->lpAdrList, (UINT) ulT);
- (*lppMyAdrList)->cMaxEntries += GROW_SIZE;
- /* Exchange the pointers */
- lpvT = (LPVOID) (*lppMyAdrList)->lpAdrList;
- (*lppMyAdrList)->lpAdrList = lpAdrListT;
- /* Free the old memory */
- lpxpl->FreeBuffer(lpvT);
- }
- /* We have room now so store the new ADRENTRY. As part of the
- storage, we're going to copy the SRow pointer from the SRowSet
- into the ADRENTRY. Once we've done this, we won't need the
- SRowSet any more ... and the SRow will be deallocated when
- we unwind the ADRLIST. */
- /* Calculate location in ADRLIST for the new entry. */
- ulT = (*lppMyAdrList)->lpAdrList->cEntries++;
- /* Copy the data from the SRowSet. */
- (*lppMyAdrList)->lpAdrList->aEntries[ulT].cValues = lpRow->aRow[ulRow].cValues;
- (*lppMyAdrList)->lpAdrList->aEntries[ulT].rgPropVals = lpRow->aRow[ulRow].lpProps;
- /* Now that we are finished with this row (eg it is in the
- adrlist) we want to disassociate it from the rowset. */
- lpRow->aRow[ulRow].lpProps = NULL;
- }
- /* We're finished with the SRowSet (since it is allocated
- separately from the SRow). Deallocate it. */
- lpxpl->FreeBuffer((LPVOID) lpRow);
- lpRow = NULL;
- } /* End of big ADRLIST builder loop */
- /* Fall into exit with hResult set if something failed. */
- ret:
- /* Clean up RowSet if any is left */
- FreeProws(lpRow);
- /* Clean up column stuff if any's left */
- lpxpl->FreeBuffer((LPVOID) lpsptT);
- /* If sc is set, feed it into hResult. Afterwards, hResult is the
- determinant of whether there was an error or not. */
- if (hResult)
- {
- /* This memory should only be hanging around in the error case. */
- FreeMyAdrList(lpxpl, lpDone);
- FreeMyAdrList(lpxpl, lpNotDone);
- *lppMyAdrListGood = NULL;
- *lppMyAdrListBad = NULL;
- }
- else
- {
- /* Success, pass the adrlists we built back to the caller */
- *lppMyAdrListGood = lpDone;
- *lppMyAdrListBad = lpNotDone;
- }
- DebugTraceResult(HrBuildAdrList, hResult);
- return hResult;
- }
- /*
- - HrSendOneMessage
- -
- * Purpose:
- * Called by HrBuildAdrList() to send a message to a recipient
- * that matched all of the caller's restrictions. Also called by
- * XPL_SubmitMessage() if transport is not peer-to-peer, in which
- * case the "Email address" is just our outbound directory.
- *
- * Parameters:
- * lpxpl The Transports logon object for this session
- * lpPropArray Logon properties that have been copied from lpxpl
- * lpMessage Message to send
- * ulRecipType MAPI_TO, MAPI_CC, etc. If 0, not a recip.
- * lpszEmailAddress Email address of this recipient.
- * lpfSent Pointer to the boolean result
- * of the operation.
- *
- * Returns:
- * (HRESULT) Set if an error encountered.
- * *lpfSent FALSE if sending failed,
- * TRUE if sending succeeded.
- *
- * Operation:
- * Initializes result in *lpfSent to FALSE. Open a stream interface
- * on the destination message file. Write all the textized envelope
- * properties into the stream, then use TNEF to encapsulate the remaining
- * message properties into the stream.
- */
- HRESULT
- HrSendOneMessage(LPXPL lpxpl,
- LPSPropValue lpPropArray,
- LPMESSAGE lpMessage,
- ULONG ulRecipType,
- LPTSTR lpszEmailAddress,
- BOOL FAR * lpfSent)
- {
- TCHAR rgchOutFileName[MAX_PATH];
- HRESULT hResult = 0;
- SCODE sc = 0;
- ULONG ulT;
- ULONG cValues;
- BOOL fFromMe;
- LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
- LPIID lpidMessage = (LPIID) &IID_IMessage;
- SPropValue spvDestMsgProps[3];
- LPSPropProblemArray lpProblems = NULL;
- LPSPropTagArray lpPropTagArray = NULL;
- LPSTnefProblemArray lptpa = NULL;
- WORD wKey = 0;
- LPITNEF lpTnef = (LPITNEF) NULL;
- LPSTREAM lpSof = (LPSTREAM) NULL;
- LPSTREAM lpXPSof = (LPSTREAM) NULL;
- /* Assume the worst, we'll fix it later if need be */
- *lpfSent = FALSE;
- /* Build file name of outgoing message. Because loopback doesn't
- always work on all platforms, we check the email address against
- our own and just substitute the inbox path if it matches. */
- if (!lstrcmpi(lpszEmailAddress,
- ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ))
- {
- DebugTrace("Email Address is mine, doing my own internal loopbackn");
- lstrcpy(rgchOutFileName, ArrayIndex(PR_SAMPLE_INBOUND_DIR, lpPropArray).Value.LPSZ);
- fFromMe = TRUE;
- }
- else
- {
- lstrcpy(rgchOutFileName, lpszEmailAddress);
- /* If this is a real email address, it won't have a
- trailing backslash. But if it's our outbound dir (when
- we're not p2p) it wiil have one. Only add one if
- it's needed. */
- ulT = lstrlen(rgchOutFileName);
- Assert(ulT > 1);
- if (lstrcmp(&rgchOutFileName[ulT], TEXT("\")))
- lstrcat(rgchOutFileName, TEXT("\"));
- fFromMe = FALSE;
- }
- hResult = OpenStreamOnFile(lpxpl->AllocateBuffer, lpxpl->FreeBuffer,
- STGM_CREATE | STGM_READWRITE | SOF_UNIQUEFILENAME,
- rgchOutFileName, TEXT("TNF"), &lpSof);
- if (HR_FAILED(hResult))
- {
- DebugTrace("OpenStreamOnFile(%s) failed.n",rgchOutFileName);
- PrintfTransportLog(TEXT("Delivery failed in OpenStreamOnFile."));
- goto ret;
- }
- /* Wrap the Stream-On-File object in our buffered wrapper. */
- hResult = HrWrapStreamOnFile(lpxpl->AllocateBuffer, lpxpl->FreeBuffer,
- XPSOF_READWRITE, lpSof, &lpXPSof);
- if (HR_FAILED(hResult))
- {
- DebugTrace("HrWrapStreamOnFile() failedn");
- goto ret;
- }
- /* Write all non-TNEF properties to the text file */
- hResult = HrIMsgToTextMsg(lpxpl, lpPropArray, lpMessage, lpXPSof);
- if (HR_FAILED(hResult))
- {
- DebugTrace("HrIMsgToTextMsg() failed.n");
- PrintfTransportLog(TEXT("Delivery failed in HrIMsgToTextMsg."));
- goto ret;
- }
- hResult = hrSuccess;
- /* Check our .2 second timer after writting textized properties. */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message delivery.n");
- goto ret;
- }
- /* Open a TNEF encapsulation on the StreamOnFile interface */
- hResult = OpenTnefStream(lpMAPISup, lpXPSof, TEXT("MAPIMAIL.DAT"),
- TNEF_ENCODE, lpMessage, 0x01AF, &lpTnef);
- if (HR_FAILED(hResult))
- {
- DebugTrace("OpenTNEFStream() failed.n");
- PrintfTransportLog(TEXT("Delivery failed in OpenTNEFStream."));
- goto ret;
- }
- /* Find out what properties there are, so we can exclude the
- "nontransmittables" and the properties we've textized. */
- hResult = lpMessage->lpVtbl->GetPropList(lpMessage, 0, /* ansi */
- &lpPropTagArray);
- if (hResult)
- {
- DebugTrace("GetPropList failed.n");
- goto ret;
- }
- Assert(lpPropTagArray);
- /* Build a new prop tag array on the memory we just got back. This
- prop tag array will only contain nontransmittable properties. */
- cValues = 0;
- for (ulT = 0; ulT < lpPropTagArray->cValues; ulT++)
- {
- ULONG ulPropTagT = lpPropTagArray->aulPropTag[ulT];
- /* FIsTransmittable is a macro in the MAPI headers. Makes it
- really easy to determine transmittable/not when we need to */
- if ((!FIsTransmittable(ulPropTagT) || FIsTextizedProp(ulPropTagT)) &&
- (ulPropTagT != PR_MESSAGE_ATTACHMENTS))
- {
- lpPropTagArray->aulPropTag[cValues++] = ulPropTagT;
- }
- }
- lpPropTagArray->cValues = cValues;
- /* Exclude selected properties from our TNEF encapsulation. */
- hResult = lpTnef->lpVtbl->AddProps(lpTnef,
- TNEF_PROP_EXCLUDE, 0L, NULL, lpPropTagArray);
- if (HR_FAILED(hResult))
- {
- DebugTrace("AddProps failed.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;
- }
- /* If we had a recipient type, we should help the receiver side out
- with some properties, as follows:
- PR_MESSAGE_TO_ME should be set TRUE if ulRecipType == MAPI_TO
- PR_MESSAGE_CC_ME should be set TRUE if ulRecipType == MAPI_CC
- PR_MESSAGE_RECIP_ME should be set TRUE for either of the above */
- if (ulRecipType)
- {
- spvDestMsgProps[0].ulPropTag = PR_MESSAGE_TO_ME;
- spvDestMsgProps[0].Value.b = (ulRecipType == MAPI_TO);
- spvDestMsgProps[1].ulPropTag = PR_MESSAGE_CC_ME;
- spvDestMsgProps[1].Value.b = (ulRecipType == MAPI_CC);
- spvDestMsgProps[2].ulPropTag = PR_MESSAGE_RECIP_ME;
- spvDestMsgProps[2].Value.b = ((ulRecipType == MAPI_TO) || (ulRecipType == MAPI_CC));
- lpxpl->FreeBuffer(lpProblems);
- lpProblems = NULL;
- hResult = lpTnef->lpVtbl->SetProps(lpTnef, 0L, 0L, 3,
- spvDestMsgProps);
- if (HR_FAILED(hResult))
- {
- DebugTrace("SetProps failed");
- goto ret;
- }
- }
- /* OK. All the properties are copied over. Save Changes on the
- message we created. */
- hResult = lpTnef->lpVtbl->Finish(lpTnef, 0L, &wKey, &lptpa);
- lpxpl->FreeBuffer(lptpa);
- if (HR_FAILED(hResult))
- {
- DebugTrace("Finish failed.n");
- goto ret;
- }
- hResult = lpXPSof->lpVtbl->Commit(lpXPSof, STGC_DEFAULT);
- if (HR_FAILED(hResult))
- {
- DebugTrace("Commit stream failed.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;
- }
- *lpfSent = TRUE;
- /* Log successful transmission. */
- PrintfTransportLog(TEXT("Delivery Complete: %s"), rgchOutFileName);
- ret:
- /* Release any open object */
- UlRelease(lpTnef);
- UlRelease(lpXPSof);
- UlRelease(lpSof);
- if (HR_FAILED(hResult) && lpSof)
- DeleteFile(rgchOutFileName);
- /* Release the prop tag array and/or problem array if any */
- lpxpl->FreeBuffer(lpPropTagArray);
- DebugTraceResult(HrSendOneMessage, hResult);
- return hResult;
- }
- /* Stuff to support the textized message formatting */
- const static SizedSPropTagArray(4, sptMsgProps) =
- {
- 4,
- {
- PR_CLIENT_SUBMIT_TIME,
- PR_SUBJECT,
- PR_PRIORITY,
- PR_BODY
- }
- };
- const static SizedSPropTagArray(5, sptRecipProps) =
- {
- 5,
- {
- PR_RECIPIENT_TYPE,
- PR_EMAIL_ADDRESS,
- PR_ADDRTYPE,
- PR_DISPLAY_NAME,
- PR_RESPONSIBILITY
- }
- };
- const static SizedSPropTagArray(3, sptSenderDelegate) =
- {
- 3,
- {
- PR_SENT_REPRESENTING_ENTRYID,
- PR_SENDER_ENTRYID,
- PR_REPLY_RECIPIENT_ENTRIES,
- }
- };
- TCHAR rgszTags[NUM_TAGS][MAX_TAG_LEN] =
- {
- TEXT("Message: "),
- TEXT("From: "),
- TEXT("Representing: "),
- TEXT("Reply To: "),
- TEXT("Date: "),
- TEXT("To: "),
- TEXT("Cc: "),
- TEXT("Bcc: "),
- TEXT("Subject: "),
- TEXT("Priority Urgent: "),
- TEXT("Priority Normal: "),
- TEXT("Priority Low: "),
- TEXT("Contents: "),
- TEXT("Text Item: "),
- TEXT("File Item: ")
- };
- TCHAR szCRLF[3] = {TEXT("rn")};
- TCHAR szCRLFCRLF[5] = {TEXT("rnrn")};
- /*
- - HrIMsgToTextMsg
- -
- * Purpose:
- * Called by HrSendOneMessage() to write the envelope properties
- * to the destination message text file. Uses the StreamOnFile
- * interface for all the file access. This stream interface
- * is then passed to the TNEF encoder, with its current file
- * pointer un-modified, so the non-envelope properties can be
- * encapsulated in a TNEF encapsulation in a "File Item" section.
- *
- * Parameters:
- * lpxpl Pointer to Transport Logon object
- * lpPropArray Copy of the sessions logon properties
- * lpMessage Message to send
- * lpSof Pointer to the stream interface
- *
- * Returns:
- * (HRESULT) Set if an error encountered.
- *
- * Operation:
- * Call GetProps() on the message to extract PR_SUBMIT_DATE, PR_SUBJECT,
- * PR_PRIORITY, and PR_BODY. Then call GetRecipientTable() to extract
- * the PR_DISPLAY_NAME and PR_EMAIL_ADDRESS for each type of
- * PR_RECIPIENT_TYPE. Write all this info to the stream (after
- * formatting appropriately).
- */
- HRESULT
- HrIMsgToTextMsg(LPXPL lpxpl, LPSPropValue lpPropArray, LPMESSAGE lpMessage, LPSTREAM lpSof)
- {
- HRESULT hr = hrSuccess;
- ULONG cMsgVals = 0;
- ULONG cSndrVals = 0;
- LPSPropValue lpMsgProps = NULL;
- LPSPropValue lpSndrProps = NULL;
- LPSPropValue lpPropT = NULL;
- LPMAPITABLE lpTbl = NULL;
- LPSRowSet lpRows = NULL;
- ULONG uli;
- ULONG cbOut;
- ULONG cbRead;
- ULONG cbCRLF = lstrlen(szCRLF);
- ULONG cbCRLFCRLF = lstrlen(szCRLFCRLF);
- TCHAR szRep[128];
- TCHAR szFrom[128];
- TCHAR szOutBuf[128];
- TCHAR rgchStrmBuf[MAX_STRM_BUF];
- LPTSTR lpszT1;
- LPTSTR lpszT2;
- LPSTREAM lpStrm = NULL;
- /* Get the 4 Message properties to be textized */
- hr = lpMessage->lpVtbl->GetProps(lpMessage,
- (LPSPropTagArray) &sptMsgProps, 0, /* ansi */
- &cMsgVals, &lpMsgProps);
- if (HR_FAILED(hr) || !cMsgVals)
- {
- DebugTrace("GetProps() MsgProps failed.n");
- goto ret;
- }
- /* Get the 3 Sender/Delegate properties to be textized */
- hr = lpMessage->lpVtbl->GetProps(lpMessage,
- (LPSPropTagArray) &sptSenderDelegate, 0, /* ansi */
- &cSndrVals, &lpSndrProps);
- if (HR_FAILED(hr) || !cSndrVals)
- {
- DebugTrace("GetProps() SndrProps failed.n");
- goto ret;
- }
- /* Returns the Recipient Table in a well defined state
- (i.e. minimal column set and restricted on our AddrType). */
- hr = HrPrepareRecipientTable(lpPropArray, lpMessage, &lpTbl);
- if (HR_FAILED(hr))
- {
- DebugTrace("HrPrepareRecipientTable() failed.n");
- goto ret;
- }
- /* Write Message: field */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, rgszTags[tagMessage],
- lstrlen(rgszTags[tagMessage]), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- /* Write From: and Representing: fields */
- /* The following code sets the Sender/Delegate */
- /* properties as follows:
- 1) If no PR_SENT_REPRESENTING_??? in message,
- a) If no PR_SENDER_??? in message,
- PR_SENDER_??? = transport identities
- b) PR_SENT_REPRESENTING_??? = PR_SENDER_???
- 2) (else) If there was a PR_SENT_REPRESENTING_??? in message,
- a) If no PR_SENDER_??? in message,
- PR_SENDER_??? = PR_SENT_REPRESENTING_???
- 3) If no PR_REPLY_RECIPIENT_???,
- PR_REPLY_RECIPIENT_ENTRIES = PR_SENT_REPRESENTING_ENTRYID
- PR_REPLY_RECIPIENT_NAMES = PR_SENT_REPRESENTING_NAME
- This just works because HrCrackSenderEID() doesn't change the
- szFrom or szRep memory unless it is successful. It is for this
- reason that we don't check the return from HrCrackSenderEID() */
- hr = hrSuccess;
- *szFrom = ' ';
- *szRep = ' ';
- if (lpSndrProps[0].ulPropTag == PR_SENT_REPRESENTING_ENTRYID)
- HrCrackSenderEID(lpxpl, lpSndrProps[0].Value.bin.cb,
- lpSndrProps[0].Value.bin.lpb, szRep);
- if (lpSndrProps[1].ulPropTag == PR_SENDER_ENTRYID)
- HrCrackSenderEID(lpxpl, lpSndrProps[1].Value.bin.cb,
- lpSndrProps[1].Value.bin.lpb, szFrom);
- if (!*szFrom && !*szRep)
- {
- lpszT1 = ArrayIndex(PR_SAMPLE_DISPLAY_NAME, lpPropArray).Value.LPSZ;
- lpszT2 = ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS, lpPropArray).Value.LPSZ;
- wsprintf(szFrom, TEXT("%s[%s]"), lpszT1, lpszT2);
- lstrcpy(szRep, szFrom);
- }
- else if (*szFrom && !*szRep)
- {
- lstrcpy(szRep, szFrom);
- }
- else
- {
- lstrcpy(szFrom, szRep);
- }
- wsprintf(szOutBuf, TEXT("%s%s"), rgszTags[tagFrom], szFrom);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szOutBuf,
- lstrlen(szOutBuf), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- wsprintf(szOutBuf, TEXT("%s%s"), rgszTags[tagRepresenting], szRep);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szOutBuf,
- lstrlen(szOutBuf), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- /* Write Reply To: fields */
- if (lpSndrProps[2].ulPropTag == PR_REPLY_RECIPIENT_ENTRIES)
- {
- LPFLATENTRYLIST lpList = (LPFLATENTRYLIST) lpSndrProps[2].Value.bin.lpb;
- LPBYTE lpb;
- ULONG cEntries;
- /* Attempt some level of validation for this property */
- if (!lpList
- || IsBadReadPtr(lpList, CbNewFLATENTRYLIST(0))
- || !lpList->abEntries
- || IsBadReadPtr(lpList, (UINT) CbFLATENTRYLIST(lpList))
- || !lpList->cEntries
- || (lpList->cEntries * sizeof(GUID) > lpList->cbEntries))
- {
- DebugTrace("Bad PR_REPLY_RECIPIENT_ENTRIES!n");
- DebugTrace("Skipping the Reply To: field.n");
- }
- else
- {
- lpb = lpList->abEntries;
- cEntries = lpList->cEntries;
- while (cEntries--)
- {
- LPFLATENTRY lpEntry = (LPFLATENTRY) lpb;
- ULONG ulSize;
- if (IsBadReadPtr(lpEntry, CbNewFLATENTRY(0))
- || IsBadReadPtr(lpEntry, (UINT) CbFLATENTRY(lpEntry)))
- {
- DebugTrace("Bad entry inside PR_REPLY_RECIPIENT_ENTRIES!n");
- break;
- }
- ulSize = lpEntry->cb;
- hr = HrCrackSenderEID(lpxpl, ulSize, lpEntry->abEntry, szFrom);
- if (!hr)
- {
- wsprintf(szOutBuf, TEXT("%s%s"),
- rgszTags[tagReplyTo], szFrom);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szOutBuf,
- lstrlen(szOutBuf), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLF,
- cbCRLF, &cbOut), ret);
- }
- lpb += offsetof (FLATENTRY, abEntry) + ((ulSize + 3) & -4L);
- }
- /* Add one more CR/LF pair after Reply Recipients */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof,
- szCRLF, cbCRLF, &cbOut), ret);
- }
- }
- else
- {
- wsprintf(szOutBuf, TEXT("%s%s"), rgszTags[tagReplyTo], szFrom);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szOutBuf,
- lstrlen(szOutBuf), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- }
- /* Write Date: field */
- if (FPropIndex(lpMsgProps, cMsgVals, PR_CLIENT_SUBMIT_TIME, &uli))
- {
- /* Property exists in message; write it to the stream */
- FormatFileTime(&lpMsgProps[uli].Value.ft, szOutBuf);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, rgszTags[tagDate],
- lstrlen(rgszTags[tagDate]), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szOutBuf,
- lstrlen(szOutBuf), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- }
- /* Write To: & Cc: fields */
- while (TRUE)
- {
- /* Get a row from the Recipient Table */
- hr = lpTbl->lpVtbl->QueryRows(lpTbl, 1, 0, &lpRows);
- if (hr || !lpRows || (lpRows->cRows != 1))
- break;
- lpPropT = lpRows->aRow[0].lpProps;
- /* Throw away MAPI_ORIG and P1 Recipient Types */
- if ((lpPropT[0].Value.l != MAPI_TO) &&
- (lpPropT[0].Value.l != MAPI_CC))
- {
- FreeProws(lpRows);
- lpRows = NULL;
- lpPropT = NULL;
- continue;
- }
- /* Write Recipients as:
- '{To: | Cc: } Display Name [email-address]' */
- Assert((lpPropT[0].Value.l == MAPI_TO) ||
- (lpPropT[0].Value.l == MAPI_CC));
- wsprintf(szOutBuf, TEXT("%s%s[%s]"),
- rgszTags[tagDate + lpPropT[0].Value.l],
- lpPropT[3].Value.LPSZ, lpPropT[1].Value.LPSZ);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szOutBuf,
- lstrlen(szOutBuf), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLF,
- cbCRLF, &cbOut), ret);
- /* Clean-Up */
- FreeProws(lpRows);
- lpRows = NULL;
- lpPropT = NULL;
- }
- /* Add one more CR/LF pair after recipients */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLF, cbCRLF, &cbOut), ret);
- /* Write Subject: field */
- if (FPropIndex(lpMsgProps, cMsgVals, PR_SUBJECT, &uli))
- {
- /* Property exists and is small enough to not require a
- stream interface to be opened on it; just write it. */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, rgszTags[tagSubject],
- lstrlen(rgszTags[tagSubject]), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLF,
- cbCRLF, &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, lpMsgProps[uli].Value.LPSZ,
- lstrlen(lpMsgProps[uli].Value.LPSZ), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- }
- else if (!(hr = lpMessage->lpVtbl->OpenProperty(lpMessage, PR_SUBJECT,
- (LPIID) &IID_IStream, 0, 0, (LPUNKNOWN *) &lpStrm)))
- {
- /* Property exists and requires a stream interface to
- access all the data. Copy between streams! */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, rgszTags[tagSubject],
- lstrlen(rgszTags[tagSubject]), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLF,
- cbCRLF, &cbOut), ret);
- while (TRUE)
- {
- hr = lpStrm->lpVtbl->Read(lpStrm, (LPVOID) rgchStrmBuf,
- MAX_STRM_BUF, &cbRead);
- if (hr || (cbRead == 0))
- break; /* There's nothing to write; we're done! */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, (LPVOID) rgchStrmBuf,
- cbRead, &cbOut), ret);
- if (cbRead < MAX_STRM_BUF)
- break; /* We've exhausted the stream; we're done! */
- }
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- lpStrm->lpVtbl->Release(lpStrm);
- lpStrm = NULL;
- }
- /* Write Priority: field */
- if (FPropIndex(lpMsgProps, cMsgVals, PR_PRIORITY, &uli))
- {
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof,
- rgszTags[tagPrioNormal - lpMsgProps[uli].Value.l],
- lstrlen(rgszTags[tagPrioNormal - lpMsgProps[uli].Value.l]),
- &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- }
- /* Write Contents: field */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, rgszTags[tagContents],
- lstrlen(rgszTags[tagContents]), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- /* Text Item: */
- if (FPropIndex(lpMsgProps, cMsgVals, PR_BODY, &uli))
- {
- /* Property exists and is small enough to not require
- a stream interface to be opened on it; just copy it */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, rgszTags[tagTextItem],
- lstrlen(rgszTags[tagTextItem]), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLF,
- cbCRLF, &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, lpMsgProps[uli].Value.LPSZ,
- lstrlen(lpMsgProps[uli].Value.LPSZ), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- }
- else if (!(hr = lpMessage->lpVtbl->OpenProperty(lpMessage, PR_BODY,
- (LPIID) &IID_IStream, 0, 0, (LPUNKNOWN *) &lpStrm)))
- {
- /* Property exists and requires a stream interface to
- access all the data. Copy between streams! */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, rgszTags[tagTextItem],
- lstrlen(rgszTags[tagTextItem]), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLF,
- cbCRLF, &cbOut), ret);
- while (TRUE)
- {
- hr = lpStrm->lpVtbl->Read(lpStrm, (LPVOID) rgchStrmBuf,
- MAX_STRM_BUF, &cbRead);
- if (hr || (cbRead == 0))
- break; /* There's nothing to write; we're done! */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, (LPVOID) rgchStrmBuf,
- cbRead, &cbOut), ret);
- if (cbRead < MAX_STRM_BUF)
- break; /* We've exhausted the stream; we're done! */
- }
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLFCRLF,
- cbCRLFCRLF, &cbOut), ret);
- lpStrm->lpVtbl->Release(lpStrm);
- lpStrm = NULL;
- }
- /* File Item: */
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, rgszTags[tagFileItem],
- lstrlen(rgszTags[tagFileItem]), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, TEXT("MESSAGE.TNF"),
- lstrlen(TEXT("MESSAGE.TNF")), &cbOut), ret);
- TraceFailedWrite(lpSof->lpVtbl->Write(lpSof, szCRLF,
- cbCRLF, &cbOut), ret);
- ret:
- lpxpl->FreeBuffer(lpMsgProps);
- lpxpl->FreeBuffer(lpSndrProps);
- FreeProws(lpRows);
- UlRelease(lpTbl);
- DebugTraceResult(HrIMsgToTextMsg(), hr);
- return hr;
- }
- /*
- - HrPrepareRecipientTable
- -
- * Purpose:
- * Gets the Recipient Table from an IMAPIMessage and sets its
- * columns, restricts the view, and sorts it (if sorts are
- * supported). All this in preparation of writing recipients
- * to the destination message file.
- *
- * Parameters:
- * lpPropArray Pointer to Transport Logon object
- * lpMsg Message to GetRecipientTable on
- * lppTbl Receives the RecipientTable
- *
- * Returns:
- * hr Indicating Success/Failure
- */
- HRESULT
- HrPrepareRecipientTable(LPSPropValue lpPropArray, LPMESSAGE lpMsg, LPMAPITABLE * lppTbl)
- {
- HRESULT hr = hrSuccess;
- LPMAPITABLE lpTbl = NULL;
- SizedSSortOrderSet(2, rgSort) =
- {
- 2, 0, 0,
- {
- PR_RECIPIENT_TYPE, TABLE_SORT_ASCEND,
- PR_ROWID, TABLE_SORT_ASCEND
- }
- };
- *lppTbl = NULL;
- hr = lpMsg->lpVtbl->GetRecipientTable(lpMsg, 0, &lpTbl);
- if (HR_FAILED(hr))
- {
- DebugTrace("GetRecipientTable() failed in HrPrepareRecipientTable()");
- goto ret;
- }
- /* SetColumns to: PR_RECIPIENT_TYPE, PR_EMAIL_ADDRESS, PR_ADDRTYPE,
- PR_DISPLAY_NAME, and PR_RESPONSIBILITY in that order */
- hr = lpTbl->lpVtbl->SetColumns(lpTbl, (LPSPropTagArray) &sptRecipProps,
- TBL_BATCH);
- if (HR_FAILED(hr))
- {
- DebugTrace("SetColumns() failed in HrPrepareRecipientTable()");
- goto ret;
- }
- /* Sort by: PR_RECIPIENT_TYPE (i.e. MAPI_TO, MAPI_CC, MAPI_BCC)
- and PR_ROWID, both in acsending order */
- hr = lpTbl->lpVtbl->SortTable(lpTbl, (LPSSortOrderSet) &rgSort, TBL_BATCH);
- if (hr)
- {
- /* Don't fail the call for no support! Just return
- the table in whatever order it may be in by default. */
- if (GetScode(hr) == MAPI_E_NO_SUPPORT)
- hr = 0;
- else
- DebugTrace("SortTable() failed in HrPrepareRecipientTable()");
- }
- /* Seek to the beginning since sorting may have moved out position */
- hr = lpTbl->lpVtbl->SeekRow(lpTbl, BOOKMARK_BEGINNING, 0, NULL);
- if (hr)
- {
- DebugTrace("SeekRow() failed in HrPrepareRecipientTable()");
- }
- ret:
- if (HR_FAILED(hr))
- {
- UlRelease(lpTbl);
- }
- else
- *lppTbl = lpTbl;
- DebugTraceResult(HrPrepareRecipientTable(), hr);
- return hr;
- }
- /*
- - HrCrackSenderEID
- -
- * Purpose:
- * Does an OpenEntry() on the EntryID and GetProps() PR_DISPLAY_NAME
- * and PR_EMAIL_ADDRESS. Then formats the return string like:
- * "Display Name[email-address]"
- *
- * Parameters:
- * lpxpl Pointer to Transport Logon object
- * cb Count of bytes in EntryID
- * lpb Pointer to EntryID
- * lpsz Receives the formatted Name/Address pair
- *
- * Returns:
- * hr Indicating Success/Failure
- *
- * Note:
- * No parameter validation! I assume the caller knew what was
- * being passed in and ensured all was well.
- */
- HRESULT
- HrCrackSenderEID(LPXPL lpxpl, ULONG cb, LPBYTE lpb, LPTSTR lpsz)
- {
- HRESULT hr = hrSuccess;
- ULONG ulObjType;
- LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
- LPMAPIPROP lpMAPIProp = NULL;
- ULONG cVals = 0;
- LPSPropValue lpProps = NULL;
- const static SizedSPropTagArray(2, sptCracked) =
- {
- 2,
- {
- PR_DISPLAY_NAME,
- PR_EMAIL_ADDRESS
- }
- };
- /* Open a Property Interface on this EntryID */
- hr = lpMAPISup->lpVtbl->OpenEntry(lpMAPISup, cb, (LPENTRYID) lpb,
- NULL, 0, &ulObjType, (LPUNKNOWN *) &lpMAPIProp);
- if (hr)
- {
- DebugTrace("OpenEntry() Failed in HrCrackSenderEID().n");
- goto ret;
- }
- /* Get the 2 properties we need from this object */
- hr = lpMAPIProp->lpVtbl->GetProps(lpMAPIProp,
- (LPSPropTagArray) &sptCracked, 0, /* ansi */
- &cVals, &lpProps);
- if (hr || !cVals)
- {
- DebugTrace("GetProps() Failed in HrCrackSenderEID().n");
- goto ret;
- }
- /* Assert that all went well so far!!! */
- Assert(lpProps);
- Assert(cVals == 2);
- Assert(lpProps[0].ulPropTag == PR_DISPLAY_NAME);
- Assert(lpProps[1].ulPropTag == PR_EMAIL_ADDRESS);
- /* Format our Name/Address pair as desired */
- wsprintf(lpsz, "%s[%s]", lpProps[0].Value.LPSZ, lpProps[1].Value.LPSZ);
- ret:
- lpxpl->FreeBuffer(lpProps);
- UlRelease(lpMAPIProp);
- DebugTraceResult(HrCrackSenderEID(), hr);
- return hr;
- }
- /*
- - FPropIndex
- -
- * Purpose:
- * Finds and returns (if it exists) the index of ulPropTag
- * in the lpProps SPropValue array.
- *
- * Parameters:
- * lpProps PropValue array to search through
- * cVals Count of properties in lpProps
- * ulPropTag PropTag to search for
- * puli Receives the index of ulPropTag in lpProps
- *
- * Returns:
- * TRUE/FALSE TRUE if found, FALSE otherwise
- */
- BOOL
- FPropIndex(LPSPropValue lpProps, ULONG cVals, ULONG ulPropTag, ULONG * puli)
- {
- Assert(lpProps);
- Assert(cVals);
- Assert(puli);
- while (cVals--)
- {
- if (lpProps[cVals].ulPropTag == ulPropTag)
- {
- *puli = cVals;
- return TRUE;
- }
- }
- return FALSE;
- }
- /*
- - FormatFileTime
- -
- * Purpose:
- * Formats a Windows NT file time as a MAPI date/time string
- * of the format: yyyy/mm/dd hh:mm
- *
- * Parameters:
- * pft Pointer to FILETIME to convert
- * szTime Destination string
- *
- * Returns:
- * void.
- */
- void
- FormatFileTime(FILETIME * pft, LPTSTR szTime)
- {
- SYSTEMTIME systime;
- FileTimeToSystemTime(pft, &systime);
- wsprintf(szTime, "%04.4d/%02.2d/%02.2d %02.2d:%02.2d",
- systime.wYear, systime.wMonth, systime.wDay,
- systime.wHour, systime.wMinute);
- }
- /*
- - FIsTextizedProp
- -
- * Purpose:
- * Used to determine if the property is one we wish to
- * exclude from the TNEF encapsulation (i.e. one we've
- * textized in the envelope of the message file).
- *
- * Parameters:
- * ulPropTag PropTag to test
- *
- * Return:
- * BOOL Indicating if the property is textized
- */
- BOOL
- FIsTextizedProp(ULONG ulPropTag)
- {
- ULONG i;
- static SizedSPropTagArray(16, spta) =
- {
- 16,
- {
- PR_SENDER_NAME,
- PR_SENDER_ENTRYID,
- PR_SENDER_SEARCH_KEY,
- PR_SENDER_EMAIL_ADDRESS,
- PR_SENDER_ADDRTYPE,
- PR_SENT_REPRESENTING_NAME,
- PR_SENT_REPRESENTING_ENTRYID,
- PR_SENT_REPRESENTING_SEARCH_KEY,
- PR_SENT_REPRESENTING_EMAIL_ADDRESS,
- PR_SENT_REPRESENTING_ADDRTYPE,
- PR_REPLY_RECIPIENT_ENTRIES,
- PR_REPLY_RECIPIENT_NAMES,
- PR_SUBJECT,
- PR_CLIENT_SUBMIT_TIME,
- PR_BODY,
- PR_PRIORITY
- }
- };
- for (i = 0; i < spta.cValues; i++)
- if (spta.aulPropTag[i] == ulPropTag)
- return TRUE;
- return FALSE;
- }
- /*
- - FreeMyAdrList
- -
- * Purpose:
- * Called by anyone who winds up with a MYADRLIST structure
- * and wants to free it.
- *
- * Parameters:
- * lpxpl Session context.
- * lpMyAdrList Structure to free.
- *
- * Returns:
- * void Data in lpMyAdrList freed.
- *
- * Operation:
- * Walks through adrlist and frees all the memory.
- */
- void
- FreeMyAdrList(LPXPL lpxpl, LPMYADRLIST lpMyAdrList)
- {
- ULONG ulT;
- LPSPropValue lpspvT;
- LPADRLIST lpAdrListT;
- /* Clean up any adrlist stuff that's lying around. */
- if (lpMyAdrList)
- {
- lpAdrListT = lpMyAdrList->lpAdrList;
- if (lpAdrListT && lpAdrListT->cEntries)
- {
- for (ulT = 0; ulT < lpAdrListT->cEntries; ulT++)
- {
- lpspvT = (lpAdrListT->aEntries[ulT]).rgPropVals;
- lpxpl->FreeBuffer((LPVOID) lpspvT);
- }
- }
- lpxpl->FreeBuffer((LPVOID) lpAdrListT);
- lpxpl->FreeBuffer((LPVOID) lpMyAdrList);
- }
- }
- CHAR lpszEOM[] = "n*** End of Message ***n";
- #define cchEOM (sizeof(lpszEOM) - 1)
- STDMETHODIMP
- PreprocessMessage (LPMAPISESSION lpSession,
- LPMESSAGE lpMessage,
- LPADRBOOK lpAdrBook,
- LPMAPIFOLDER lpFolder,
- LPALLOCATEBUFFER AllocateBuffer,
- LPALLOCATEMORE AllocateMore,
- LPFREEBUFFER FreeBuffer,
- ULONG FAR *lpcOutbound,
- LPMESSAGE FAR * FAR * lpppMessage,
- LPADRLIST FAR *lppRecipList)
- {
- HRESULT hr;
- LPSTREAM lpstrm = NULL;
- ULONG cb;
- LARGE_INTEGER liTo = {0};
- hr = lpMessage->lpVtbl->OpenProperty (lpMessage,
- PR_BODY_A,
- (LPIID)&IID_IStream,
- 0,
- MAPI_MODIFY,
- (LPUNKNOWN FAR *)&lpstrm);
- if (!HR_FAILED (hr))
- {
- hr = lpstrm->lpVtbl->Seek (lpstrm, liTo, STREAM_SEEK_END, NULL);
- if (!HR_FAILED (hr))
- {
- hr = lpstrm->lpVtbl->Write (lpstrm, lpszEOM, cchEOM, &cb);
- if (!HR_FAILED (hr) && (cb == cchEOM))
- {
- if (!HR_FAILED (hr = lpstrm->lpVtbl->Commit (lpstrm, 0L)))
- hr = lpMessage->lpVtbl->SaveChanges (lpMessage, KEEP_OPEN_READWRITE);
- }
- }
- UlRelease (lpstrm);
- }
- *lpcOutbound = 0;
- *lpppMessage = NULL;
- DebugTraceResult (PreprocessMessage(), hr);
- return hr;
- }
- STDMETHODIMP
- RemovePreprocessInfo (LPMESSAGE lpMessage)
- {
- CHAR lpszBuf[sizeof(lpszEOM)] = {0};
- HRESULT hr;
- LARGE_INTEGER liTo;
- LPSTREAM lpstrm = NULL;
- ULARGE_INTEGER liSize;
- ULONG cb;
- BOOL fUpd = FALSE;
- hr = lpMessage->lpVtbl->OpenProperty (lpMessage,
- PR_BODY_A,
- (LPIID)&IID_IStream,
- 0,
- MAPI_MODIFY,
- (LPUNKNOWN FAR *)&lpstrm);
- if (!HR_FAILED (hr))
- {
- liTo.HighPart = -1;
- liTo.LowPart = (ULONG)(-(LONG)(cchEOM));
- hr = lpstrm->lpVtbl->Seek (lpstrm, liTo, STREAM_SEEK_END, &liSize);
- if (!HR_FAILED (hr))
- {
- hr = lpstrm->lpVtbl->Read (lpstrm, lpszBuf, cchEOM, &cb);
- if (!HR_FAILED (hr) && (cb == cchEOM))
- {
- if (!lstrcmpiA (lpszEOM, lpszBuf))
- {
- if (!HR_FAILED (hr = lpstrm->lpVtbl->SetSize (lpstrm, liSize)) &&
- !HR_FAILED (hr = lpstrm->lpVtbl->Commit (lpstrm, 0L)))
- hr = lpMessage->lpVtbl->SaveChanges (lpMessage, KEEP_OPEN_READWRITE);
- }
- }
- }
- }
- UlRelease (lpstrm);
- DebugTraceResult (RemovePreprocessInfo(), hr);
- return hr;
- }