You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2524 lines
63 KiB
2524 lines
63 KiB
/*
|
|
- 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);
|
|
}
|