SMH.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:44k
源码类别:
Windows编程
开发平台:
Visual C++
- /*
- * S M H . C
- *
- * Sample mail handling hook
- *
- * Purpose:
- *
- * The sample mail handling (SMH) hook illustrates the use of the
- * MAPI Spooler Hook Provider Interface (ISpoolerHook) and those
- * parts of the general MAPI API that are available to a spooler
- * hook implementation.
- *
- * Specifically, SMH illusttrates the operation of both an inbound
- * message hook as well as outbound. SMH also has examples of the
- * configuration of a spooler hook provider via calls to SMH's
- * ServiceEntry() and/or through calls from the Profile Wizard.
- *
- * Features:
- *
- * Sent Mail:
- *
- * SMH allows the archiving of outbound messages (sent mail), into a
- * well defined set of subfolders in the default stores sent mail
- * folder. The archive folders are comprised of monthly archive
- * folders. The monthly folders can be, optionally, created under a
- * year based folder in the sent mail folder. Thus in a typical
- * message store, a fully archived sent mail folder might have a
- * hierarchy that looks similar to the following:
- *
- * Sent Mail
- * |
- * |-- 1994
- * | |
- * | |-- 10 October
- * | |-- 11 November
- * | |-- 12 December
- * |
- * |-- 1995
- * |
- * |-- 01 January
- *
- * This allows for a mail user to organize their outgoing mail in
- * a managible fashion.
- *
- * Deleted Mail:
- *
- * SMH allows the archiving of deleted mail in the same fashion as
- * sent mail can be archived. This feature helps people who choose
- * keep their 'deleted' mail accessible. It should be noted here
- * that this feature does not make use of the ISpoolerHook
- * interface, but is an example of what all can be done with spooler
- * hook providers.
- *
- * Incoming Mail:
- *
- * SMH can also 'filter' incoming messages and route the message
- * directly to folders, other than the default stores inbox, based
- * on message content. The user can define any number of filters
- * that can help organize and manage the email. Additionally, the
- * user can specify a sound scheme to be used on message delivery.
- * This allows the user to specify specific sounds based on message
- * content and priority.
- *
- * Unread Search Folders:
- *
- * Because SMH can filter unread messages deep into a message store
- * folder hierarchy, SMH can also create a search folder in the root
- * of the IPM_SUBTREE that searches the entire subtree for unread
- * messages.
- *
- * Out-of-office Processing:
- *
- * SMH can generate OOF notifications for incomming mail. It will
- * do it's best to not send multiple OOF's to any single recipient
- * over the period in which the OOF processing is enabled. The OOF
- * engine supports full rich-text.
- *
- * Copyright 1992-95 Microsoft Corporation. All Rights Reserved.
- */
- #include "_pch.h"
- extern SPropTagArray sptRule;
- extern SPropTagArray sptConfigProps;
- /*
- * sptMessageProps
- *
- * These are the properties that are required to check filters against
- * messages.
- */
- const static SizedSPropTagArray (cpMsgPrps, sptMsgPrps) =
- {
- cpMsgPrps,
- {
- PR_MESSAGE_FLAGS,
- PR_SUBJECT,
- PR_SENT_REPRESENTING_NAME,
- PR_SENT_REPRESENTING_EMAIL_ADDRESS,
- PR_IMPORTANCE
- }
- };
- /*
- * vtblSMH
- *
- * This is the SMH object's vtable. The table and its functions are
- * defined by MAPI's ISpoolerHook interface.
- */
- static const SMH_Vtbl vtblSMH =
- {
- SMH_QueryInterface,
- SMH_AddRef,
- SMH_Release,
- SMH_InboundMsgHook,
- SMH_OutboundMsgHook
- };
- /*
- * lpCtl3D
- *
- * Holds context for the 3D control DLL.
- */
- LPVOID lpCtl3D = NULL;
- /*
- * HrInitUnreadSearch()
- *
- * Purpose:
- *
- * Inits/creates an 'Unread Messages' search folder in the root of
- * the given store's IPM_SUBTREE hierarchy.
- *
- * Arguments:
- *
- * lpsmh the sample mail handler object
- * lpmdb the store getting the search folder
- *
- * Returns:
- *
- * (HRESULT)
- */
- HRESULT
- HrInitUnreadSearch (LPSMH lpsmh)
- {
- HRESULT hr;
- ENTRYLIST el = {0};
- LPMAPIFOLDER lpfldr = NULL;
- LPMAPIFOLDER lpfldrUM = NULL;
- LPMDB lpmdb = NULL;
- LPSPropValue lpval = NULL;
- SRestriction res = {0};
- ULONG ulType = 0;
- UINT cerr = 0;
- UINT i;
- for (i = 0; i < lpsmh->lpstotbl->cSto; i++)
- {
- hr = HrOpenStoEntry (lpsmh->lpsess, &lpsmh->lpstotbl->aSto[i], &lpmdb);
- if (!HR_FAILED (hr))
- {
- hr = HrGetOneProp ((LPMAPIPROP)lpmdb, PR_IPM_SUBTREE_ENTRYID, &lpval);
- if (!HR_FAILED (hr))
- {
- hr = lpmdb->lpVtbl->OpenEntry (lpmdb,
- lpval->Value.bin.cb,
- (LPENTRYID)lpval->Value.bin.lpb,
- NULL,
- MAPI_MODIFY,
- &ulType,
- (LPUNKNOWN FAR *)&lpfldr);
- if (!HR_FAILED (hr))
- {
- hr = lpfldr->lpVtbl->CreateFolder (lpfldr,
- FOLDER_SEARCH,
- "Unread Messages",
- "Simple Mail Handler: unread message search",
- NULL,
- MAPI_MODIFY | OPEN_IF_EXISTS,
- &lpfldrUM);
- if (!HR_FAILED (hr))
- {
- el.cValues = 1;
- el.lpbin = &lpval->Value.bin;
- res.rt = RES_BITMASK;
- res.res.resBitMask.relBMR = BMR_EQZ;
- res.res.resBitMask.ulPropTag = PR_MESSAGE_FLAGS;
- res.res.resBitMask.ulMask = MSGFLAG_READ;
- hr = lpfldrUM->lpVtbl->SetSearchCriteria (lpfldrUM,
- &res,
- &el,
- RECURSIVE_SEARCH | BACKGROUND_SEARCH | RESTART_SEARCH);
- UlRelease (lpfldrUM);
- lpfldrUM = NULL;
- }
- UlRelease (lpfldr);
- lpfldr = NULL;
- }
- (*lpsmh->lpfnFree) (lpval);
- lpval = NULL;
- }
- }
- if (HR_FAILED (hr))
- {
- DebugTrace ("SMH: WARNING: failed to init unread search (store:%d)n", i);
- cerr++;
- }
- }
- hr = ResultFromScode (cerr ? MAPI_W_ERRORS_RETURNED : S_OK);
- DebugTraceResult (HrInitUnreadSearch(), hr);
- return hr;
- }
- /*
- * LpszFindChar()
- *
- * Purpose:
- *
- * Finds the given character in the passed in string. This is an
- * exact matching model so strings should be normalized to either
- * upper or lower case if case insensitvity is required.
- *
- * Arguments:
- *
- * lpszSrc source string
- * ch character to find
- *
- * Returns:
- *
- * NULL iff the char was not found, otherwise, the return is a
- * pointer to the character in the source string.
- */
- LPTSTR
- LpszFindChar (LPTSTR lpszSrc, TCHAR ch)
- {
- LPTSTR lpsz = lpszSrc;
- if (lpszSrc)
- while (*lpsz && (*lpsz != ch))
- lpsz++;
- return ((lpsz && *lpsz) ? lpsz : NULL);
- }
- /*
- * HrCheckExclusions()
- *
- * Purpose:
- *
- * Checks the message class against the list of message classes
- * excluded from filtering.
- *
- * Arguments:
- *
- * lpsmh the smh parent object
- * lpmsg the message to check for exclusion
- *
- * Returns:
- *
- * (HRESULT) If the message is to be excluded, then hrSuccess
- * is returned, otherwize MAPI_E_NOT_ME indicates it
- * is OK to filter the message
- */
- HRESULT
- HrCheckExclusions (LPSMH lpsmh, LPMESSAGE lpmsg)
- {
- SCODE sc = S_OK;
- UINT isz = 0;
- LPSPropValue lpval = NULL;
- if (lpsmh->valEx.ulPropTag == PR_SMH_EXCLUSIONS)
- {
- if (!HR_FAILED (HrGetOneProp ((LPMAPIPROP)lpmsg, PR_MESSAGE_CLASS, &lpval)))
- {
- /* See if this is in the list of exclusions */
- for (isz = 0; isz < lpsmh->valEx.Value.MVSZ.cValues; isz++)
- if (FLpszContainsLpsz (lpval->Value.LPSZ, lpsmh->valEx.Value.MVSZ.LPPSZ[isz]))
- break;
- (*lpsmh->lpfnFree) (lpval);
- }
- sc = ((isz == lpsmh->valEx.Value.MVSZ.cValues) ? S_OK : MAPI_E_NOT_ME);
- }
- DebugTraceSc (HrCheckExclusions(), sc);
- return ResultFromScode (sc);
- }
- /*
- * HrCheckRule()
- *
- * Purpose:
- *
- * Examines a message to see if the current rule applies to the
- * message.
- *
- * IMPORTANT: If a rule is of type RL_SUBJECT, RL_FROM, or
- * RL_ATTACH, then the set of properties required to check for
- * matches with the message are retained and passed back to the
- * caller such that subsequent calls to HrCheckRule() will not have
- * to get those props a second time. THEREFORE the caller is
- * responsible for cleaning up any returned property values.
- *
- * Arguments:
- *
- * lprl pointer to the rule
- * lpmsg pointer to the message to examine
- * lppval [OUT] buffer containing the target entryid value struct
- *
- * Returns:
- *
- * (HRESULT) If the rule does apply, hrSuccess is returned and
- * the lppval parameter will point to a lpval struct
- * containing the entryid of the target folder.
- *
- * If the rule does not apply, the return value is
- * an HRESULT with MAPI_E_NOT_ME as the SCODE.
- *
- * Otherwise normal error codes apply.
- */
- HRESULT
- HrCheckRule (LPSMH lpsmh, LPRULE lprl, LPMESSAGE lpmsg, LPSPropValue FAR * lppval)
- {
- HRESULT hr;
- LPMAPITABLE lptbl = NULL;
- LPSPropValue lpval = *lppval;
- LPSPropValue lpvalT = NULL;
- ULONG cval;
- if (!lpval)
- {
- hr = lpmsg->lpVtbl->GetProps (lpmsg,
- (LPSPropTagArray)&sptMsgPrps,
- 0,
- &cval,
- &lpval);
- if (HR_FAILED (hr))
- goto ret;
- }
- /* Init for failure */
- hr = ResultFromScode (MAPI_E_NOT_ME);
- if ((lprl->rlTyp == RL_TO_RECIP) ||
- (lprl->rlTyp == RL_CC_RECIP) ||
- (lprl->rlTyp == RL_BCC_RECIP) ||
- (lprl->rlTyp == RL_ANY_RECIP))
- {
- hr = lpmsg->lpVtbl->GetRecipientTable (lpmsg, 0, &lptbl);
- if (HR_FAILED (hr))
- goto ret;
- hr = lptbl->lpVtbl->FindRow (lptbl, lprl->lpres, BOOKMARK_BEGINNING, 0);
- UlRelease (lptbl);
- if (HR_FAILED (hr) && (GetScode (hr) == MAPI_E_NOT_FOUND))
- hr = ResultFromScode (MAPI_E_NOT_ME);
- }
- else if (lprl->rlTyp == RL_SUBJECT)
- {
- if (lpval[ipMsgSubj].ulPropTag == PR_SUBJECT)
- if (FLpszContainsLpsz (lpval[ipMsgSubj].Value.LPSZ, lprl->lpszData))
- hr = hrSuccess;
- }
- else if (lprl->rlTyp == RL_SENDER)
- {
- if (lpval[ipMsgSentRep].ulPropTag == PR_SENT_REPRESENTING_NAME)
- if (FLpszContainsLpsz (lpval[ipMsgSentRep].Value.LPSZ, lprl->lpszData))
- hr = hrSuccess;
- if (HR_FAILED (hr))
- if (lpval[ipMsgSentRepEA].ulPropTag == PR_SENT_REPRESENTING_EMAIL_ADDRESS)
- if (FLpszContainsLpsz (lpval[ipMsgSentRepEA].Value.LPSZ, lprl->lpszData))
- hr = hrSuccess;
- }
- else if (lprl->rlTyp == RL_HAS_ATTACH)
- {
- if (lpval[ipMsgFlgs].ulPropTag == PR_MESSAGE_FLAGS)
- if (lpval[ipMsgFlgs].Value.l & MSGFLAG_HASATTACH)
- hr = hrSuccess;
- }
- else if (lprl->rlTyp == RL_BODY)
- {
- if (!HR_FAILED (HrGetOneProp ((LPMAPIPROP)lpmsg, PR_BODY, &lpvalT)))
- {
- if (FLpszContainsLpsz (lpvalT->Value.LPSZ, lprl->lpszData))
- hr = hrSuccess;
- (*lpsmh->lpfnFree) (lpvalT);
- }
- }
- else if (lprl->rlTyp == RL_MSG_CLASS)
- {
- if (!HR_FAILED (HrGetOneProp ((LPMAPIPROP)lpmsg, PR_MESSAGE_CLASS, &lpvalT)))
- {
- if (FLpszContainsLpsz (lpvalT->Value.LPSZ, lprl->lpszData))
- hr = hrSuccess;
- (*lpsmh->lpfnFree) (lpvalT);
- }
- }
- if (lprl->ulFlags & RULE_NOT)
- {
- if (GetScode (hr) == MAPI_E_NOT_ME)
- hr = hrSuccess;
- else if (hr == hrSuccess)
- hr = ResultFromScode (MAPI_E_NOT_ME);
- }
- ret:
- *lppval = lpval;
- DebugTraceResult (HrCheckRule(), hr);
- return hr;
- }
- /*
- * HrFolderFromPath()
- *
- * Purpose:
- *
- * Takes a IPM root-based path string and returns a folder
- * corresponding to the path given. The '' character is the path
- * separator. And non-existing folders are created as a psrt of the
- * process.
- *
- * Arguments:
- *
- * lpsmh pointer to smh parent object
- * lpmdb store in which the path is to exist
- * lpszPath the root-based path to use
- * lppfldr [OUT] buffer to place target folder
- * lppvalEid [OUT] buffer for target entryid value struct pointer
- *
- * Returns:
- *
- * (HRESULT)
- */
- HRESULT
- HrFolderFromPath (LPSMH lpsmh,
- LPMDB lpmdb,
- LPTSTR lpszPath,
- LPMAPIFOLDER FAR * lppfldr,
- LPSPropValue FAR * lppvalEid)
- {
- HRESULT hr;
- LPMAPIFOLDER lpfldr = NULL;
- LPMAPIFOLDER lpfldrT = NULL;
- LPSPropValue lpval = NULL;
- LPTSTR lpch;
- TCHAR rgch[MAX_PATH];
- ULONG ulType;
- if (!LoadString (lpsmh->hinst, SMH_FolderComment, rgch, sizeof(rgch)))
- rgch[0] = 0;
- hr = HrGetOneProp ((LPMAPIPROP)lpmdb, PR_IPM_SUBTREE_ENTRYID, &lpval);
- if (!HR_FAILED (hr))
- {
- hr = lpmdb->lpVtbl->OpenEntry (lpmdb,
- lpval->Value.bin.cb,
- (LPENTRYID)lpval->Value.bin.lpb,
- NULL,
- MAPI_MODIFY,
- &ulType,
- (LPUNKNOWN FAR *)&lpfldr);
- (*lpsmh->lpfnFree) (lpval);
- lpval = NULL;
- if (!HR_FAILED (hr))
- {
- do
- {
- if (lpch = LpszFindChar (lpszPath, '\'))
- *lpch = 0;
- Assert (lstrlen (lpszPath));
- hr = lpfldr->lpVtbl->CreateFolder (lpfldr,
- FOLDER_GENERIC,
- lpszPath,
- rgch,
- NULL,
- MAPI_MODIFY | OPEN_IF_EXISTS,
- &lpfldrT);
- if (HR_FAILED (hr))
- {
- #ifdef DEBUG
- LPMAPIERROR lperr = NULL;
- lpfldr->lpVtbl->GetLastError (lpfldr, hr, 0, &lperr);
- DebugTrace ("SMH: WARNING: unable to open/create folder: '%s' in %sn",
- lperr->lpszError, lperr->lpszComponent);
- (*lpsmh->lpfnFree) (lperr);
- #endif
- break;
- }
- UlRelease (lpfldr);
- lpfldr = lpfldrT;
- lpfldrT = NULL;
- lpszPath = (lpch ? ++lpch : NULL);
- } while (lpszPath);
- }
- if (!HR_FAILED (hr))
- {
- hr = HrGetOneProp ((LPMAPIPROP)lpfldr, PR_ENTRYID, &lpval);
- if (!HR_FAILED (hr))
- {
- *lppfldr = lpfldr;
- *lppvalEid = lpval;
- lpfldr = NULL;
- lpval = NULL;
- }
- }
- }
- (*lpsmh->lpfnFree) (lpval);
- UlRelease (lpfldr);
- DebugTraceResult (HrFolderFromPath(), hr);
- return hr;
- }
- /*
- * HrBuildRule()
- *
- * Purpose:
- *
- * Takes a profile section and builds a rule structure that
- * corresponds to the properties in the profile section.
- *
- * Arguments:
- *
- * lpsmh pointer to smh parent object
- * lpmuid profile section UID
- * lpprl [OUT] buffer for the newly created rule pointer
- *
- * Returns:
- *
- * (HRESULT)
- */
- HRESULT
- HrBuildRule (LPSMH lpsmh, LPMAPIUID lpmuid, LPRULE FAR * lpprl)
- {
- SCODE sc;
- HRESULT hr;
- LPMAPISESSION lpsess = lpsmh->lpsess;
- LPPROFSECT lpprof = NULL;
- LPRULE lprl = NULL;
- LPSPropValue lpval = NULL;
- LPSPropValue lpvalEid = NULL;
- LPSPropValue lpvalT;
- LPSRestriction lpres = NULL;
- ULONG cval;
- ULONG ulType;
- UINT cb;
- UINT i;
- sc = (*lpsmh->lpfnAlloc) (sizeof(RULE), &lprl);
- if (FAILED (sc))
- {
- hr = ResultFromScode (sc);
- goto ret;
- }
- memset (lprl, 0, sizeof(RULE));
- memcpy (&lprl->muid, lpmuid, sizeof(MAPIUID));
- hr = lpsess->lpVtbl->OpenProfileSection (lpsess,
- lpmuid,
- NULL,
- MAPI_MODIFY,
- &lpprof);
- if (HR_FAILED (hr))
- goto ret;
- hr = lpprof->lpVtbl->GetProps (lpprof,
- (LPSPropTagArray)&sptRule,
- 0,
- &cval,
- &lpval);
- if (HR_FAILED (hr))
- goto ret;
- if ((lpval[ipRLType].ulPropTag != PR_RULE_TYPE) ||
- (lpval[ipRLData].ulPropTag != PR_RULE_DATA) ||
- (lpval[ipRLFlags].ulPropTag != PR_RULE_FLAGS) ||
- (!(lpval[ipRLFlags].Value.l & (RULE_DELETE | RULE_NO_MOVE)) &&
- (lpval[ipRLType].ulPropTag != PR_RULE_TYPE) ||
- (lpval[ipRLPath].ulPropTag != PR_RULE_TARGET_PATH) ||
- (lpval[ipRLStore].ulPropTag != PR_RULE_STORE_DISPLAY_NAME)))
- {
- /* Something very important is missing */
- hr = ResultFromScode (MAPI_E_UNCONFIGURED);
- goto ret;
- }
- lprl->rlTyp = (UINT)lpval[ipRLType].Value.l;
- lprl->ulFlags = lpval[ipRLFlags].Value.l;
- /* Get the filter value */
- sc = (*lpsmh->lpfnAllocMore) (lpval[ipRLData].Value.bin.cb, lprl, &lprl->lpszData);
- if (FAILED (sc))
- {
- hr = ResultFromScode (sc);
- goto ret;
- }
- memcpy (lprl->lpszData,
- lpval[ipRLData].Value.bin.lpb,
- (UINT)lpval[ipRLData].Value.bin.cb);
- /* Get the sounds */
- if (lpval[ipRLFlags].Value.l & RULE_PLAY_SOUNDS)
- {
- for (i = 0; i < csndMax; i++)
- {
- if ((lpval[ipRLLoPri + i].ulPropTag == sptRule.aulPropTag[ipRLLoPri + i]) &&
- (cb = lstrlen (lpval[ipRLLoPri + i].Value.lpszA)))
- {
- cb += sizeof(TCHAR);
- sc = (*lpsmh->lpfnAllocMore) (cb, lprl, (LPVOID FAR *)&lprl->rgszSnd[i]);
- if (FAILED (sc))
- {
- hr = ResultFromScode (sc);
- goto ret;
- }
- lstrcpy (lprl->rgszSnd[i], lpval[ipRLLoPri + i].Value.lpszA);
- }
- }
- }
- /* Fill in the auto response */
- if (lpval[ipRLFlags].Value.l & RULE_AUTO_RESPONSE)
- {
- if (lpval[ipRLRepFwdRTF].ulPropTag == PR_RULE_REP_FWD_RTF)
- {
- sc = (*lpsmh->lpfnAllocMore) (lpval[ipRLRepFwdRTF].Value.bin.cb,
- lprl,
- (LPVOID FAR *)&lprl->lpbRTF);
- if (FAILED (sc))
- {
- hr = ResultFromScode (sc);
- goto ret;
- }
- lprl->cbRTF = lpval[ipRLRepFwdRTF].Value.bin.cb;
- memcpy (lprl->lpbRTF, lpval[ipRLRepFwdRTF].Value.bin.lpb, (UINT)lprl->cbRTF);
- }
- else if (lpval[ipRLRepFwd].ulPropTag == PR_RULE_REP_FWD_TEXT)
- {
- cb = lstrlen (lpval[ipRLRepFwd].Value.lpszA) + sizeof(TCHAR);
- sc = (*lpsmh->lpfnAllocMore) (cb, lprl, (LPVOID FAR *)&lprl->lpszAnno);
- if (FAILED (sc))
- {
- hr = ResultFromScode (sc);
- goto ret;
- }
- lstrcpy (lprl->lpszAnno, lpval[ipRLRepFwd].Value.lpszA);
- }
- if (lpval[ipRLFlags].Value.l & RULE_AUTO_FORWARD)
- {
- if (lpval[ipRLFwdEid].ulPropTag != PR_RULE_FORWARD_RECIP_ENTRYID)
- {
- hr = ResultFromScode (MAPI_E_UNCONFIGURED);
- goto ret;
- }
- else
- {
- sc = (*lpsmh->lpfnAlloc) (sizeof(SPropValue), &lprl->lpvalRecip);
- if (!FAILED (sc))
- {
- sc = (*lpsmh->lpfnAllocMore) (lpval[ipRLFwdEid].Value.bin.cb,
- lprl->lpvalRecip,
- &lprl->lpvalRecip[0].Value.bin.lpb);
- if (!FAILED (sc))
- {
- lprl->lpvalRecip[0].ulPropTag = PR_ENTRYID;
- lprl->lpvalRecip[0].Value.bin.cb = lpval[ipRLFwdEid].Value.bin.cb;
- memcpy (lprl->lpvalRecip[0].Value.bin.lpb,
- lpval[ipRLFwdEid].Value.bin.lpb,
- lpval[ipRLFwdEid].Value.bin.cb);
- }
- }
- }
- if (FAILED (sc))
- {
- hr = ResultFromScode (sc);
- goto ret;
- }
- }
- }
- /* See if we are not going to delete the message */
- if (!(lpval[ipRLFlags].Value.l & (RULE_DELETE | RULE_NO_MOVE)))
- {
- /* Find the target folder */
- hr = HrOpenMdbFromName (lpsmh, lpval[ipRLStore].Value.LPSZ, &lprl->lpmdb);
- if (HR_FAILED (hr))
- goto ret;
- if ((lpval[ipRLEid].ulPropTag != PR_RULE_TARGET_ENTRYID) ||
- (HR_FAILED (lpsess->lpVtbl->OpenEntry (lpsess,
- lpval[ipRLEid].Value.bin.cb,
- (LPENTRYID)lpval[ipRLEid].Value.bin.lpb,
- NULL,
- MAPI_MODIFY,
- &ulType,
- (LPUNKNOWN FAR *)&lprl->lpfldr))))
- {
- hr = HrFolderFromPath (lpsmh,
- lprl->lpmdb,
- lpval[ipRLPath].Value.LPSZ,
- &lprl->lpfldr,
- &lpvalEid);
- if (HR_FAILED (hr))
- goto ret;
- lpvalEid->ulPropTag = PR_RULE_TARGET_ENTRYID;
- HrSetOneProp ((LPMAPIPROP)lpprof, lpvalEid);
- lprl->lpvalEid = lpvalEid;
- }
- else
- {
- hr = HrGetOneProp ((LPMAPIPROP)lprl->lpfldr, PR_ENTRYID, &lprl->lpvalEid);
- if (HR_FAILED (hr))
- goto ret;
- }
- }
- if ((lpval[ipRLType].Value.l == RL_TO_RECIP) ||
- (lpval[ipRLType].Value.l == RL_CC_RECIP) ||
- (lpval[ipRLType].Value.l == RL_BCC_RECIP) ||
- (lpval[ipRLType].Value.l == RL_ANY_RECIP))
- {
- cb = (sizeof(SRestriction) * cresMax) + (sizeof(SPropValue) * cvMax);
- sc = (*lpsmh->lpfnAllocMore) (cb, lprl, &lpres);
- if (FAILED (sc))
- {
- hr = ResultFromScode (sc);
- goto ret;
- }
- lpvalT = (LPSPropValue)&lpres[cresMax];
- lpres[iresAnd].rt = RES_AND;
- lpres[iresAnd].res.resAnd.cRes = 2;
- lpres[iresAnd].res.resAnd.lpRes = &lpres[iresRecip];
- lpvalT[ivRecip].ulPropTag = PR_RECIPIENT_TYPE;
- lpvalT[ivRecip].Value.l = ((lpval[ipRLType].Value.l == RL_TO_RECIP)
- ? MAPI_TO
- : ((lpval[ipRLType].Value.l == RL_CC_RECIP)
- ? MAPI_CC
- : ((lpval[ipRLType].Value.l == RL_BCC_RECIP)
- ? MAPI_BCC
- : 0)));
- lpres[iresRecip].rt = RES_PROPERTY;
- lpres[iresRecip].res.resProperty.relop = RELOP_EQ;
- lpres[iresRecip].res.resContent.ulPropTag = PR_RECIPIENT_TYPE;
- lpres[iresRecip].res.resContent.lpProp = &lpvalT[ivRecip];
- lpres[iresOr].rt = RES_OR;
- lpres[iresOr].res.resOr.cRes = 2;
- lpres[iresOr].res.resOr.lpRes = &lpres[iresEmail];
- lpvalT[ivEmail].ulPropTag = PR_EMAIL_ADDRESS;
- lpvalT[ivEmail].Value.LPSZ = (LPTSTR)lprl->lpszData;
- lpres[iresEmail].rt = RES_CONTENT;
- lpres[iresEmail].res.resContent.ulFuzzyLevel = FL_SUBSTRING | FL_IGNORECASE;
- lpres[iresEmail].res.resContent.ulPropTag = PR_EMAIL_ADDRESS;
- lpres[iresEmail].res.resContent.lpProp = &lpvalT[ivEmail];
- lpvalT[ivDispNm].ulPropTag = PR_DISPLAY_NAME;
- lpvalT[ivDispNm].Value.LPSZ = (LPTSTR)lprl->lpszData;
- lpres[iresDispNm].rt = RES_CONTENT;
- lpres[iresDispNm].res.resContent.ulFuzzyLevel = FL_SUBSTRING | FL_IGNORECASE;
- lpres[iresDispNm].res.resContent.ulPropTag = PR_DISPLAY_NAME;
- lpres[iresDispNm].res.resContent.lpProp = &lpvalT[ivDispNm];
- if ((lpval[ipRLType].Value.l == RL_TO_RECIP) ||
- (lpval[ipRLType].Value.l == RL_CC_RECIP) ||
- (lpval[ipRLType].Value.l == RL_BCC_RECIP))
- lprl->lpres = &lpres[iresAnd];
- else
- lprl->lpres = &lpres[iresOr];
- }
- ret:
- (*lpsmh->lpfnFree) (lpval);
- UlRelease (lpprof);
- if (HR_FAILED (hr))
- {
- (*lpsmh->lpfnFree) (lprl->lpvalRecip);
- (*lpsmh->lpfnFree) (lprl->lpvalEid);
- (*lpsmh->lpfnFree) (lprl);
- lprl = NULL;
- }
- *lpprl = lprl;
- DebugTraceResult (HrBuildRule(), hr);
- return hr;
- }
- /*
- * ReleaseBkit()
- *
- * Purpose:
- *
- * Cleans up all resources held by a bucket structure and wipes the
- * structure clean.
- *
- * Arguments:
- *
- * lpsmh pointer to the smh object (uses allocation fn's)
- * lpbkit pointer to the bucket needing cleaning
- *
- */
- VOID
- ReleaseBkit (LPSMH lpsmh, LPBKIT lpbkit)
- {
- UlRelease (lpbkit->lpfldr);
- UlRelease (lpbkit->lpfldrYr);
- UlRelease (lpbkit->lpfldrParent);
- (*lpsmh->lpfnFree) (lpbkit->lpeid);
- (*lpsmh->lpfnFree) (lpbkit->lpeidYr);
- (*lpsmh->lpfnFree) (lpbkit->lpeidParent);
- memset (lpbkit, 0, sizeof(BKIT));
- return;
- }
- HRESULT
- HrInitSMH (LPSMH lpsmh)
- {
- HRESULT hr;
- LPPROFSECT lpprof = NULL;
- LPRULE lprl;
- LPSPropValue lpval = NULL;
- LPSPropValue lpvalOld;
- UINT crl;
- ULONG cval;
- /* Get options from the profile */
- hr = lpsmh->lpsess->lpVtbl->OpenProfileSection (lpsmh->lpsess,
- &lpsmh->muid,
- NULL,
- MAPI_MODIFY,
- &lpprof);
- if (HR_FAILED (hr))
- goto ret;
- hr = lpprof->lpVtbl->GetProps (lpprof,
- (LPSPropTagArray)&sptConfigProps,
- 0,
- &cval,
- &lpval);
- if (HR_FAILED (hr))
- goto ret;
- /* Check to see if we are configured */
- if (lpval[ipFlags].ulPropTag != PR_SMH_FLAGS)
- {
- hr = ResultFromScode (MAPI_E_UNCONFIGURED);
- goto ret;
- }
- /* Check that the rules are stored in the correct format */
- if (lpval[ipRules].ulPropTag != PR_SMH_RULES)
- {
- hr = HrGetOneProp ((LPMAPIPROP)lpprof,
- CHANGE_PROP_TYPE(PR_SMH_RULES, PT_BINARY),
- &lpvalOld);
- if (!HR_FAILED (hr))
- {
- /* The rules are stored in the wrong format */
- hr = HrUpdateProfileFormat (lpsmh->lpsess,
- lpsmh->lpsess->lpVtbl->OpenProfileSection,
- lpsmh->lpfnAllocMore,
- lpsmh->lpfnFree,
- lpval,
- lpvalOld);
- (*lpsmh->lpfnFree) (lpvalOld);
- if (HR_FAILED (hr))
- goto ret;
- /* Save out anything we got back */
- lpprof->lpVtbl->SetProps (lpprof, cpMax, lpval, NULL);
- }
- }
- UlRelease (lpprof);
- lpprof = NULL;
- /* Grab the exclusions list */
- hr = ResultFromScode (PropCopyMore (&lpsmh->valEx,
- &lpval[ipExc],
- lpsmh->lpfnAllocMore,
- lpsmh));
- if (HR_FAILED (hr))
- goto ret;
- /* Init the stores table */
- hr = HrInitStoresTable (lpsmh, lpsmh->lpsess);
- if (HR_FAILED (hr))
- goto ret;
- /* Store the values */
- lpsmh->fAtp = !!(lpval[ipFlags].Value.l & SMH_ADD_TO_PAB);
- lpsmh->fCatSm = !!(lpval[ipFlags].Value.l & SMH_FILTER_SENTMAIL);
- lpsmh->fCatSmByYr = !!(lpval[ipFlags].Value.l & SMH_FILTER_SENTMAIL_YR);
- /* If we are archiving deleted mail, init the filters */
- if (lpval[ipFlags].Value.l & SMH_FILTER_DELETED)
- {
- HrInitDeletedMailFilter (lpsmh);
- lpsmh->fCatWb = !!(lpval[ipFlags].Value.l & SMH_FILTER_DELETED_YR);
- }
- /* If the unread folder is desired, make sure it is there */
- if (!!(lpval[ipFlags].Value.l & SMH_UNREAD_VIEWER))
- HrInitUnreadSearch (lpsmh);
- /* Setup the oof text */
- if ((lpval[ipOofEnabled].ulPropTag == PR_SMH_OOF_ENABLED) &&
- lpval[ipOofEnabled].Value.b)
- {
- lpsmh->fOof = !HR_FAILED (HrInitOof (lpsmh,
- &lpval[ipOof],
- &lpval[ipOofRtf]));
- }
- /* Build the rules if need be */
- if ((lpval[ipFlags].Value.l & SMH_FILTER_INBOUND) &&
- (lpval[ipRules].ulPropTag == PR_SMH_RULES) &&
- (lpval[ipRules].Value.MVbin.cValues != 0))
- {
- crl = (UINT)lpval[ipRules].Value.MVbin.cValues;
- while (crl--)
- {
- hr = HrBuildRule (lpsmh,
- (LPMAPIUID)lpval[ipRules].Value.MVbin.lpbin[crl].lpb,
- &lprl);
- if (!HR_FAILED (hr))
- {
- lprl->rlNext = lpsmh->lstRl;
- lpsmh->lstRl = lprl;
- }
- }
- hr = hrSuccess;
- }
- ret:
- UlRelease (lpprof);
- (*lpsmh->lpfnFree) (lpval);
- DebugTraceResult (HrInitSMH(), hr);
- return hr;
- }
- VOID
- DeinitSMH (LPSMH lpsmh)
- {
- LPRULE lprl;
- LPRULE lprlT;
- LPWB lpwb;
- LPWB lpwbT;
- ReleaseBkit (lpsmh, &lpsmh->bkitSm);
- memset (&lpsmh->bkitSm, 0, sizeof(BKIT));
- for (lpwb = lpsmh->lstWb; lpwb; lpwb = lpwbT)
- {
- lpwbT = lpwb->wbNext;
- lpwb->lptbl->lpVtbl->Unadvise (lpwb->lptbl, lpwb->ulAdvz);
- #ifdef _WIN32
- if (lpwb->ht)
- {
- lpwb->fBail = TRUE;
- WaitForSingleObject (lpwb->ht, INFINITE);
- }
- #endif
- ReleaseBkit (lpsmh, &lpwb->bkit);
- UlRelease (lpwb->lptbl);
- UlRelease (lpwb->lpfldr);
- (*lpsmh->lpfnFree) (lpwb->lpvalEid);
- (*lpsmh->lpfnFree) (lpwb);
- }
- lpsmh->lstWb = NULL;
- for (lprl = lpsmh->lstRl; lprl; lprl = lprlT)
- {
- lprlT = lprl->rlNext;
- ReleaseBkit (lpsmh, &lprl->bkit);
- UlRelease (lprl->lpfldr);
- (*lpsmh->lpfnFree) (lprl->lpvalEid);
- (*lpsmh->lpfnFree) (lprl->lpvalRecip);
- (*lpsmh->lpfnFree) (lprl);
- }
- lpsmh->lstRl = NULL;
- UlRelease (lpsmh->oof.lptad);
- UlRelease (lpsmh->oof.lptbl);
- (*lpsmh->lpfnFree) (lpsmh->oof.lpbRTF);
- (*lpsmh->lpfnFree) (lpsmh->oof.lpszBody);
- memset (&lpsmh->oof, 0, sizeof(OOF));
- ReleaseStoresTable (lpsmh);
- return;
- }
- /*
- * SMH Object Methods
- *
- * SMH_QueryInterface (See OLE IUnknown object methods)
- * SMH_AddRef (See OLE IUnknown object methods)
- * SMH_Release (See OLE IUnknown object methods)
- * SMH_InboundMsgHook Filters inbound messages
- * SMH_OutboundMsgHook Filters sent mail messages
- *
- */
- STDMETHODIMP
- SMH_QueryInterface (LPSMH lpsmh, REFIID lpiid, LPVOID FAR * lppv)
- {
- if (IsBadWritePtr (lpsmh, sizeof(SMH)) ||
- IsBadReadPtr (lpiid, sizeof(IID)) ||
- IsBadWritePtr (lppv, sizeof(LPVOID)))
- return ResultFromScode (MAPI_E_INVALID_PARAMETER);
- if (!memcmp (lpiid, &IID_ISpoolerHook, sizeof(IID)) ||
- !memcmp (lpiid, &IID_IUnknown, sizeof(IID)))
- {
- *lppv = (LPVOID)lpsmh;
- lpsmh->lcInit++;
- return hrSuccess;
- }
- DebugTraceSc (SMH_QueryInterface(), MAPI_E_INTERFACE_NOT_SUPPORTED);
- return ResultFromScode (MAPI_E_INTERFACE_NOT_SUPPORTED);
- }
- STDMETHODIMP_ (ULONG)
- SMH_AddRef (LPSMH lpsmh)
- {
- if (IsBadWritePtr (lpsmh, sizeof(SMH)))
- return 0;
- return ++lpsmh->lcInit;
- }
- STDMETHODIMP_ (ULONG)
- SMH_Release (LPSMH lpsmh)
- {
- if (IsBadWritePtr (lpsmh, sizeof(SMH)))
- return 0;
- if (--lpsmh->lcInit)
- return lpsmh->lcInit;
- DeinitSMH (lpsmh);
- CloseHandle (lpsmh->hevtCfg);
- UlRelease (lpsmh->lpsess);
- (*lpsmh->lpfnFree) (lpsmh);
- if (lpCtl3D)
- {
- CTL3D_Uninitialize (lpCtl3D);
- lpCtl3D = NULL;
- }
- return 0;
- }
- /*
- * SMH_InboundMsgHook()
- *
- * Purpose:
- *
- * The purpose of this filter is to match inbound messages to
- * individual rules from the profile and re-route the messages based
- * on the results of the comparisons.
- *
- * Arguments:
- *
- * lpsmh this filter hook obj
- * lpmsg the message to be filtered
- * lpfldrDef owning folder of message
- * lpmdbDef owning store of message
- * lpulFlags flags returned by filter
- * lpcbeid cb for entryid of default target for message
- * lppbeid pb for entryid of default target for message
- *
- * Operation:
- *
- * Opens the suggested folder (if needed) and checks for the
- * existence of the appropriate "bucket" folder. If it does exist,
- * then the folder is created and cached. The entryid is grabbed
- * and passed back in to the spooler.
- *
- * Returns:
- *
- * (HRESULT)
- * lpulFlags [out] set HOOK_CANCEL if this is the last hook
- * lpcbeid [out] the size of the returned EntryID
- * lppbeid [out] the data of the returned EntryID
- *
- */
- STDMETHODIMP
- SMH_InboundMsgHook (LPSMH lpsmh,
- LPMESSAGE lpmsg,
- LPMAPIFOLDER lpfldrDef,
- LPMDB lpmdbDef,
- ULONG FAR * lpulFlags,
- ULONG FAR * lpcbeid,
- LPBYTE FAR * lppeid)
- {
- HRESULT hr = hrSuccess;
- LPRULE lprl;
- LPBYTE lpeid;
- LPSPropValue lpval = NULL;
- /* Quick and dirty parameter check */
- if (IsBadWritePtr (lpsmh, sizeof(SMH)) ||
- IsBadWritePtr (lpcbeid, sizeof(ULONG)) ||
- IsBadWritePtr (lppeid, sizeof(LPBYTE)) ||
- IsBadWritePtr (*lppeid, (UINT)(*lpcbeid)))
- return ResultFromScode (MAPI_E_INVALID_PARAMETER);
- #ifdef _WIN32
- if (FConfigChanged (lpsmh->hevtCfg))
- {
- /* reconfiguration required */
- DeinitSMH (lpsmh);
- hr = HrInitSMH (lpsmh);
- if (HR_FAILED (hr))
- return hr;
- ResetEvent (lpsmh->hevtCfg);
- }
- #endif // _WIN32
- if (lprl = lpsmh->lstRl) /* Yup '=' */
- {
- hr = HrCheckExclusions (lpsmh, lpmsg);
- if (!HR_FAILED (hr))
- {
- /* We have not been excluded */
- for (; lprl; lprl = lprl->rlNext)
- {
- hr = HrCheckRule (lpsmh, lprl, lpmsg, &lpval);
- if (!HR_FAILED (hr))
- {
- /* We have a match. What do we do, filter or delete? */
- if (!(lprl->ulFlags & (RULE_DELETE | RULE_NO_MOVE)))
- {
- /* Filter the critter */
- hr = ResultFromScode ((*lpsmh->lpfnAlloc) (lprl->lpvalEid->Value.bin.cb, &lpeid));
- if (!HR_FAILED (hr))
- {
- memcpy (lpeid, lprl->lpvalEid->Value.bin.lpb,
- (UINT)lprl->lpvalEid->Value.bin.cb);
- (*lpsmh->lpfnFree) (*lppeid);
- *lpcbeid = lprl->lpvalEid->Value.bin.cb;
- *lppeid = lpeid;
- if (lprl->ulFlags & RULE_ARCHIVED)
- {
- hr = HrArchiveMessage (lpsmh,
- lpmsg,
- lpfldrDef,
- lpmdbDef,
- &lprl->bkit,
- !!(lprl->ulFlags & RULE_ARCHIVED_BY_YEAR),
- lpcbeid,
- lppeid);
- if (lprl->ulFlags & RULE_TERMINAL)
- *lpulFlags = HOOK_CANCEL;
- }
- }
- /* Play the sound */
- if ((lpval[ipPriority].Value.l < 3) &&
- lprl->rgszSnd[lpval[ipPriority].Value.l])
- sndPlaySound (lprl->rgszSnd[lpval[ipPriority].Value.l], SND_ASYNC);
- }
- else
- {
- if (lprl->ulFlags & RULE_DELETE)
- *lpulFlags |= HOOK_DELETE;
- *lpulFlags |= HOOK_CANCEL;
- }
- /* Check for an auto-forwardreply */
- if (lprl->ulFlags & RULE_AUTO_RESPONSE)
- {
- /* We have a response that needs to
- * be created, and sent on.
- */
- hr = HrGenerateResponse (lpsmh, lprl, lpfldrDef, lpmsg);
- }
- break;
- }
- else if (GetScode (hr) != MAPI_E_NOT_ME)
- {
- /* We have a failure that is not really
- * expected, we need to bail. Also, this
- * should cancel any further hooking
- */
- *lpulFlags = HOOK_CANCEL;
- break;
- }
- else
- hr = hrSuccess;
- }
- }
- }
- if (lpsmh->fOof)
- {
- /* OOF'ing is done by calling HrGenerateResponse()
- * and passing in a NULL for the rule.
- */
- hr = HrGenerateResponse (lpsmh, NULL, lpfldrDef, lpmsg);
- }
- (*lpsmh->lpfnFree) (lpval);
- DebugTraceResult (SMH_InboundMsgHook(), hr);
- return hrSuccess;
- }
- /*
- * SMH_OutboundMsgHook()
- *
- * Purpose:
- *
- * The purpose of this filter is to "hash" a users sent mail
- * processing based on date. The most obvious bucket size is
- * monthly but there is no reason not to make this an option the
- * user could confiigure.
- *
- * Arguments:
- *
- * lpsmh this filter hook obj
- * lpmsg the message to be filtered
- * lpfldrDef owning folder of message
- * lpmdbDef owning store of message
- * lpulFlags flags returned by filter
- * lpcbeid cb for entryid of default target for message
- * lppbeid pb for entryid of default target for message
- *
- * Operation:
- *
- * Opens the suggested folder (if needed) and checks for the
- * existence of the appropriate "bucket" folder. If it does exist,
- * then the folder is created and cached. The entryid is grabbed
- * and passed back in to the spooler.
- *
- * Returns:
- *
- * (HRESULT)
- * lpulFlags [out] set HOOK_CANCEL if this is the last hook
- * lpcbeid [out] the size of the returned EntryID
- * lppbeid [out] the data of the returned EntryID
- *
- */
- STDMETHODIMP
- SMH_OutboundMsgHook (LPSMH lpsmh,
- LPMESSAGE lpmsg,
- LPMAPIFOLDER lpfldrDef,
- LPMDB lpmdbDef,
- ULONG FAR * lpulFlags,
- ULONG FAR * lpcbeid,
- LPBYTE FAR * lppeid)
- {
- HRESULT hr = hrSuccess;
- /* Quick and dirty parameter check */
- if (IsBadWritePtr (lpsmh, sizeof(SMH)) ||
- IsBadWritePtr (lpcbeid, sizeof(ULONG)) ||
- IsBadWritePtr (lppeid, sizeof(LPBYTE)) ||
- IsBadWritePtr (*lppeid, (UINT)(*lpcbeid)))
- return ResultFromScode (MAPI_E_INVALID_PARAMETER);
- #ifdef _WIN32
- if (FConfigChanged (lpsmh->hevtCfg))
- {
- /* reconfiguration required */
- DeinitSMH (lpsmh);
- hr = HrInitSMH (lpsmh);
- if (HR_FAILED (hr))
- return hr;
- ResetEvent (lpsmh->hevtCfg);
- }
- #endif // _WIN32
- if (lpsmh->fAtp)
- (void) HrAddEntriesToPab (lpsmh, lpmsg);
- if (lpsmh->fCatSm)
- hr = HrArchiveMessage (lpsmh,
- lpmsg,
- lpfldrDef,
- lpmdbDef,
- &lpsmh->bkitSm,
- lpsmh->fCatSmByYr,
- lpcbeid,
- lppeid);
- DebugTraceResult (SMH_OutboundMsgHook(), hr);
- return hrSuccess;
- }
- /*
- * SMH_Init()
- *
- * Purpose:
- *
- * Spooler's entry into the sample mail handler. This function is
- * equivilent to a provider logon in that it returns an object to
- * the spooler that will be used to make any additional calls into
- * the handler.
- *
- * Arguments:
- *
- * lpsess the session this handler relates to
- * hinst hinst of the SMH dll
- * lpfnAlloc pointer to MAPIAllocateBuffer()
- * lpfnAllocMore pointer to MAPIAllocateMore()
- * lpfnFree pointer to MAPIFreeBuffer()
- * lpmuid pointer to profile section muid
- * ulFlags flags
- * lppHook buffer to hold handler object
- *
- * Returns:
- *
- * (HRESULT)
- * lpphook [OUT] holds the returned handler object iff successful
- */
- STDINITMETHODIMP
- SMH_Init (LPMAPISESSION lpsess,
- HINSTANCE hinst,
- LPALLOCATEBUFFER lpfnAlloc,
- LPALLOCATEMORE lpfnAllocMore,
- LPFREEBUFFER lpfnFree,
- LPMAPIUID lpmuid,
- ULONG ulFlags,
- LPSPOOLERHOOK FAR * lppHook)
- {
- SCODE sc;
- LPSMH lpsmh = NULL;
- HRESULT hr;
- sc = (*lpfnAlloc) (sizeof(SMH), &lpsmh);
- if (FAILED (sc))
- return ResultFromScode (sc);
- memset (lpsmh, 0, sizeof(SMH));
- hr = lpsess->lpVtbl->QueryInterface (lpsess,
- &IID_IMAPISession,
- &lpsmh->lpsess);
- if (!HR_FAILED (hr))
- {
- /* Fill in all fields of the object */
- lpsmh->lpVtbl = (SMH_Vtbl FAR *)&vtblSMH;
- lpsmh->lcInit = 1;
- lpsmh->hinst = hinst;
- lpsmh->lpsess = lpsess;
- lpsmh->lpfnAlloc = lpfnAlloc;
- lpsmh->lpfnAllocMore = lpfnAllocMore;
- lpsmh->lpfnFree = lpfnFree;
- memcpy (&lpsmh->muid, lpmuid, sizeof(MAPIUID));
- #ifdef _WIN32
- /* Setup listening for configuration changes */
- (void)HrGetConfigEvent (&lpsmh->hevtCfg);
- #endif
- /* Fill out the rest of the structure */
- hr = HrInitSMH (lpsmh);
- }
- if (HR_FAILED (hr))
- {
- UlRelease (lpsmh);
- lpsmh = NULL;
- }
- *lppHook = (LPSPOOLERHOOK)lpsmh;
- DebugTraceResult (SMH_Init(), hr);
- return hr;
- }