CLIENT.C
/* 
 -  C L I E N T . C 
 - 
 *    Purpose: 
 *      Sample routing mail client for the MAPI SDK. 
 *      Exclusively uses the Extended MAPI interface. 
 * 
 *  Copyright 1986-1996, Microsoft Corporation. All Rights Reserved. 
 * 
 */ 
 
#include <string.h> 
#include <stdlib.h> 
#include <windows.h> 
#include <windowsx.h> 
#ifdef _WIN32 
#include <objerror.h> 
#include <objbase.h> 
#endif 
#ifdef WIN16 
#include <compobj.h> 
#endif 
#include <mapiutil.h> 
#include <mapidbg.h> 
#include <mapix.h> 
#include <mapiwin.h> 
#include <pdkver.h> 
#include <mapiform.h> 
#include <ole2.h> 
#include <wrap3d.h> 
 
#define USES_IID_IMAPIStatus 1 
#define USES_IID_IMessage  1 
#include <mapiguid.h> 
 
#include "client.h" 
#include "bitmap.h" 
#include "route.h" 
#ifdef _WIN32 
#include "chsfld.h" 
#endif 
 
#ifdef WIN16 
#define GWL_USERDATA    DWL_USER 
#endif 
 
 
/* Application instance */ 
HANDLE hInst; 
                             
/* Static Data */ 
 
static ULONG cbeidFolderToView; 
static LPENTRYID lpeidFolderToView = NULL; 
 
LPADRBOOK pabAddrB = NULL; 
LPMAPISESSION pses = NULL; 
LPMDB pmdb = NULL; 
LPMAPIFOLDER pfldOutBox = NULL; 
LPSPropValue pvalSentMailEID = NULL; 
HCURSOR hWaitCur; 
 
LPVOID lpCtl3d = NULL;      /* 3D control context */ 
 
#ifdef _WIN32 
/* Choose folder stuff */ 
HMODULE             g_hChsFldDll; 
HRPICKFOLDER        g_lpfnHrPickFolder; 
ULONG               cbCFDState = 0; 
LPBYTE              pbCFDState = NULL; 
#endif /*_WIN32 */ 
 
int PASCAL 
WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszCmd, int nCmdShow) 
{ 
    MSG msg; 
 
    if (!hPrevInst) 
        if (!InitApplication (hInstance)) 
            return (FALSE); 
 
    if (!InitInstance (hInstance, nCmdShow)) 
        return (FALSE); 
 
    while (GetMessage (&msg, 0, 0, 0)) 
    { 
        TranslateMessage (&msg); 
        DispatchMessage (&msg); 
    } 
 
    DeinitApplication (); 
 
    return (msg.wParam); 
} 
 
/* 
 -  InitApplication 
 - 
 *  Purpose: 
 *      Initialize the application. 
 * 
 *  Parameters: 
 *      hInstance   - Instance handle 
 * 
 *  Returns: 
 *      True/False 
 * 
 */ 
 
BOOL 
InitApplication (HANDLE hInstance) 
{ 
    WNDCLASS wc; 
 
    wc.style = 0; 
    wc.lpfnWndProc = MainWndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hInstance; 
    wc.hIcon = LoadIcon (hInstance, "NoMail"); 
    wc.hCursor = LoadCursor (0, IDC_ARROW); 
    wc.hbrBackground = GetStockObject (WHITE_BRUSH); 
    wc.lpszMenuName = "MailMenu"; 
    wc.lpszClassName = "RoutingSample"; 
 
    return (RegisterClass (&wc)); 
} 
 
/* 
 -  InitInstance 
 - 
 *  Purpose: 
 *      Initialize this instance. 
 * 
 *  Parameters: 
 *      hInstance   - Instance handle 
 *      nCmdShow    - Do we show the window? 
 * 
 *  Returns: 
 *      True/False 
 * 
 */ 
 
BOOL 
InitInstance (HANDLE hInstance, int nCmdShow) 
{ 
    HWND hWnd; 
    BOOL fInit; 
    BOOL f; 
 
    hInst = hInstance; 
 
    fInit = InitMAPI(0); 
 
    if (!lpCtl3d) 
    { 
        lpCtl3d = CTL3D_Initialize(hInstance); 
        CTL3D_AutoSubclass(lpCtl3d, hInstance, &f); 
    } 
 
    hWnd = CreateWindow ("RoutingSample", "Routing Sample", WS_OVERLAPPEDWINDOW, 
        5, 5, 550, 75, 0, 0, hInst, NULL); 
 
    if (!hWnd) 
        return (FALSE); 
 
    ShowWindow (hWnd, nCmdShow); 
    UpdateWindow (hWnd); 
 
    hWaitCur = LoadCursor(0, IDC_WAIT); 
 
    if (fInit) 
    { 
        if (ClientLogon (hWnd)) 
            ToggleMenuState (hWnd, TRUE); 
    } 
 
    return (fInit); 
} 
 
BOOL 
InitMAPI (HWND hWnd) 
{ 
    HRESULT hr; 
 
    hr = MAPIInitialize(NULL); 
    if(hr) 
    { 
        MakeMessageBox(hWnd, GetScode(hr), IDS_MAPIINIF, NULL, MBS_ERROR); 
        return FALSE; 
    } 
    return TRUE; 
} 
 
void 
DeinitApplication () 
{ 
    DeinitMAPI (); 
 
    CTL3D_Uninitialize(lpCtl3d); 
    lpCtl3d = NULL; 
 
#ifdef _WIN32 
    if(g_hChsFldDll) 
        FreeLibrary(g_hChsFldDll); 
         
#endif /* _WIN32 */ 
} 
 
void 
DeinitMAPI () 
{ 
    MAPIUninitialize(); 
 
} 
 
/* 
 *  Log on to MAPI 
 *   
 *  Error messages are in subroutings. 
 * 
 *  Globals: 
 *      pses        MAPI session handle 
 *      pmdb        MAPI message store object 
 *      pabAddrB    MAPI address book object 
 *      pfldOutBox  Out folder 
 *      pvalSentMailEID     EntryID of the "Sent mail" folder 
 */ 
 
BOOL ClientLogon (HWND hWnd) 
{ 
    HRESULT hr; 
    /* We should not yet be logged on*/ 
    Assert(pses == NULL); 
    Assert(pmdb == NULL); 
 
     
        /* MAPILogon might yield control to Windows. So to prevent the user 
    from clicking "logon" while we are in the process of loggin on we 
    have to disable it*/ 
 
    SecureMenu(hWnd, TRUE); 
 
    /* Create a MAPI session*/ 
    hr = MAPILogonEx((ULONG) hWnd, NULL, NULL, 
            MAPI_EXTENDED | MAPI_EXPLICIT_PROFILE | MAPI_LOGON_UI | 
            MAPI_NEW_SESSION, &pses); 
    if(hr) 
    { 
        SecureMenu(hWnd, FALSE); 
        pses = NULL; 
        if (GetScode(hr) != MAPI_E_USER_CANCEL) 
            MakeMessageBox (hWnd, GetScode(hr), IDS_LOGONFAIL, NULL, MBS_ERROR); 
        return FALSE; 
    } 
 
 
    pmdb = OpenDefaultStore(hWnd); 
    if (!pmdb) goto err; 
 
    pabAddrB = OpenAddressBook(hWnd); 
    if (!pabAddrB) goto err; 
 
    if(!OpenOutFolder(hWnd, &pfldOutBox)) goto err; 
     
    /* retrieve the EntryID of the sentmail folder and change the property tag 
        so that it is ready to use on a message*/ 
    hr = HrGetOneProp((LPMAPIPROP)pmdb, PR_IPM_SENTMAIL_ENTRYID, &pvalSentMailEID); 
    if(hr) 
    { 
        goto err; 
    } 
    pvalSentMailEID->ulPropTag = PR_SENTMAIL_ENTRYID; 
 
    return TRUE; 
 
err: 
     
    ClientLogoff(hWnd); 
    SecureMenu(hWnd, FALSE); 
     
    return FALSE; 
} 
 
/* 
 *  Releases  the global objects and logs off MAPI. 
 * 
 *  Globals: 
 *      pses        Extended-MAPI session object 
 *      pmdb        Extended-MAPI message store object 
 *      pabAddrB        Address Book 
 *      pfldOutBox  out folder 
 *      pvalSetmailEID contains EID of the "Sent" folder 
 */ 
