CLIENT.C
/* 
 -  C L I E N T . C 
 - 
 *  Purpose: 
 *      Sample mail client for the MAPI 1.0 PDK. 
 *              Exclusively uses the Simple MAPI interface. 
 * 
 *  Copyright 1993-1995 Microsoft Corporation. All Rights Reserved. 
 */ 
 
#include <string.h> 
#include <stdlib.h> 
#include <windows.h> 
#include <commdlg.h> 
#include <mapiwin.h> 
#include <mapidbg.h> 
#include "client.h" 
#include "bitmap.h" 
#include "pvalloc.h" 
 
HANDLE hInst; 
HINSTANCE hlibMAPI = 0; 
 
LPMAPILOGON lpfnMAPILogon = NULL; 
LPMAPILOGOFF lpfnMAPILogoff = NULL; 
LPMAPISENDMAIL lpfnMAPISendMail = NULL; 
LPMAPISENDDOCUMENTS lpfnMAPISendDocuments = NULL; 
LPMAPIFINDNEXT lpfnMAPIFindNext = NULL; 
LPMAPIREADMAIL lpfnMAPIReadMail = NULL; 
LPMAPISAVEMAIL lpfnMAPISaveMail = NULL; 
LPMAPIDELETEMAIL lpfnMAPIDeleteMail = NULL; 
LPMAPIFREEBUFFER lpfnMAPIFreeBuffer = NULL; 
LPMAPIADDRESS lpfnMAPIAddress = NULL; 
LPMAPIDETAILS lpfnMAPIDetails = NULL; 
LPMAPIRESOLVENAME lpfnMAPIResolveName = NULL; 
 
/* Static Data */ 
 
static BOOL fDialogIsActive = FALSE; 
static DWORD cUsers = 0; 
static ULONG flSendMsgFlags = 0; 
static LHANDLE lhSession = 0L; 
static HBITMAP hReadBmp = 0; 
static HBITMAP hReadABmp = 0; 
static HBITMAP hUnReadBmp = 0; 
static HBITMAP hUnReadABmp = 0; 
static HCURSOR hWaitCur; 
static LPMSGID lpReadMsgNode; 
static lpMapiMessage lpmsg = NULL; 
 
#ifdef _WIN32 
#define szMAPIDLL       "MAPI32.DLL" 
#else 
#define szMAPIDLL       "MAPI.DLL" 
#endif 
 
int WINAPI 
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 = "Client"; 
 
    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; 
    ULONG ulResult; 
 
    hInst = hInstance; 
 
    hWnd = CreateWindow ("Client", "MAPI Sample Mail Client", 
        WS_OVERLAPPEDWINDOW, 5, 5, 300, 75, 0, 0, hInst, NULL); 
 
    if (!hWnd) 
    return (FALSE); 
 
    ShowWindow (hWnd, nCmdShow); 
    UpdateWindow (hWnd); 
 
    hWaitCur = LoadCursor(0, IDC_WAIT); 
 
    if (fInit = InitSimpleMAPI ()) 
    { 
     
        /* 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); 
         
        if ((ulResult = MAPILogon ((ULONG) hWnd, NULL, NULL, 
            MAPI_LOGON_UI | MAPI_NEW_SESSION, 
            0, &lhSession)) == SUCCESS_SUCCESS) 
        { 
            ToggleMenuState (hWnd, TRUE); 
        } 
        else 
        { 
            SecureMenu(hWnd, FALSE); 
            lhSession = 0; 
            MakeMessageBox (hWnd, ulResult, IDS_LOGONFAIL, MBS_ERROR); 
        } 
    } 
 
    return (fInit); 
} 
 
/* 
 -  InitSimpleMAPI 
 - 
 *  Purpose: 
 *      Loads the DLL containing the simple MAPI functions and sets 
 *      up a pointer to each. Wrappers for the  function pointers 
 *      are declared in SMAPI.H. 
 * 
 *  Returns: 
 *      TRUE if sucessful, else FALSE 
 * 
 *  Side effects: 
 *      Loads a DLL and sets up function pointers 
 */ 
BOOL 
InitSimpleMAPI (void) 
{ 
    UINT fuError; 
 
    /* 
     *Check if MAPI is installed on the system 
     */ 
    if(!fSMAPIInstalled()) 
        return FALSE; 
 
    fuError = SetErrorMode(SEM_NOOPENFILEERRORBOX); 
    hlibMAPI = LoadLibrary(szMAPIDLL); 
    SetErrorMode(fuError); 
 
#ifdef _WIN32 
    if (!hlibMAPI) 
#else 
    if (hlibMAPI < 32) 
#endif 
    return (FALSE); 
 
    if (!(lpfnMAPILogon = (LPMAPILOGON) GetProcAddress (hlibMAPI, "MAPILogon"))) 
    return (FALSE); 
    if (!(lpfnMAPILogoff = (LPMAPILOGOFF) GetProcAddress (hlibMAPI, "MAPILogoff"))) 
    return (FALSE); 
    if (!(lpfnMAPISendMail = (LPMAPISENDMAIL) GetProcAddress (hlibMAPI, "MAPISendMail"))) 
    return (FALSE); 
    if (!(lpfnMAPISendDocuments = (LPMAPISENDDOCUMENTS) GetProcAddress (hlibMAPI, "MAPISendDocuments"))) 
    return (FALSE); 
    if (!(lpfnMAPIFindNext = (LPMAPIFINDNEXT) GetProcAddress (hlibMAPI, "MAPIFindNext"))) 
    return (FALSE); 
    if (!(lpfnMAPIReadMail = (LPMAPIREADMAIL) GetProcAddress (hlibMAPI, "MAPIReadMail"))) 
    return (FALSE); 
    if (!(lpfnMAPISaveMail = (LPMAPISAVEMAIL) GetProcAddress (hlibMAPI, "MAPISaveMail"))) 
    return (FALSE); 
    if (!(lpfnMAPIDeleteMail = (LPMAPIDELETEMAIL) GetProcAddress (hlibMAPI, "MAPIDeleteMail"))) 
    return (FALSE); 
    if (!(lpfnMAPIFreeBuffer = (LPMAPIFREEBUFFER) GetProcAddress (hlibMAPI, "MAPIFreeBuffer"))) 
    return (FALSE); 
    if (!(lpfnMAPIAddress = (LPMAPIADDRESS) GetProcAddress (hlibMAPI, "MAPIAddress"))) 
    return (FALSE); 
    if (!(lpfnMAPIDetails = (LPMAPIDETAILS) GetProcAddress (hlibMAPI, "MAPIDetails"))) 
    return (FALSE); 
    if (!(lpfnMAPIResolveName = (LPMAPIRESOLVENAME) GetProcAddress (hlibMAPI, "MAPIResolveName"))) 
    return (FALSE); 
 
    return (TRUE); 
} 
 
/* 
 -  fSMAPIInstalled 
 - 
 *  Purpose: 
 *      Checks the appropriate win.ini/registry value to see if Simple MAPI is 
 *      installed in the system.  
 *   
 *  Returns: 
 *      TRUE if Simple MAPI is installed, else FALSE 
 * 
 */ 
BOOL 
fSMAPIInstalled(void) 
{ 
#ifdef _WIN32 
    /* on win32, if it's NT 3.51 or lower the value to check is  
        win.ini \ [Mail] \ MAPI, otherwise it's a registry value 
        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Messaging Subsystem\MAPI 
    */ 
     
    OSVERSIONINFO osvinfo; 
    LONG lr; 
    HKEY hkWMS; 
     
    #define MAPIVSize 8 
    char szMAPIValue[MAPIVSize]; 
    DWORD dwType; 
    DWORD cbMAPIValue = MAPIVSize; 
 
    osvinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 
 
    if(!GetVersionEx(&osvinfo)) 
        return FALSE; 
 
    if( osvinfo.dwMajorVersion > 3 || 
        (osvinfo.dwMajorVersion == 3 && osvinfo.dwMinorVersion > 51)) 
    { //check the registry value 
        lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
                        "SOFTWARE\\Microsoft\\Windows Messaging Subsystem", 
                         0, KEY_READ, &hkWMS); 
        if(ERROR_SUCCESS == lr) 
        { 
            lr = RegQueryValueEx(hkWMS, "MAPI", 0, &dwType, szMAPIValue, &cbMAPIValue); 
            RegCloseKey(hkWMS); 
            if(ERROR_SUCCESS == lr) 
            { 
                Assert(dwType == REG_SZ); 
                if(lstrcmp(szMAPIValue, "1") == 0) 
                    return TRUE; 
            } 
        } 
         
        return FALSE; 
    } 
 
    /* fall through*/ 
#endif /*_WIN32*/ 
     
    /*check the win.ini value*/ 
    return GetProfileInt("Mail", "MAPI", 0); 
     
} 
 
 
void 
DeinitApplication () 
{ 
    DeinitSimpleMAPI (); 
} 
 
void 
DeinitSimpleMAPI () 
{ 
    if (hlibMAPI) 
    { 
    FreeLibrary (hlibMAPI); 
    hlibMAPI = 0; 
    } 
} 
 
/* 
 -  MainWndProc 
 - 
 *  Purpose: 
 *      Main Window Procedure for test program. 
 * 
 *  Parameters: 
 *      hWnd 
 *      message 
 *      wParam 
 *      lParam 
 * 
 *  Returns: 
 * 
 * 
 */ 
 
