SMHWB.C
/* 
 *  S M H W B . C 
 * 
 *  Sample mail handling wastbasket message archiving 
 *  Copyright 1992-95 Microsoft Corporation.  All Rights Reserved. 
 */ 
 
#include "_pch.h" 
 
/* 
 *  sptFilterWb 
 * 
 *  These are the columns used in wastebasket filtering\archiving 
 */ 
enum { iwbEid, iwbDlv, iwbSbmt }; 
const static SizedSPropTagArray (3, sptFilterWb) = 
{ 
    3, 
    { 
        PR_ENTRYID, 
        PR_MESSAGE_DELIVERY_TIME, 
        PR_CLIENT_SUBMIT_TIME 
    } 
}; 
 
 
/* 
 *  HrFilterDeleted() 
 * 
 *  Purpose: 
 * 
 *      Filters all the current message from the 'Wastebasket'/'Deleted Items' 
 *      folder based on the archiving model used in sent mail processing. 
 * 
 *  Arguments: 
 * 
 *      lpwb            wastbucket struct for the current store 
 *      lpbin           sbinary holding the entryid of the message 
 * 
 *  Returns: 
 * 
 *      (HRESULT) 
 */ 
HRESULT 
HrFilterDeleted (LPWB lpwb, LPSRowSet lprws) 
{ 
    HRESULT hr = ResultFromScode (MAPI_E_NOT_ENOUGH_MEMORY); 
    FILETIME ft; 
    LPBYTE lpeid = NULL; 
    LPMAPIFOLDER lpfldr = lpwb->lpfldr; 
    LPMDB lpmdb = lpwb->lpmdb; 
    LPSBinary lpbin = NULL; 
    LPSMH lpsmh = lpwb->lpsmh; 
    SBinaryArray sba; 
    UINT ib; 
    UINT irw; 
    ULONG cb = lpwb->lpvalEid->Value.bin.cb; 
    ULONG ulFlags = 0; 
 
    if (!FAILED ((*lpsmh->lpfnAlloc) (lprws->cRows * sizeof(SBinary), &lpbin))) 
    { 
        for (irw = 0; irw < lprws->cRows; ) 
        { 
            ib = 0; 
            if (!FAILED ((*lpsmh->lpfnAlloc) (cb, &lpeid))) 
            { 
                memcpy (lpeid, lpwb->lpvalEid->Value.bin.lpb, (UINT)cb); 
                if (lprws->aRow[irw].lpProps[iwbDlv].ulPropTag == PR_MESSAGE_DELIVERY_TIME) 
                    ft = lprws->aRow[irw].lpProps[iwbDlv].Value.ft; 
                else if (lprws->aRow[irw].lpProps[iwbSbmt].ulPropTag == PR_CLIENT_SUBMIT_TIME) 
                    ft = lprws->aRow[irw].lpProps[iwbSbmt].Value.ft; 
                else 
                { 
                    ++irw; 
                    continue; 
                } 
                 
                hr = HrArchiveByDate (lpsmh, 
                                &ft, 
                                lpfldr, 
                                lpmdb, 
                                &lpwb->bkit, 
                                lpsmh->fCatWb, 
                                cb, 
                                lpeid); 
                if (!HR_FAILED (hr)) 
                { 
                    lpbin[ib++] = lprws->aRow[irw].lpProps[iwbEid].Value.bin; 
                    for (irw += 1; irw < lprws->cRows; irw++) 
                    { 
                        if (lprws->aRow[irw].lpProps[iwbDlv].ulPropTag == PR_MESSAGE_DELIVERY_TIME) 
                        { 
                            ft = lprws->aRow[irw].lpProps[iwbDlv].Value.ft; 
                            if ((CompareFileTime (&lpwb->bkit.dft.ftStart, &ft) == 1) || 
                                (CompareFileTime (&lpwb->bkit.dft.ftEnd, &ft) == -1)) 
                                break; 
 
                            lpbin[ib++] = lprws->aRow[irw].lpProps[iwbEid].Value.bin; 
                        } 
                        else if (lprws->aRow[irw].lpProps[iwbSbmt].ulPropTag == PR_CLIENT_SUBMIT_TIME) 
                        { 
                            ft = lprws->aRow[irw].lpProps[iwbSbmt].Value.ft; 
                            if ((CompareFileTime (&lpwb->bkit.dft.ftStart, &ft) == 1) || 
                                (CompareFileTime (&lpwb->bkit.dft.ftEnd, &ft) == -1)) 
                                break; 
 
                            lpbin[ib++] = lprws->aRow[irw].lpProps[iwbEid].Value.bin; 
                        } 
                        else 
                            break; 
                    } 
 
                    sba.cValues = ib; 
                    sba.lpbin = lpbin; 
                    hr = lpfldr->lpVtbl->CopyMessages (lpfldr, 
                                &sba, 
                                NULL, 
                                lpwb->bkit.lpfldr, 
                                0, 
                                NULL, 
                                MAPI_MOVE); 
                } 
            } 
            (*lpsmh->lpfnFree) (lpeid); 
            lpeid = NULL; 
        } 
    } 
    (*lpsmh->lpfnFree) (lpbin); 
    DebugTraceResult (HrFilterDeleted(), hr); 
    return hr; 
} 
 
 
/* 
 *  FilterDeletedThread() 
 *   
 *  Purpose: 
 *   
 *      This function will spin off and do the archiving of the messages 
 *      in the deleted folder.  It is important to note that on 32 bit 
 *      platforms, this function will belong to its own thread.  Thus 
 *      cleanup and logoff must wait for the thread to terminate before 
 *      releasing returning. 
 *   
 *  Arguments: 
 *   
 *      lpwb        pointer to the wastebasket object 
 *   
 *  Returns: 
 *   
 *      (DOWRD) : Ignored 
 */ 