VOID 
ClientLogoff (HWND hWnd) 
{ 
 
#ifdef _WIN32 
    MAPIFreeBuffer(pbCFDState); 
    pbCFDState = NULL; 
    cbCFDState = 0; 
#endif 
 
    UlRelease(pfldOutBox); 
    pfldOutBox = NULL; 
 
    UlRelease(pmdb); 
    pmdb = NULL; 
 
    UlRelease(pabAddrB); 
    pabAddrB = NULL; 
 
    MAPIFreeBuffer(pvalSentMailEID); 
    pvalSentMailEID = NULL; 
 
    pses->lpVtbl->Logoff(pses, (ULONG)hWnd, MAPI_LOGOFF_UI, 0); 
    UlRelease(pses); 
    pses = NULL; 
 
    SetWindowText(hWnd, "Routing Sample"); 
} 
 
LPMDB 
OpenDefaultStore(HWND hWnd) 
{ 
    HRESULT hr; 
    LPMDB lpmdb = NULL; 
    LPMAPITABLE ptable = NULL; 
    LPSRowSet prows = NULL; 
    LPSPropValue pvalProp = NULL; 
    static SizedSPropTagArray(2, columns) = 
                { 2, { PR_DEFAULT_STORE, PR_ENTRYID} }; 
    SPropValue valDefStore; 
    SPropertyRestriction restpropDefStore; 
    SRestriction restDefStore; 
 
     
    valDefStore.ulPropTag = PR_DEFAULT_STORE; 
    valDefStore.dwAlignPad = 0; 
    valDefStore.Value.b = TRUE; 
 
    restpropDefStore.relop = RELOP_EQ; 
    restpropDefStore.ulPropTag = PR_DEFAULT_STORE; 
    restpropDefStore.lpProp = &valDefStore; 
 
    restDefStore.rt = RES_PROPERTY; 
    restDefStore.res.resProperty = restpropDefStore; 
 
    hr = pses->lpVtbl->GetMsgStoresTable(pses, 0, &ptable); 
    if (HR_FAILED(hr)) 
    { 
        MakeMessageBox (hWnd, GetScode(hr), IDS_STORETBLFAIL, NULL, MBS_ERROR); 
        goto ret; 
    } 
 
     
    hr = HrQueryAllRows(ptable, (LPSPropTagArray) &columns, &restDefStore, NULL, 0, &prows); 
    if (HR_FAILED(hr)) 
    { 
        MakeMessageBox (hWnd, GetScode(hr), IDS_QUERYROWFAIL, NULL, MBS_ERROR); 
        goto ret; 
    } 
 
    if (prows == NULL || prows->cRows == 0 
        || prows->aRow[0].lpProps[1].ulPropTag != PR_ENTRYID) 
    { 
        MakeMessageBox (hWnd, 0L, IDS_NODEFAULTSTORE, NULL, MBS_ERROR); 
        goto ret; 
    } 
     
    Assert(prows->cRows == 1); 
 
    hr = pses->lpVtbl->OpenMsgStore(pses, (ULONG)hWnd, 
                        prows->aRow[0].lpProps[1].Value.bin.cb, 
                        (LPENTRYID)prows->aRow[0].lpProps[1].Value.bin.lpb, 
                        NULL, MDB_WRITE | MAPI_DEFERRED_ERRORS, &lpmdb); 
    if (HR_FAILED(hr)) 
    { 
        if (GetScode(hr) != MAPI_E_USER_CANCEL) 
            MakeMessageBox (hWnd, GetScode(hr), IDS_OPENSTOREFAIL, NULL, MBS_ERROR); 
        Assert(lpmdb == NULL); 
        goto ret; 
    } 
    if(hr) /*if we have a warning, display it and succeed */ 
    { 
        LPMAPIERROR perr = NULL; 
 
        pses->lpVtbl->GetLastError(pses, hr, 0, &perr); 
        MakeMessageBox(hWnd, GetScode(hr), IDS_OPENSTOREWARN, perr, MBS_ERROR); 
        MAPIFreeBuffer(perr); 
    } 
 
 
    Assert(lpmdb != NULL); 
 
    hr = HrGetOneProp((LPMAPIPROP)lpmdb, PR_DISPLAY_NAME, &pvalProp); 
    if(!hr) 
    {    
        char buf[128]; 
 
        wsprintf(buf, "Routing Sample: %s", pvalProp->Value.lpszA); 
 
        SetWindowText(hWnd, buf); 
        MAPIFreeBuffer(pvalProp); 
    } 
                     
ret: 
    FreeProws(prows); 
    UlRelease(ptable); 
 
    return lpmdb; 
} 
 
 
#ifdef _WIN32 
BOOL FGetFoldChooser(void) 
{ 
    UINT uiErrMode; 
     
    if(g_lpfnHrPickFolder) 
        return TRUE; 
 
    Assert(!g_hChsFldDll); 
 
    uiErrMode = SetErrorMode(SEM_NOOPENFILEERRORBOX); 
 
    g_hChsFldDll = LoadLibrary(szChsFldDllName); 
 
    SetErrorMode(uiErrMode); 
 
    if(g_hChsFldDll) 
    { 
        if((g_lpfnHrPickFolder = (HRPICKFOLDER)GetProcAddress(g_hChsFldDll, 
                                        szChsFldFnName))) 
        { 
            return TRUE; 
        } 
 
        DebugTrace("route.cli: GetProcAddress for %s failed", szChsFldFnName); 
         
        FreeLibrary(g_hChsFldDll); 
        g_hChsFldDll = NULL; 
    } 
    else 
    { 
        DebugTrace("smpfrm: failed to load choose folder dll\n"); 
    } 
 
    return FALSE; 
} 
#endif /* _WIN32 */ 
 
/* 
 -  MainWndProc 
 - 
 *   Purpose: 
 *      Main Window Procedure. 
 *      Handles the menu bar and standard window messages. 
 * 
 *   Parameters: 
 *       hWnd 
 *       message 
 *       wParam 
 *       lParam 
 * 
 *   Returns: 
 * 
 * 
 */ 
 
