XPRCVMSG.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:51k
源码类别:
Windows编程
开发平台:
Visual C++
- /*
- - X P R C V M S G . C
- -
- * Purpose:
- * Code to support the MAPI Transport SPI entry points for
- * message reception. This module contains the following
- * SPI entry points:
- *
- * Poll()
- * StartMessage()
- *
- * Additional support functions found here:
- *
- * HrIMsgFromTextMsg()
- * HrBuildSenderProps()
- * HrAddRecipToAdrList()
- * HrAddRecipToReplyList()
- * HrMakeSearchKey()
- * HrGetLine()
- * FGetTagAndToken()
- * FileTimeFromSzTime()
- * SetFromMeFlag()
- *
- * Also, the Idle() code in XPQUEUE.C will call into this module to
- * find out if there's any mail to tell SpoolerNotify() about.
- *
- * Copyright 1992-1995 Microsoft Corporation. All Rights Reserved.
- */
- #include "xppch.h"
- #include <tnef.h>
- #include <stdlib.h>
- #include "xpsof.h"
- #include "xptxtmsg.h"
- /* Local function prototype(s) */
- VOID SetFromMeFlag(LPXPL lpxpl, LPMESSAGE lpMsg);
- /*
- - Poll
- -
- * Purpose:
- * Called by the Spooler periodically in its idle loop. Also called from
- * the Idle() entry point code.
- *
- * Parameters:
- * lpulIncoming Pointer to a ULONG.
- *
- * Returns:
- * *lpulIncoming Nonzero if any messages are found;
- * Zero if no messages were found.
- *
- * Operation:
- * This routine uses FindFirst/FindNext to look for message container
- * files in the inbound directory. Because its FIND_DATA structure and
- * the associated Handle is contained in the session structure, it's
- * easy to keep context and pass it along to StartMessage().
- *
- * Because it can be called from multiple places, and there's no
- * guarantee that StartMessage() will be called between the time we
- * signal the presence of inbound mail and the next time we're called,
- * we maintain a boolean in the session structure which we set to TRUE
- * when we find a message, and which StartMessage() sets to FALSE after
- * processing that message. If we see it as TRUE when called, we return
- * immediately with *lpulIncoming set.
- *
- * Otherwise, we do a FindNext if a find handle is open. If it fails, we
- * close the handle.
- *
- * If we have no open handle (either because one wasn't open or because
- * we just closed one), we do a FindFirst.
- *
- * If we find a message container file, we set the boolean and
- * *lpulIncoming and return. Else we close the find handle.
- *
- * This function always returns SUCCESS_SUCCESS.
- */
- STDMETHODIMP
- XPL_Poll(LPXPL lpxpl, ULONG * lpulIncoming)
- {
- HANDLE *lpPollHandle;
- LPWIN32_FIND_DATA lpFindData;
- LPMAPISUP lpMAPISup;
- LPSPropValue lpPropArray = lpxpl->lpPropArray;
- BOOL fFound = FALSE;
- DWORD dwIgnoreAttrs =
- FILE_ATTRIBUTE_READONLY |
- FILE_ATTRIBUTE_SYSTEM |
- FILE_ATTRIBUTE_DIRECTORY |
- FILE_ATTRIBUTE_TEMPORARY;
- lpPollHandle = &lpxpl->hInFindHandle;
- lpFindData = &lpxpl->wfdInFindData;
- lpMAPISup = lpxpl->lpMAPISup;
- /* Start out with default of no incoming message */
- *lpulIncoming = 0;
- /* Is inbound enabled for this session? */
- if (!(lpxpl->ulTransportStatus & STATUS_INBOUND_ENABLED))
- goto ret;
- /* See if we found one on a previous pass through here and haven't
- done a StartMessage() yet... */
- if (lpxpl->fFoundInMessage)
- {
- *lpulIncoming = 1;
- goto ret;
- }
- /* One of the following is now true:
- A) We have a search already active, use FindNextFile.
- If it fails, we will want to restart the search
- (in case something appeared in the search behind
- us.
- B) We don't have a search active, use FindFirstFile.
- */
- /* Try the active search */
- if (*lpPollHandle != INVALID_HANDLE_VALUE)
- {
- fFound = FindNextFile(*lpPollHandle, lpFindData);
- /* If we fail, close the old search so we can start
- a new one below. */
- if (!fFound)
- {
- FindClose(*lpPollHandle);
- *lpPollHandle = INVALID_HANDLE_VALUE;
- }
- }
- /* If there was no search or if the old one was just closed above */
- if (*lpPollHandle == INVALID_HANDLE_VALUE)
- {
- HANDLE hFindT;
- TCHAR chFileName[MAX_PATH];
- /* Copy the directory name. Note that we trust the value in the
- profile to be correct, since the UI should have enforced a
- syntax that included a trailing : or in the spec. */
- lstrcpy(chFileName,
- (ArrayIndex(PR_SAMPLE_INBOUND_DIR, lpPropArray)).Value.LPSZ);
- lstrcat(chFileName, TEXT("TNF*.TMP"));
- hFindT = FindFirstFile(chFileName, lpFindData);
- /* If nothing's found, we're done here. */
- if (hFindT == INVALID_HANDLE_VALUE)
- goto ret;
- /* Found something, continue along. */
- fFound = TRUE;
- *lpPollHandle = hFindT;
- }
- /*
- Here on a match. Exclude unwanted files.
- Any match with DIRECTORY, READONLY, SYSTEM or TEMPORARY attribute
- is ignored. Keep trying until we exhaust the current supply or we
- find a file without these attributes. Also, ignore files smaller
- than some arbitrary size, they're probably trash.
- */
- while (fFound)
- {
- /* We found a file. Does it have any of the attributes we
- want to ignore? If not, get out. If so, try another. */
- #define MIN_USEFUL_FILESIZE ((DWORD) 64)
- if ((!((lpFindData)->dwFileAttributes & dwIgnoreAttrs)) &&
- ((lpFindData->nFileSizeHigh != 0) ||
- (lpFindData->nFileSizeLow >= MIN_USEFUL_FILESIZE)))
- break;
- fFound = FindNextFile(*lpPollHandle, lpFindData);
- }
- if (fFound)
- lpxpl->fFoundInMessage = TRUE;
- else
- {
- FindClose(*lpPollHandle);
- *lpPollHandle = INVALID_HANDLE_VALUE;
- }
- ret:
- if (lpxpl->fFoundInMessage)
- {
- /* Got a hit. If fFound is set, we found it this time. If fFound
- is not set, we got it before and we were called again before
- StartMessage(). */
- *lpulIncoming = 1;
- DebugTrace("XPL_Poll returns *lpulIncoming=%lxn", *lpulIncoming);
- }
- else if (lpxpl->ulTransportStatus & STATUS_INBOUND_FLUSH)
- {
- lpxpl->ulTransportStatus &= ~STATUS_INBOUND_FLUSH;
- (void)HrUpdateTransportStatus(lpxpl, 0L);
- }
- return hrSuccess;
- }
- /*
- - StartMessage
- -
- * Purpose:
- * Called by the Spooler for receipt of an inbound message. This sequence
- * of events is set off by a SpoolerNotify (NOTIFY_NEWMAIL) or a Poll()
- * returning *lpulIncoming != 0.
- *
- * Parameters:
- * ulFlags Flags from the Spooler. Currently
- * there are no StartMessage() flags
- * defined in the MAPI 1.0 TSPI.
- * lpMessage Pointer to message object into which
- * the Spooler wants the transport to
- * store the incoming message.
- * lpulMsgRef Pointer to where the transport should
- * store a unsigned long for use in
- * identifying TransportNotify() message
- * events. Initialized to 0 by the
- * Spooler. We don't do anything with
- * message events in this transport, so
- * we don't store anything there.
- *
- * Returns:
- * (HRESULT) MAPI_E_BUSY if the Spooler calls
- * here again while we're busy, else
- * errors encountered if any.
- * (*lpMessage) Contains the new input message if any.
- *
- * Operation:
- * Checks for the result of a FindFirst/FindNext operation in the
- * session's FIND_DATA buffer. If none, exit without changing the input
- * message (this should result in the new message being destroyed when
- * the Spooler releases its object).
- *
- * If a file was found, attempt to open it. If the open fails and the
- * reason is not attributable to network locking, return the error; if
- * attributable to network locking (like if a peer's transmit code is
- * writing a container file), return no error. In either case, exit
- * without changing the input message.
- *
- * Open a stream interface on the input message file. Pass this off
- * to HrIMsgFromTxtMsg() to convert all the textized envelope properties
- * to SPropValues which are then set on the spoolers IMessage. When
- * we return, the input stream will be pointing to the beginning of
- * the embedded TNEF encapsulation in the input message file. Make
- * the appropriate calls to TNEF to extract the properties from the
- * encapsulation and set them on the message.
- *
- * Finally, SaveChanges() on the Spooler's message to retain the result,
- * delete the container file, and reset the "found message" flag for the
- * benefit of Poll().
- */
- STDMETHODIMP
- XPL_StartMessage(LPXPL lpxpl,
- ULONG ulFlags,
- LPMESSAGE lpMessage,
- ULONG * lpulMsgRef)
- {
- LPWIN32_FIND_DATA lpFindData;
- LPSPropValue lpMyIDArray = NULL;
- LPSPropValue lpPropArray = NULL;
- SPropValue rgDelegateProps[3];
- SPropValue spvTime;
- LPSPropProblemArray lpProblems = NULL;
- TCHAR rgchFileName[MAX_PATH];
- LPTSTR lptMyDir;
- HRESULT hResult = 0;
- SCODE sc = 0;
- BOOL fUpdatedStatus = FALSE;
- LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
- WORD wKey = 0;
- SPropTagArray sptExcludeNone = {0};
- LPITNEF lpTnef = (LPITNEF) NULL;
- LPSTREAM lpSof = (LPSTREAM) NULL;
- LPSTREAM lpXPSof = (LPSTREAM) NULL;
- LPSTnefProblemArray lptpa = NULL;
- /* Reset our .2 second timer before starting. */
- HrCheckSpoolerYield(lpMAPISup, TRUE);
- /* Do this first so we know at exit time if we tried to open a file */
- rgchFileName[0] = ' ';
- /* Simple re-entrancy test. Should never happen anyway. */
- if (lpxpl->ulTransportStatus & STATUS_INBOUND_ACTIVE)
- {
- hResult = ResultFromScode(MAPI_E_BUSY);
- DebugTrace("XPL_StartMessage reentrancy test failedn");
- goto ret;
- }
- /* Signal that we're downloading. */
- *lpulMsgRef = 1L; /* This is good enough. */
- lpxpl->ulTransportStatus |= STATUS_INBOUND_ACTIVE;
- hResult = HrUpdateTransportStatus(lpxpl, 0L);
- if (hResult)
- {
- DebugTrace("Update of status row failedn");
- goto ret;
- }
- fUpdatedStatus = TRUE;
- /* Get the current findfirst/findnext buffer */
- lpFindData = &lpxpl->wfdInFindData;
- /* Is there actually a message available? If not, go away. */
- if (!lpxpl->fFoundInMessage)
- goto ret;
- sc = ScCopySessionProps(lpxpl, &lpPropArray, &lpMyIDArray);
- if (FAILED(sc))
- {
- hResult = ResultFromScode(sc);
- goto ret;
- }
- /* Build file name of incoming message */
- lptMyDir = ArrayIndex(PR_SAMPLE_INBOUND_DIR, lpPropArray).Value.LPSZ;
- lstrcpy(rgchFileName, lptMyDir);
- lstrcat(rgchFileName, lpFindData->cFileName);
- PrintfTransportLog(TEXT("Start Incoming: %s"), rgchFileName);
- hResult = OpenStreamOnFile(lpxpl->AllocateBuffer, lpxpl->FreeBuffer,
- STGM_READ, rgchFileName, NULL, &lpSof);
- if (hResult)
- {
- sc = GetScode(hResult);
- DebugTrace("OpenStreamOnFile() failed in StartMessage()n");
- PrintfTransportLog(TEXT("OpenStreamOnFile(%s) returns %lx"), rgchFileName, sc);
- /* If "Access Denied" just don't do anything.
- It's usually a situation that will clear up (when another
- instance of this transport closes the msg file or when the
- other system comes online) */
- if (sc == MAPI_E_NO_ACCESS)
- hResult = hrSuccess;
- /* If "Not Found", clear fFoundInMessage so that we'll do a
- FindNext. */
- if (sc == MAPI_E_NOT_FOUND)
- lpxpl->fFoundInMessage = FALSE;
- goto ret;
- }
- /* Wrap the Stream-On-File object in our buffered wrapper. */
- hResult = HrWrapStreamOnFile(lpxpl->AllocateBuffer, lpxpl->FreeBuffer,
- XPSOF_READ, lpSof, &lpXPSof);
- if (HR_FAILED(hResult))
- {
- DebugTrace("HrWrapStreamOnFile() failedn");
- goto ret;
- }
- /* Check our .2 second timer before attempting to receive */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message download.n");
- goto ret;
- }
- hResult = HrIMsgFromTextMsg(lpxpl, lpPropArray, lpMessage, lpXPSof);
- if (HR_FAILED(hResult))
- {
- DebugTrace("HrIMsgFromTextMsg() failedn");
- goto ret;
- }
- /* Check our .2 second timer again. */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message download.n");
- goto ret;
- }
- /* The 0x01AF if a key used to identify the TNEF. A real transport
- should generate a pseudo-random sequence for this field. */
- hResult = OpenTnefStream(lpxpl->lpMAPISup, lpXPSof,
- TEXT("MAPIMAIL.DAT"), TNEF_DECODE, lpMessage, 0x01AF, &lpTnef);
- if (HR_FAILED(hResult))
- {
- DebugTrace("OpenTNEF() failed.n");
- goto ret;
- }
- /* Extract properties from the incomming message and add them to
- the target message. */
- hResult = lpTnef->lpVtbl->ExtractProps(lpTnef,
- TNEF_PROP_EXCLUDE, &sptExcludeNone, &lptpa);
- lpxpl->FreeBuffer(lptpa);
- if (HR_FAILED(hResult))
- {
- DebugTrace("GetTNEFProps() failed.n");
- goto ret;
- }
- /* Check our .2 second timer again. */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message download.n");
- goto ret;
- }
- /* All the properties have been copied over. Set the PR_RECEIVED_BY
- delegate properties (all the others were set by the transmitter) */
- if (lpMyIDArray)
- {
- Assert(!IsBadReadPtr(lpMyIDArray, 3 * sizeof(SPropValue)));
- Assert(lpMyIDArray[0].ulPropTag == PR_SENDER_ENTRYID);
- Assert(lpMyIDArray[1].ulPropTag == PR_SENDER_NAME);
- Assert(lpMyIDArray[2].ulPropTag == PR_SENDER_SEARCH_KEY);
- memcpy(rgDelegateProps, lpMyIDArray, 3 * sizeof(SPropValue));
- rgDelegateProps[0].ulPropTag = PR_RECEIVED_BY_ENTRYID;
- rgDelegateProps[1].ulPropTag = PR_RECEIVED_BY_NAME;
- rgDelegateProps[2].ulPropTag = PR_RECEIVED_BY_SEARCH_KEY;
- /* At this point we have all the delegate properties set. Put them into
- the old message and then we'll just get them on the CopyTo(). */
- hResult = lpMessage->lpVtbl->SetProps(lpMessage, 3,
- rgDelegateProps, &lpProblems);
- if (hResult)
- {
- DebugTrace("SetProps of Receiver ID to message failed.n");
- goto ret;
- }
- if (lpProblems)
- {
- /* If there were problems, let's dump them to the debugger. */
- DebugTraceProblems("XPL_StartMessage", lpProblems);
- lpxpl->FreeBuffer(lpProblems);
- lpProblems = NULL;
- }
- }
- /* Set the Received Time to be the last-modified time on the file. */
- spvTime.ulPropTag = PR_MESSAGE_DELIVERY_TIME;
- spvTime.Value.ft = lpFindData->ftLastWriteTime;
- hResult = lpMessage->lpVtbl->SetProps(lpMessage, 1, &spvTime, NULL);
- if (hResult)
- {
- DebugTrace("SetProps of PR_MESSAGE_DELIVERY_TIME failed.n");
- goto ret;
- }
- /* Finished with all properties and recipients now, SaveChanges
- on the message. */
- /* Check our .2 second timer again. */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message download.n");
- goto ret;
- }
- hResult = lpMessage->lpVtbl->SaveChanges(lpMessage, 0L);
- if (hResult)
- {
- DebugTrace("SaveChanges on incoming message failed.n");
- goto ret;
- }
- /* Finally, set the found message flag so we'll get another file. */
- lpxpl->fFoundInMessage = FALSE;
- ret:
- /* Log end of incoming if we logged start. */
- if (*rgchFileName)
- PrintfTransportLog(TEXT("End Incoming: %s"), rgchFileName);
- UlRelease(lpTnef);
- UlRelease(lpXPSof);
- UlRelease(lpSof);
- /* If we got the message into the store, delete the inbound file. */
- if (!(HR_FAILED (hResult)) && *rgchFileName)
- (void)DeleteFile(rgchFileName);
- /* Release the prop tag array and/or problem array if any */
- lpxpl->FreeBuffer(lpPropArray);
- lpxpl->FreeBuffer(lpMyIDArray);
- /* Reset download status if set. */
- if (fUpdatedStatus)
- {
- lpxpl->ulTransportStatus &= ~STATUS_INBOUND_ACTIVE;
- (void)HrUpdateTransportStatus(lpxpl, 0L);
- }
- DebugTraceResult(XPL_StartMessage, hResult);
- return hResult;
- }
- /*
- - HrIMsgFromTextMsg
- -
- * Purpose:
- * Called by StartMessage() to read a text formatted message file,
- * containing a TNEF encapsulation, and converting it into a
- * MAPI Message. The TNEF DLL is used to decode the binary portion
- * of this message into all the correct IMessage components.
- *
- * Parameters:
- * lpxpl Pointer to Transport Logon object
- * lpPropArray Array of the transports logon properties
- * lpMessage Message to receive into
- * lpSof Pointer to the stream interface
- *
- * Returns:
- * hr Indicating Success/Failure
- *
- * Operation:
- * Read each Tag out of the text file and process its Token according
- * to my rules for the Tag ID. PR_SUBJECT and PR_BODY are automatically
- * streamed into the message, PR_CLIENT_SUBMIT_TIME, PR_PRIORITY,
- * PR_SENDER_NAME, and PR_SENDER_ENTRYID are added with SetProps().
- * All To: and Cc: recipients are added by building an AdrList
- * and doing a ModifyRecipients() on the message. When we're finished
- * here, the file pointer in the input stream will (hopefully) be
- * left pointing to the start of the TNEF encapsulation.
- */
- HRESULT
- HrIMsgFromTextMsg(LPXPL lpxpl, LPSPropValue lpPropArray, LPMESSAGE lpMessage, LPSTREAM lpSof)
- {
- SCODE sc;
- HRESULT hr = hrSuccess;
- BOOL fHaveTagAndToken = FALSE;
- TCHAR szLine[MAX_LINE];
- ULONG cbRead;
- ULONG ulTag;
- LPTSTR lpszToken;
- ULONG cValues = 0;
- LPSPropValue lpMsgProps = NULL;
- LPMYADRLIST lpMyRecipList = NULL;
- LPTSTR lpszAddrType;
- LPTSTR lpszReplyNames = NULL;
- ULONG cbReplyEntryList = 0;
- LPFLATENTRYLIST lpReplyEntryList = NULL;
- LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
- lpszAddrType = ArrayIndex(PR_SAMPLE_EMAIL_ADDR_TYPE, lpPropArray).Value.LPSZ;
- sc = lpxpl->AllocateBuffer(MAX_TXTMSG_PROPS * sizeof(SPropValue),
- &lpMsgProps);
- if (sc)
- {
- hr = ResultFromScode(sc);
- DebugTrace("Allocation failed.n");
- goto ret;
- }
- memset(lpMsgProps, 0, MAX_TXTMSG_PROPS * sizeof(SPropValue));
- sc = lpxpl->AllocateBuffer(sizeof(MYADRLIST), &lpMyRecipList);
- if (sc)
- {
- hr = ResultFromScode(sc);
- DebugTrace("Allocation failed.n");
- goto ret;
- }
- memset(lpMyRecipList, 0, sizeof(MYADRLIST));
- while (TRUE)
- {
- /* fHaveTagAndToken gets set only when we return from
- HrGetStreamedProp and the call actually gets
- the next tagged line and tokenizes it for us. */
- if (!fHaveTagAndToken)
- {
- hr = HrGetLine(lpSof, MAX_LINE, szLine, &cbRead);
- if (hr)
- break;
- if (szLine[0] == ' ')
- continue;
- }
- if (fHaveTagAndToken || FGetTagAndToken(szLine, &ulTag, &lpszToken))
- {
- fHaveTagAndToken = FALSE;
- /* Check our .2 second timer again. */
- sc = GetScode(HrCheckSpoolerYield(lpMAPISup, FALSE));
- if (sc == MAPI_W_CANCEL_MESSAGE)
- {
- DebugTrace("Cancelling message download.n");
- goto ret;
- }
- switch (ulTag)
- {
- case tagFrom:
- case tagRepresenting:
- /* Create an addressing triplet (DisplayName, EntryID,
- SearchKey) from this line and add these properties
- to the array of props. */
- hr = HrBuildSenderProps(lpxpl, lpPropArray, ulTag, lpszToken,
- lpszAddrType, lpMessage, &cValues, lpMsgProps);
- if (hr)
- {
- DebugTrace("HrBuildSenderProps() failed.n");
- goto ret;
- }
- break;
- case tagReplyTo:
- hr = HrAddRecipToReplyList(lpxpl, lpszToken, lpszAddrType,
- &lpszReplyNames, &cbReplyEntryList, &lpReplyEntryList);
- if (hr)
- goto ret;
- break;
- case tagDate:
- lpMsgProps[cValues].ulPropTag = PR_CLIENT_SUBMIT_TIME;
- FileTimeFromSzTime(lpszToken, &lpMsgProps[cValues++].Value.ft);
- break;
- case tagTo:
- case tagCc:
- hr = HrAddRecipToAdrList(lpxpl, (LONG) ulTag - tagDate, lpszToken,
- lpszAddrType, lpMyRecipList);
- if (hr)
- goto ret;
- break;
- case tagSubject:
- case tagTextItem:
- hr = HrGetStreamedProp(lpxpl, lpSof, lpMessage,
- ((ulTag == tagSubject) ? PR_SUBJECT : PR_BODY),
- &cValues, lpMsgProps, szLine, &ulTag, &lpszToken);
- if (HR_FAILED(hr))
- goto ret;
- if(S_OK ==GetScode(hr))
- fHaveTagAndToken = TRUE;
- break;
- case tagPrioLow:
- case tagPrioNormal:
- case tagPrioUrgent:
- lpMsgProps[cValues].ulPropTag = PR_PRIORITY;
- lpMsgProps[cValues++].Value.l = tagPrioNormal - ulTag;
- break;
- case tagFileItem:
- goto ret;
- case tagMessage:
- case tagBcc:
- case tagContents:
- default:
- break;
- } /* end switch() */
- } /* end if() */
- } /* end while() */
- ret:
- if (lpszReplyNames && lpReplyEntryList)
- {
- lpMsgProps[cValues].ulPropTag = PR_REPLY_RECIPIENT_NAMES;
- lpMsgProps[cValues++].Value.LPSZ = lpszReplyNames;
- lpMsgProps[cValues].ulPropTag = PR_REPLY_RECIPIENT_ENTRIES;
- lpMsgProps[cValues].Value.bin.cb = cbReplyEntryList;
- lpMsgProps[cValues++].Value.bin.lpb = (LPBYTE) lpReplyEntryList;
- }
- if (cValues)
- lpMessage->lpVtbl->SetProps(lpMessage, cValues, lpMsgProps, NULL);
- if (lpMyRecipList && lpMyRecipList->lpAdrList)
- {
- hr = lpMessage->lpVtbl->ModifyRecipients(lpMessage,
- MODRECIP_ADD, lpMyRecipList->lpAdrList);
- FreeMyAdrList(lpxpl, lpMyRecipList);
- if (hr)
- DebugTrace("ModifyRecipients failed.n");
- }
- else
- lpxpl->FreeBuffer(lpMyRecipList);
- lpxpl->FreeBuffer(lpMsgProps);
- lpxpl->FreeBuffer(lpszReplyNames);
- lpxpl->FreeBuffer(lpReplyEntryList);
- DebugTraceResult(HrIMsgFromTextMsg(), hr);
- return hr;
- }
- /*
- - HrBuildSenderProps
- -
- * Purpose:
- * Creates the 5 identity properties: PR_***_SEARCH_KEY,
- * PR_***_NAME, PR_***_ENTRYID, PR_***_EMAIL_ADDRESS,
- * PR_***_ADDRTYPE, where *** is either SENDER or
- * SENT_REPRESENTING.
- *
- * Parameters:
- * lpxpl The transports logon object
- * lpPropArray The session logon properties
- * ulTag Either tagFrom or tagRepresenting
- * lpszToken Display name and address for triplet
- * lpszAddrType This transports address type
- * lpMessage The spoolers IMessage object
- * lpcValues Count of and index into lpMsgProps
- * lpMsgProps Array of message properties we are building
- *
- * Returns:
- * hr Indicating Success/Failure
- */
- HRESULT
- HrBuildSenderProps(LPXPL lpxpl,
- LPSPropValue lpPropArray,
- ULONG ulTag,
- LPTSTR lpszToken,
- LPTSTR lpszAddrType,
- LPMESSAGE lpMessage,
- ULONG * lpcValues,
- LPSPropValue lpMsgProps)
- {
- SCODE sc;
- HRESULT hr;
- LPTSTR lpszDisplayName = NULL;
- LPTSTR lpszAddress = NULL;
- LPTSTR lpsz;
- ULONG cbEntryID = 0;
- LPBYTE lpEntryID = NULL;
- LPBYTE lpb = NULL;
- ULONG cbSK;
- LPBYTE lpSearchKey;
- LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
- ULONG cValues = *lpcValues;
- lpsz = strtok(lpszToken, "[");
- sc = lpxpl->AllocateMore(lstrlen(lpsz) + 1,
- lpMsgProps, &lpszDisplayName);
- if (sc)
- {
- hr = ResultFromScode(sc);
- DebugTrace("AllocateMore failed.n");
- goto ret;
- }
- lstrcpy(lpszDisplayName, lpsz);
- lpsz = strtok(NULL, "]");
- sc = lpxpl->AllocateMore(lstrlen(lpsz) + 1,
- lpMsgProps, &lpszAddress);
- if (sc)
- {
- hr = ResultFromScode(sc);
- DebugTrace("AllocateMore failed.n");
- goto ret;
- }
- lstrcpy(lpszAddress, lpsz);
- /* Create OneOff Entry ID for Sender/Delegate */
- hr = lpMAPISup->lpVtbl->CreateOneOff(lpMAPISup,
- lpszDisplayName, lpszAddrType, lpszAddress, 0,
- &cbEntryID, (LPENTRYID FAR *) &lpEntryID);
- if (hr)
- {
- DebugTrace("CreateOneOff() failed.n");
- goto ret;
- }
- /* Chain the EntryID to the lpMsgProp block */
- sc = lpxpl->AllocateMore(cbEntryID, lpMsgProps, &lpb);
- if (sc)
- {
- hr = ResultFromScode(sc);
- DebugTrace("AllocateMore failed.n");
- goto ret;
- }
- if (cbEntryID)
- memcpy(lpb, lpEntryID, (size_t) cbEntryID);
- lpxpl->FreeBuffer(lpEntryID);
- lpEntryID = NULL;
- /* Make the PR_***_SEARCH_KEY */
- hr = HrMakeSearchKey(lpxpl, lpMsgProps, lpszAddrType,
- lpszAddress, &cbSK, &lpSearchKey);
- if (hr)
- {
- DebugTrace("HrMakeSearchKey() failed.n");
- goto ret;
- }
- if (ulTag == tagFrom)
- {
- lpMsgProps[cValues].ulPropTag = PR_SENDER_NAME;
- lpMsgProps[cValues + 1].ulPropTag = PR_SENDER_ENTRYID;
- lpMsgProps[cValues + 2].ulPropTag = PR_SENDER_SEARCH_KEY;
- lpMsgProps[cValues + 3].ulPropTag = PR_SENDER_ADDRTYPE;
- lpMsgProps[cValues + 4].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
- if (!lstrcmpi(lpszAddress,
- ArrayIndex(PR_SAMPLE_EMAIL_ADDRESS,
- lpPropArray).Value.LPSZ))
- SetFromMeFlag(lpxpl, lpMessage);
- }
- else
- {
- Assert(ulTag == tagRepresenting);
- lpMsgProps[cValues].ulPropTag = PR_SENT_REPRESENTING_NAME;
- lpMsgProps[cValues + 1].ulPropTag = PR_SENT_REPRESENTING_ENTRYID;
- lpMsgProps[cValues + 2].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY;
- lpMsgProps[cValues + 3].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE;
- lpMsgProps[cValues + 4].ulPropTag = PR_SENT_REPRESENTING_EMAIL_ADDRESS;
- }
- lpMsgProps[cValues++].Value.LPSZ = lpszDisplayName;
- lpMsgProps[cValues].Value.bin.cb = cbEntryID;
- lpMsgProps[cValues++].Value.bin.lpb = lpb;
- lpMsgProps[cValues].Value.bin.cb = cbSK;
- lpMsgProps[cValues++].Value.bin.lpb = lpSearchKey;
- lpMsgProps[cValues++].Value.LPSZ = lpszAddrType;
- lpMsgProps[cValues++].Value.LPSZ = lpszAddress;
- *lpcValues = cValues;
- ret:
- lpxpl->FreeBuffer(lpEntryID);
- DebugTraceResult(HrBuildSenderProps(), hr);
- return hr;
- }
- /*
- - HrGetStreamedProp
- -
- * Purpose:
- * Reads either the PR_BODY or PR_SUBJECT from the message file and
- * adds it to the spoolers IMessage.
- *
- * Parameters:
- * lpSof The stream we are reading the message from
- * lpMsg The spoolers IMessage we are building up
- * ulPropTag Either PR_SUBJECT or PR_BODY
- * lpcValues Current size of the lpMsgProps array
- * lpMsgProps The message property array we are building
- * lpszLine Char array we use to read lines into
- * lpulTag The text file tag we return as a side effect
- * lppszToken The token we return as a side effect
- *
- * Returns:
- * hr Indicating Success/Failure
- *
- * 10/5/95 the functon can return S_FALSE when the call to OpenProperty fails.
- * in this case the property still gets set using SetProps, but we don't
- * get the next token for the caller. So S_FALSE is to inform the
- * caller that we didn't get token for him and he has to do it himself.
- */
- HRESULT
- HrGetStreamedProp(LPXPL lpxpl,
- LPSTREAM lpSof,
- LPMESSAGE lpMsg,
- ULONG ulPropTag,
- ULONG * lpcValues,
- LPSPropValue lpMsgProps,
- LPTSTR lpszLine,
- ULONG * lpulTag,
- LPTSTR * lppszToken)
- {
- SCODE sc;
- HRESULT hr;
- LPSTREAM lpStrm = NULL;
- LPTSTR lpsz = NULL;
- ULONG cbCRLF = lstrlen(szCRLF);
- ULONG cbRead;
- ULONG cbWritten;
- #define cbSubjMax 4096
- LPSTR szSubj = NULL;
- sc = lpxpl->AllocateBuffer(cbSubjMax, &szSubj);
- if (sc)
- {
- hr = ResultFromScode(sc);
- DebugTrace("Allocation failed.n");
- goto ret;
- }
- *szSubj = ' ';
- hr = HrGetLine(lpSof, MAX_LINE, lpszLine, &cbRead);
- if (hr)
- {
- DebugTrace("HrGetLine failed.n");
- goto ret;
- }
- if (ulPropTag == PR_SUBJECT)
- {
- /* Once in the context of the subject, go until we reach the
- next tag. Then return and process the next tag and token */
- UINT cbCurrentSubj = 0;
- while (!FGetTagAndToken(lpszLine, lpulTag, lppszToken))
- {
- if(cbCurrentSubj < cbSubjMax)
- {
- cbCurrentSubj += lstrlen(lpszLine);
- if(cbCurrentSubj < cbSubjMax)
- lstrcat(szSubj, lpszLine);
- }
- hr = HrGetLine(lpSof, MAX_LINE, lpszLine, &cbRead);
- if (hr)
- goto ret;
- }
- /* this is in order to get inside the 'if' clause after OpenProperty*/
- hr = 1;
- }
- else
- {
- /* If we fail to open a stream on the property, then slam
- this line into the property array and break outta here */
- hr = lpMsg->lpVtbl->OpenProperty(lpMsg, ulPropTag,
- (LPIID) &IID_IStream, 0, MAPI_CREATE | MAPI_MODIFY,
- (LPUNKNOWN *) &lpStrm);
- }
- if (hr)
- {
- LPSTR szBuf = (ulPropTag == PR_SUBJECT) ? szSubj : lpszLine;
- sc = lpxpl->AllocateMore(lstrlen(szBuf) + 1, lpMsgProps, &lpsz);
- if (sc)
- {
- hr = ResultFromScode(sc);
- DebugTrace("Allocation failed.n");
- goto ret;
- }
- lstrcpy(lpsz, szBuf);
- lpMsgProps[*lpcValues].ulPropTag = ulPropTag;
- lpMsgProps[(*lpcValues)++].Value.LPSZ = lpsz;
- hr = (ulPropTag == PR_SUBJECT) ? hrSuccess : ResultFromScode(S_FALSE);
- goto ret;
- }
- /* Once we're in the context of the body, the only
- valid Tag is the TNEF File Item Tag. So, we
- ignore all other message text lines that may
- contain a Tag (by chance). */
- while (TRUE)
- {
- FGetTagAndToken(lpszLine, lpulTag, lppszToken);
- if ((*lpulTag == tagFileItem) &&
- !lstrcmp(*lppszToken, "MESSAGE.TNF"))
- break;
- TraceFailedWrite(hr = lpStrm->lpVtbl->Write(lpStrm, lpszLine,
- lstrlen(lpszLine), &cbWritten), ret);
- if (cbRead < MAX_LINE - 1)
- {
- TraceFailedWrite(lpStrm->lpVtbl->Write(lpStrm,
- szCRLF, cbCRLF, &cbWritten), ret);
- }
- hr = HrGetLine(lpSof, MAX_LINE, lpszLine, &cbRead);
- if (hr)
- break;
- }
- ret:
- UlRelease(lpStrm);
- lpxpl->FreeBuffer(szSubj);
- DebugTraceResult(HrGetStreamedProp(), hr);
- return hr;
- }
- /*
- - HrAddRecipToAdrList
- -
- * Purpose:
- * Called by HrIMsgFromTextMsg() to add a single recipient to the
- * AdrList. Pre-allocates space (cMaxEntries) for 10 AdrEntrys the
- * first time called. If all cMaxEntries slots are filled, then we
- * ReAlloc for (cMaxEntries + cMaxEntries/2) more slots and continue
- * adding the recipient. New memory is allocated for the attributes
- * passed in and chained-up to the rgProps array.
- *
- * Parameters:
- * lpxpl Needed for access to support obj and mem allocators
- * ulRecipType MAPI_TO or MAPI_CC
- * lpszNameAddr recipient token (Format: Display Name[email-address] )
- * lpszAddrType This transports Address Type
- * lpMyAdrList Pointer to the Recipient List
- *
- * Returns:
- * hr Indicating Suucess/Failure
- */
- HRESULT
- HrAddRecipToAdrList(LPXPL lpxpl, LONG lRecipType,
- LPTSTR lpszNameAddr, LPTSTR lpszAddrType, LPMYADRLIST lpMyAdrList)
- {
- HRESULT hr = hrSuccess;
- SCODE sc;
- BOOL fAlloc = FALSE;
- BOOL fReAlloc = FALSE;
- ULONG cb;
- ULONG cMaxEntries;
- LPADRLIST lpAdrList = NULL;
- LPSPropValue rgProps = NULL;
- LPTSTR lpsz;
- LPTSTR lpszDisplayName = NULL;
- LPTSTR lpszAddress = NULL;
- LPTSTR lpszAddrTypeT = NULL;
- ULONG cbEntryID = 0;
- LPBYTE lpEntryID = NULL;
- LPBYTE lpb = NULL;
- LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
- enum enumRecipProps
- {
- iRecipType,
- iDisplayName,
- iAddrType,
- iAddress,
- iEntryID,
- cRecipProps
- };
- /* Determine if we need to Allocate or ReAllocate memory */
- if (!lpMyAdrList->cMaxEntries)
- {
- /* First time in; list should be NULL */
- Assert(lpMyAdrList->lpAdrList == NULL);
- fAlloc = TRUE;
- cMaxEntries = 10;
- }
- else if (lpMyAdrList->lpAdrList &&
- (lpMyAdrList->lpAdrList->cEntries == lpMyAdrList->cMaxEntries))
- {
- /* List is full; we need to ReAlloc */
- fReAlloc = TRUE;
- cMaxEntries = lpMyAdrList->cMaxEntries + lpMyAdrList->cMaxEntries / 2;
- }
- else
- {
- /* List exists and is not full; just point to it */
- Assert(lpMyAdrList->lpAdrList);
- Assert(lpMyAdrList->lpAdrList->cEntries < lpMyAdrList->cMaxEntries);
- lpAdrList = lpMyAdrList->lpAdrList;
- }
- /* If the list was NULL or full we'll Alloc/ReAlloc */
- if (fAlloc || fReAlloc)
- {
- cb = CbNewADRLIST(cMaxEntries);
- sc = lpxpl->AllocateBuffer(cb, &lpAdrList);
- if (sc)
- {
- DebugTrace("AllocateBuffer() failed in HrAddRecipToAdrList()");
- goto ret;
- }
- /* Zero-out new list */
- memset(lpAdrList, 0, (size_t) cb);
- if (fReAlloc)
- {
- /* We're ReAllocing; copy old list into new memory */
- cb = CbNewADRLIST(lpMyAdrList->lpAdrList->cEntries);
- if (cb)
- memcpy(lpAdrList, lpMyAdrList->lpAdrList, (size_t) cb);
- /* Free old list */
- lpxpl->FreeBuffer(lpMyAdrList->lpAdrList);
- }
- /* Fix-up size and pointer elements */
- lpMyAdrList->cMaxEntries = cMaxEntries;
- lpMyAdrList->lpAdrList = lpAdrList;
- }
- /* Allocate room for cRecipProps PropValues and chain memory needed
- for AdrEntry data to the rgProps block to make freeing easier. */
- sc = lpxpl->AllocateBuffer(cRecipProps * sizeof(SPropValue), &rgProps);
- if (sc)
- {
- DebugTrace("AllocateBuffer() failed in HrAddRecipToAdrList()");
- goto ret;
- }
- /* Allocate memory for AddrType */
- sc = lpxpl->AllocateMore(lstrlen(lpszAddrType) + 1, rgProps, &lpszAddrTypeT);
- if (sc)
- {
- DebugTrace("AllocateMore() failed in HrAddRecipToAdrList()");
- goto ret;
- }
- /* Copy AddrType into chained memory buffer */
- lstrcpy(lpszAddrTypeT, lpszAddrType);
- /* Break lpszNameAddr into lpszDisplayName and lpszAddress */
- lpsz = strtok(lpszNameAddr, "[");
- sc = lpxpl->AllocateMore(lstrlen(lpsz) + 1, rgProps, &lpszDisplayName);
- if (sc)
- {
- DebugTrace("AllocateMore() failed in HrAddRecipToAdrList()");
- goto ret;
- }
- /* Copy Display Name into chained memory buffer */
- lstrcpy(lpszDisplayName, lpsz);
- lpsz = strtok(NULL, "]");
- sc = lpxpl->AllocateMore(lstrlen(lpsz) + 1, rgProps, &lpszAddress);
- if (sc)
- {
- DebugTrace("AllocateMore() failed in HrAddRecipToAdrList()");
- goto ret;
- }
- /* Copy Address into chained memory buffer */
- lstrcpy(lpszAddress, lpsz);
- /* Create OneOff Entry ID */
- hr = lpMAPISup->lpVtbl->CreateOneOff(lpMAPISup,
- lpszDisplayName, lpszAddrType, lpszAddress, 0,
- &cbEntryID, (LPENTRYID FAR *) &lpEntryID);
- if (hr)
- {
- DebugTrace("CreateOneOff() failed in HrAddRecipToAdrList()");
- goto ret;
- }
- /* We need to copy the EntryID into chained memory */
- sc = lpxpl->AllocateMore(cbEntryID, rgProps, &lpb);
- if (sc)
- {
- DebugTrace("AllocateMore() failed in HrAddRecipToAdrList()");
- goto ret;
- }
- /* Copy EntryID into chained memory buffer */
- if (cbEntryID)
- memcpy(lpb, lpEntryID, (size_t) cbEntryID);
- lpxpl->FreeBuffer(lpEntryID);
- lpEntryID = NULL;
- /* Now, build the PropValue array */
- rgProps[iRecipType].ulPropTag = PR_RECIPIENT_TYPE;
- rgProps[iRecipType].Value.l = lRecipType;
- rgProps[iDisplayName].ulPropTag = PR_DISPLAY_NAME;
- rgProps[iDisplayName].Value.LPSZ = lpszDisplayName;
- rgProps[iAddrType].ulPropTag = PR_ADDRTYPE;
- rgProps[iAddrType].Value.LPSZ = lpszAddrTypeT;
- rgProps[iAddress].ulPropTag = PR_EMAIL_ADDRESS;
- rgProps[iAddress].Value.LPSZ = lpszAddress;
- rgProps[iEntryID].ulPropTag = PR_ENTRYID;
- rgProps[iEntryID].Value.bin.cb = cbEntryID;
- rgProps[iEntryID].Value.bin.lpb = lpb;
- /* It's now safe to hook in the new AdrEntry */
- lpAdrList->aEntries[lpAdrList->cEntries].cValues = cRecipProps;
- lpAdrList->aEntries[lpAdrList->cEntries++].rgPropVals = rgProps;
- return hrSuccess;
- ret:
- lpxpl->FreeBuffer(rgProps);
- lpxpl->FreeBuffer(lpEntryID);
- if (lpAdrList != lpMyAdrList->lpAdrList)
- lpxpl->FreeBuffer(lpAdrList);
- if (!hr && sc)
- hr = ResultFromScode(sc);
- DebugTraceResult(HrAddRecipToAdrList()Failed !, hr);
- return hr;
- }
- /*
- - HrAddRecipToReplyList
- -
- * Purpose:
- * Builds the PR_REPLY_RECIPIENT_NAMES and PR_REPLY_RECIPIENT_ENTRIES
- * properties by re-allocing as new ones are added to the list.
- *
- * Parameters:
- * lpxpl Points to Transport Logon object
- * lpszToken Contains Display Name and E-Mail Address
- * lpszAddrType Address Type for this transport
- * lppszNames Semi-colon delimited list of Display Names
- * lpcbEIDList Current size of EntryList
- * lppEIDList Pointer to current EntryList
- *
- * Returns:
- * hr Indicating Suucess/Failure
- */
- HRESULT
- HrAddRecipToReplyList(LPXPL lpxpl, LPTSTR lpszToken, LPTSTR lpszAddrType,
- LPTSTR * lppszNames, ULONG * lpcbEIDList, LPFLATENTRYLIST * lppEIDList)
- {
- SCODE sc;
- HRESULT hr = hrSuccess;
- LPTSTR lpszAddress;
- LPTSTR lpszName;
- LPMAPISUP lpMAPISup = lpxpl->lpMAPISup;
- ULONG cbEID;
- LPBYTE lpEID = NULL;
- LPFLATENTRYLIST lpOld = *lppEIDList;
- ULONG cbOld;
- LPFLATENTRYLIST lpNew = NULL;
- LPFLATENTRY lpEntry;
- ULONG cbNew;
- LPTSTR lpszNewNames = NULL;
- lpszName = strtok(lpszToken, "[");
- lpszAddress = strtok(NULL, "]");
- /* Create OneOff Entry ID for this Recipient */
- hr = lpMAPISup->lpVtbl->CreateOneOff(lpMAPISup,
- lpszName, lpszAddrType, lpszAddress, 0,
- &cbEID, (LPENTRYID FAR *) &lpEID);
- if (hr)
- goto ret;
- /* Determine size of new list and allocate memory for it.
- The "+ 3) & -4L" will round up the allocation to be a
- multiple of 4 bytes. */
- if (lpOld)
- {
- Assert(!IsBadReadPtr(lpOld, CbNewFLATENTRYLIST(0)));
- Assert(!IsBadReadPtr(lpOld->abEntries, (UINT) lpOld->cbEntries));
- cbOld = lpOld->cbEntries;
- cbNew = (cbOld + offsetof(FLATENTRY, abEntry) + cbEID + 3) & -4L;
- }
- else
- {
- cbNew = cbOld = (cbEID + offsetof(FLATENTRY, abEntry) + 3) & -4L;
- }
- sc = lpxpl->AllocateBuffer(cbNew + offsetof(FLATENTRYLIST, abEntries), &lpNew);
- if (sc)
- {
- hr = ResultFromScode(sc);
- goto ret;
- }
- /* If Re-Allocing then copy old list and new EID, else build new list */
- if (lpOld)
- {
- ULONG cbNewOff = (cbOld + 3) & -4L;
- /* Copy the old data to the new structure */
- lpNew->cEntries = lpOld->cEntries + 1;
- lpNew->cbEntries = cbNew;
- if (cbOld)
- memcpy(lpNew->abEntries, lpOld->abEntries, (size_t) cbOld);
- /* Resolve the pointer to the new FLATENTRY */
- lpEntry = (LPFLATENTRY) & lpNew->abEntries[cbNewOff];
- }
- else
- {
- lpNew->cEntries = 1;
- lpNew->cbEntries = cbNew;
- /* Resolve the pointer to the new FLATENTRY */
- lpEntry = (LPFLATENTRY) lpNew->abEntries;
- }
- /* Add in the new FLATENTRY */
- lpEntry->cb = cbEID;
- if (cbEID)
- memcpy(lpEntry->abEntry, lpEID, (size_t) cbEID);
- /* Now, build the Display Name(s) String */
- if (*lppszNames)
- {
- /* We're Re-Allocing: copy old string and cat new one */
- sc = lpxpl->AllocateBuffer(lstrlen(*lppszNames) + lstrlen(lpszName) + 3,
- &lpszNewNames);
- if (sc)
- {
- hr = ResultFromScode(sc);
- goto ret;
- }
- lstrcpy(lpszNewNames, *lppszNames);
- lstrcat(lpszNewNames, "; ");
- lstrcat(lpszNewNames, lpszName);
- lpxpl->FreeBuffer(*lppszNames);
- }
- else
- {
- /* First name; just alloc and copy... */
- sc = lpxpl->AllocateBuffer(lstrlen(lpszName) + 1, &lpszNewNames);
- if (sc)
- {
- hr = ResultFromScode(sc);
- goto ret;
- }
- lstrcpy(lpszNewNames, lpszName);
- }
- /* It's now safe to hook in the new list. */
- /* Free old list and pass back new one. */
- lpxpl->FreeBuffer(lpOld);
- *lppEIDList = lpNew;
- *lpcbEIDList = cbNew + offsetof(FLATENTRYLIST, abEntries);
- *lppszNames = lpszNewNames;
- ret:
- lpxpl->FreeBuffer(lpEID);
- if (hr)
- {
- lpxpl->FreeBuffer(lpNew);
- lpxpl->FreeBuffer(lpszNewNames);
- }
- return hr;
- }
- /*
- - HrMakeSearchKey
- -
- * Purpose:
- * Makes a Search Key (for the PR_???_SEARCH_KEY property) from
- * the values passed in. Memory is chained to some parent block.
- * SearchKeys look like: ADDRTYPE:EMAILADDRESS.
- *
- * Parameters:
- * lpxpl Points to Transport Logon object
- * lpParent Memory block to chain Search Key to
- * lpszAddrType Address Type
- * lpszAddress E-mail Address
- * lpcbSK Returned size of Search Key
- * lppSK The returned Search Key
- *
- * Returns:
- * hr Indicating Suucess/Failure
- */
- HRESULT
- HrMakeSearchKey(LPXPL lpxpl, LPVOID lpParent, LPTSTR lpszAddrType,
- LPTSTR lpszAddress, ULONG * lpcbSK, LPBYTE * lppSK)
- {
- SCODE sc;
- HRESULT hr = hrSuccess;
- LPBYTE lpb = NULL;
- ULONG ulSize;
- /* The 2 is for the colon and the NULL terminator */
- ulSize = sizeof(TCHAR) * (2 + lstrlen(lpszAddrType) + lstrlen(lpszAddress));
- sc = lpxpl->AllocateMore(ulSize, lpParent, &lpb);
- if (sc)
- {
- hr = ResultFromScode(sc);
- goto ret;
- }
- /* We need to convert to upper case, that's the law! */
- wsprintf((LPTSTR) lpb, "%s:%s", lpszAddrType, lpszAddress);
- CharUpperBuff((LPTSTR) lpb, (UINT) (ulSize - sizeof(TCHAR)));
- *lpcbSK = ulSize;
- *lppSK = lpb;
- ret:
- return hr;
- }
- /*
- - HrGetLine
- -
- * Purpose:
- * Kind of like fgets() except it strips CRLF pairs for us.
- * Reads cbDest bytes from the lpSof stream or until a CR/LF
- * pair is reached, whichever comes first. Returns count of
- * bytes read into lpsz.
- *
- * Parameters:
- * lpSof Points to an OLE 2.0 Stream (to be read from)
- * cbDest Size of memory pointed to by lpsz
- * lpsz Points to a chunck of memory that receives the
- * line being read in. Must be of size cbDest.
- * pcbRead Receives the count of bytes actually read in.
- *
- * Returns:
- * hr Indicating Suucess/Failure
- */
- HRESULT
- HrGetLine(LPSTREAM lpSof, ULONG cbDest, LPTSTR lpsz, ULONG * pcbRead)
- {
- HRESULT hr = S_OK;
- BOOL fCRLF = FALSE;
- TCHAR rgch1[1];
- TCHAR rgch2[1];
- ULONG cbRead;
- if (!lpSof || (cbDest == 0) || !lpsz || !pcbRead)
- return ResultFromScode(MAPI_E_INVALID_PARAMETER);
- for (*pcbRead = 0; *pcbRead < cbDest - sizeof(TCHAR);)
- {
- /* read one TCHAR from stream */
- hr = lpSof->lpVtbl->Read(lpSof, (LPVOID) rgch1, sizeof(TCHAR), &cbRead);
- if (hr || (cbRead != sizeof(TCHAR)))
- break;
- /* Test for CR/LF pair; if not then add to line */
- if (*rgch1 == 'r')
- {
- hr = lpSof->lpVtbl->Read(lpSof, (LPVOID) rgch2, sizeof(TCHAR), &cbRead);
- if (hr)
- break;
- if (cbRead == sizeof(TCHAR))
- {
- if (*rgch2 == 'n')
- {
- fCRLF = TRUE;
- break;
- }
- }
- else
- {
- *lpsz++ = *rgch1;
- *lpsz++ = *rgch2;
- *pcbRead += 2 * sizeof(TCHAR);
- }
- }
- else
- {
- *lpsz++ = *rgch1;
- *pcbRead += sizeof(TCHAR);
- }
- }
- /* NULL terminate and leave */
- *lpsz = ' ';
- /* Test for the EOF case. Since the stream
- won't return errors, we will!!!! */
- if (!fCRLF && !*pcbRead)
- hr = ResultFromScode(MAPI_E_CALL_FAILED);
- return hr;
- }
- /*
- - FGetTagAndToken
- -
- * Purpose:
- * Breaks a line read from the input stream into Tag and Token.
- * If no Tag is found, then returns FALSE indicating this is not
- * a Tag'd line.
- *
- * Parameters:
- * lpsz A line from the messsage file that may have
- * the format: 'Tag: Token'. Must be of size MAX_LINE.
- * pulTag Will receive the index of lpsz's Tag in rgszTag
- * lppszToken Will point to the token in lpsz
- *
- * Returns:
- * TRUE If lpsz starts with a valid Tag
- * FALSE otherwise
- */
- BOOL
- FGetTagAndToken(LPTSTR lpsz, ULONG * pulTag, LPTSTR * lppszToken)
- {
- ULONG uli;
- TCHAR chT;
- LPTSTR lpszT;
- if (!lpsz || !pulTag || !lppszToken)
- return FALSE;
- /* Tags end with ':' If lpsz has a ':' then it MIGHT be
- a Tag'd line, else it's definitely NOT a Tag'd line. */
- lpszT = strchr(lpsz, ':');
- if (!lpszT)
- return FALSE;
- /* Check that we're not at the MAX_LINE extent of lpsz. If we are
- then just return, cause this can't possibly be a Tag'd line!
- The '3' accounts for the space, colon, and null terminator. */
- if ((lpszT - lpsz) > (MAX_LINE - 3))
- return FALSE;
- /* Swap *(lpszT+2) with a NULL to seperate Tag from Token */
- lpszT += 2;
- chT = *lpszT;
- *lpszT = ' ';
- /* Look-Up 'Potential' Tag in Tag Table */
- for (uli = 0; uli < NUM_TAGS; uli++)
- {
- if (!lstrcmp(lpsz, rgszTags[uli]))
- {
- /* Found! Remember index */
- *pulTag = uli;
- break;
- }
- }
- /* Swap that NULL out. lpszT now points to the token (maybe) */
- *lpszT = chT;
- if (uli == NUM_TAGS)
- return FALSE; /* Tag wasn't found; it's just a line */
- *lppszToken = lpszT;
- return TRUE;
- }
- /*
- - FileTimeFromSzTime
- -
- * Purpose:
- * Converts the textized data field in the text file format
- * to a FILETIME struct format. If we encounter errors in
- * parsing the lpszDateTime string, we jump to the conversion
- * call and will translate as much as we've filled in so far.
- *
- * Parameters:
- * lpszDateTime Date/Time in the format: yyyy/mm/dd hh:mm
- * pft Pointer to a FILETIME struct
- */
- void
- FileTimeFromSzTime(LPTSTR lpszDateTime, FILETIME * pft)
- {
- SYSTEMTIME systime =
- {0, 0, 0, 0, 0, 0, 0, 0};
- LPTSTR lpsz;
- /* Feeble attempt at parameter validation! */
- if (!lpszDateTime || !pft)
- return;
- /* Grab the Year */
- lpsz = strtok(lpszDateTime, "/");
- if (!lpsz)
- goto ret;
- systime.wYear = atoi(lpsz);
- /* Grab the Month */
- lpsz = strtok(NULL, "/");
- if (!lpsz)
- goto ret;
- systime.wMonth = atoi(lpsz);
- /* Grab the Day */
- lpsz = strtok(NULL, " ");
- if (!lpsz)
- goto ret;
- systime.wDay = atoi(lpsz);
- /* Grab the Hour */
- lpsz = strtok(NULL, ":");
- if (!lpsz)
- goto ret;
- systime.wHour = atoi(lpsz);
- /* Grab the Minutes */
- lpsz = strtok(NULL, "rn:");
- if (!lpsz)
- goto ret;
- systime.wMinute = atoi(lpsz);
- ret:
- SystemTimeToFileTime(&systime, pft);
- }
- /*
- - SetFromMeFlag
- -
- * Purpose:
- * Sets the PR_MESSAGE_FLAGS MSGFLAG_FROMME bit to on.
- *
- */
- VOID
- SetFromMeFlag(LPXPL lpxpl, LPMESSAGE lpMsg)
- {
- HRESULT hResult;
- LPSPropValue lpProp = NULL;
- /* Get the current state of the Message Flags */
- hResult = HrGetOneProp((LPMAPIPROP)lpMsg, PR_MESSAGE_FLAGS, &lpProp);
- if (HR_FAILED(hResult))
- goto ret;
- /* Add the FromMe bit */
- lpProp->Value.l |= MSGFLAG_FROMME;
- hResult = HrSetOneProp((LPMAPIPROP)lpMsg, lpProp);
- ret:
- lpxpl->FreeBuffer(lpProp);
- }