LONG FAR PASCAL 
MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    ULONG ulResult; 
 
    switch (msg) 
    { 
    case WM_COMMAND: 
    switch (LOWORD (wParam)) 
    { 
    case IDM_LOGON: 
        if (!lhSession) 
        { 
        /* 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); 
 
        if ((ulResult = MAPILogon ((ULONG) hWnd, NULL, NULL, 
                MAPI_LOGON_UI | MAPI_NEW_SESSION, 
                0, &lhSession)) == SUCCESS_SUCCESS) 
        { 
            ToggleMenuState (hWnd, TRUE); 
        } 
        else 
        { 
            SecureMenu(hWnd, FALSE); 
            lhSession = 0; 
            MakeMessageBox (hWnd, ulResult, IDS_LOGONFAIL, MBS_ERROR); 
        } 
        } 
        break; 
 
    case IDM_LOGOFF: 
        if (lhSession) 
        { 
        MAPILogoff (lhSession, (ULONG) hWnd, 0, 0); 
        ToggleMenuState (hWnd, FALSE); 
        lhSession = 0; 
        } 
        break; 
 
    case IDM_COMPOSE: 
            fDialogIsActive = TRUE;  
        DialogBox (hInst, "ComposeNote", hWnd, ComposeDlgProc); 
            fDialogIsActive = FALSE;         
        break; 
 
    case IDM_READ: 
            fDialogIsActive = TRUE;  
        DialogBox (hInst, "InBox", hWnd, InBoxDlgProc); 
            fDialogIsActive = FALSE;         
        break; 
 
    case IDM_SEND: 
        if(lhSession) 
            { 
                MapiMessage msgSend; 
 
                memset(&msgSend, 0, sizeof(MapiMessage)); 
                fDialogIsActive = TRUE;  
                MAPISendMail(lhSession, (ULONG)hWnd, &msgSend, MAPI_DIALOG, 0L); 
                fDialogIsActive = FALSE;         
            } 
        break; 
 
    case IDM_ADDRBOOK: 
        if (lhSession) 
        { 
                fDialogIsActive = TRUE;  
        if ((ulResult = MAPIAddress (lhSession, (ULONG) hWnd, 
                NULL, 0, NULL, 0, NULL, 0, 0, NULL, NULL))) 
        { 
            if (ulResult != MAPI_E_USER_ABORT) 
            MakeMessageBox (hWnd, ulResult, IDS_ADDRBOOKFAIL, MBS_ERROR); 
        } 
                fDialogIsActive = FALSE;         
        } 
        break; 
 
    case IDM_DETAILS: 
        if (lhSession) 
            { 
                fDialogIsActive = TRUE;  
        DialogBox(hInst, "Details", hWnd, DetailsDlgProc); 
                fDialogIsActive = FALSE;         
            } 
        break; 
 
    case IDM_ABOUT: 
            fDialogIsActive = TRUE;  
        DialogBox (hInst, "AboutBox", hWnd, AboutDlgProc); 
            fDialogIsActive = FALSE;         
        break; 
 
    case IDM_EXIT: 
        if (lhSession) 
        MAPILogoff (lhSession, (ULONG) hWnd, 0, 0); 
 
        PostQuitMessage (0); 
        break; 
 
    default: 
        return (DefWindowProc (hWnd, msg, wParam, lParam)); 
    } 
    break; 
 
    case WM_QUERYENDSESSION: 
    {        
 
        /* 
         *      If we have a modal dialog open (all our dialogs are modal, so 
         *      just see if we have a dialog open), veto the shutdown. 
         */ 
 
        if (fDialogIsActive) 
        { 
            LPCSTR szTitle = "MAPI Sample Mail Client";  
            char szText[256];  
 
        LoadString (hInst, IDS_DIALOGACTIVE, szText, 255); 
 
        #ifdef WIN16 
            MessageBox((HWND)NULL, szText, szTitle, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); 
        #else 
            MessageBoxA(NULL, szText, szTitle, MB_OK | MB_ICONSTOP | MB_TASKMODAL | MB_SETFOREGROUND); 
        #endif 
        return FALSE; 
        } 
 
        else 
        { 
        return TRUE; 
        } 
    } 
 
    case WM_ENDSESSION: 
 
        if (wParam) 
        { 
        DestroyWindow (hWnd); 
        } 
 
    break; 
 
    case WM_CLOSE: 
    case WM_DESTROY: 
    if (lhSession) 
        MAPILogoff (lhSession, (ULONG) hWnd, 0, 0); 
 
    PostQuitMessage (0); 
    break; 
 
    default: 
    return (DefWindowProc (hWnd, msg, wParam, lParam)); 
    } 
    return FALSE; 
} 
 
/* 
 -  AboutDlgProc 
 - 
 *  Purpose: 
 *      About box dialog procedure 
 * 
 *  Parameters: 
 *      hDlg 
 *      message 
 *      wParam 
 *      lParam 
 * 
 *  Returns: 
 *      True/False 
 * 
 */ 
 
BOOL FAR PASCAL 
AboutDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam) 
{ 
 
#include <pdkver.h> 
 
    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; 
} 
 
/* 
 -  OptionsDlgProc 
 - 
 *  Purpose: 
 *      Message Options dialog procedure 
 * 
 *  Parameters: 
 *      hDlg 
 *      message 
 *      wParam 
 *      lParam 
 * 
 *  Returns: 
 *      True/False 
 * 
 */ 
 
BOOL FAR PASCAL 
OptionsDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam) 
{ 
    switch (msg) 
    { 
    case WM_INITDIALOG: 
    CheckDlgButton (hDlg, IDC_RETURN, 
        !!(flSendMsgFlags & MAPI_RECEIPT_REQUESTED)); 
    return TRUE; 
 
    case WM_COMMAND: 
    switch (LOWORD (wParam)) 
    { 
    case IDOK: 
        if (IsDlgButtonChecked (hDlg, IDC_RETURN)) 
        flSendMsgFlags |= MAPI_RECEIPT_REQUESTED; 
        else 
        flSendMsgFlags &= ~MAPI_RECEIPT_REQUESTED; 
 
    case IDCANCEL: 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
    } 
    break; 
    } 
    return FALSE; 
} 
 
/* 
 -  DetailsDlgProc 
 - 
 *  Purpose: 
 *      User Details dialog procedure 
 * 
 *  Parameters: 
 *      hDlg 
 *      message 
 *      wParam 
 *      lParam 
 * 
 *  Returns: 
 *      True/False 
 * 
 */ 
 
BOOL FAR PASCAL 
DetailsDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam) 
{ 
    LPSTR lpszType = NULL; 
    LPSTR lpszAddr = NULL; 
    LPSTR lpszName; 
    ULONG cRecips; 
    ULONG ulResult; 
    lpMapiRecipDesc lpRecip = NULL; 
 
    switch (msg) 
    { 
    case WM_INITDIALOG: 
    while(!lpRecip) 
    { 
        if ((ulResult = MAPIAddress (lhSession, (ULONG) hDlg, 
            "Select One User", 1, "User:", 0, NULL, 0, 0, 
            &cRecips, &lpRecip))) 
        { 
        if (ulResult != MAPI_E_USER_ABORT) 
            MakeMessageBox (hDlg, ulResult, IDS_ADDRBOOKFAIL, MBS_ERROR); 
 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
        } 
 
        if (cRecips == 0) 
        { 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
        } 
 
        if (cRecips > 1) 
        { 
        cRecips = 0; 
        MAPIFreeBuffer (lpRecip); 
        lpRecip = NULL; 
        MakeMessageBox (hDlg, 0, IDS_DETAILS_TOO_MANY, MBS_OOPS); 
        } 
    } 
    lpszName = lpRecip->lpszName; 
    if(lpRecip->lpszAddress) 
    { 
        lpszType = strtok(lpRecip->lpszAddress, ":"); 
        lpszAddr = strtok(NULL, "\n"); 
    } 
 
    SetDlgItemText(hDlg, IDC_NAME, lpszName); 
    SetDlgItemText(hDlg, IDC_TYPE, (lpszType ? lpszType : "MSPEER")); 
    SetDlgItemText(hDlg, IDC_ADDR, (lpszAddr ? lpszAddr : "")); 
 
    MAPIFreeBuffer (lpRecip); 
    return TRUE; 
 
    case WM_COMMAND: 
    if(LOWORD(wParam) == IDC_CLOSE || LOWORD(wParam) ==IDCANCEL) 
    { 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
    } 
    break; 
    } 
    return FALSE; 
} 
 
/* 
 -  ComposeDlgProc 
 - 
 *  Purpose: 
 *      Dialog procedure for the ComposeNote dialog. 
 * 
 *  Parameters: 
 *      hDlg 
 *      message 
 *      wParam 
 *      lParam 
 * 
 *  Returns: 
 *      True/False 
 * 
 */ 
 