LONG FAR PASCAL 
MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (msg) 
    { 
    HANDLE_MSG(hWnd, WM_COMMAND, MAIN_OnCommand); 
     
    case WM_ENDSESSION: 
        DestroyWindow (hWnd); 
        break; 
 
    case WM_CLOSE: 
    case WM_DESTROY: 
        if (pses) 
            ClientLogoff (hWnd); 
 
        PostQuitMessage (0); 
        break; 
 
    default: 
        return (DefWindowProc (hWnd, msg, wParam, lParam)); 
    } 
    return FALSE; 
} 
 
 
LONG MAIN_OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify) 
{ 
    HRESULT hr; 
#ifndef _WIN32 
    LPDIALOGDATA pDialogData; 
#endif 
    LPMESSAGE pmsgOutgoing = NULL; 
    ULONG ulMsgToken = 0; 
     
    switch (id) 
    { 
    case IDM_NEWFORM: 
        { 
            LPMAPIFORMMGR pfmmgr = NULL; 
            LPMAPIFORMINFO pfminfo = NULL;           
            LPSPropValue pvalMsgClass = NULL; 
            LPMESSAGE pmsgForm = NULL; 
 
            hr = MAPIOpenFormMgr(pses, &pfmmgr); 
            if(!hr) 
            { 
                hr = pfmmgr->lpVtbl->SelectForm(pfmmgr, (ULONG) hWnd, 0, NULL, NULL, &pfminfo); 
 
                if(!hr) 
                { 
                     
                    /*Get the form's msg class */ 
                    hr = HrGetOneProp((LPMAPIPROP)pfminfo, PR_MESSAGE_CLASS, &pvalMsgClass); 
                    DebugTraceResult(HrGetOneProp, hr); 
                     
                    if(!hr) 
                    { 
                        /*create new message*/ 
                        if(CreateOutMessage(&pmsgForm)) 
                        { 
                            hr = pses->lpVtbl->PrepareForm(pses, NULL, pmsgForm, (LPULONG) &ulMsgToken); 
                            if(S_OK != GetScode(hr)) 
                            { 
                                DebugTrace("Client: PrepareForm failed"); 
                                break; 
                            } 
                            UlRelease(pmsgForm); 
                            pmsgForm = NULL; 
                 
                            hr = pses->lpVtbl->ShowForm(pses, (ULONG) hWnd, pmdb, pfldOutBox, 
                                                        NULL, ulMsgToken, NULL, MAPI_NEW_MESSAGE, 
                                                        0, MSGFLAG_UNSENT | MSGFLAG_READ, 0, 
                                                        pvalMsgClass->Value.lpszA ); 
                            if(S_OK != GetScode(hr)) 
                            MakeMessageBox(hWnd, GetScode(hr), IDS_SHOWFORM, NULL, MBS_ERROR); 
                        } 
                        else 
                            MakeMessageBox(hWnd, 1, IDS_CRTOUTMSG, NULL, MBS_ERROR); 
                    } 
 
                    MAPIFreeBuffer(pvalMsgClass); 
                    UlRelease(pfminfo); 
                } 
 
                UlRelease(pfmmgr); 
            } 
        } 
                 
        break;               
                 
 
    case IDM_LOGON: 
        if (!pses) 
        { 
            if (ClientLogon (hWnd)) 
                ToggleMenuState (hWnd, TRUE); 
        } 
        break; 
     
    case IDM_LOGOFF: 
        if (pses) 
        { 
            ClientLogoff (hWnd); 
            ToggleMenuState (hWnd, FALSE); 
        } 
        break;                   
         
    case IDM_HIER: 
        Assert(pses); 
        //on win32 use the sample Choose Folder Dialog 
#ifdef _WIN32  
        { 
            HRESULT hr; 
            LPMAPIFOLDER pfld = NULL; 
            LPMDB pmdbNew = NULL; 
 
            if(!FGetFoldChooser()) 
                return TRUE; 
                 
            hr = (*g_lpfnHrPickFolder)(NULL, hWnd, pses, &pfld, &pmdbNew, 
                                    &cbCFDState, &pbCFDState); 
            if(HR_SUCCEEDED(hr)) 
            { 
                LPSPropValue pval = NULL; 
 
                UlRelease(pmdb); 
                pmdb = pmdbNew; 
                pmdbNew = NULL; 
 
                hr = HrGetOneProp((LPMAPIPROP)pmdb, PR_DISPLAY_NAME, &pval); 
                if(!hr) 
                {    
                    char buf[128]; 
 
                    wsprintf(buf, "Routing Sample: %s", pval->Value.lpszA); 
 
                    SetWindowText(hWnd, buf); 
                    MAPIFreeBuffer(pval); 
                    pval = NULL; 
                } 
 
     
                hr = HrGetOneProp((LPMAPIPROP)pfld, PR_ENTRYID, &pval); 
                if(!hr) 
                { 
                    cbeidFolderToView = pval->Value.bin.cb; 
                    lpeidFolderToView = (LPENTRYID)pval->Value.bin.lpb; 
 
                    DialogBox (hInst, "InBox", hWnd, InBoxDlgProc); 
 
                    cbeidFolderToView = 0; 
                    lpeidFolderToView = NULL; 
 
                    MAPIFreeBuffer(pval); 
                } 
                 
                UlRelease(pfld); 
            } 
        } 
 
#else 
 
         
        Assert(pmdb); 
        if (pDialogData = CreateDialogData (iHierarchy)) 
            DialogBoxParam (hInst, "HierarchyTable", hWnd, CommonDlgProc, (LPARAM)pDialogData); 
#endif /* _WIN32 */ 
        break; 
 
#ifndef _WIN32         
    case IDM_OPEN: 
        Assert(pses); 
        if (pDialogData = CreateDialogData (iStores)) 
            DialogBoxParam (hInst, "OpenStore", hWnd, CommonDlgProc, (LPARAM)pDialogData); 
        break; 
#endif /* _WIN32 */ 
                                                                       
    case IDM_ROUTE: 
        Assert(pses); 
        DialogBoxParam(hInst, "RouteNote", hWnd, RouteNoteDlgProc, (LPARAM) NULL ); 
        break; 
 
    case IDM_READ: 
        Assert(pses); 
        Assert(pmdb); 
        Assert(lpeidFolderToView == NULL); 
 
        { 
            /* Get the entry ID of the Inbox from the message store. */ 
            if ((hr = pmdb->lpVtbl->GetReceiveFolder(pmdb, 
                    "IPM", 0, 
                    &cbeidFolderToView, &lpeidFolderToView, NULL)) 
                        == hrSuccess) 
            { 
                DialogBox (hInst, "InBox", hWnd, InBoxDlgProc); 
                MAPIFreeBuffer(lpeidFolderToView); 
                lpeidFolderToView = NULL; 
            } 
            else 
                MakeMessageBox (hWnd, GetScode(hr), IDS_GETRCVFAIL, NULL, MBS_ERROR); 
        } 
        break; 
 
    case IDM_SEND: 
        Assert(pses); 
        { 
            if(CreateOutMessage(&pmsgOutgoing)) 
            { 
                hr = pses->lpVtbl->PrepareForm(pses, NULL, pmsgOutgoing, (LPULONG) &ulMsgToken); 
                if(S_OK != GetScode(hr)) 
                { 
                    DebugTrace("Client: PrepareForm failed"); 
                    break; 
                } 
                UlRelease(pmsgOutgoing); 
                pmsgOutgoing = NULL; 
                 
                hr = pses->lpVtbl->ShowForm(pses, (ULONG) hWnd, pmdb, pfldOutBox, NULL, ulMsgToken, 
                                            NULL, MAPI_NEW_MESSAGE, 0, MSGFLAG_UNSENT | MSGFLAG_READ, 0, "IPM.Note"); 
                if(S_OK != GetScode(hr)) 
                    MakeMessageBox(hWnd, GetScode(hr), IDS_SHOWFORM, NULL, MBS_ERROR); 
            } 
            else 
                MakeMessageBox(hWnd, 1, IDS_CRTOUTMSG, NULL, MBS_ERROR);                 
 
        } 
        break; 
           
    case IDM_ABOUT: 
        DialogBox (hInst, "AboutBox", hWnd, AboutDlgProc); 
        break; 
     
 
    case IDM_EXIT: 
        if (pses) 
            ClientLogoff (hWnd); 
     
        PostQuitMessage (0); 
        break; 
 
        default: 
            return TRUE; 
    } 
 
    return FALSE; 
} 
     
 
/* 
 *  Displays an About dialog for the sample client. 
 */ 
 
BOOL CALLBACK 
AboutDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    char    rgchVersion[80]; 
 
    switch (msg) 
    { 
    case WM_INITDIALOG: 
        wsprintf(rgchVersion, "Version %d.%d.%d (%s)", rmj, rmm, rup, 
            szVerName && *szVerName ? szVerName : "BUDDY"); 
        SetDlgItemText(hDlg, IDC_VERSION, rgchVersion); 
        return TRUE; 
 
    case WM_COMMAND: 
        if (wParam == IDOK || wParam == IDCANCEL) 
        { 
            EndDialog (hDlg, TRUE); 
            return TRUE; 
        } 
        break; 
    } 
    return FALSE; 
} 
             
 
 
/* 
 *  Handles the Inbox list view, its command buttons. 
 *  The main window is a listbox presenting a summary line for 
 *  each message in the Inbox. There are command buttons for 
 *  refreshing the list, displaying a message, and deleting a 
 *  message. 
 * 
 *  All operations are on single messages; multiple selection is 
 *  not supported. 
 * 
 *  The EntryID of the folder to examine is passed in using 
 *  the global lpeidFolderToView. 
 */ 
 
BOOL CALLBACK 
InBoxDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    LPMSGID lpMsgIdList = NULL; 
    HCURSOR hOldCur; 
    LPMESSAGE pmsgRead = NULL; 
    ULONG ulObjType = 0; 
    ULONG ulMsgToken = 0; 
    LPINBOXDATA pIBData = NULL; 
 
    switch (msg) 
    { 
    case WM_INITDIALOG: 
        if(MAPIAllocateBuffer(sizeof(INBOXDATA), &pIBData)) 
        { 
            EndDialog(hDlg, FALSE); 
            return TRUE; 
        } 
         
        hOldCur = SetCursor(hWaitCur); 
 
        ZeroMemory(pIBData, sizeof(INBOXDATA)); 
         
        InitBmps(hDlg, IDC_MSG); 
 
        /* Populate List Box with all messages in InBox. */ 
        PopulateMessages(hDlg, pIBData); 
 
        SetCursor(hOldCur); 
        SetFocus (GetDlgItem (hDlg, IDC_MSG)); 
        SetWindowLong(hDlg, GWL_USERDATA, (LONG)pIBData); 
        return TRUE; 
        break; 
 
    case WM_SETFOCUS: 
        SetFocus (GetDlgItem (hDlg, IDC_MSG)); 
        break; 
 
    case WM_MEASUREITEM: 
        /* Sets the height of the owner-drawn List-Box */ 
        MeasureItem(hDlg, (MEASUREITEMSTRUCT *)lParam); 
        break; 
 
    case WM_DRAWITEM: 
        DrawItem((DRAWITEMSTRUCT *)lParam); 
        break; 
 
    case WM_CHARTOITEM:     /* don't select item by character*/ 
        return  -2; 
 
    /* Handled by IDC_DELETE */ 
    case WM_DELETEITEM: 
        return TRUE; 
    HANDLE_MSG(hDlg, WM_COMMAND, INBOX_OnCommand); 
        break; 
    } 
 
    return FALSE; 
} 
 