static DWORD WINAPI 
FilterDeletedThread (LPWB lpwb) 
{ 
    HRESULT hr; 
    LPMAPITABLE lptbl; 
    LPSRowSet lprws = NULL; 
 
    lptbl = lpwb->lptbl; 
 
#ifdef  _WIN32 
    SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_IDLE); 
#endif 
 
    while (!lpwb->fBail) 
    { 
        lptbl->lpVtbl->SeekRow (lptbl, BOOKMARK_BEGINNING, 0, NULL); 
        hr = lptbl->lpVtbl->QueryRows (lptbl, 64, 0, &lprws); 
        if (HR_FAILED (hr)) 
            break; 
 
        if (lprws->cRows) 
        { 
            //  Filter the deleted messages 
            // 
            HrFilterDeleted (lpwb, lprws); 
 
            while (lprws->cRows) 
                (*lpwb->lpsmh->lpfnFree) (lprws->aRow[--lprws->cRows].lpProps); 
        } 
        else 
            break; 
 
        (*lpwb->lpsmh->lpfnFree) (lprws); 
        lprws = NULL; 
    } 
     
    (*lpwb->lpsmh->lpfnFree) (lprws); 
     
    /*  Reset the filtering indicator */ 
#ifdef  _WIN32 
    CloseHandle (lpwb->ht); 
    lpwb->ht = NULL; 
#endif 
    return 0; 
} 
 
 
/* 
 *  WBNotify() 
 * 
 *  Purpose: 
 * 
 *      Notification callback on the WB folders of message stores.  When 
 *      rows are added to the WB contents table, we enum the table and 
 *      filter each message added. 
 * 
 *  Arguments: 
 * 
 *      lpv         void pointer to current WB struct 
 *      cntf        count of notifications 
 *      lpntf       notifications 
 * 
 *  Returns: 
 * 
 *      (SCODE) 
 */ 