BOOL FAR PASCAL 
ComposeDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam) 
{ 
    char szUnResNames[TO_EDIT_MAX]; 
    char szDisplayNames[TO_EDIT_MAX]; 
   /* char szAttach[FILE_ATTACH_MAX];*/ 
    BOOL fUnResTo, fUnResCc; 
    LONG cb, cLines; 
    ULONG ulResult; 
    HCURSOR hOldCur; 
    static LPSTR lpszSubject; 
    static LPSTR lpszNoteText; 
    static ULONG cRecips; 
    static ULONG cNewRecips; 
    static ULONG cAttach; 
    static lpMapiRecipDesc lpRecips; 
    static lpMapiRecipDesc lpNewRecips; 
    static lpMapiFileDesc lpAttach; 
    ULONG idx; 
 
    switch (msg) 
    { 
    case WM_INITDIALOG: 
    if (lpmsg) 
    { 
        /* ComposeNote is being called to either forward or reply */ 
        /* to a message in the Inbox.  So, we'll initialize the   */ 
        /* ComposeNote form with data from the global MapiMessage */ 
 
        lpszSubject = lpmsg->lpszSubject; 
        lpszNoteText = lpmsg->lpszNoteText; 
        cRecips = lpmsg->nRecipCount; 
        cAttach = lpmsg->nFileCount; 
        lpRecips = lpmsg->lpRecips; 
        lpAttach = lpmsg->lpFiles; 
 
        if (cRecips) 
        { 
        MakeDisplayNameStr (szDisplayNames, MAPI_TO, 
            cRecips, lpRecips); 
        if (*szDisplayNames) 
            SetDlgItemText (hDlg, IDC_TO, szDisplayNames); 
 
        MakeDisplayNameStr (szDisplayNames, MAPI_CC, 
            cRecips, lpRecips); 
        if (*szDisplayNames) 
            SetDlgItemText (hDlg, IDC_CC, szDisplayNames); 
        } 
        SetDlgItemText (hDlg, IDC_SUBJECT, lpmsg->lpszSubject); 
        SetDlgItemText (hDlg, IDC_NOTE, lpmsg->lpszNoteText); 
        if (!cAttach) 
        { 
            EnableWindow (GetDlgItem (hDlg, IDC_CATTACHMENT), FALSE); 
        EnableWindow (GetDlgItem (hDlg, IDT_CATTACHMENT), FALSE); 
        } 
        else 
        { 
            for(idx = 0; idx < cAttach; idx++) 
            if (lpAttach[idx].lpszFileName) 
                SendDlgItemMessage(hDlg, IDC_CATTACHMENT, LB_ADDSTRING, 0, 
                (LPARAM)lpAttach[idx].lpszFileName); 
 
           /*SendDlgItemMessage(hDlg, IDC_CATTACHMENT, LB_SETCURSEL, 0, 0L);*/ 
        } 
 
        SendDlgItemMessage (hDlg, IDC_TO, EM_SETMODIFY, FALSE, 0); 
        SendDlgItemMessage (hDlg, IDC_CC, EM_SETMODIFY, FALSE, 0); 
        SendDlgItemMessage (hDlg, IDC_SUBJECT, EM_SETMODIFY, FALSE, 0); 
        SendDlgItemMessage (hDlg, IDC_NOTE, EM_SETMODIFY, FALSE, 0); 
        if(cRecips) 
        SetFocus (GetDlgItem (hDlg, IDC_NOTE)); 
        else 
        SetFocus (GetDlgItem (hDlg, IDC_TO)); 
    } 
    else 
    { 
        lpmsg = (lpMapiMessage)PvAlloc(sizeof(MapiMessage)); 
 
        if (!lpmsg) 
        goto cleanup; 
 
            memset (lpmsg, 0, sizeof (MapiMessage)); 
 
        lpszSubject = NULL; 
        lpszNoteText = NULL; 
        cRecips = 0; 
        cAttach = 0; 
        lpRecips = NULL; 
        lpNewRecips = NULL; 
        lpAttach = NULL; 
 
        lpmsg->flFlags = flSendMsgFlags; 
        SetFocus (GetDlgItem (hDlg, IDC_TO)); 
    } 
    return FALSE; 
 
    case WM_COMMAND: 
    switch (LOWORD (wParam)) 
    { 
    case IDC_ATTACH: 
        if (GetNextFile (hDlg, (ULONG) -1, &cAttach, &lpAttach) == SUCCESS_SUCCESS) 
        { 
                /* if the first attachment */ 
                if (cAttach == 1) 
                { 
                    EnableWindow (GetDlgItem (hDlg, IDC_CATTACHMENT), TRUE); 
            EnableWindow (GetDlgItem (hDlg, IDT_CATTACHMENT), TRUE); 
                } 
 
                if (lpAttach[cAttach - 1].lpszFileName) 
            SendDlgItemMessage(hDlg, IDC_CATTACHMENT, LB_ADDSTRING, 0, 
            (LPARAM)lpAttach[cAttach -1].lpszFileName); 
 
             /* Now, send a little render message to the NoteText edit */ 
 
        /*wsprintf (szAttach, "<<File: %s>>", 
            lpAttach[cAttach - 1].lpszFileName); 
 
        SendDlgItemMessage (hDlg, IDC_NOTE, EM_REPLACESEL, 0, 
            (LPARAM) ((LPSTR) szAttach));*/ 
        } 
        break; 
 
    case IDC_ADDRBOOK: 
            SendMessage(hDlg, WM_COMMAND, MAKELONG(IDC_RESOLVE,0), 0); 
        ulResult = MAPIAddress (lhSession, (ULONG) hDlg, NULL, 
        2, NULL, cRecips, lpRecips, 0, 0, 
        &cNewRecips, &lpNewRecips); 
        if (ulResult) 
        { 
        if (ulResult != MAPI_E_USER_ABORT) 
            MakeMessageBox (hDlg, ulResult, IDS_ADDRBOOKFAIL, MBS_ERROR); 
        } 
        else 
        { 
        if (cNewRecips) 
        { 
            PvFree(lpRecips); 
            lpRecips = (lpMapiRecipDesc)PvAlloc(cNewRecips*sizeof(MapiRecipDesc)); 
            cRecips = cNewRecips; 
 
                    while(cNewRecips--) 
                        CopyRecipient(lpRecips, &lpRecips[cNewRecips], 
                                &lpNewRecips[cNewRecips]); 
 
            MAPIFreeBuffer(lpNewRecips); 
            lpNewRecips = NULL; 
            cNewRecips = 0; 
 
            MakeDisplayNameStr (szDisplayNames, MAPI_TO, 
            cRecips, lpRecips); 
            if (*szDisplayNames) 
            SetDlgItemText (hDlg, IDC_TO, szDisplayNames); 
 
            MakeDisplayNameStr (szDisplayNames, MAPI_CC, 
            cRecips, lpRecips); 
            if (*szDisplayNames) 
            SetDlgItemText (hDlg, IDC_CC, szDisplayNames); 
 
            SendDlgItemMessage (hDlg, IDC_TO, EM_SETMODIFY, FALSE, 0); 
            SendDlgItemMessage (hDlg, IDC_CC, EM_SETMODIFY, FALSE, 0); 
        } 
        } 
        break; 
 
    case IDC_OPTIONS: 
        DialogBox (hInst, "Options", hDlg, OptionsDlgProc); 
        break; 
 
    case IDC_SEND: 
    case IDC_RESOLVE: 
        fUnResTo = FALSE; 
        fUnResCc = FALSE; 
 
        hOldCur = SetCursor(hWaitCur); 
 
         
        /* Get the names from the To: field and resolve them first */ 
 
        /*if (SendDlgItemMessage (hDlg, IDC_TO, EM_GETMODIFY, 0, 0) && */ 
         if (cb = SendDlgItemMessage (hDlg, IDC_TO, WM_GETTEXT, 
            (WPARAM)sizeof(szUnResNames), (LPARAM)szUnResNames)) 
        { 
        if (!ResolveFriendlyNames (hDlg, szUnResNames, MAPI_TO, 
            &cRecips, &lpRecips)) 
        { 
            MakeDisplayNameStr (szDisplayNames, MAPI_TO, 
            cRecips, lpRecips); 
            if (*szDisplayNames) 
            { 
            if (*szUnResNames) 
            { 
                lstrcat (szDisplayNames, "; "); 
                lstrcat (szDisplayNames, szUnResNames); 
                fUnResTo = TRUE; 
            } 
 
            SetDlgItemText (hDlg, IDC_TO, szDisplayNames); 
            } 
            else 
            { 
            if (*szUnResNames) 
            { 
                SetDlgItemText (hDlg, IDC_TO, szUnResNames); 
                fUnResTo = TRUE; 
            } 
            } 
        } 
        /*SendDlgItemMessage (hDlg, IDC_TO, EM_SETMODIFY, FALSE, 0);*/ 
        } 
 
        /* Now, get the names from the Cc: field and resolve them */ 
 
        /*if (SendDlgItemMessage (hDlg, IDC_CC, EM_GETMODIFY, 0, 0) &&*/ 
        if (cb = SendDlgItemMessage (hDlg, IDC_CC, WM_GETTEXT, 
            (WPARAM)sizeof(szUnResNames), (LPARAM)szUnResNames)) 
        { 
        if (!ResolveFriendlyNames (hDlg, szUnResNames, MAPI_CC, 
            &cRecips, &lpRecips)) 
        { 
            MakeDisplayNameStr (szDisplayNames, MAPI_CC, 
            cRecips, lpRecips); 
            if (*szDisplayNames) 
            { 
            if (*szUnResNames) 
            { 
                lstrcat (szDisplayNames, "; "); 
                lstrcat (szDisplayNames, szUnResNames); 
                fUnResCc = TRUE; 
            } 
 
            SetDlgItemText (hDlg, IDC_CC, szDisplayNames); 
            } 
            else 
            { 
            if (*szUnResNames) 
            { 
                SetDlgItemText (hDlg, IDC_CC, szUnResNames); 
                fUnResCc = TRUE; 
            } 
            } 
        } 
        /*SendDlgItemMessage (hDlg, IDC_CC, EM_SETMODIFY, FALSE, 0);*/ 
        } 
 
        /* If we were just Resolving Names then we can leave now */ 
 
        if (LOWORD (wParam) == IDC_RESOLVE) 
        { 
        SetCursor(hOldCur); 
        break; 
        } 
 
        if (cRecips == 0 || fUnResTo || fUnResCc) 
        { 
        if (!cRecips) 
            MakeMessageBox (hDlg, 0, IDS_NORECIPS, MBS_OOPS); 
 
        if (fUnResTo) 
            SetFocus (GetDlgItem (hDlg, IDC_TO)); 
        else if (fUnResCc) 
            SetFocus (GetDlgItem (hDlg, IDC_CC)); 
        else 
            SetFocus (GetDlgItem (hDlg, IDC_TO)); 
 
        SetCursor(hOldCur); 
        break; 
        } 
 
        /* Everything is OK so far, lets get the Subject */ 
        /* and the NoteText and try to send the message. */ 
 
        /* Get Subject from Edit */ 
 
        if (SendDlgItemMessage (hDlg, IDC_SUBJECT, EM_GETMODIFY, 0, 0)) 
        { 
        cb = SendDlgItemMessage (hDlg, IDC_SUBJECT, EM_LINELENGTH, 0, 0L); 
 
        PvFree(lpszSubject); 
        lpszSubject = (LPTSTR)PvAlloc(cb + 1); 
 
        if (!lpszSubject) 
            goto cleanup; 
 
        GetDlgItemText (hDlg, IDC_SUBJECT, lpszSubject, (int)cb+1); 
        } 
 
        /* Get the NoteText from Edit */ 
 
        if (SendDlgItemMessage (hDlg, IDC_NOTE, EM_GETMODIFY, 0, 0)) 
        { 
        cLines = SendDlgItemMessage (hDlg, IDC_NOTE, 
            EM_GETLINECOUNT, 0, 0L); 
 
        if (cLines) 
        { 
            /* Get the total number of bytes in the multi-line */ 
 
            cb = SendDlgItemMessage (hDlg, IDC_NOTE, EM_LINEINDEX, 
            (UINT)cLines - 1, 0L); 
            cb += SendDlgItemMessage (hDlg, IDC_NOTE, EM_LINELENGTH, 
            (UINT)cb, 0L); 
 
            /* The next line is to account for CR-LF pairs per line. */ 
 
            cb += cLines * 2; 
 
                    PvFree(lpszNoteText); 
            lpszNoteText = (LPTSTR)PvAlloc(cb + 1); 
 
            if (!lpszNoteText) 
            goto cleanup; 
 
            /* Get the Note Text from the edit */ 
 
            GetDlgItemText (hDlg, IDC_NOTE, lpszNoteText, (int)cb); 
        } 
        else 
        { 
            /* Make an empty string for NoteText */ 
 
            lpszNoteText = (LPTSTR)PvAlloc(1); 
            if (!lpszNoteText) 
            goto cleanup; 
            *lpszNoteText = '\0'; 
        } 
        } 
 
        lpmsg->lpszSubject = lpszSubject; 
        lpmsg->lpszNoteText = lpszNoteText; 
        lpmsg->nRecipCount = cRecips; 
        lpmsg->lpRecips = lpRecips; 
        lpmsg->nFileCount = cAttach; 
        lpmsg->lpFiles = lpAttach; 
        lpmsg->flFlags = flSendMsgFlags; 
 
        ulResult = MAPISendMail (lhSession, (ULONG) hDlg, lpmsg, 0, 0); 
 
        LogSendMail(ulResult); 
 
        if (ulResult) 
        { 
        MakeMessageBox (hDlg, ulResult, IDS_SENDERROR, MBS_ERROR); 
        SetCursor(hOldCur); 
        break; 
        } 
cleanup: 
        SetCursor(hOldCur); 
 
    case IDCANCEL: 
        PvFree(lpmsg->lpszMessageType); 
        PvFree(lpmsg->lpszConversationID); 
        PvFree(lpmsg); 
        PvFree(lpRecips); 
        PvFree(lpAttach); 
        PvFree(lpszSubject); 
        PvFree(lpszNoteText); 
        lpmsg = NULL; 
 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
        break; 
 
    default: 
        break; 
    } 
    break; 
    } 
    return FALSE; 
} 
 