void INBOX_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify) 
{ 
    LPMSGID lpMsgNode = NULL; 
    LPINBOXDATA pibData = NULL; 
    HCURSOR hOldCur; 
    UINT nIndex; 
    RECT Rect; 
    LPMESSAGE pmsgRead = NULL; 
    ULONG ulObjType = 0; 
    HRESULT hr; 
    ULONG ulMsgToken = 0; 
    ULONG cProps = 0; 
    LPSPropValue pvalProps = NULL; 
    LONG lStat = 0, lFlags = 0, lAccess = 0; 
    LPSTR lpszMsgClass = "IPM.Note"; 
 
    enum { PRSTAT, PRFLAGS, PRACCESS, PRCLASS, PRDIM};      /* used to retrieve props*/ 
    SizedSPropTagArray(PRDIM, sptaSFProps) =                /*required for ShowForm call*/ 
    { PRDIM, {PR_MSG_STATUS, PR_MESSAGE_FLAGS, PR_ACCESS_LEVEL, PR_MESSAGE_CLASS} }; 
 
     
    switch (id) 
    { 
     
    case IDC_FLUSH: 
        hr = DeliverNow(hDlg); 
        if(hr) 
            break; 
         /*fall through if the flush was succesfull*/ 
    case IDC_NEW: 
         
        pibData = (LPINBOXDATA)GetWindowLong(hDlg, GWL_USERDATA); 
        if(!pibData) 
        { 
            DebugTrace("Client: userdata == 0 (inboxdlgproc)"); 
        } 
        hOldCur = SetCursor(hWaitCur); 
     
        /* Destroy the old message list. */ 
        FreeMsgList (pibData->lpMsgIdList); 
        pibData->lpMsgIdList = NULL; 
 
        /* Populate List Box with all messages in InBox. */ 
        PopulateMessages(hDlg, pibData); 
         
        SetCursor(hOldCur); 
        break; 
 
    case IDC_MSG: 
        if(codeNotify != LBN_DBLCLK) 
        break; 
        /* FALL THROUGH to read the double-clicked message */ 
     
    case IDC_READ: 
        nIndex = (UINT)ListBox_GetCurSel(GetDlgItem(hDlg, IDC_MSG)); 
        if (nIndex == LB_ERR) 
        break; 
     
        lpMsgNode = (LPMSGID)ListBox_GetItemData(GetDlgItem(hDlg, IDC_MSG), nIndex); 
        if (lpMsgNode) 
        {    
            hr = pmdb->lpVtbl->OpenEntry(pmdb, lpMsgNode->cbEID, lpMsgNode->lpEID, 
                                NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS, 
                                &ulObjType, (LPUNKNOWN FAR *) &pmsgRead); 
     
            if(S_OK != GetScode(hr)) 
            { 
                LPMAPIERROR perr = NULL; 
                 
                pmdb->lpVtbl->GetLastError(pmdb, hr, 0, &perr); 
                MakeMessageBox(hDlg, GetScode(hr), IDS_READFAIL, perr, MBS_ERROR); 
                MAPIFreeBuffer(perr); 
                DebugTrace("Client: OpenEntry failed"); 
                break; 
            } 
            else 
            {  
                Assert(ulObjType == MAPI_MESSAGE); 
     
                lpMsgNode->fUnRead = FALSE; 
         
                /* get all the props in one call */ 
                hr = pmsgRead->lpVtbl-> 
                GetProps(pmsgRead, (LPSPropTagArray)&sptaSFProps, 0, 
                                                    &cProps, &pvalProps); 
                if(HR_SUCCEEDED(hr)) 
                { 
                    if(pvalProps[PRSTAT].ulPropTag == PR_MSG_STATUS)  
                        lStat = pvalProps[PRSTAT].Value.l; 
                    if(pvalProps[PRFLAGS].ulPropTag == PR_MESSAGE_FLAGS) 
                        lFlags = pvalProps[PRFLAGS].Value.l; 
                    if(pvalProps[PRACCESS].ulPropTag == PR_ACCESS_LEVEL) 
                        lAccess = pvalProps[PRACCESS].Value.l; 
                    if(pvalProps[PRCLASS].ulPropTag == PR_MESSAGE_CLASS) 
                        lpszMsgClass = pvalProps[PRCLASS].Value.lpszA; 
                } 
                 
                else 
                { 
                    DebugTrace("Client: GetProps (for ShowForm) failed"); 
                    break; 
                } 
                 
                if (!lstrcmpi(lpszMsgClass, lpszSmplRTMsgClass)) 
                { 
                    DialogBoxParam(hInst, "RouteNote", hDlg, RouteNoteDlgProc, (LPARAM) pmsgRead); 
                    /* RouteNoteDlgPropc will release pmsgRead*/ 
                } 
                else 
                {                                    
                    hr = pses->lpVtbl->PrepareForm(pses, NULL, pmsgRead, (LPULONG) &ulMsgToken); 
                    if(S_OK != GetScode(hr)) 
                    { 
                        DebugTrace("Client: PrepareForm failed"); 
                        MAPIFreeBuffer(pvalProps); 
                        break; 
                    } 
                    UlRelease(pmsgRead); 
                    pmsgRead = NULL; 
                    hr = pses->lpVtbl->ShowForm(pses, (ULONG) hDlg, pmdb, pfldOutBox, NULL, ulMsgToken, 
                                            NULL, 0, lStat, lFlags, lAccess, lpszMsgClass); 
                     
                } 
            } 
             
        } 
         
        MAPIFreeBuffer(pvalProps); 
        pvalProps = NULL; 
        /* Update the Messages List-Box with new icon */ 
        lpMsgNode = NULL; 
 
        ListBox_GetItemRect(GetDlgItem(hDlg, IDC_MSG),nIndex, (LPARAM) &Rect); 
        InvalidateRect(GetDlgItem(hDlg, IDC_MSG), &Rect, FALSE); 
         
        break; 
         
    case IDC_DELETE: 
        { 
        ENTRYLIST el; 
        SBinary sb; 
         
        nIndex = (UINT)ListBox_GetCurSel(GetDlgItem(hDlg, IDC_MSG)); 
        if (nIndex == LB_ERR) 
            break; 
     
        pibData = (LPINBOXDATA)GetWindowLong(hDlg, GWL_USERDATA); 
        if(!pibData) 
        { 
            DebugTrace("Client: userdata == 0 (inboxdlgproc)"); 
        } 
         
        lpMsgNode = (LPMSGID) ListBox_GetItemData(GetDlgItem(hDlg, IDC_MSG), 
                                                nIndex); 
        if (lpMsgNode) 
        {    
            sb.cb = lpMsgNode->cbEID; 
            sb.lpb = (LPBYTE)lpMsgNode->lpEID; 
            el.cValues = 1; 
            el.lpbin = &sb; 
 
            hr = pibData->pfld->lpVtbl-> 
                    DeleteMessages(pibData->pfld, &el, 0, NULL, 0); 
            DeleteMsgNode (lpMsgNode, &pibData->lpMsgIdList); 
        } 
 
        ListBox_DeleteString(GetDlgItem(hDlg, IDC_MSG), nIndex); 
        } 
        break; 
     
    case IDC_CLOSE: 
    case IDCANCEL: 
        pibData = (LPINBOXDATA)GetWindowLong(hDlg, GWL_USERDATA); 
        if(!pibData) 
        { 
            DebugTrace("Client: userdata == 0 (inboxdlgproc)"); 
             
        } 
         
        FreeMsgList (pibData->lpMsgIdList); 
        pibData->lpMsgIdList = NULL; 
        UlRelease(pibData->pfld); 
        pibData->pfld = NULL; 
        MAPIFreeBuffer(pibData); 
        pibData = NULL; 
        DeInitBmps(); 
        EndDialog (hDlg, TRUE); 
        break; 
     
    default: 
        break; 
    } 
} 
 
