зеркало из https://github.com/mozilla/pjs.git
459 строки
11 KiB
C++
459 строки
11 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
//
|
|
// msgmapi.cpp -- implements XP mail/news support for the Microsoft Mail API (MAPI)
|
|
//
|
|
|
|
#include "msg.h" // Leave this first for Windows precompiled headers
|
|
|
|
#if defined (XP_WIN)
|
|
|
|
#include "xp.h"
|
|
#include "msgmapi.h"
|
|
#include "msgzap.h"
|
|
#include "maildb.h"
|
|
#include "mailhdr.h"
|
|
#include "msgfinfo.h"
|
|
#include "msgpane.h"
|
|
#include "pmsgsrch.h"
|
|
#include "abcinfo.h"
|
|
#include "abpane2.h"
|
|
#include "msgstrob.h"
|
|
|
|
//*****************************************************************************
|
|
// Encapsulate the XP DB stuff required to enumerate messages
|
|
|
|
class MSG_MapiListContext : public MSG_ZapIt
|
|
{
|
|
public:
|
|
MSG_MapiListContext () {}
|
|
~MSG_MapiListContext ();
|
|
|
|
MsgERR OpenDatabase (MSG_FolderInfo *folder);
|
|
|
|
MessageKey GetFirst ();
|
|
MessageKey GetNext ();
|
|
MsgERR MarkRead (MessageKey key, XP_Bool read);
|
|
|
|
lpMapiMessage GetMessage (MessageKey);
|
|
|
|
protected:
|
|
|
|
char *ConvertDateToMapiFormat (time_t);
|
|
char *ConvertBodyToMapiFormat (MailMessageHdr *hdr);
|
|
void ConvertRecipientsToMapiFormat (const char *ourRecips, lpMapiRecipDesc mapiRecips,
|
|
int numRecips, int mapiRecipClass);
|
|
|
|
MSG_FolderInfo *m_folder;
|
|
MailDB *m_db;
|
|
ListContext *m_listContext;
|
|
};
|
|
|
|
|
|
MSG_MapiListContext::~MSG_MapiListContext ()
|
|
{
|
|
if (m_listContext && m_db)
|
|
m_db->ListDone (m_listContext);
|
|
if (m_db)
|
|
m_db->Close();
|
|
}
|
|
|
|
|
|
MsgERR MSG_MapiListContext::OpenDatabase (MSG_FolderInfo *folder)
|
|
{
|
|
MsgERR dbErr = eFAILURE;
|
|
MSG_FolderInfoMail *mailFolder = NULL;
|
|
if (folder && (mailFolder = folder->GetMailFolderInfo()))
|
|
{
|
|
XP_Bool wasCreated;
|
|
if (FOLDER_MAIL == mailFolder->GetType())
|
|
dbErr = MailDB::Open (mailFolder->GetPathname(), FALSE, &m_db, FALSE);
|
|
else
|
|
dbErr = ImapMailDB::Open (mailFolder->GetPathname(), FALSE, &m_db, mailFolder->GetMaster(), &wasCreated);
|
|
|
|
m_folder = folder;
|
|
}
|
|
return dbErr;
|
|
}
|
|
|
|
|
|
MessageKey MSG_MapiListContext::GetFirst ()
|
|
{
|
|
MessageKey key = MSG_MESSAGEKEYNONE;
|
|
XP_ASSERT (NULL == m_listContext);
|
|
XP_ASSERT (NULL != m_db);
|
|
|
|
DBMessageHdr *headers = NULL;
|
|
if (eSUCCESS == m_db->ListFirst (&m_listContext, &headers) && headers)
|
|
{
|
|
key = headers->GetMessageKey ();
|
|
delete headers;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
|
|
MessageKey MSG_MapiListContext::GetNext ()
|
|
{
|
|
MessageKey key = MSG_MESSAGEKEYNONE;
|
|
|
|
XP_ASSERT (m_listContext && m_db);
|
|
if (m_listContext && m_db)
|
|
{
|
|
DBMessageHdr *headers = NULL;
|
|
if (eSUCCESS == m_db->ListNext (m_listContext, &headers))
|
|
{
|
|
key = headers->GetMessageKey ();
|
|
delete headers;
|
|
}
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
|
|
MsgERR MSG_MapiListContext::MarkRead (MessageKey key, XP_Bool read)
|
|
{
|
|
MsgERR err = eFAILURE;
|
|
XP_ASSERT(m_db);
|
|
if (m_db)
|
|
err = m_db->MarkRead (key, read);
|
|
return err;
|
|
}
|
|
|
|
|
|
lpMapiMessage MSG_MapiListContext::GetMessage (MessageKey key)
|
|
{
|
|
lpMapiMessage message = (lpMapiMessage) XP_CALLOC (1, sizeof(MapiMessage));
|
|
if (message)
|
|
{
|
|
char scratch[256];
|
|
|
|
MailMessageHdr *header = m_db->GetMailHdrForKey (key);
|
|
if (header)
|
|
{
|
|
header->GetSubject (scratch, sizeof(scratch), TRUE /*withRe?*/, m_db->GetDB());
|
|
message->lpszSubject = XP_STRDUP (scratch);
|
|
message->lpszDateReceived = ConvertDateToMapiFormat (header->GetDate());
|
|
|
|
// Pull out the flags info
|
|
// anything to do with MAPI_SENT? Since we're only reading the Inbox, I guess not
|
|
uint32 ourFlags = header->GetFlags();
|
|
if (!(ourFlags & kIsRead))
|
|
message->flFlags |= MAPI_UNREAD;
|
|
if (ourFlags & kMDNNeeded || ourFlags & kMDNSent)
|
|
message->flFlags |= MAPI_RECEIPT_REQUESTED;
|
|
|
|
// Pull out the author/originator info
|
|
message->lpOriginator = (lpMapiRecipDesc) XP_CALLOC (1, sizeof(MapiRecipDesc));
|
|
if (message->lpOriginator)
|
|
{
|
|
header->GetAuthor (scratch, sizeof(scratch), m_db->GetDB());
|
|
ConvertRecipientsToMapiFormat (scratch, message->lpOriginator, 1, MAPI_ORIG);
|
|
}
|
|
|
|
// Pull out the To/CC info
|
|
int32 numToRecips = header->GetNumRecipients();
|
|
int32 numCCRecips = header->GetNumCCRecipients();
|
|
message->lpRecips = (lpMapiRecipDesc) XP_CALLOC (numToRecips + numCCRecips, sizeof(MapiRecipDesc));
|
|
if (message->lpRecips)
|
|
{
|
|
XPStringObj ourRecips;
|
|
|
|
header->GetRecipients (ourRecips, m_db->GetDB());
|
|
ConvertRecipientsToMapiFormat (ourRecips, message->lpRecips, numToRecips, MAPI_TO);
|
|
|
|
header->GetCCList (ourRecips, m_db->GetDB());
|
|
ConvertRecipientsToMapiFormat (ourRecips, &message->lpRecips[numToRecips], numCCRecips, MAPI_CC);
|
|
|
|
message->nRecipCount = numToRecips + numCCRecips;
|
|
}
|
|
|
|
// Convert any body text that we have locally
|
|
message->lpszNoteText = ConvertBodyToMapiFormat (header);
|
|
|
|
delete header;
|
|
}
|
|
}
|
|
return message;
|
|
}
|
|
|
|
|
|
char *MSG_MapiListContext::ConvertDateToMapiFormat (time_t ourTime)
|
|
{
|
|
char *date = (char*) XP_ALLOC(32);
|
|
if (date)
|
|
{
|
|
// MAPI time format is YYYY/MM/DD HH:MM
|
|
// Note that we're not using XP_StrfTime because that localizes the time format,
|
|
// and the way I read the MAPI spec is that their format is canonical, not localized.
|
|
struct tm *local = localtime (&ourTime);
|
|
if (local)
|
|
strftime (date, 32, "%Y/%m/%d %I:%M", local); //use %H if hours should be 24 hour format
|
|
}
|
|
return date;
|
|
}
|
|
|
|
|
|
void MSG_MapiListContext::ConvertRecipientsToMapiFormat (const char *ourRecips, lpMapiRecipDesc mapiRecips,
|
|
int numRecips, int mapiRecipClass)
|
|
{
|
|
char *names = NULL;
|
|
char *addresses = NULL;
|
|
|
|
int count = MSG_ParseRFC822Addresses (ourRecips, &names, &addresses);
|
|
if (count > 0)
|
|
{
|
|
char *walkNames = names;
|
|
char *walkAddresses = addresses;
|
|
for (int i = 0; i < count && i < numRecips; i++)
|
|
{
|
|
if (walkNames)
|
|
{
|
|
mapiRecips[i].lpszName = XP_STRDUP (walkNames);
|
|
walkNames += XP_STRLEN (walkNames) + 1;
|
|
}
|
|
|
|
if (walkAddresses)
|
|
{
|
|
mapiRecips[i].lpszAddress = XP_STRDUP (walkAddresses);
|
|
walkAddresses += XP_STRLEN (walkAddresses) + 1;
|
|
}
|
|
|
|
mapiRecips[i].ulRecipClass = mapiRecipClass;
|
|
}
|
|
}
|
|
|
|
XP_FREEIF (names);
|
|
XP_FREEIF (addresses);
|
|
}
|
|
|
|
|
|
char *MSG_MapiListContext::ConvertBodyToMapiFormat (MailMessageHdr *hdr)
|
|
{
|
|
const int kBufLen = 64000;
|
|
int bytesUsed = 0;
|
|
int bytesThisLine;
|
|
|
|
char *body = (char*) XP_ALLOC (kBufLen);
|
|
if (body)
|
|
{
|
|
MSG_ScopeTerm *scope = new MSG_ScopeTerm (NULL /*search frame not needed, I hope*/, scopeMailFolder, m_folder);
|
|
if (scope)
|
|
{
|
|
MSG_BodyHandler *handler = new MSG_BodyHandler (scope, hdr->GetArticleNum(), hdr->GetLineCount(), hdr, m_db);
|
|
if (handler)
|
|
{
|
|
*body = '\0';
|
|
while (TRUE)
|
|
{
|
|
bytesThisLine = handler->GetNextLine (&body[bytesUsed], kBufLen - bytesUsed);
|
|
bytesUsed += bytesThisLine;
|
|
if (0 == bytesThisLine)
|
|
break;
|
|
else
|
|
bytesUsed--; // strip off null terminator
|
|
}
|
|
body[bytesUsed++] = '\0'; // rhp - fix last line garbage...
|
|
delete handler;
|
|
}
|
|
delete scope;
|
|
}
|
|
}
|
|
return body = (char*) XP_REALLOC(body, bytesUsed);
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
// MSGMAPI API implementation
|
|
|
|
|
|
extern "C" MessageKey MSG_GetFirstKeyInFolder (MSG_FolderInfo *folder, MSG_MapiListContext **context)
|
|
{
|
|
MessageKey key = MSG_MESSAGEKEYNONE;
|
|
|
|
*context = new MSG_MapiListContext ();
|
|
if (*context)
|
|
{
|
|
if (eSUCCESS == (*context)->OpenDatabase (folder))
|
|
key = (*context)->GetFirst ();
|
|
}
|
|
else
|
|
delete *context;
|
|
|
|
return key;
|
|
}
|
|
|
|
|
|
extern "C" MessageKey MSG_GetNextKeyInFolder (MSG_MapiListContext *context)
|
|
{
|
|
MessageKey key = MSG_MESSAGEKEYNONE;
|
|
|
|
XP_ASSERT(context);
|
|
if (context)
|
|
{
|
|
key = context->GetNext();
|
|
if (MSG_MESSAGEKEYNONE == key) // Do we know they're always going to run to completion?
|
|
delete context;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
|
|
extern "C" XP_Bool MSG_GetMapiMessageById (MSG_FolderInfo *folder, MessageKey key, lpMapiMessage *message)
|
|
{
|
|
XP_Bool success = FALSE;
|
|
MSG_MapiListContext *context = new MSG_MapiListContext();
|
|
if (context)
|
|
{
|
|
if (eSUCCESS == context->OpenDatabase(folder))
|
|
{
|
|
*message = context->GetMessage (key);
|
|
success = TRUE;
|
|
}
|
|
delete context;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
static void msg_FreeMAPIFile(lpMapiFileDesc f)
|
|
{
|
|
if (f)
|
|
{
|
|
XP_FREEIF(f->lpszPathName);
|
|
XP_FREEIF(f->lpszFileName);
|
|
}
|
|
}
|
|
|
|
static void msg_FreeMAPIRecipient(lpMapiRecipDesc rd)
|
|
{
|
|
if (rd)
|
|
{
|
|
XP_FREEIF(rd->lpszName);
|
|
XP_FREEIF(rd->lpszAddress);
|
|
XP_FREEIF(rd->lpEntryID);
|
|
}
|
|
}
|
|
|
|
extern "C" void MSG_FreeMapiMessage (lpMapiMessage msg)
|
|
{
|
|
ULONG i;
|
|
|
|
if (msg)
|
|
{
|
|
XP_FREEIF(msg->lpszSubject);
|
|
XP_FREEIF(msg->lpszNoteText);
|
|
XP_FREEIF(msg->lpszMessageType);
|
|
XP_FREEIF(msg->lpszDateReceived);
|
|
XP_FREEIF(msg->lpszConversationID);
|
|
|
|
if (msg->lpOriginator)
|
|
msg_FreeMAPIRecipient(msg->lpOriginator);
|
|
|
|
for (i=0; i<msg->nRecipCount; i++)
|
|
if (&(msg->lpRecips[i]) != NULL)
|
|
msg_FreeMAPIRecipient(&(msg->lpRecips[i]));
|
|
|
|
XP_FREEIF(msg->lpRecips);
|
|
|
|
for (i=0; i<msg->nFileCount; i++)
|
|
if (&(msg->lpFiles[i]) != NULL)
|
|
msg_FreeMAPIFile(&(msg->lpFiles[i]));
|
|
|
|
XP_FREEIF(msg->lpFiles);
|
|
|
|
XP_FREE(msg);
|
|
}
|
|
}
|
|
|
|
|
|
extern "C" XP_Bool MSG_MarkMapiMessageRead (MSG_FolderInfo *folder, MessageKey key, XP_Bool read)
|
|
{
|
|
XP_Bool success = FALSE;
|
|
MSG_MapiListContext *context = new MSG_MapiListContext();
|
|
if (context)
|
|
{
|
|
if (eSUCCESS == context->OpenDatabase(folder))
|
|
{
|
|
if (eSUCCESS == context->MarkRead (key, read))
|
|
success = TRUE;
|
|
}
|
|
delete context;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
extern "C" int AB_MAPI_ResolveName(char * string,AB_ContainerInfo ** ctr, /* caller allocates ptr to ctr, BE fills. Caller must close the ctr when done */
|
|
ABID * entryID)
|
|
{
|
|
*ctr = NULL;
|
|
*entryID = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* Caller must free the character strings returned by these functions using XP_FREE */
|
|
extern "C" char * AB_MAPI_GetEmailAddress(AB_ContainerInfo * ctr,ABID id)
|
|
{
|
|
return XP_STRDUP("johndoe@netscape.com"); // just a temporary stub
|
|
}
|
|
|
|
extern "C" char * AB_MAPI_GetFullName(AB_ContainerInfo * ctr,ABID id)
|
|
{
|
|
return XP_STRDUP("John Doe");
|
|
}
|
|
|
|
|
|
extern "C" char * AB_MAPI_ConvertToDescription(AB_ContainerInfo * ctr)
|
|
{
|
|
AB_ContainerAttribValue * value;
|
|
if (AB_GetContainerAttribute(ctr, attribName, &value) == AB_SUCCESS)
|
|
{
|
|
char * temp = XP_STRDUP(value->u.string);
|
|
AB_FreeContainerAttribValue(value);
|
|
return temp;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
extern "C" AB_ContainerInfo * AB_MAPI_ConvertToContainer(MWContext * context, char * description)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
extern "C" int AB_MAPI_CreatePropertySheetPane(MWContext * context,MSG_Master * master,AB_ContainerInfo * ctr, ABID id, MSG_Pane ** personPane)
|
|
{
|
|
AB_PersonPane * pPane = new AB_PersonPane(context, master, ctr, id);
|
|
*personPane = pPane;
|
|
return AB_SUCCESS; // let Rich know what this value is???
|
|
}
|
|
|
|
extern "C" void AB_MAPI_CloseContainer(AB_ContainerInfo ** ctr)
|
|
{
|
|
if (*ctr)
|
|
(*ctr)->Close();
|
|
*ctr = NULL;
|
|
}
|
|
|
|
#endif /* XP_WIN */
|