/* 
 -  InBoxDlgProc 
 - 
 *  Purpose: 
 *      Dialog procedure for the InBox dialog. 
 * 
 *  Parameters: 
 *      hDlg 
 *      message 
 *      wParam 
 *      lParam 
 * 
 *  Returns: 
 *      True/False 
 * 
 */ 
 
BOOL FAR PASCAL 
InBoxDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam) 
{ 
    char szMsgID[512]; 
    char szSeedMsgID[512]; 
    LPMSGID lpMsgNode; 
    static LPMSGID lpMsgIdList = NULL; 
    lpMapiMessage lpMessage; 
    ULONG ulResult; 
    DWORD nIndex; 
    RECT Rect; 
    HCURSOR hOldCur; 
 
    switch (msg) 
    { 
    case WM_INITDIALOG: 
    hOldCur = SetCursor(hWaitCur); 
 
        InitBmps(hDlg, IDC_MSG); 
 
    /* Populate List Box with all messages in InBox. */ 
    /* This is a painfully slow process for now.     */ 
 
    ulResult = MAPIFindNext (lhSession, (ULONG) hDlg, NULL, NULL, 
        MAPI_GUARANTEE_FIFO | MAPI_LONG_MSGID, 0, szMsgID); 
 
    while (ulResult == SUCCESS_SUCCESS) 
    { 
        ulResult = MAPIReadMail (lhSession, (ULONG) hDlg, szMsgID, 
        MAPI_PEEK | MAPI_ENVELOPE_ONLY, 
        0, &lpMessage); 
 
        if (!ulResult) 
        { 
        lpMsgNode = MakeMsgNode (lpMessage, szMsgID); 
 
        if (lpMsgNode) 
        { 
            InsertMsgNode (lpMsgNode, &lpMsgIdList); 
 
            SendDlgItemMessage (hDlg, IDC_MSG, LB_ADDSTRING, 
            0, (LONG) lpMsgNode); 
} 
        MAPIFreeBuffer (lpMessage); 
        } 
 
        lstrcpy (szSeedMsgID, szMsgID); 
        ulResult = MAPIFindNext (lhSession, (ULONG) hDlg, NULL, szSeedMsgID, 
        MAPI_GUARANTEE_FIFO | MAPI_LONG_MSGID, 0, szMsgID); 
    } 
 
    SetCursor(hOldCur); 
    SetFocus (GetDlgItem (hDlg, IDC_MSG)); 
    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_DELETEITEM: 
    /* This message is handled by the IDC_DELETE message */ 
    return TRUE; 
    break; 
 
    case WM_COMMAND: 
    switch (LOWORD (wParam)) 
    { 
    case IDC_NEW: 
        hOldCur = SetCursor(hWaitCur); 
 
        ulResult = MAPIFindNext (lhSession, (ULONG) hDlg, NULL, NULL, 
        MAPI_UNREAD_ONLY | MAPI_LONG_MSGID, 0, szMsgID); 
 
        while (ulResult == SUCCESS_SUCCESS) 
        { 
        if (!FindNode (lpMsgIdList, szMsgID)) 
        { 
            ulResult = MAPIReadMail (lhSession, (ULONG) hDlg, szMsgID, 
            MAPI_PEEK | MAPI_ENVELOPE_ONLY, 0, &lpMessage); 
 
            if (!ulResult) 
            { 
            lpMsgNode = MakeMsgNode (lpMessage, szMsgID); 
            InsertMsgNode (lpMsgNode, &lpMsgIdList); 
 
            SendDlgItemMessage (hDlg, IDC_MSG, LB_ADDSTRING, 
                0, (LONG) lpMsgNode); 
 
            MAPIFreeBuffer (lpMessage); 
            } 
        } 
 
        lstrcpy (szSeedMsgID, szMsgID); 
        ulResult = MAPIFindNext (lhSession, (ULONG) hDlg, NULL, szSeedMsgID, 
            MAPI_UNREAD_ONLY | MAPI_LONG_MSGID, 0, szMsgID); 
        } 
        SetCursor(hOldCur); 
        break; 
 
    case IDC_MSG: 
        if(HIWORD(wParam) != LBN_DBLCLK) 
        break; 
 
    case IDC_READ: 
        nIndex = SendDlgItemMessage (hDlg, IDC_MSG, LB_GETCURSEL, 0, 0); 
 
        if (nIndex == LB_ERR) 
        break; 
 
        lpReadMsgNode = (LPMSGID) SendDlgItemMessage (hDlg, IDC_MSG, 
        LB_GETITEMDATA, (UINT)nIndex, 0L); 
 
        if (lpReadMsgNode) 
        DialogBox (hInst, "ReadNote", hDlg, ReadMailDlgProc); 
 
        /* Update the Messages List-Box with new icon */ 
 
        SendDlgItemMessage (hDlg, IDC_MSG, LB_GETITEMRECT, (UINT)nIndex, (LPARAM) &Rect); 
        InvalidateRect(GetDlgItem(hDlg, IDC_MSG), &Rect, FALSE); 
        break; 
 
    case IDC_DELETE: 
        nIndex = SendDlgItemMessage (hDlg, IDC_MSG, LB_GETCURSEL, 0, 0); 
 
        if (nIndex == LB_ERR) 
        break; 
 
        lpMsgNode = (LPMSGID) SendDlgItemMessage (hDlg, IDC_MSG, 
        LB_GETITEMDATA, (UINT)nIndex, 0); 
 
        if (lpMsgNode) 
        { 
        MAPIDeleteMail (lhSession, (ULONG) hDlg, lpMsgNode->lpszMsgID, 0, 0); 
        DeleteMsgNode (lpMsgNode, &lpMsgIdList); 
        } 
 
        SendDlgItemMessage (hDlg, IDC_MSG, LB_DELETESTRING, (UINT)nIndex, 0); 
        break; 
 
    case IDC_CLOSE: 
    case IDCANCEL: 
        FreeMsgList (lpMsgIdList); 
        lpMsgIdList = NULL; 
 
            DeInitBmps(); 
 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
        break; 
 
    default: 
        break; 
    } 
    break; 
    } 
 
    return FALSE; 
} 
 
/* 
 -  ReadMailDlgProc 
 - 
 *  Purpose: 
 *      Dialog procedure for the ReadMail dilaog. 
 * 
 *  Parameters: 
 *      hDlg 
 *      message 
 *      wParam 
 *      lParam 
 * 
 *  Returns: 
 *      True/False 
 * 
 */ 
 