/* 
 *  DeliverNow flushes outbound and inboud queues. 
 * 
 */ 
HRESULT DeliverNow(HWND hWnd) 
{ 
    HRESULT hr; 
    LPMAPISTATUS pstatSpooler = NULL; 
    ULONG ulObjType = 0; 
    LPMAPITABLE ptblStatus = NULL; 
    SizedSPropTagArray(1, columns) = 
                { 1, { PR_ENTRYID} }; 
    SPropValue valSpooler; 
    SPropertyRestriction restpropSpooler; 
    SRestriction restSpooler; 
    LPSRowSet prows = NULL; 
     
    /*Build property restriction (PR_RESOURCE_TYPE == MAPI_SPOOLER)*/ 
    valSpooler.ulPropTag = PR_RESOURCE_TYPE; 
    valSpooler.dwAlignPad = 0; 
    valSpooler.Value.l = MAPI_SPOOLER; 
 
    restpropSpooler.relop = RELOP_EQ; 
    restpropSpooler.ulPropTag = PR_RESOURCE_TYPE; 
    restpropSpooler.lpProp = &valSpooler; 
 
    restSpooler.rt = RES_PROPERTY; 
    restSpooler.res.resProperty = restpropSpooler; 
 
    /*open session status table*/ 
    hr = pses->lpVtbl->GetStatusTable(pses, 0, &ptblStatus); 
    if(hr) 
    { 
        DebugTraceResult(GetStatusTable, hr); 
        goto err; 
    } 
 
    /*find a row corresponding to the spooler*/ 
    hr = HrQueryAllRows(ptblStatus, (LPSPropTagArray) &columns, &restSpooler, NULL, 0, &prows); 
    if (HR_FAILED(hr)) 
    { 
        DebugTraceResult(HrQueryAllRows, hr); 
        goto err; 
    } 
 
    Assert(prows && prows->cRows == 1); /*hope the spooler is always there */ 
    Assert(prows->aRow[0].lpProps[0].ulPropTag == PR_ENTRYID); 
    /*open spooler as a status object*/ 
    hr = pses->lpVtbl-> 
            OpenEntry(pses, prows->aRow->lpProps->Value.bin.cb, 
                        (LPENTRYID)prows->aRow->lpProps->Value.bin.lpb, 
                        &IID_IMAPIStatus, MAPI_BEST_ACCESS, &ulObjType, 
                        (LPUNKNOWN FAR *) &pstatSpooler); 
    if(hr) 
    { 
        DebugTraceResult(OpenEntry, hr); 
        goto err; 
    } 
 
    Assert(ulObjType == MAPI_STATUS); 
 
    /*call FlushQueues()*/ 
    hr = pstatSpooler->lpVtbl->FlushQueues(pstatSpooler, (ULONG) hWnd, 0, NULL,  
                                            FLUSH_DOWNLOAD | FLUSH_UPLOAD); 
    if(hr) 
    { 
        DebugTraceResult(FlushQueues, hr); 
        goto err; 
    } 
     
    /*release all used objects*/ 
 
err: 
    UlRelease(ptblStatus); 
    FreeProws(prows); 
    UlRelease(pstatSpooler); 
 
    return hr; 
} 
 
    /* 
 -  MakeMessageBox 
 - 
 *  Purpose: 
 *      Gets resource string and displays an error message box. 
 * 
 *  Parameters: 
 *      hWnd            - Handle to parent window 
 *      sc              - SCODE 
 *      idString        - Resource ID of message in StringTable 
 *      perr            - pointer to MAPIERROR from last GetLastError 
 *      fStyle          - style for MessageBox 
 * 
 *  Returns: 
 *      Void 
 * 
 */ 
 
void 
MakeMessageBox (HWND hWnd, SCODE sc, UINT idString, LPMAPIERROR perr, UINT fStyle) 
{ 
    char szMessage[512]; 
    char szbuf[256]; 
 
    if(!LoadString (hInst, idString, szMessage, 255)) 
        return; 
 
    if(perr) 
    { 
        wsprintf(szbuf, "\n%s\n%s\nLowLevelError: 0x%08lx context: %ld ", (perr->lpszError ? perr->lpszError:""), 
                        perr->lpszComponent ? perr->lpszComponent:"", perr->ulLowLevelError, perr->ulContext); 
        lstrcat(szMessage, szbuf); 
    } 
    if (sc) 
    { 
        wsprintf (szbuf, "\nReturn Code: 0x%08lx", sc); 
        lstrcat (szMessage, szbuf); 
    } 
 
    MessageBox (hWnd, szMessage, "Sample Routing Form", fStyle); 
} 
 
 
/* 
 * Common Dialog Proc for store and folder listboxes 
 * 
 */ 
BOOL CALLBACK 
CommonDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    MEASUREITEMSTRUCT *pmis; 
    DRAWITEMSTRUCT *pdis; 
    HCURSOR hOldCur; 
    LPDIALOGDATA pdd = (LPDIALOGDATA) GetWindowLong(hDlg, DWL_USER); 
 
    switch (msg) 
    { 
    case WM_INITDIALOG: 
        /* Remember the address of our dialog data*/ 
        SetWindowLong(hDlg, DWL_USER, lParam); 
        pdd = (LPDIALOGDATA)lParam; 
        Assert(pdd->poarHead == NULL); 
 
        /*/ Load up the rows of the dialog*/ 
        hOldCur = SetCursor(hWaitCur); 
        PopulateStores (hDlg, &pdd->poarHead, pdd->iDlgType, 
            pdd->cbEntryID, pdd->lpEntryID); 
        SetCursor(hOldCur); 
 
        SetFocus (GetDlgItem (hDlg, IDC_MSG)); 
        return TRUE; 
 
    case WM_DESTROY: 
        /* Discard our dialog data*/ 
        FreeOarList(&pdd->poarHead); 
        MAPIFreeBuffer(pdd); 
        return TRUE; 
 
    case WM_SETFOCUS: 
        SetFocus (GetDlgItem (hDlg, IDC_MSG)); 
        break; 
 
    case WM_MEASUREITEM: 
        /* Sets the height of the owner-drawn List-Box */ 
        pmis = (MEASUREITEMSTRUCT *) lParam; 
        pmis->itemHeight = 15; 
        break; 
 
    case WM_DRAWITEM: 
        pdis = (DRAWITEMSTRUCT *) lParam; 
        DrawOarItem (pdis, pdd->iDlgType); 
        break; 
 
    case WM_CHARTOITEM:     /* don't select item by character*/ 
        return -2; 
 
    /* Handled by IDC_DELETE */ 
    case WM_DELETEITEM: 
        return TRUE; 
 
//  HANDLE_MSG(hDlg, WM_COMMAND, Common_OnCommand); 
    case WM_COMMAND: 
        return ((Common_OnCommand)((hDlg), (int)(wParam), (HWND)(LOWORD(lParam)), 0L)); 
 
    }   /* switch (msg) */ 
 
    return FALSE; 
} 
 
 
BOOL Common_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify) 
{ 
    LPDIALOGDATA pdd = (LPDIALOGDATA) GetWindowLong(hDlg, DWL_USER); 
 
    switch (id) 
    { 
    case IDC_MSG: 
        if(codeNotify != LBN_DBLCLK) 
            break; 
            /* FALL THROUGH to read the double-clicked store */ 
 
    case IDC_DOWN: 
    case IDC_READ: 
        /*/ open a Hierarchy or Store*/ 
    { 
            /*/ Open one of the items in the list*/ 
        LPMDB pmdbTemp; 
        UINT nIndex; 
        LPOAR poar; 
        LPSPropValue pProp; 
        LPSPropValue pvalProp = NULL; 
        HRESULT hr; 
 
        nIndex = (UINT)ListBox_GetCurSel(GetDlgItem(hDlg, IDC_MSG)); 
 
        if (nIndex == LB_ERR) 
            return TRUE; 
 
        poar = (LPOAR) ListBox_GetItemData(GetDlgItem(hDlg, IDC_MSG), nIndex); 
 
        if (!poar) 
            return TRUE; 
 
                /* PropFindProp from mapiutil.h */ 
        pProp = PpropFindProp(poar->lpProps,  poar->cValues, PR_ENTRYID); 
         
        Assert(pProp); 
        /*/ Every row should have an EntryID */ 
         
        if (pdd->iDlgType == iStores) 
        { 
            hr = pses->lpVtbl->OpenMsgStore(pses, 
                (ULONG)hDlg, 
                pProp->Value.bin.cb, 
                (LPENTRYID)pProp->Value.bin.lpb, 
                NULL, MDB_WRITE, &pmdbTemp); 
 
            if (HR_FAILED(hr)) 
            { 
                if (GetScode(hr) != MAPI_E_USER_CANCEL) 
                    MakeMessageBox (hDlg, GetScode(hr), IDS_OPENSTOREFAIL, NULL, MBS_ERROR); 
                return TRUE; 
                } 
            if(hr) /*if we have a warning*/ 
            { 
                LPMAPIERROR perr = NULL; 
 
                pses->lpVtbl->GetLastError(pses, hr, 0, &perr); 
                MakeMessageBox(hDlg, GetScode(hr), IDS_OPENSTOREWARN, perr, MBS_ERROR); 
                MAPIFreeBuffer(perr); 
            } 
 
 
            Assert(hr == hrSuccess);    /* no warnings (for now?)*/ 
 
            UlRelease(pmdb); 
            pmdb = pmdbTemp; 
 
            /*Change the caption of the main window */ 
            hr = HrGetOneProp((LPMAPIPROP)pmdb, PR_DISPLAY_NAME, &pvalProp); 
            if(!hr) 
            { 
                char buf[128]; 
             
                wsprintf(buf, "Routing Sample: %s", pvalProp->Value.lpszA); 
                SetWindowText(GetParent(hDlg), buf); 
 
                MAPIFreeBuffer(pvalProp); 
                pvalProp = NULL; 
            } 
                     
            EndDialog (hDlg, TRUE); 
            return TRUE; 
        } 
 
        Assert (pdd->iDlgType == iHierarchy); 
 
        if (id == IDC_DOWN) 
        { 
            LPDIALOGDATA pDialogData; 
            if (pDialogData = CreateDialogData (iHierarchy)) 
            { 
                pDialogData->cbEntryID = pProp->Value.bin.cb; 
                pDialogData->lpEntryID = (LPENTRYID)pProp->Value.bin.lpb; 
                DialogBoxParam (hInst, "HierarchyTable", hDlg, CommonDlgProc, (LPARAM)pDialogData); 
            } 
 
        } 
        else    /* IDC_READ */ 
        { 
            /* OPEN a contents table*/ 
            Assert(lpeidFolderToView == NULL); 
            cbeidFolderToView = pProp->Value.bin.cb; 
            lpeidFolderToView = (LPENTRYID)pProp->Value.bin.lpb; 
            DialogBox (hInst, "InBox", hDlg, InBoxDlgProc); 
            lpeidFolderToView = NULL; 
        } 
    } 
    return TRUE; 
 
    case IDC_CLOSE: 
    case IDCANCEL: 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
 
    } 
 
    return TRUE; 
} 
 
