/* - 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 #include #include #include #include #include #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 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, "<>", 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); }