BOOL FAR PASCAL 
ReadMailDlgProc (HWND hDlg, UINT msg, UINT wParam, LONG lParam) 
{ 
    ULONG ulResult; 
    char szTo[TO_EDIT_MAX]; 
    char szCc[TO_EDIT_MAX]; 
    char szChangeMsg[512]; 
    ULONG idx; 
    static lpMapiMessage lpReadMsg; 
 
    switch (msg) 
    { 
    case WM_INITDIALOG: 
    if (ulResult = MAPIReadMail (lhSession, (LONG) hDlg, lpReadMsgNode->lpszMsgID, 
        0, 0, &lpReadMsg)) 
    { 
        MakeMessageBox(hDlg, ulResult, IDS_READFAIL, MBS_ERROR); 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
    } 
 
    lpReadMsgNode->fUnRead = FALSE; 
 
    szTo[0] = '\0'; 
    szCc[0] = '\0'; 
 
    for (idx = 0; idx < lpReadMsg->nRecipCount; idx++) 
    { 
        if (lpReadMsg->lpRecips[idx].ulRecipClass == MAPI_TO) 
        { 
        lstrcat (szTo, lpReadMsg->lpRecips[idx].lpszName); 
        lstrcat (szTo, "; "); 
        } 
        else if (lpReadMsg->lpRecips[idx].ulRecipClass == MAPI_CC) 
        { 
        lstrcat (szCc, lpReadMsg->lpRecips[idx].lpszName); 
        lstrcat (szCc, "; "); 
        } 
        else 
        { 
        /* Must be Bcc, lets ignore it! */ 
        } 
    } 
 
    if(*szTo) 
        szTo[lstrlen (szTo) - 2] = '\0'; 
    if(*szCc) 
        szCc[lstrlen (szCc) - 2] = '\0'; 
 
    SetDlgItemText (hDlg, IDC_RFROM, 
        (lpReadMsg->lpOriginator && lpReadMsg->lpOriginator->lpszName ? 
                lpReadMsg->lpOriginator->lpszName : "")); 
    SetDlgItemText (hDlg, IDC_RDATE, 
        (lpReadMsg->lpszDateReceived ? lpReadMsg->lpszDateReceived : "")); 
    SetDlgItemText (hDlg, IDC_RTO, szTo); 
    SetDlgItemText (hDlg, IDC_RCC, szCc); 
    SetDlgItemText (hDlg, IDC_RSUBJECT, 
        (lpReadMsg->lpszSubject ? lpReadMsg->lpszSubject : "")); 
    SetDlgItemText (hDlg, IDC_READNOTE, 
        (lpReadMsg->lpszNoteText ? lpReadMsg->lpszNoteText : "")); 
 
    if (!lpReadMsg->nFileCount) 
    { 
        EnableWindow (GetDlgItem (hDlg, IDC_SAVEATTACH), FALSE); 
        EnableWindow (GetDlgItem (hDlg, IDC_ATTACHMENT), FALSE); 
        EnableWindow (GetDlgItem (hDlg, IDT_ATTACHMENT), FALSE); 
    } 
    else 
    { 
        for(idx = 0; idx < lpReadMsg->nFileCount; idx++) 
        if (lpReadMsg->lpFiles[idx].lpszFileName) 
            SendDlgItemMessage(hDlg, IDC_ATTACHMENT, LB_ADDSTRING, 0, 
            (LPARAM)lpReadMsg->lpFiles[idx].lpszFileName); 
 
        SendDlgItemMessage(hDlg, IDC_ATTACHMENT, LB_SETCURSEL, 0, 0L); 
    } 
 
    SetFocus (GetDlgItem (hDlg, IDC_READNOTE)); 
    return FALSE; 
 
    case WM_COMMAND: 
    switch (LOWORD (wParam)) 
    { 
    case IDC_SAVECHANGES: 
        if (SendDlgItemMessage (hDlg, IDC_READNOTE, EM_GETMODIFY, 0, 0)) 
        ulResult = SaveMsgChanges (hDlg, lpReadMsg, lpReadMsgNode->lpszMsgID); 
        SendDlgItemMessage (hDlg, IDC_READNOTE, EM_SETMODIFY, 0, 0); 
        break; 
 
    case IDC_ATTACHMENT: 
        if(HIWORD(wParam) != LBN_DBLCLK) 
        break; 
 
    case IDC_SAVEATTACH: 
        idx = SendDlgItemMessage(hDlg, IDC_ATTACHMENT, LB_GETCURSEL, 0, 0L); 
 
        if(idx != LB_ERR) 
        { 
        SaveFileAttachments(hDlg, &lpReadMsg->lpFiles[idx]); 
        SetFocus(GetDlgItem (hDlg, IDC_ATTACHMENT)); 
        return FALSE; 
 
        } 
        break; 
 
    case IDC_REPLY: 
    case IDC_REPLYALL: 
    case IDC_FORWARD: 
        MakeNewMessage (lpReadMsg, LOWORD (wParam)); 
        DialogBox (hInst, "ComposeNote", hDlg, ComposeDlgProc); 
        break; 
 
    case IDCANCEL: 
        if (SendDlgItemMessage (hDlg, IDC_READNOTE, EM_GETMODIFY, 0, 0)) 
        { 
        wsprintf (szChangeMsg, "Save changes to: '%s' in Inbox?", 
            (lpReadMsg->lpszSubject ? lpReadMsg->lpszSubject : "")); 
 
        if (MessageBox (hDlg, szChangeMsg, "Mail", MB_YESNO) == IDYES) 
        { 
            ulResult = SaveMsgChanges (hDlg, lpReadMsg, lpReadMsgNode->lpszMsgID); 
        } 
        } 
 
        /* If there were file attachments, then delete the temps */ 
 
        for(idx = 0; idx < lpReadMsg->nFileCount; idx++) 
        if (lpReadMsg->lpFiles[idx].lpszPathName) 
            DeleteFile(lpReadMsg->lpFiles[idx].lpszPathName); 
 
        MAPIFreeBuffer (lpReadMsg); 
        lpReadMsg = NULL; 
        EndDialog (hDlg, TRUE); 
        return TRUE; 
    } 
    break; 
    } 
    return FALSE; 
} 
 
/* 
 -  MakeMessageBox 
 - 
 *  Purpose: 
 *      Gets resource string and displays an error message box. 
 * 
 *  Parameters: 
 *      hWnd            - Handle to parent window 
 *      idString        - Resource ID of message in StringTable 
 * 
 *  Returns: 
 *      Void 
 * 
 */ 
 
void 
MakeMessageBox (HWND hWnd, ULONG ulResult, UINT idString, UINT fStyle) 
{ 
    char szMessage[256]; 
    char szMapiReturn[64]; 
 
    LoadString (hInst, idString, szMessage, 255); 
 
    if (ulResult) 
    { 
    LoadString (hInst, (UINT)ulResult, szMapiReturn, 64); 
    lstrcat (szMessage, "\nReturn Code: "); 
    lstrcat (szMessage, szMapiReturn); 
    } 
 
    MessageBox (hWnd, szMessage, "Problem", fStyle); 
} 
 
/* 
 -  ResolveFriendlyNames 
 - 
 *  Purpose: 
 *      Helper function to convert a string of ';' delimited friendly 
 *      names into an array of MapiRecipDescs. 
 * 
 *  Side Effects:                                              
 *      The display string passed in is modified to contain the 
 *      friendly names of the mail users as found in the sample 
 *      address book. 
 * 
 *  Note: 
 *      Duplicate names in the address book will result in undefined 
 *      behavior. 
 * 
 *  Parameters: 
 *      hWnd                - Handle to parent window 
 *      lpszDisplayNames    - string of ';' delimited user names 
 *      ulRecipClass        - either MAPI_TO, MAPI_CC, or MAPI_BCC 
 *      lpcRecips           - Address of recipient count to be returned 
 *      lppRecips           - Address of recipient array to be returned 
 * 
 *  Return: 
 *      ulResult 
 */ 
 
ULONG 
ResolveFriendlyNames (HWND hWnd, LPSTR lpszDisplayNames, ULONG ulRecipClass, 
    ULONG * lpcRecips, lpMapiRecipDesc * lppRecips) 
{ 
    char szResolve[TO_EDIT_MAX]; 
    LPSTR lpszNameToken; 
    ULONG cRecips = 0; 
    ULONG cFails = 0; 
    ULONG ulResult; 
    lpMapiRecipDesc lpRecip; 
    lpMapiRecipDesc lpRecipList; 
 
    *szResolve = '\0'; 
    lpszNameToken = strtok (lpszDisplayNames, ";\n"); 
 
    while (lpszNameToken) 
    { 
    /* Strip leading blanks from name */ 
 
    while (*lpszNameToken == ' ') 
        lpszNameToken++; 
 
    /* Check if name has already been resolved */ 
 
    if (!FNameInList (lpszNameToken, *lpcRecips, *lppRecips)) 
    { 
        lstrcat (szResolve, lpszNameToken); 
        lstrcat (szResolve, "; "); 
        cRecips++; 
    } 
 
    /* Get Next Token */ 
 
    lpszNameToken = strtok (NULL, ";\n"); 
    } 
 
    *lpszDisplayNames = '\0'; 
 
    if (!szResolve[0]) 
    { 
    ulResult = SUCCESS_SUCCESS; 
    goto err; 
    } 
 
    szResolve[lstrlen (szResolve) - 2] = '\0'; 
 
    lpRecipList = (lpMapiRecipDesc)PvAlloc((cRecips + *lpcRecips) * sizeof (MapiRecipDesc)); 
 
    if (!lpRecipList) 
    { 
    ulResult = MAPI_E_INSUFFICIENT_MEMORY; 
    goto err; 
    } 
    memset (lpRecipList, 0, (size_t)(cRecips+*lpcRecips)*sizeof(MapiRecipDesc)); 
 
    cRecips = 0; 
 
    while (cRecips < *lpcRecips) 
    { 
    ulResult = CopyRecipient (lpRecipList, &lpRecipList[cRecips], 
        *lppRecips + cRecips); 
 
    if (ulResult) 
    { 
        PvFree(lpRecipList); 
        goto err; 
    } 
 
    cRecips++; 
    } 
 
    PvFree(*lppRecips); 
 
    lpszNameToken = strtok (szResolve, ";\n"); 
 
    while (lpszNameToken) 
    { 
    /* Strip leading blanks (again) */ 
 
    while (*lpszNameToken == ' ') 
        lpszNameToken++; 
 
    ulResult = MAPIResolveName (lhSession, (ULONG) hWnd, lpszNameToken, 
        MAPI_DIALOG, 0, &lpRecip); 
 
    if (ulResult == SUCCESS_SUCCESS) 
    { 
        lpRecip->ulRecipClass = ulRecipClass; 
        ulResult = CopyRecipient (lpRecipList, &lpRecipList[cRecips], lpRecip); 
 
        MAPIFreeBuffer (lpRecip); 
 
        if (ulResult) 
        goto cleanup; 
 
        cRecips++; 
    } 
    else 
    { 
        lstrcat (lpszDisplayNames, lpszNameToken); 
        lstrcat (lpszDisplayNames, "; "); 
        cFails++; 
    } 
    lpszNameToken = strtok (NULL, ";\n"); 
    } 
 
    /* if cFails > 0 then we have partial success */ 
 
    ulResult = SUCCESS_SUCCESS; 
 
    if (cFails) 
    MakeMessageBox (hWnd, 0, IDS_UNRESOLVEDNAMES, MBS_INFO); 
 
cleanup: 
    *lpcRecips = cRecips; 
    *lppRecips = lpRecipList; 
err: 
    if (*lpszDisplayNames) 
    lpszDisplayNames[lstrlen (lpszDisplayNames) - 2] = '\0'; 
 
    return ulResult; 
} 
 