/* 
 -  PopulateStores 
 - 
 *  Accumulate all the rows of a table onto the OAR list. 
 *  idlgType indicates iStores, iHierarchy. 
 * 
 *  If iHierarchy, the EntryID of the folder is in cb/lpeid. 
 */ 
 
VOID 
PopulateStores ( HWND hDlg, LPOAR FAR * ppoarHead, int idlgType, 
        ULONG cb, LPENTRYID lpeid) 
{ 
    HRESULT hr; 
    SCODE sc; 
    LPMAPIFOLDER pfld = NULL; 
    LPMAPITABLE ptable = NULL; 
    LPSRowSet prows = NULL; 
    LPSPropValue pvalProp = NULL; 
    UINT idx; 
 
    /* Get the list of available message stores or folderes from MAPI*/ 
    Assert(pses); 
 
    switch (idlgType) 
    { 
    case iStores: 
        if (hr = pses->lpVtbl->GetMsgStoresTable(pses, 0, &ptable)) 
        { 
            MakeMessageBox (hDlg, GetScode(hr), IDS_STORETBLFAIL, NULL, MBS_ERROR); 
            goto ret; 
        } 
        break; 
    case iHierarchy: 
        { 
            ULONG ulObjType; 
            if (hr = pmdb->lpVtbl->OpenEntry(pmdb, cb, lpeid, NULL, 
                                MAPI_DEFERRED_ERRORS, 
                            &ulObjType, (LPUNKNOWN FAR *) &pfld)) 
            { 
                MakeMessageBox (hDlg, GetScode(hr), IDS_OPENFOLDERFAIL, NULL, MBS_ERROR); 
                goto ret; 
            } 
            Assert(ulObjType == MAPI_FOLDER); 
            if (hr = pfld->lpVtbl->GetHierarchyTable(pfld, MAPI_DEFERRED_ERRORS, 
                                                        &ptable)) 
            { 
                MakeMessageBox (hDlg, GetScode(hr), IDS_STORETBLFAIL, NULL, MBS_ERROR); 
                goto ret; 
            } 
            hr = HrGetOneProp((LPMAPIPROP)pfld, PR_DISPLAY_NAME, &pvalProp); 
            if(!hr) 
            { 
                if(*pvalProp->Value.lpszA) 
                    SetWindowText(hDlg, pvalProp->Value.lpszA); 
                MAPIFreeBuffer(pvalProp); 
                pvalProp = NULL; 
            } 
                     
        } 
        break; 
    default: 
        Assert(0); 
    } 
 
    if(hr = HrQueryAllRows(ptable, NULL, NULL, NULL, 1000l, &prows)) 
    { 
        MakeMessageBox (hDlg, GetScode(hr), IDS_QUERYROWFAIL, NULL, MBS_ERROR); 
        goto ret; 
    } 
    for(idx = 0; idx < prows->cRows; ++idx) 
    { 
        LPOAR poar = NULL; 
        sc = MAPIAllocateBuffer(sizeof(OAR), &poar); 
        if (sc) 
        { 
            hr = ResultFromScode(sc); 
            FreeProws(prows);   /* free ENTIRE row*/ 
            break; 
        } 
        /*/ Transfer the data of the row to our OAR structure.*/ 
        poar->cValues = prows->aRow[idx].cValues; 
        poar->lpProps = prows->aRow[idx].lpProps; 
 
        /* Put OAR at head of the list*/ 
        if (*ppoarHead) 
            (*ppoarHead)->lpPrev = poar; 
        poar->lpPrev = NULL; 
        poar->lpNext = (*ppoarHead); 
        *ppoarHead  = poar; 
 
        ListBox_AddString(GetDlgItem(hDlg, IDC_MSG), (LONG) poar); 
    } 
     
    MAPIFreeBuffer(prows);  /* free OUTER buffer only*/ 
 
ret: 
    UlRelease(ptable); 
    UlRelease(pfld); 
} 
 
/* 
 -  FreeOarList 
 - 
 *  Free the memory of the rows on the screen. 
 *  Zero the pointer passed in. 
 */ 
VOID 
FreeOarList (LPOAR FAR *ppoarHead) 
{ 
    LPOAR poar = *ppoarHead; 
 
    while (poar) 
    { 
        LPOAR poarTemp = poar; 
 
        poar = poarTemp->lpNext; 
        MAPIFreeBuffer(poarTemp->lpProps); 
        MAPIFreeBuffer(poarTemp); 
    } 
 
    *ppoarHead = NULL; 
} 
 
/* 
 -  DrawOarItem 
 - 
 *  Purpose: 
 *      Paint the client area of the owner-drawn listbox. 
 * 
 *  Parameters: 
 *      pdis        - Pointer to a DRAWITEMSTRUCT 
 * 
 *  Returns: 
 *      void 
 * 
 */ 
 