STDAPI_(SCODE) 
WBNotify (LPVOID lpv, ULONG cntf, LPNOTIFICATION lpntf) 
{ 
    BOOL fFilter = FALSE; 
    LPWB lpwb = (LPWB)lpv; 
 
    /* Quick and dirty check on the context */ 
 
    if (IsBadReadPtr (lpv, sizeof(WB)) || 
        IsBadReadPtr (((LPWB)lpv)->lpsmh, sizeof(SMH))) 
        return S_OK; 
 
    /* Just incase we were turned off */ 
 
    if (lpwb->lpsmh->fCatWb) 
    { 
        while (cntf--) 
        { 
            Assert (lpntf->ulEventType == fnevTableModified); 
            if (lpntf->info.tab.ulTableEvent == TABLE_ROW_ADDED) 
            { 
                fFilter |= TRUE; 
                break; 
            } 
        } 
         
        if (fFilter) 
        { 
#ifdef  _WIN32 
            if(!lpwb->ht) 
            { 
                DWORD dw; 
                 
                lpwb->ht = CreateThread (NULL, 
                            1024, 
                            (LPTHREAD_START_ROUTINE)FilterDeletedThread, 
                            lpwb, 
                            0, 
                            &dw); 
            } 
#else 
            FilterDeletedThread (lpwb); 
#endif  // _WIN32 
        }        
    } 
    return S_OK; 
} 
 
 
/* 
 *  HrInitDeletedMailFilter() 
 * 
 *  Purpose: 
 * 
 *      Inits the deleted mail filters by opening the store, finding the 
 *      WB folder, opening the contents table of the WB, and registering 
 *      for table modification notifications. 
 * 
 *  Arguments: 
 * 
 *      lpsmg           the sample mail handler object 
 * 
 *  Returns: 
 * 
 *      (HRESULT) 
 */ 
HRESULT 
HrInitDeletedMailFilter (LPSMH lpsmh) 
{ 
    HRESULT hr; 
    LPMAPIADVISESINK lpadvz = NULL; 
    LPMAPIFOLDER lpfldr = NULL; 
    LPMAPITABLE lptbl = NULL; 
    LPMDB lpmdb = NULL; 
    LPSPropValue lpval = NULL; 
    LPWB lpwb = NULL; 
    ULONG ulType; 
    UINT cerr = 0; 
    UINT i; 
 
    for (i = 0; i < lpsmh->lpstotbl->cSto; i++) 
    { 
        hr = ResultFromScode ((*lpsmh->lpfnAlloc) (sizeof(WB), &lpwb)); 
        if (HR_FAILED (hr)) 
            goto nxt; 
        memset (lpwb, 0, sizeof(WB)); 
 
        hr = HrOpenStoEntry (lpsmh->lpsess, &lpsmh->lpstotbl->aSto[i], &lpmdb); 
        if (HR_FAILED (hr)) 
            goto nxt; 
 
        hr = HrGetOneProp ((LPMAPIPROP)lpmdb, PR_IPM_WASTEBASKET_ENTRYID, &lpval); 
        if (HR_FAILED (hr)) 
            goto nxt; 
 
        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)) 
            goto nxt; 
 
        hr = lpfldr->lpVtbl->GetContentsTable (lpfldr, 0, &lptbl); 
        if (HR_FAILED (hr)) 
            goto nxt; 
 
        hr = lptbl->lpVtbl->SetColumns (lptbl, (LPSPropTagArray)&sptFilterWb, 0); 
        if (HR_FAILED (hr)) 
            goto nxt; 
 
        hr = HrAllocAdviseSink ((LPNOTIFCALLBACK)&WBNotify, lpwb, &lpadvz); 
        if (HR_FAILED (hr)) 
            goto nxt; 
 
        hr = lptbl->lpVtbl->Advise (lptbl, fnevTableModified, lpadvz, &lpwb->ulAdvz); 
        if (HR_FAILED (hr)) 
            goto nxt; 
 
        UlAddRef (lptbl); 
        UlAddRef (lpfldr); 
        lpwb->lpmdb = lpmdb; 
        lpwb->lptbl = lptbl; 
        lpwb->lpfldr = lpfldr; 
        lpwb->lpvalEid = lpval; 
        lpwb->lpsmh = lpsmh; 
        lpval = NULL; 
 
        /* Hook it in */ 
 
        lpwb->wbNext = lpsmh->lstWb; 
        lpsmh->lstWb = lpwb; 
        lpwb = NULL; 
nxt: 
 
        if (HR_FAILED (hr)) 
            cerr++; 
 
        (*lpsmh->lpfnFree) (lpval); 
        lpval = NULL; 
 
        (*lpsmh->lpfnFree) (lpwb); 
        lpwb = NULL; 
 
        UlRelease (lpadvz); 
        lpadvz = NULL; 
 
        UlRelease (lpfldr); 
        lpfldr = NULL; 
 
        UlRelease (lptbl); 
        lptbl = NULL; 
    } 
 
    hr = ResultFromScode (cerr ? MAPI_W_ERRORS_RETURNED : S_OK); 
    DebugTraceResult (HrInitDeletedMailFilter(), hr); 
    return hr; 
}