/* 
 -  CopyRecipient 
 - 
 *  Purpose: 
 *      Called in support of ResolveFriendlyNames() to build an array 
 *      of chained MapiRecipDescs. 
 * 
 *  Parameters: 
 *      lpParent        - Parent memory that allocations get chained to 
 *      lpDest          - Destination Recipient 
 *      lpSrc           - Source Recipient 
 * 
 *  Return: 
 *      ulResult 
 */ 
 
ULONG 
CopyRecipient (lpMapiRecipDesc lpParent, 
    lpMapiRecipDesc lpDest, 
    lpMapiRecipDesc lpSrc) 
{ 
    lpDest->ulReserved = lpSrc->ulReserved; 
    lpDest->ulRecipClass = lpSrc->ulRecipClass; 
    lpDest->ulEIDSize = lpSrc->ulEIDSize; 
 
    if (lpSrc->lpszName) 
    { 
    lpDest->lpszName = (LPTSTR)PvAllocMore(lstrlen(lpSrc->lpszName) + 1, 
            (LPVOID)lpParent); 
 
    if (!lpDest->lpszName) 
        return MAPI_E_INSUFFICIENT_MEMORY; 
 
    lstrcpy (lpDest->lpszName, lpSrc->lpszName); 
    } 
    else 
    lpDest->lpszName = NULL; 
 
    if (lpSrc->lpszAddress) 
    { 
    lpDest->lpszAddress = (LPTSTR)PvAllocMore(lstrlen (lpSrc->lpszAddress) + 1, 
            (LPVOID)lpParent); 
 
    if (!lpDest->lpszAddress) 
        return MAPI_E_INSUFFICIENT_MEMORY; 
 
    lstrcpy (lpDest->lpszAddress, lpSrc->lpszAddress); 
    } 
    else 
    lpDest->lpszAddress = NULL; 
 
    if (lpSrc->lpEntryID) 
    { 
    lpDest->lpEntryID = (LPBYTE)PvAllocMore(lpSrc->ulEIDSize, 
            (LPVOID)lpParent); 
 
    if (!lpDest->lpEntryID) 
        return MAPI_E_INSUFFICIENT_MEMORY; 
 
        if (lpSrc->ulEIDSize) 
            memcpy (lpDest->lpEntryID, lpSrc->lpEntryID, (size_t)lpSrc->ulEIDSize); 
    } 
    else 
    lpDest->lpEntryID = NULL; 
 
    return SUCCESS_SUCCESS; 
 
} 
 
/* 
 -  GetNextFile 
 - 
 *  Purpose: 
 *      Called when user clicks 'Attach' button in Compose Note form. 
 *      We will build a chained memory chunk for mmore than one file 
 *      attachment so the memory can be freed with a single call to 
 *      PvFree. 
 * 
 *  Parameters: 
 *      hWnd            - Window handle of Compose Note dialog 
 *      nPos            - Render position of attachment in Notetext. 
 *      lpcAttach       - Pointer to the count of attachments. 
 *      lppAttach       - Pointer to the MapiFileDesc array. 
 * 
 *  Return: 
 *      ulResult. 
 */ 
 
ULONG 
GetNextFile (HWND hWnd, ULONG nPos, ULONG * lpcAttach, 
    lpMapiFileDesc * lppAttach) 
{ 
    lpMapiFileDesc lpAttach; 
    lpMapiFileDesc lpAttachT; 
    OPENFILENAME ofn; 
    char szFileName[256] = ""; 
    char szFilter[256]; 
    static char szFileTitle[16]; 
    static char szDirName[256] = ""; 
    LPSTR lpszEndPath; 
    ULONG idx; 
    ULONG ulResult = SUCCESS_SUCCESS; 
 
    if (!szDirName[0]) 
    GetSystemDirectory ((LPSTR) szDirName, 255); 
    else 
    lstrcpy (szFileName, szFileTitle); 
 
    LoadString(hInst, IDS_FILTER, szFilter, sizeof(szFilter)); 
 
    for (idx = 0; szFilter[idx] != '\0'; idx++) 
    if (szFilter[idx] == '|') 
        szFilter[idx] = '\0'; 
 
    ofn.lStructSize = sizeof (OPENFILENAME); 
    ofn.hwndOwner = 0; 
    ofn.hInstance = 0; 
    ofn.lpstrFilter = szFilter; 
    ofn.lpstrCustomFilter = NULL; 
    ofn.nMaxCustFilter = 0L; 
    ofn.nFilterIndex = 1L; 
    ofn.lpstrFile = szFileName; 
    ofn.nMaxFile = 256; 
    ofn.lpstrFileTitle = szFileTitle; 
    ofn.nMaxFileTitle = 16; 
    ofn.lpstrInitialDir = szDirName; 
    ofn.lpstrTitle = "Attach"; 
    ofn.nFileOffset = 0; 
    ofn.nFileExtension = 0; 
    ofn.lpstrDefExt = NULL; 
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 
 
    if (!GetOpenFileName (&ofn)) 
    return MAPI_USER_ABORT; 
 
    /* Save the directory for the next time we call this */ 
 
    lstrcpy (szDirName, szFileName); 
    if (lpszEndPath = strstr (szDirName, szFileTitle)) 
    *(--lpszEndPath) = '\0'; 
 
    lpAttach = (lpMapiFileDesc)PvAlloc(((*lpcAttach) + 1) * sizeof (MapiFileDesc)); 
 
    if(!lpAttach) 
    goto err; 
 
    memset (lpAttach, 0, (size_t)(*lpcAttach + 1) * sizeof (MapiFileDesc)); 
 
    lpAttachT = *lppAttach; 
 
    for (idx = 0; idx < *lpcAttach; idx++) 
    if(ulResult = CopyAttachment (lpAttach, &lpAttach[idx], &lpAttachT[idx])) 
        goto err; 
 
    lpAttach[idx].ulReserved = 0; 
    lpAttach[idx].flFlags = 0; 
    lpAttach[idx].nPosition = (ULONG)(-1); 
    lpAttach[idx].lpFileType = NULL; 
 
    lpAttach[idx].lpszPathName = (LPTSTR)PvAllocMore(lstrlen (szFileName) + 1, 
        (LPVOID)lpAttach); 
 
    if(!lpAttach[idx].lpszPathName) 
    goto err; 
 
    lpAttach[idx].lpszFileName = (LPTSTR)PvAllocMore(lstrlen (szFileTitle) + 1, 
        (LPVOID)lpAttach); 
 
    if(!lpAttach[idx].lpszFileName) 
    goto err; 
 
    lstrcpy (lpAttach[idx].lpszPathName, szFileName); 
    lstrcpy (lpAttach[idx].lpszFileName, szFileTitle); 
 
    PvFree(lpAttachT); 
 
    *lppAttach = lpAttach; 
    (*lpcAttach)++; 
 
err: 
    if(ulResult) 
    PvFree(lpAttach); 
 
    return ulResult; 
} 
 
/* 
 -  CopyAttachment 
 - 
 *  Purpose: 
 *      Called in support of GetNextFile() to re-build an array 
 *      of chained MapiFileDescs. 
 * 
 *  Parameters: 
 *      lpParent        - Parent memory that allocations get chained to 
 *      lpDest          - Destination Recipient 
 *      lpSrc           - Source Recipient 
 * 
 *  Return: 
 *      Void. 
 */ 
 
ULONG 
CopyAttachment (lpMapiFileDesc lpParent, 
    lpMapiFileDesc lpDest, 
    lpMapiFileDesc lpSrc) 
{ 
    lpDest->ulReserved = lpSrc->ulReserved; 
    lpDest->flFlags = lpSrc->flFlags; 
    lpDest->nPosition = lpSrc->nPosition; 
    lpDest->lpFileType = lpSrc->lpFileType; 
 
    if (lpSrc->lpszPathName) 
    { 
    lpDest->lpszPathName = (LPTSTR)PvAllocMore(lstrlen (lpSrc->lpszPathName) + 1, 
            (LPVOID)lpParent); 
 
    if (!lpDest->lpszPathName) 
        return MAPI_E_INSUFFICIENT_MEMORY; 
 
    lstrcpy (lpDest->lpszPathName, lpSrc->lpszPathName); 
    } 
    else 
    lpDest->lpszPathName = NULL; 
 
    if (lpSrc->lpszFileName) 
    { 
    lpDest->lpszFileName = (LPTSTR)PvAllocMore(lstrlen (lpSrc->lpszFileName) + 1, 
            (LPVOID)lpParent); 
 
    if (!lpDest->lpszFileName) 
        return MAPI_E_INSUFFICIENT_MEMORY; 
 
    lstrcpy (lpDest->lpszFileName, lpSrc->lpszFileName); 
    } 
    else 
    lpDest->lpszFileName = NULL; 
 
    return SUCCESS_SUCCESS; 
 
} 
 