VOID 
DrawOarItem (DRAWITEMSTRUCT FAR * pdis, int idlgType) 
{ 
    HBRUSH hSolidBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); 
    HBRUSH hOldBrush = SelectObject(pdis->hDC, hSolidBrush); 
 
    if (ODA_DRAWENTIRE & pdis->itemAction) 
    { 
        LPOAR poar; 
        LPSPropValue pProp; 
        UINT c; 
 
        /* Clear the item Rectangle */ 
 
        PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, 
            pdis->rcItem.right - pdis->rcItem.left, 
            pdis->rcItem.bottom - pdis->rcItem.top, PATCOPY); 
 
        /* Draw the item */ 
 
        poar = (LPOAR) pdis->itemData; 
 
        for (pProp = poar->lpProps, c = (UINT)poar->cValues; 
            c > 0; 
            c-- , pProp++) 
        { 
            /* Identify the Default Store*/ 
            if (idlgType == iStores 
                    && pProp->ulPropTag == PR_DEFAULT_STORE && pProp->Value.b) 
                TextOut (pdis->hDC, pdis->rcItem.left + 10, pdis->rcItem.top+2, 
                    TEXT(">"), 1); 
 
            if (pProp->ulPropTag == PR_DISPLAY_NAME) 
                TextOut (pdis->hDC, pdis->rcItem.left + 20, pdis->rcItem.top+2, 
                    pProp->Value.LPSZ, 
                    lstrlen (pProp->Value.LPSZ)); 
 
        } 
 
        /* Invert item rectangle if item is selected */ 
 
        if (ODS_SELECTED & pdis->itemState) 
            PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, 
                pdis->rcItem.right - pdis->rcItem.left, 
                pdis->rcItem.bottom - pdis->rcItem.top, DSTINVERT); 
 
        /* Draw a focus rectangle if item has focus */ 
 
        if (ODS_FOCUS & pdis->itemState) 
            DrawFocusRect (pdis->hDC, &pdis->rcItem); 
    } 
    else 
    { 
        /* Invert the item if the selection state is changing */ 
 
        if (ODA_SELECT & pdis->itemAction) 
            PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, 
                pdis->rcItem.right - pdis->rcItem.left, 
                pdis->rcItem.bottom - pdis->rcItem.top, DSTINVERT); 
 
        /* Draw a focus if the focus state is changing */ 
 
        if (ODA_FOCUS & pdis->itemAction) 
            DrawFocusRect (pdis->hDC, &pdis->rcItem); 
    } 
 
    SelectObject(pdis->hDC, hOldBrush); 
    DeleteObject(hSolidBrush); 
} 
 
 
/* Fill the lppMsgIdList with info about the messages in the specified folder. */ 
enum { E_EID=0, E_SUBJECT, E_SENDER_NAME, E_MSG_DEL_TIME, E_FLAGS, E_PRIORITY, E_CONVERS_KEY, 
        E_SEARCH_KEY, E_CLASS, E_RECORD_KEY, E_PTINBOXDIM}; 
SizedSPropTagArray(E_PTINBOXDIM, ptInbox) = 
{ 
    E_PTINBOXDIM, 
    { 
        PR_ENTRYID, 
        PR_SUBJECT, 
        PR_SENDER_NAME, 
        PR_MESSAGE_DELIVERY_TIME, 
        PR_MESSAGE_FLAGS, 
        PR_PRIORITY, 
        PR_CONVERSATION_KEY, 
        PR_SEARCH_KEY, 
        PR_MESSAGE_CLASS, 
        PR_RECORD_KEY 
    } 
}; 
 
VOID 
PopulateMessages( HWND hDlg, LPINBOXDATA pibData ) 
{ 
    LPMAPIFOLDER pfld = pibData->pfld; 
    LPMAPITABLE ptable = NULL; 
    LPSRowSet prows = NULL; 
    HRESULT hr; 
    ULONG ulType; 
    SizedSSortOrderSet(1, sos) = 
        { 1, 0, 0, { PR_MESSAGE_DELIVERY_TIME, TABLE_SORT_ASCEND } }; 
    UINT nIndex; 
    LPMSGID lpMsgNode; 
    LPSPropValue pvalProp = NULL; 
 
    ListBox_ResetContent(GetDlgItem(hDlg, IDC_MSG)); 
 
    if(!pfld) 
    { 
        /* Open the right folder, and get the list of messages. */ 
        hr = pmdb->lpVtbl->OpenEntry(pmdb,cbeidFolderToView, lpeidFolderToView, 
                                 NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS, 
                                    &ulType, (LPUNKNOWN FAR *)&pfld); 
        if(GetScode(hr) != S_OK)    goto ret; 
 
        Assert(ulType == MAPI_FOLDER); 
        pibData->pfld = pfld; 
        hr = HrGetOneProp((LPMAPIPROP)pfld, PR_DISPLAY_NAME, &pvalProp); 
        if(!hr) 
        { 
            if(*pvalProp->Value.lpszA) 
                SetWindowText(hDlg, pvalProp->Value.lpszA); 
            MAPIFreeBuffer(pvalProp); 
            pvalProp = NULL; 
        } 
    } 
    hr = pfld->lpVtbl->GetContentsTable(pfld, MAPI_DEFERRED_ERRORS, &ptable); 
    if (hr) 
        goto ret; 
 
    if (hr = HrQueryAllRows(ptable, (LPSPropTagArray) &ptInbox, NULL, 
        (LPSSortOrderSet) &sos, 0, &prows)) 
    { 
        MakeMessageBox (hDlg, GetScode(hr), IDS_QUERYROWFAIL, NULL, MBS_ERROR); 
        goto ret; 
    } 
 
    for (nIndex = 0; nIndex < prows->cRows; ++nIndex) 
    { 
        lpMsgNode = MakeMsgNode(prows->aRow + nIndex); 
 
        if (lpMsgNode) 
        { 
            InsertMsgNode(lpMsgNode, &pibData->lpMsgIdList); 
 
            ListBox_AddString(GetDlgItem(hDlg, IDC_MSG),(LONG) lpMsgNode); 
        } 
    } 
    FreeProws(prows); 
 
     
 
ret: 
    UlRelease(ptable); 
} 
 
/* 
 -  MakeMsgNode 
 - 
 *  Purpose: 
 *      Allocate memory for a new MSGID node and initialize its 
 *      data members to the values passed in. 
 *      A separate allocation is used for each property which is pretty 
 *      wastefull. This can be changed to a smarter allocation scheme. 
 * 
 *  Parameters: 
 *       
 *  Return: 
 *      lpMsgNode       - Pointer to new node 
 */ 
 
LPMSGID 
MakeMsgNode (LPSRow prow) 
{ 
    LPMSGID lpMsgNode = NULL; 
 
    if (!prow) 
        goto err; 
 
    if (MAPIAllocateBuffer (sizeof (MSGID), (LPVOID far *) & lpMsgNode)) 
        goto err; 
 
    ZeroMemory(lpMsgNode, sizeof (MSGID)); 
 
    if(prow->lpProps[E_FLAGS].ulPropTag == PR_MESSAGE_FLAGS) 
    { 
        lpMsgNode->fHasAttach = !!(prow->lpProps[E_FLAGS].Value.l & MSGFLAG_HASATTACH); 
        lpMsgNode->fUnRead = !(prow->lpProps[E_FLAGS].Value.l & MSGFLAG_READ); 
    } 
 
    if(prow->lpProps[E_EID].ulPropTag == PR_ENTRYID) 
    {    
        if (MAPIAllocateMore(prow->lpProps[E_EID].Value.bin.cb, lpMsgNode, 
                    (LPVOID FAR *)&lpMsgNode->lpEID)) 
            goto err; 
        CopyMemory(lpMsgNode->lpEID, prow->lpProps[E_EID].Value.bin.lpb, prow->lpProps[E_EID].Value.bin.cb); 
        lpMsgNode->cbEID = prow->lpProps[E_EID].Value.bin.cb; 
    } 
 
    if(prow->lpProps[E_SENDER_NAME].ulPropTag == PR_SENDER_NAME) 
    { 
        if (MAPIAllocateMore (lstrlen (prow->lpProps[E_SENDER_NAME].Value.LPSZ) + 1, 
                    lpMsgNode, (LPVOID far *) & lpMsgNode->lpszFrom)) 
        goto err; 
        lstrcpy (lpMsgNode->lpszFrom, prow->lpProps[E_SENDER_NAME].Value.LPSZ); 
    } 
         
    if(prow->lpProps[E_SUBJECT].ulPropTag == PR_SUBJECT) 
    { 
        if (MAPIAllocateMore (lstrlen (prow->lpProps[E_SUBJECT].Value.LPSZ) + 1, lpMsgNode, 
                    (LPVOID far *) & lpMsgNode->lpszSubject)) 
            goto err; 
        lstrcpy (lpMsgNode->lpszSubject, prow->lpProps[E_SUBJECT].Value.LPSZ); 
    } 
     
    if(prow->lpProps[E_MSG_DEL_TIME].ulPropTag == PR_MESSAGE_DELIVERY_TIME) 
    { 
        if (MAPIAllocateMore (32, lpMsgNode,(LPVOID far *) & lpMsgNode->lpszDateRec)) 
            goto err; 
        FormatFILETIME (&prow->lpProps[E_MSG_DEL_TIME].Value.ft, lpMsgNode->lpszDateRec); 
    } 
     
    return lpMsgNode; 
 
err: 
    MAPIFreeBuffer (lpMsgNode); 
    return NULL; 
} 
 
/* 
 -  InsertMsgNode 
 - 
 *  Purpose: 
 *      We insert the nodes 
 *      at the beginning of the list.  This can be 
 *      replaced with a routine that inserts sorted on 
 *      different criteria, like DateReceived, From, or 
 *      Subject. 
 * 
 *  Parameters: 
 *      lpMsgNode       - Pointer to a MSGID node 
 *      lppMsgHead      - Pointer to the head of the list 
 * 
 *  Return: 
 *      Void. 
 */ 
 
void 
InsertMsgNode (LPMSGID lpMsgNode, LPMSGID * lppMsgHead) 
{ 
    if (*lppMsgHead) 
    { 
        lpMsgNode->lpNext = *lppMsgHead; 
        (*lppMsgHead)->lpPrev = lpMsgNode; 
    } 
    else 
        lpMsgNode->lpNext = NULL; 
 
    /* The next 2 assignments are here in case the node came from somewhere */ 
    /* other than a call to MakeMsgNode () in which case we aren't sure */ 
    /* they're already NULL. */ 
 
    lpMsgNode->lpPrev = NULL; 
    *lppMsgHead = lpMsgNode; 
} 
 
/* 
 -  DeleteMsgNode 
 - 
 *  Purpose: 
 *      Removes the node passed in from the list.  This 
 *      may seem like a strange way to do this but it's 
 *      not, because the Owner-Drawn List Box gives us 
 *      direct access to elements in the list that makes 
 *      it easier to do things this way. 
 * 
 *  Parameters: 
 *      lpMsgNode       - Pointer to the MSGID node to delete 
 *      lppMsgHead      - Pointer to the head of the list 
 * 
 *  Return: 
 *      Void. 
 */ 
 
void 
DeleteMsgNode (LPMSGID lpMsgNode, LPMSGID * lppMsgHead) 
{ 
    if (!lpMsgNode) 
        return; 
 
    if (lpMsgNode->lpPrev) 
    { 
        /* Adjust Previous node to point to Next*/ 
        Assert(*lppMsgHead != lpMsgNode); 
        lpMsgNode->lpPrev->lpNext = lpMsgNode->lpNext; 
    } 
    else 
    { 
        /*/ Adjust Head to point to Next*/ 
        Assert(*lppMsgHead == lpMsgNode); 
        *lppMsgHead = lpMsgNode->lpNext; 
    } 
 
    /* Adjust next node to point to Previous*/ 
 
    if (lpMsgNode->lpNext) 
        lpMsgNode->lpNext->lpPrev = lpMsgNode->lpPrev; 
 
    MAPIFreeBuffer (lpMsgNode); 
    return; 
} 
 
 
 
/* 
 -  FindNode 
 - 
 *  Purpose: 
 *      Returns a pointer to the node with EntryID equal to *pEntryID. 
 *      Returns NULL if node doesn't exist. 
 * 
 *  Parameters: 
 *      lpMsgHead       - Pointer to the head of the list 
 *      pEntryID + cbEntryID    - Message ID to search for 
 * 
 *  Return: 
 *      lpMsgNode       - Pointer to the node returned 
 */ 
 
LPMSGID 
FindNode (LPMSGID lpMsgHead, LPENTRYID pEntryID, ULONG cbEntryID) 
{ 
    ULONG fl; 
    HRESULT hr; 
 
    Assert(pmdb); 
 
    while (lpMsgHead) 
    { 
        hr = pmdb->lpVtbl->CompareEntryIDs(pmdb, cbEntryID, pEntryID, lpMsgHead->cbEID, lpMsgHead->lpEID, 
                                            0, &fl); 
        if(S_OK != GetScode(hr)) 
            return NULL; 
        if(fl) 
            break; 
 
        lpMsgHead = lpMsgHead->lpNext; 
    } 
 
    return lpMsgHead; 
} 
 
/* 
 -  FreeMsgList 
 - 
 *  Purpose: 
 *      Walks down the MsgList and frees each node. 
 * 
 *  Parameters: 
 *      lpMsgHead       - Pointer to the head of the list 
 * 
 *  Return: 
 *      Void. 
 */ 
 
void 
FreeMsgList (LPMSGID lpMsgHead) 
{ 
    LPMSGID lpT; 
 
    while (lpMsgHead) 
    { 
        lpT = lpMsgHead; 
        lpMsgHead = lpMsgHead->lpNext; 
        MAPIFreeBuffer (lpT); 
    } 
} 
 
/* 
 -  ToggleMenuState 
 - 
 *  Purpose: 
 *      Enables/Disables menu items depending on the session state. 
 * 
 *  Parameters: 
 *      hWnd            - handle to the window/dialog who called us 
 *      fLoggedOn       - TRUE if logged on, FALSE if logged off 
 * 
 *  Return: 
 *      Void. 
 */ 
 
void ToggleMenuState(HWND hWnd, BOOL fLoggedOn) 
{ 
    EnableMenuItem (GetMenu (hWnd), IDM_HIER,     !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_OPEN,     !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_LOGOFF,   !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_ROUTE,    !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_READ,     !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_SEND,     !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_NEWFORM,  !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_LOGON,    fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_EXIT,       FALSE); 
} 
 
// 
//  SecureMenu 
// 
//  Purpose: 
//      Enables/Disables Logon and Exit menu items. 
//      CMCLogon might yield control to Windows, so the user might be able to 
//      access the window menu (for example click Logon) after we call 
//      MAPILogon, but before it returns. 
// 
//  Parameters: 
//      hWnd            - handle to the window/dialog who called us 
//      fBeforeLogon    - TRUE when this function is called when we are about 
//                      to call MAPILogon, FALSE if called after logon (failed) 
//                      if Logon succeddes ToggleMenuState is called instead of 
//                      this function. 
// 
//  Return: 
//      Void. 
// 
 
 
void SecureMenu(HWND hWnd, BOOL fBeforeLogon) 
{ 
    EnableMenuItem (GetMenu (hWnd), IDM_LOGON, fBeforeLogon); 
    EnableMenuItem (GetMenu (hWnd), IDM_EXIT,  fBeforeLogon); 
} 
 
 
/* 
 *  Formats a Win32 file time as a MAPI date/time string. 
 *  NOTE: converts from GMT to local time. 
 */ 
void FormatFILETIME(FILETIME *pft, LPSTR szTime) 
{ 
    FILETIME        ft; 
    SYSTEMTIME      systime; 
 
    FileTimeToLocalFileTime(pft, &ft); 
    FileTimeToSystemTime(&ft, &systime); 
    wsprintf(szTime, 
        "%04.4d/%02.2d/%02.2d %02.2d:%02.2d", 
        systime.wYear, systime.wMonth, systime.wDay, 
        systime.wHour, systime.wMinute); 
} 
 
/* 
 *  Create a data block used in CommonDlgProc to remember 
 *  the entire chain of rows in the scrolling list box. 
 */ 
LPDIALOGDATA 
CreateDialogData (int iDlgType) 
{ 
    LPDIALOGDATA pDialogData; 
 
    SCODE sc; 
 
    sc = MAPIAllocateBuffer(sizeof(DIALOGDATA), &pDialogData); 
    if (sc) 
    { 
        MakeMessageBox (0, MAPI_E_NOT_ENOUGH_MEMORY, IDS_OPERATION, NULL, MBS_ERROR); 
        return NULL; 
    } 
 
    pDialogData->iDlgType = iDlgType; 
    pDialogData->poarHead = NULL; 
    pDialogData->cbEntryID = 0; 
    pDialogData->lpEntryID = NULL; 
    return pDialogData; 
}