/* 
 -  FNameInList 
 - 
 *  Purpose: 
 *      To find lpszName in an array of recipients.  Used to determine 
 *      if user name has already been resolved. 
 * 
 *  Parameters: 
 *      lpszName        - Friendly name to search for 
 *      cRecips         - Count of recipients in lpRecips 
 *      lpRecips        - Array of MapiRecipDescs 
 * 
 *  Return: 
 *      TRUE/FALSE 
 */ 
 
BOOL 
FNameInList (LPSTR lpszName, ULONG cRecips, lpMapiRecipDesc lpRecips) 
{ 
    /* Case sensitive compare of each friendly name in list.  */ 
 
    if (!cRecips || !lpRecips) 
    return FALSE; 
 
    while (cRecips--) 
    if (!lstrcmp (lpszName, lpRecips[cRecips].lpszName)) 
        return TRUE; 
 
    return FALSE; 
} 
 
 
/* 
 -  MakeMsgNode 
 - 
 *  Purpose: 
 *      Allocate memory for a new MSGID node and initialize its 
 *      data members to the values passed in. 
 * 
 *  Parameters: 
 *      lpMsg           - Pointer to a MapiMessage 
 *      lpszMsgID       - Opaque message identifier 
 * 
 *  Return: 
 *      lpMsgNode       - Pointer to new node 
 */ 
 
LPMSGID 
MakeMsgNode (lpMapiMessage lpMsg, LPSTR lpszMsgID) 
{ 
    LPMSGID lpMsgNode = NULL; 
 
    if (!lpMsg || !lpszMsgID) 
    goto err; 
 
    lpMsgNode = (LPMSGID)PvAlloc(sizeof (MSGID)); 
 
    if (!lpMsgNode) 
    goto err; 
 
    memset (lpMsgNode, 0, sizeof (MSGID)); 
 
    if (lpMsg->nFileCount) 
    lpMsgNode->fHasAttach = TRUE; 
 
    if (lpMsg->flFlags & MAPI_UNREAD) 
    lpMsgNode->fUnRead = TRUE; 
 
    lpMsgNode->lpszMsgID = (LPTSTR)PvAllocMore(lstrlen (lpszMsgID) + 1, 
        (LPVOID)lpMsgNode); 
 
    if (!lpMsgNode->lpszMsgID) 
    goto err; 
 
    lstrcpy (lpMsgNode->lpszMsgID, lpszMsgID); 
 
    if (lpMsg->lpOriginator && lpMsg->lpOriginator->lpszName) 
    { 
    lpMsgNode->lpszFrom = (LPTSTR)PvAllocMore(lstrlen(lpMsg->lpOriginator->lpszName) + 1, 
            (LPVOID)lpMsgNode); 
 
    if (!lpMsgNode->lpszFrom) 
        goto err; 
 
    lstrcpy (lpMsgNode->lpszFrom, lpMsg->lpOriginator->lpszName); 
    } 
 
    if (lpMsg->lpszSubject) 
    { 
    lpMsgNode->lpszSubject = (LPTSTR)PvAllocMore(lstrlen (lpMsg->lpszSubject) + 1, 
            (LPVOID)lpMsgNode); 
 
    if (!lpMsgNode->lpszSubject) 
        goto err; 
 
    lstrcpy (lpMsgNode->lpszSubject, lpMsg->lpszSubject); 
    } 
 
    if (lpMsg->lpszDateReceived) 
    { 
    lpMsgNode->lpszDateRec = (LPTSTR)PvAllocMore(lstrlen (lpMsg->lpszDateReceived) + 1, 
            (LPVOID)lpMsgNode); 
 
    if (!lpMsgNode->lpszDateRec) 
        goto err; 
 
    lstrcpy (lpMsgNode->lpszDateRec, lpMsg->lpszDateReceived); 
    } 
 
    return lpMsgNode; 
 
err: 
    PvFree(lpMsgNode); 
    return NULL; 
} 
 
/* 
 -  InsertMsgNode 
 - 
 *  Purpose: 
 *      Currently (for simplicity) we will insert the nodes 
 *      at the beginning of the list.  This can later be 
 *      replaced with a routine that can insert sorted on 
 *      different criteria, like DateReceived, From, or 
 *      Subject.  But for now... 
 * 
 *  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; 
 
    /* Check if we are the first node */ 
 
    if (lpMsgNode->lpPrev) 
    lpMsgNode->lpPrev->lpNext = lpMsgNode->lpNext; 
 
    /* Check if we are the last node */ 
 
    if (lpMsgNode->lpNext) 
    lpMsgNode->lpNext->lpPrev = lpMsgNode->lpPrev; 
 
    /* check if we are the only node */ 
 
    if(lpMsgNode == *lppMsgHead) 
    *lppMsgHead = NULL; 
 
    PvFree(lpMsgNode); 
    return; 
} 
 
 
 
/* 
 -  FindNode 
 - 
 *  Purpose: 
 *      Returns a pointer to the node containing lpszMsgID. 
 *      Returns NULL if node doesn't exist or lpszMsgID is NULL. 
 * 
 *  Parameters: 
 *      lpMsgHead       - Pointer to the head of the list 
 *      lpszMsgID       - Message ID to search for 
 * 
 *  Return: 
 *      lpMsgNode       - Pointer to the node returned 
 */ 
 
LPMSGID 
FindNode (LPMSGID lpMsgHead, LPSTR lpszMsgID) 
{ 
    if (!lpszMsgID) 
    return NULL; 
 
    while (lpMsgHead) 
    { 
    if (!lstrcmp (lpMsgHead->lpszMsgID, lpszMsgID)) 
        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; 
    PvFree(lpT); 
    } 
} 
 
/* 
 -  MakeDisplayNameStr 
 - 
 *  Purpose: 
 *      Finds all recipients of type ulRecipClass in lpRecips and adds 
 *      their friendly name to the display string. 
 * 
 *  Parameters: 
 *      lpszDisplay         - Destination string for names 
 *      ulRecipClass        - Recipient types to search for 
 *      cRecips             - Count of recipients in lpRecips 
 *      lpRecips            - Pointer to array of MapiRecipDescs 
 * 
 *  Return: 
 *      Void. 
 */ 
 
void 
MakeDisplayNameStr (LPSTR lpszDisplay, ULONG ulRecipClass, 
    ULONG cRecips, lpMapiRecipDesc lpRecips) 
{ 
    ULONG idx; 
 
    *lpszDisplay = '\0'; 
 
    for (idx = 0; idx < cRecips; idx++) 
    { 
    if (lpRecips[idx].ulRecipClass == ulRecipClass) 
    { 
        lstrcat (lpszDisplay, lpRecips[idx].lpszName); 
        lstrcat (lpszDisplay, "; "); 
    } 
    } 
 
    if (*lpszDisplay) 
    lpszDisplay[lstrlen (lpszDisplay) - 2] = '\0'; 
} 
 
 
 
/* 
 -  SaveMsgChanges 
 - 
 *  Purpose: 
 *      If while reading a message the user changes the notetext at all 
 *      then this function is called to save those changes in the Inbox. 
 * 
 *  Parameters: 
 *      hWnd            - handle to the window/dialog who called us 
 *      lpMsg           - pointer to the MAPI message to be saved 
 *      lpszMsgID       - ID of the message to save 
 * 
 *  Return: 
 *      ulResult        - Indicating success/failure 
 */ 
 
ULONG 
SaveMsgChanges (HWND hWnd, lpMapiMessage lpMsg, LPSTR lpszMsgID) 
{ 
    LPSTR lpszT; 
    LPSTR lpszNoteText = NULL; 
    LONG cLines, cb; 
    ULONG ulResult = MAPI_E_INSUFFICIENT_MEMORY; 
 
    lpszT = lpMsg->lpszNoteText; 
 
    cLines = SendDlgItemMessage (hWnd, IDC_READNOTE, EM_GETLINECOUNT, 0, 0L); 
    cb = SendDlgItemMessage (hWnd, IDC_READNOTE, EM_LINEINDEX, (UINT)cLines - 1, 0L); 
    cb += SendDlgItemMessage (hWnd, IDC_READNOTE, EM_LINELENGTH, (UINT)cb, 0L); 
    cb += cLines * 2; 
 
    lpszNoteText = (LPTSTR)PvAlloc(cb + 1); 
 
    if (!lpszNoteText) 
    goto err; 
 
    SendDlgItemMessage (hWnd, IDC_READNOTE, WM_GETTEXT, 
    (WPARAM) cb, (LPARAM) lpszNoteText); 
 
    lpMsg->lpszNoteText = lpszNoteText; 
    ulResult = MAPISaveMail (lhSession, (ULONG) hWnd, lpMsg, MAPI_LONG_MSGID, 
        0, lpReadMsgNode->lpszMsgID); 
 
    PvFree(lpszNoteText); 
 
err: 
    lpMsg->lpszNoteText = lpszT; 
    return ulResult; 
} 
 
 
 
/* 
 -  MakeNewMessage 
 - 
 *  Purpose: 
 *      This function is used to construct a new message for the 
 *      ComposeNote UI.  This gets called as a result of a Reply, 
 *      ReplyAll, or a Forward action on a message being read. 
 *      The destination for the new message is lpmsg, the global 
 *      MapiMessage struct pointer used by ComposeNoteDlgProc. 
 *      ComposeNoteDlgProc always frees the memory consumed by 
 *      this object whether it allocated it or not. 
 * 
 *  Parameters: 
 *      lpSrcMsg            - MapiMessage to be copied 
 *      flType              - Specifies the action that caused this call 
 *                            either: IDC_REPLY, IDC_REPLYALL, or IDC_FORWARD 
 * 
 *  Return: 
 *      ulResult            - Indicates success/failure 
 */ 
 
ULONG 
MakeNewMessage (lpMapiMessage lpSrcMsg, UINT flType) 
{ 
    ULONG idx; 
    ULONG ulResult = SUCCESS_SUCCESS; 
 
    if (!lpSrcMsg) 
    return MAPI_E_FAILURE; 
 
    lpmsg = (lpMapiMessage)PvAlloc(sizeof (MapiMessage)); 
 
    if (!lpmsg) 
    goto err; 
 
    memset (lpmsg, 0, sizeof (MapiMessage)); 
 
    lpmsg->flFlags = flSendMsgFlags; 
 
    if (lpSrcMsg->lpszSubject) 
    { 
    lpmsg->lpszSubject = (LPTSTR)PvAlloc(lstrlen(lpSrcMsg->lpszSubject) + 5); 
 
    if (!lpmsg->lpszSubject) 
        goto err; 
 
    if (flType == IDC_FORWARD) 
        lstrcpy (lpmsg->lpszSubject, "FW: "); 
    else 
        lstrcpy (lpmsg->lpszSubject, "RE: "); 
 
    lstrcat (lpmsg->lpszSubject, lpSrcMsg->lpszSubject); 
    } 
 
    if (lpSrcMsg->lpszNoteText) 
    { 
    lpmsg->lpszNoteText = (LPTSTR)PvAlloc(lstrlen(lpSrcMsg->lpszNoteText) + 32); 
 
    if (!lpmsg->lpszNoteText) 
        goto err; 
 
    lstrcpy (lpmsg->lpszNoteText, "\r\n--------------------------\r\n"); 
    lstrcat (lpmsg->lpszNoteText, lpSrcMsg->lpszNoteText); 
    } 
 
    if (lpSrcMsg->lpszMessageType) 
    { 
    lpmsg->lpszMessageType = (LPTSTR)PvAlloc(lstrlen (lpSrcMsg->lpszMessageType) + 1); 
    if (!lpmsg->lpszMessageType) 
        goto err; 
 
    lstrcpy (lpmsg->lpszMessageType, lpSrcMsg->lpszMessageType); 
    } 
 
    if (lpSrcMsg->lpszConversationID) 
    { 
    lpmsg->lpszConversationID = (LPTSTR)PvAlloc(lstrlen(lpSrcMsg->lpszConversationID) + 1); 
 
    if (!lpmsg->lpszConversationID) 
        goto err; 
 
    lstrcpy (lpmsg->lpszConversationID, lpSrcMsg->lpszConversationID); 
    } 
 
    if (lpSrcMsg->nFileCount && flType == IDC_FORWARD ) 
    { 
    lpmsg->nFileCount = lpSrcMsg->nFileCount; 
 
    lpmsg->lpFiles = (lpMapiFileDesc)PvAlloc(lpmsg->nFileCount * sizeof (MapiFileDesc)); 
 
    if (!lpmsg->lpFiles) 
        goto err; 
        memset (lpmsg->lpFiles, 0, (size_t)lpmsg->nFileCount * sizeof (MapiFileDesc)); 
 
        for (idx = 0; idx < lpmsg->nFileCount; idx++) 
    {        
        CopyAttachment (lpmsg->lpFiles, &lpmsg->lpFiles[idx], 
        &lpSrcMsg->lpFiles[idx]); 
         
            if ((&lpmsg->lpFiles[idx])->nPosition != (ULONG) -1) 
            {        
                /*lpmsg->lpszNoteText[(&lpmsg->lpFiles[idx])->nPosition  
                            + lstrlen("\r\n--------------------------\r\n")] = '+';*/ 
                (&lpmsg->lpFiles[idx])->nPosition = (ULONG) -1; 
                 
            } 
                                 
             
        } 
    } 
 
    if (flType == IDC_REPLY || flType == IDC_REPLYALL) 
    { 
        ULONG idxSrc; 
 
    if(lpSrcMsg->lpOriginator) 
        lpmsg->nRecipCount = 1; 
 
    if (flType == IDC_REPLYALL) 
        lpmsg->nRecipCount += lpSrcMsg->nRecipCount; 
 
        if(!lpmsg->nRecipCount) 
            return ulResult; 
 
    lpmsg->lpRecips = (lpMapiRecipDesc)PvAlloc(lpmsg->nRecipCount * sizeof (MapiRecipDesc)); 
 
    if (!lpmsg->lpRecips) 
        goto err; 
 
        memset (lpmsg->lpRecips, 0, (size_t)lpmsg->nRecipCount * sizeof (MapiRecipDesc)); 
        idx = 0; 
 
        if(lpSrcMsg->lpOriginator) 
        { 
        lpSrcMsg->lpOriginator->ulRecipClass = MAPI_TO; 
        CopyRecipient (lpmsg->lpRecips, lpmsg->lpRecips, 
                lpSrcMsg->lpOriginator); 
        lpSrcMsg->lpOriginator->ulRecipClass = MAPI_ORIG; 
            idx = 1; 
        } 
 
    for (idxSrc = 0; idx < lpmsg->nRecipCount; idxSrc++, idx++) 
        CopyRecipient (lpmsg->lpRecips, &lpmsg->lpRecips[idx], 
        &lpSrcMsg->lpRecips[idxSrc]); 
    } 
 
    return ulResult; 
 
err: 
    if(lpmsg) 
    { 
        PvFree(lpmsg->lpszSubject); 
    PvFree(lpmsg->lpszNoteText); 
        PvFree(lpmsg->lpszMessageType); 
        PvFree(lpmsg->lpszConversationID); 
        PvFree(lpmsg->lpRecips); 
        PvFree(lpmsg->lpFiles); 
        PvFree(lpmsg); 
        lpmsg = NULL; 
    } 
    return ulResult; 
} 
 
 
 
/* 
 -  LogSendMail 
 - 
 *  Purpose: 
 *      Used to track how many messages were sent with this client. 
 *      This information is used strictly for gathering stats on 
 *      how many messages were pumped through the spooler/transport. 
 * 
 *  Usage: 
 *      Add the following to the win.ini file: 
 *          [MAPI Client] 
 *          LogFile=filepath 
 * 
 *      where: filepath can be a full UNC path or some local path & file 
 * 
 *  Parameters: 
 *      ulResult        - Currently unused; should be used to count errors 
 * 
 *  Result: 
 *      Void. 
 */ 
 
void LogSendMail(ULONG ulResult) 
{ 
    char szLogFile[128]; 
    char szCount[32]; 
    OFSTRUCT ofs; 
    HFILE hf = HFILE_ERROR; 
    int cSent = 1; 
 
    if(!GetProfileString("MAPI Client", "LogFile", "mapicli.log", 
        szLogFile, sizeof(szLogFile))) 
    return; 
 
    if((hf = OpenFile(szLogFile, &ofs, OF_READWRITE)) == HFILE_ERROR) 
    { 
    if((hf = OpenFile(szLogFile, &ofs, OF_CREATE|OF_READWRITE)) == HFILE_ERROR) 
        return; 
    } 
    else 
    { 
    if(!_lread(hf, szCount, sizeof(szCount))) 
    { 
        _lclose(hf); 
        return; 
    } 
 
    cSent = atoi(szCount) + 1; 
    } 
 
    wsprintf(szCount, "%d", cSent); 
 
    _llseek(hf, 0, 0); 
 
    _lwrite(hf, szCount, lstrlen(szCount)); 
    _lclose(hf); 
 
    return; 
} 
 
 
 
/* 
 -  SaveFileAttachments 
 - 
 *  Purpose: 
 *      Displays a 'Save As' common dialog to allow the user to save 
 *      file attachments contained in the current message. 
 * 
 *  Parameters: 
 *      hWnd            - Window handle of calling WndProc 
 *      cFiles          - Count of the files in the file array 
 *      lpFiles         - Array of MapiFileDescs 
 * 
 *  Return: 
 *      Void. 
 */ 
 
void SaveFileAttachments(HWND hWnd, lpMapiFileDesc lpFile) 
{ 
    OPENFILENAME ofn; 
    char szFileName[256] = ""; 
    char szFilter[256]; 
    static char szFileTitle[16]; 
    static char szDirName[256] = ""; 
    LPSTR lpszEndPath; 
    ULONG idx; 
 
    if (!lpFile) 
    return; 
 
    if (!szDirName[0]) 
    GetTempPath (sizeof(szDirName), szDirName); 
 
    LoadString(hInst, IDS_FILTER, szFilter, sizeof(szFilter)); 
 
    for (idx = 0; szFilter[idx] != '\0'; idx++) 
    if (szFilter[idx] == '|') 
        szFilter[idx] = '\0'; 
 
    lstrcpy (szFileName, lpFile->lpszFileName); 
 
    ofn.lStructSize = sizeof (OPENFILENAME); 
    ofn.hwndOwner = hWnd; 
    ofn.hInstance = 0; 
    ofn.lpstrFilter = szFilter; 
    ofn.lpstrCustomFilter = NULL; 
    ofn.nMaxCustFilter = 0L; 
    ofn.nFilterIndex = 1L; 
    ofn.lpstrFile = szFileName; 
    ofn.nMaxFile = sizeof(szFileName); 
    ofn.lpstrFileTitle = szFileTitle; 
    ofn.nMaxFileTitle = sizeof(szFileTitle); 
    ofn.lpstrInitialDir = szDirName; 
    ofn.lpstrTitle = "Save Attachment"; 
    ofn.nFileOffset = 0; 
    ofn.nFileExtension = 0; 
    ofn.lpstrDefExt = NULL; 
    ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; 
 
    if (!GetSaveFileName (&ofn)) 
    return; 
 
    /* Save the directory for the next time we call this */ 
 
    lstrcpy (szDirName, szFileName); 
    if (lpszEndPath = strstr (szDirName, szFileTitle)) 
    *(--lpszEndPath) = '\0'; 
 
    /* Use CopyFile to carry out the operation. */ 
 
    if(!CopyFile(lpFile->lpszPathName, szFileName, FALSE)) 
    MakeMessageBox (hWnd, 0, IDS_SAVEATTACHERROR, MBS_ERROR); 
} 
 
 
 
/* 
 -  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_LOGOFF,   !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_COMPOSE,  !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_READ,     !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_SEND,     !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_ADDRBOOK, !fLoggedOn); 
    EnableMenuItem (GetMenu (hWnd), IDM_DETAILS,  !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); 
}