mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-26 10:10:31 +00:00
1578 lines
38 KiB
C++
1578 lines
38 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.
|
|
*/
|
|
|
|
// This file contains the deliver queued mail state machine
|
|
#include "rosetta.h"
|
|
#include "msg.h"
|
|
|
|
#include "xp_str.h"
|
|
#include "merrors.h"
|
|
#include "msgtpane.h"
|
|
#include "msgmast.h"
|
|
#include "maildb.h"
|
|
#include "msgfinfo.h"
|
|
#include "msgimap.h"
|
|
#include "msgprefs.h"
|
|
#include "msgurlq.h"
|
|
#include "mailhdr.h"
|
|
#include "prefapi.h"
|
|
#include "imaphost.h"
|
|
|
|
#include "msgdlqml.h"
|
|
|
|
extern "C"
|
|
{
|
|
#include "xpgetstr.h"
|
|
extern int MK_MIME_ERROR_WRITING_FILE;
|
|
/* extern int MK_MSG_CANT_COPY_TO_DRAFTS_FOLDER; */
|
|
extern int MK_MSG_CANT_COPY_TO_QUEUE_FOLDER;
|
|
extern int MK_MSG_CANT_COPY_TO_QUEUE_FOLDER_OLD;
|
|
extern int MK_MSG_CANT_COPY_TO_SAME_FOLDER;
|
|
extern int MK_MSG_CANT_CREATE_INBOX;
|
|
extern int MK_MSG_ERROR_WRITING_MAIL_FOLDER;
|
|
extern int MK_MSG_FOLDER_SUMMARY_UNREADABLE;
|
|
extern int MK_MSG_FOLDER_UNREADABLE;
|
|
extern int MK_MSG_NON_MAIL_FILE_WRITE_QUESTION;
|
|
extern int MK_MSG_NO_POP_HOST;
|
|
extern int MK_OUT_OF_MEMORY;
|
|
extern int MK_UNABLE_TO_OPEN_FILE;
|
|
extern int MK_MSG_COULDNT_OPEN_FCC_FILE;
|
|
extern int MK_MSG_COMPRESS_FOLDER_ETC;
|
|
extern int MK_MSG_COMPRESS_FOLDER_DONE;
|
|
extern int MK_MSG_CANT_OPEN;
|
|
extern int MK_MSG_BOGUS_QUEUE_MSG_1;
|
|
extern int MK_MSG_BOGUS_QUEUE_MSG_N;
|
|
extern int MK_MSG_BOGUS_QUEUE_MSG_1_OLD;
|
|
extern int MK_MSG_BOGUS_QUEUE_MSG_N_OLD;
|
|
extern int MK_MSG_BOGUS_QUEUE_REASON;
|
|
extern int MK_MSG_WHY_QUEUE_SPECIAL;
|
|
extern int MK_MSG_WHY_QUEUE_SPECIAL_OLD;
|
|
extern int MK_MSG_QUEUED_DELIVERY_FAILED;
|
|
extern int MK_MSG_DELIVERING_MESSAGE_TO;
|
|
extern int MK_MSG_DELIVERING_MESSAGE;
|
|
|
|
/* #### Why is this alegedly netlib-specific? What else am I to do? */
|
|
extern char *NET_ExplainErrorDetails (int code, ...);
|
|
|
|
}
|
|
|
|
#define UNHEX(C) \
|
|
((C >= '0' && C <= '9') ? C - '0' : \
|
|
((C >= 'A' && C <= 'F') ? C - 'A' + 10 : \
|
|
((C >= 'a' && C <= 'f') ? C - 'a' + 10 : 0)))
|
|
|
|
MSG_DeliverQueuedMailState::MSG_DeliverQueuedMailState(const char *folderPath, MSG_Pane *pane)
|
|
{
|
|
m_context = NULL;
|
|
m_folderName = XP_STRDUP(folderPath);
|
|
m_tmpName = NULL;
|
|
m_infile = 0;
|
|
m_outfile = 0;
|
|
|
|
m_bcc = m_to = m_newsgroups = m_fcc = NULL;
|
|
m_newshost = NULL;
|
|
m_flags = 0;
|
|
m_status = 0;
|
|
m_done = FALSE;
|
|
|
|
m_awaitingDelivery = FALSE;
|
|
m_deliveryFailed = FALSE;
|
|
m_deliveryFailureCount = 0;
|
|
m_bogusMessageCount = 0;
|
|
m_unreadMessages = 0;
|
|
m_totalMessages = 0;
|
|
|
|
m_inhead = FALSE;
|
|
m_position = 0;
|
|
m_headersPosition = 0;
|
|
m_flagsPosition = 0;
|
|
|
|
m_obuffer = NULL;
|
|
m_obufferSize = 0;
|
|
|
|
m_ibuffer = NULL;
|
|
m_ibufferSize = 0;
|
|
m_ibufferFP = 0;
|
|
|
|
m_headers = NULL;
|
|
m_headersSize = 0;
|
|
m_headersFP = 0;
|
|
|
|
m_msgNumber = 0;
|
|
m_folderSize = 0;
|
|
m_bytesRead = 0;
|
|
|
|
m_pane = pane;
|
|
|
|
m_imapFolderInfo = NULL;
|
|
m_localFolderInfo = NULL;
|
|
|
|
m_msgKeys.Add(0); // dummy message id in case we are appending to online Sent folder
|
|
}
|
|
|
|
MSG_DeliverQueuedMailState::~MSG_DeliverQueuedMailState()
|
|
{
|
|
}
|
|
|
|
/* static */ void MSG_DeliverQueuedMailState::PostLiteSelectExitFunction( URL_Struct *url,
|
|
int status,
|
|
MWContext *context)
|
|
{
|
|
MSG_FolderInfoMail *folderInfo = (MSG_IMAPFolderInfoMail *)url->fe_data;
|
|
if (folderInfo)
|
|
url->msg_pane->SetLoadingImapFolder(folderInfo->GetIMAPFolderInfoMail());
|
|
url->fe_data = NULL;
|
|
ImapFolderSelectCompleteExitFunction(url, status, context);
|
|
NET_FreeURLStruct(url);
|
|
}
|
|
|
|
int MSG_DeliverQueuedMailState::DeliverMoreQueued(URL_Struct* url)
|
|
{
|
|
XP_StatStruct folderst;
|
|
char* dbName;
|
|
char *line;
|
|
|
|
if (m_done)
|
|
goto ALLDONE;
|
|
|
|
/* If we're waiting for our post to a "mailto:" or "news:" URL to
|
|
complete, just return. We'll be called again after the current
|
|
batch of stuff is serviced, and eventually this will go FALSE.
|
|
|
|
#### I think this means that, though we will be servicing user
|
|
events, netlib will be running full-tilt until the message is
|
|
delivered, calling this function as frequently as it can.
|
|
That's kind of bad...
|
|
*/
|
|
if (m_awaitingDelivery)
|
|
return MK_WAITING_FOR_CONNECTION;
|
|
|
|
if (m_obuffer == NULL)
|
|
{
|
|
/* First time through. */
|
|
|
|
if (XP_Stat (m_folderName, &folderst, xpMailFolder))
|
|
{
|
|
/* Can't stat the file; must not have any queued messages. */
|
|
goto ALLDONE;
|
|
}
|
|
|
|
m_folderSize = folderst.st_size;
|
|
if (m_folderSize)
|
|
FE_GraphProgressInit(m_context, url, m_folderSize);
|
|
|
|
m_obufferSize = 8192;
|
|
while (!m_obuffer)
|
|
{
|
|
m_obufferSize /= 2;
|
|
m_obuffer = (char *) XP_ALLOC (m_obufferSize);
|
|
if (!m_obuffer && m_obufferSize < 2)
|
|
{
|
|
m_status = MK_OUT_OF_MEMORY;
|
|
goto FAIL;
|
|
}
|
|
}
|
|
|
|
m_infile = XP_FileOpen(m_folderName, xpMailFolder,
|
|
XP_FILE_READ_BIN);
|
|
if (!m_infile) goto ALLDONE;
|
|
|
|
return MK_WAITING_FOR_CONNECTION;
|
|
}
|
|
|
|
if (m_infile)
|
|
{
|
|
/* We're in the middle of parsing the folder. Do a line.
|
|
(It would be nice to use msg_LineBuffer() here, but because
|
|
of the goofy flow of control, that won't work.)
|
|
*/
|
|
line = XP_FileReadLine(m_obuffer, m_obufferSize,
|
|
m_infile);
|
|
if (!line)
|
|
/* Finally finished parsing. Close and clean up. */
|
|
goto ALLDONE;
|
|
|
|
m_status = DeliverQueuedLine (line, XP_STRLEN(line));
|
|
if (m_status < 0)
|
|
goto FAIL;
|
|
|
|
return MK_WAITING_FOR_CONNECTION;
|
|
}
|
|
|
|
ALLDONE:
|
|
if (m_infile)
|
|
{
|
|
XP_FileClose(m_infile);
|
|
m_infile = NULL;
|
|
|
|
if (!m_inhead && m_headersFP > 0 && m_status >= 0)
|
|
{
|
|
/* Ah, not really done now, are we? */
|
|
m_status = DeliverQueuedMessage ();
|
|
if (m_awaitingDelivery)
|
|
return MK_WAITING_FOR_CONNECTION;
|
|
}
|
|
}
|
|
|
|
/* Actually truncate the queue file if all messages in it have been
|
|
delivered successfully. */
|
|
if (m_status >= 0 && m_deliveryFailureCount == 0 && m_bogusMessageCount == 0)
|
|
{
|
|
/* If there is a summary file, it is now out of date. Delete it,
|
|
and recreate a new empty one.
|
|
*/
|
|
|
|
dbName = WH_FileName(m_folderName, xpMailFolderSummary);
|
|
if (dbName)
|
|
{
|
|
MailDB *db = (MailDB *) MessageDB::FindInCache(dbName);
|
|
XP_FREEIF(dbName);
|
|
if (db)
|
|
{
|
|
ListContext *listContext = NULL;
|
|
MsgERR dbErr;
|
|
DBMessageHdr *pHeader;
|
|
MSG_Pane *threadPane = (m_pane ?
|
|
m_pane->GetMaster()->FindThreadPaneNamed(m_folderName) :
|
|
(MSG_Pane *)NULL);
|
|
|
|
if (threadPane)
|
|
threadPane->StartingUpdate(MSG_NotifyNone, 0, 0);
|
|
dbErr = db->ListFirst(&listContext, &pHeader);
|
|
while (dbErr == eSUCCESS && pHeader != NULL)
|
|
{
|
|
// can't delete hdr that iterator is on, so save it.
|
|
DBMessageHdr *saveHdr = pHeader;
|
|
dbErr = db->ListNext(listContext, &pHeader);
|
|
|
|
if (dbErr == eDBEndOfList)
|
|
db->ListDone(listContext);
|
|
|
|
if (saveHdr)
|
|
db->DeleteHeader(saveHdr, NULL, FALSE);
|
|
delete saveHdr;
|
|
}
|
|
|
|
if (threadPane)
|
|
threadPane->EndingUpdate(MSG_NotifyNone, 0, 0);
|
|
// MessageDB::FindInCache() does not add refCount so don't close
|
|
// db->Close();
|
|
db = NULL;
|
|
if (m_imapFolderInfo)
|
|
{
|
|
MSG_Pane *urlPane = NULL;
|
|
|
|
if (!urlPane)
|
|
m_pane->GetMaster()->FindPaneOfType(m_imapFolderInfo, MSG_THREADPANE);
|
|
|
|
if (!urlPane)
|
|
urlPane = m_pane;
|
|
|
|
dbName = WH_FileName (m_imapFolderInfo->GetPathname(), xpMailFolderSummary);
|
|
if (dbName)
|
|
db = (MailDB *) MessageDB::FindInCache(dbName);
|
|
XP_FREEIF(dbName);
|
|
if (db && urlPane)
|
|
{
|
|
char *url = CreateImapMailboxLITESelectUrl(
|
|
m_imapFolderInfo->GetHostName(),
|
|
m_imapFolderInfo->GetOnlineName(),
|
|
m_imapFolderInfo->GetOnlineHierarchySeparator());
|
|
if (url)
|
|
{
|
|
URL_Struct *url_struct =
|
|
NET_CreateURLStruct(url,
|
|
NET_NORMAL_RELOAD);
|
|
if (url_struct)
|
|
{
|
|
m_imapFolderInfo->SetFolderLoadingContext(urlPane->GetContext());
|
|
urlPane->SetLoadingImapFolder(m_imapFolderInfo);
|
|
url_struct->fe_data = (void *) m_imapFolderInfo;
|
|
url_struct->internal_url = TRUE;
|
|
url_struct->msg_pane = urlPane;
|
|
urlPane->GetContext()->imapURLPane = urlPane;
|
|
|
|
MSG_UrlQueue::AddUrlToPane (url_struct,
|
|
PostLiteSelectExitFunction,
|
|
urlPane, TRUE);
|
|
|
|
}
|
|
XP_FREEIF(url);
|
|
}
|
|
// MessageDB::FindInCache() does not add refCount so don't call close
|
|
// db->Close();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XP_FileRemove(m_folderName, xpMailFolderSummary);
|
|
// create emtpy, blank db
|
|
MailDB::Open(m_folderName,TRUE, &db, FALSE);
|
|
if (db)
|
|
db->Close();
|
|
}
|
|
}
|
|
XP_FileClose(XP_FileOpen(m_folderName, xpMailFolder,
|
|
XP_FILE_WRITE_BIN));
|
|
|
|
if (m_pane && m_pane->GetMaster())
|
|
{
|
|
MailDB::SetFolderInfoValid(m_folderName, 0, 0);
|
|
MSG_FolderInfoMail *mailFolder = m_pane->GetMaster()->FindMailFolder(m_folderName, FALSE);
|
|
if (mailFolder)
|
|
mailFolder->SummaryChanged();
|
|
}
|
|
}
|
|
m_status = MK_CONNECTED;
|
|
|
|
/* Warn about failed delivery.
|
|
*/
|
|
if (m_deliveryFailureCount > 0)
|
|
{
|
|
char *fmt, *buf;
|
|
int L;
|
|
if (m_deliveryFailureCount == 1)
|
|
fmt = ("Delivery failed for 1 message.\n"
|
|
"\n"
|
|
"This message has been left in the Outbox folder.\n"
|
|
"Before it can be delivered, the error must be\n"
|
|
"corrected."); /* #### i18n */
|
|
else
|
|
fmt = ("Delivery failed for %d messages.\n"
|
|
"\n"
|
|
"These messages have been left in the Outbox folder.\n"
|
|
"Before they can be delivered, the errors must be\n"
|
|
"corrected."); /* #### i18n */
|
|
|
|
L = XP_STRLEN(fmt) + 30;
|
|
buf = (char *) XP_ALLOC (L);
|
|
if (buf)
|
|
{
|
|
PR_snprintf(buf, L-1, fmt, m_deliveryFailureCount);
|
|
FE_Alert(m_context, buf);
|
|
XP_FREE(buf);
|
|
}
|
|
}
|
|
|
|
/* Warn about bogus messages in the Outbox.
|
|
*/
|
|
else if (m_bogusMessageCount)
|
|
{
|
|
char *msg1, *msg2, *msg3;
|
|
char *buf1, *buf2;
|
|
|
|
if (m_bogusMessageCount == 1)
|
|
{
|
|
buf1 = NULL;
|
|
msg1 = XP_GetString(MK_MSG_BOGUS_QUEUE_MSG_1);
|
|
msg3 = XP_GetString(MK_MSG_WHY_QUEUE_SPECIAL);
|
|
const char *q = MSG_GetQueueFolderName();
|
|
if (q)
|
|
{
|
|
if (!strcasecomp(q,QUEUE_FOLDER_NAME_OLD))
|
|
msg1 = XP_GetString(MK_MSG_BOGUS_QUEUE_MSG_1_OLD);
|
|
msg3 = XP_GetString(MK_MSG_WHY_QUEUE_SPECIAL_OLD);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const char *q = MSG_GetQueueFolderName();
|
|
if (q)
|
|
{
|
|
if (!strcasecomp(q,QUEUE_FOLDER_NAME_OLD))
|
|
{
|
|
buf1 = PR_smprintf(XP_GetString(MK_MSG_BOGUS_QUEUE_MSG_N_OLD),
|
|
m_bogusMessageCount);
|
|
msg3 = XP_GetString(MK_MSG_WHY_QUEUE_SPECIAL_OLD);
|
|
}
|
|
else
|
|
{
|
|
buf1 = PR_smprintf(XP_GetString(MK_MSG_BOGUS_QUEUE_MSG_N),
|
|
m_bogusMessageCount);
|
|
msg3 = XP_GetString(MK_MSG_WHY_QUEUE_SPECIAL);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
buf1 = PR_smprintf(XP_GetString(MK_MSG_BOGUS_QUEUE_MSG_N),
|
|
m_bogusMessageCount);
|
|
msg3 = XP_GetString(MK_MSG_WHY_QUEUE_SPECIAL);
|
|
}
|
|
|
|
msg1 = buf1;
|
|
}
|
|
|
|
msg2 = XP_GetString(MK_MSG_BOGUS_QUEUE_REASON);
|
|
|
|
if (msg1 && msg2 && msg3)
|
|
{
|
|
buf2 = PR_smprintf("%s%s%s", msg1, msg2, msg3);
|
|
if (buf2)
|
|
{
|
|
FE_Alert(m_context, buf2);
|
|
XP_FREE(buf2);
|
|
}
|
|
}
|
|
|
|
if (buf1)
|
|
XP_FREE(buf1);
|
|
}
|
|
|
|
FAIL:
|
|
return m_status;
|
|
}
|
|
|
|
int MSG_DeliverQueuedMailState::CloseDeliverQueuedSock(URL_Struct* url)
|
|
{
|
|
if (m_infile)
|
|
XP_FileClose(m_infile);
|
|
if (m_outfile)
|
|
XP_FileClose(m_outfile);
|
|
FREEIF(m_to);
|
|
FREEIF(m_bcc);
|
|
FREEIF(m_newsgroups);
|
|
FREEIF(m_newshost);
|
|
FREEIF(m_ibuffer);
|
|
FREEIF(m_obuffer);
|
|
FREEIF(m_headers);
|
|
FREEIF(m_folderName);
|
|
if (m_tmpName)
|
|
{
|
|
XP_FileRemove(m_tmpName, xpFileToPost);
|
|
XP_FREEIF(m_tmpName);
|
|
}
|
|
|
|
if (m_folderSize)
|
|
FE_GraphProgressDestroy(m_context, url,
|
|
m_folderSize, m_bytesRead);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int MSG_DeliverQueuedMailState::DeliverQueuedMessage ()
|
|
{
|
|
XP_ASSERT (m_outfile && m_tmpName);
|
|
if (!m_outfile || !m_tmpName) return -1;
|
|
|
|
XP_FileClose (m_outfile);
|
|
m_outfile = 0;
|
|
|
|
if ((! (m_flags & MSG_FLAG_EXPUNGED)) &&
|
|
(m_flags & MSG_FLAG_QUEUED))
|
|
{
|
|
/* If this message is marked to be delivered, and does not have its
|
|
expunged bit set (meaning it has not yet been successfully delivered)
|
|
then deliver it now.
|
|
*/
|
|
|
|
m_totalMessages++;
|
|
if (! (m_flags & MSG_FLAG_READ))
|
|
m_unreadMessages++;
|
|
|
|
#ifdef XP_UNIX
|
|
m_status = msg_DeliverMessageExternally(m_context,
|
|
m_tmpName);
|
|
if (m_status != 0)
|
|
{
|
|
if (m_status >= 0)
|
|
m_status = DoFcc();
|
|
else
|
|
DeliverDone ();
|
|
return m_status;
|
|
}
|
|
#endif /* XP_UNIX */
|
|
|
|
DeliverAsNews ();
|
|
}
|
|
else
|
|
{
|
|
/* Just to delete the temp file. */
|
|
DeliverDone ();
|
|
}
|
|
|
|
return m_status;
|
|
}
|
|
|
|
|
|
int
|
|
MSG_DeliverQueuedMailState::DeliverDone ()
|
|
{
|
|
int local_status = 0;
|
|
if (m_status >= 0 &&
|
|
!m_deliveryFailed &&
|
|
m_flagsPosition > 0 &&
|
|
(m_flags & MSG_FLAG_QUEUED) &&
|
|
(! (m_flags & MSG_FLAG_EXPUNGED)))
|
|
{
|
|
/* If delivery was successful, mark the message as expunged in the file
|
|
right now - we do this by opening the file a second time, updating it,
|
|
and closing it, to make sure that this informationn gets flushed to
|
|
disk as quickly as possible. If we make it through the entire folder
|
|
and deliver them all, we will delete the whole file - but if we crash
|
|
in the middle, it's important that we not re-transmit all the already-
|
|
sent messages next time.
|
|
|
|
The message should have an X-Mozilla-Status header that is suitable
|
|
for us overwriting, but if it doesn't, then we will simply not mark
|
|
it as expunged - and should delivery fail, it will get sent again.
|
|
*/
|
|
XP_File out;
|
|
char buf[50];
|
|
#if 0
|
|
XP_Bool summary_valid = FALSE;
|
|
XP_StatStruct st;
|
|
#endif
|
|
|
|
XP_Bool was_read = (m_flags & MSG_FLAG_READ) != 0;
|
|
m_flags |= MSG_FLAG_EXPUNGED;
|
|
m_flags &= (~MSG_FLAG_QUEUED);
|
|
/* it's pretty important that this take up the same space...
|
|
We can't write out a line terminator because at this point,
|
|
we don't know what the file had in it before. (Safe to
|
|
assume LINEBREAK?) */
|
|
PR_snprintf(buf, sizeof(buf), X_MOZILLA_STATUS_FORMAT, m_flags);
|
|
|
|
#if 0
|
|
XP_Stat (m_folderName, &st, xpURL); /* must succeed */
|
|
summary_valid = msg_IsSummaryValid (m_folderName, &st);
|
|
#endif
|
|
|
|
out = XP_FileOpen (m_folderName, xpMailFolder,
|
|
XP_FILE_UPDATE_BIN);
|
|
if (!out)
|
|
{
|
|
local_status = m_status = MK_MSG_ERROR_WRITING_MAIL_FOLDER;
|
|
goto FAIL;
|
|
}
|
|
XP_FileSeek (out, m_flagsPosition, SEEK_SET);
|
|
m_flagsPosition = 0; /* Just in case we get called again... */
|
|
m_status = XP_FileWrite (buf, XP_STRLEN(buf), out);
|
|
XP_FileClose (out);
|
|
if (m_status < (int) XP_STRLEN(buf)) {
|
|
local_status = m_status = MK_MIME_ERROR_WRITING_FILE;
|
|
goto FAIL;
|
|
}
|
|
|
|
XP_ASSERT(m_totalMessages > 0);
|
|
if (m_totalMessages > 0)
|
|
m_totalMessages--;
|
|
|
|
if (!was_read)
|
|
{
|
|
XP_ASSERT(m_unreadMessages > 0);
|
|
if (m_unreadMessages > 0)
|
|
m_unreadMessages--;
|
|
}
|
|
}
|
|
|
|
FAIL:
|
|
/* Now we can delete the temp file too. */
|
|
if (m_tmpName)
|
|
{
|
|
int status2 = XP_FileRemove (m_tmpName, xpFileToPost);
|
|
if (local_status >= 0)
|
|
local_status = m_status = status2;
|
|
XP_FREE (m_tmpName);
|
|
m_tmpName = 0;
|
|
}
|
|
|
|
m_awaitingDelivery = FALSE;
|
|
|
|
if (m_deliveryFailed || m_status < 0)
|
|
m_deliveryFailureCount++;
|
|
m_deliveryFailed = FALSE;
|
|
|
|
if (local_status < 0)
|
|
/* If local_status is set, then it's an error that occurred in this
|
|
routine, not earlier -- so it wasn't a problem with delivery, but
|
|
rather, with the post-delivery stuff like updating the summary info.
|
|
(This would actually be a rather large problem, as now the message
|
|
has been sent, but we were unable to mark it as sent...)
|
|
*/
|
|
{
|
|
char *alert = NET_ExplainErrorDetails(local_status,0,0,0,0);
|
|
if (!alert) alert = XP_STRDUP("Unknown error!"); /* ####i18n */
|
|
if (alert)
|
|
{
|
|
FE_Alert(m_context, alert);
|
|
XP_FREE(alert);
|
|
}
|
|
}
|
|
|
|
return m_status;
|
|
}
|
|
|
|
|
|
int
|
|
MSG_DeliverQueuedMailState::DeliverAsNews ()
|
|
{
|
|
URL_Struct *url;
|
|
char *ng = m_newsgroups;
|
|
char *host_and_port = m_newshost;
|
|
XP_Bool xxx_p = FALSE;
|
|
char *buf;
|
|
|
|
if (ng) while (XP_IS_SPACE(*ng)) ng++;
|
|
|
|
if (!ng || !*ng)
|
|
return DeliverAsMail ();
|
|
|
|
m_awaitingDelivery = TRUE;
|
|
|
|
if (host_and_port && *host_and_port)
|
|
{
|
|
HG87355
|
|
}
|
|
if (host_and_port && !*host_and_port)
|
|
host_and_port = 0;
|
|
|
|
buf = (char *) XP_ALLOC (30 + (host_and_port ? XP_STRLEN(host_and_port) :0));
|
|
if (!buf) return MK_OUT_OF_MEMORY;
|
|
XP_STRCPY(buf, HG25525 "news:");
|
|
if (host_and_port)
|
|
{
|
|
XP_STRCAT (buf, "//");
|
|
XP_STRCAT (buf, host_and_port);
|
|
}
|
|
|
|
url = NET_CreateURLStruct (buf, NET_NORMAL_RELOAD);
|
|
XP_FREE (buf);
|
|
if (!url) return MK_OUT_OF_MEMORY;
|
|
|
|
url->post_data = XP_STRDUP(m_tmpName);
|
|
url->post_data_size = XP_STRLEN(url->post_data);
|
|
url->post_data_is_file = TRUE;
|
|
url->method = URL_POST_METHOD;
|
|
url->fe_data = this;
|
|
url->internal_url = TRUE;
|
|
// We don't need to set msg_pane here. It's a good idea but little
|
|
// risky for now.
|
|
// url->msg_pane = m_pane;
|
|
|
|
{
|
|
char buf[100];
|
|
const char *fmt = XP_GetString(MK_MSG_DELIVERING_MESSAGE_TO);
|
|
|
|
PR_snprintf(buf, sizeof(buf)-1, fmt, (long) m_msgNumber, ng);
|
|
FE_Progress(m_context, buf);
|
|
}
|
|
|
|
/* We can ignore the return value of NET_GetURL() because we have
|
|
handled the error in msg_deliver_queued_message_as_news_exit(). */
|
|
#if 0
|
|
NET_GetURL (url, FO_CACHE_AND_PRESENT, m_context,
|
|
msg_deliver_queued_message_as_news_exit);
|
|
#else
|
|
MSG_UrlQueue::AddUrlToPane (url, msg_deliver_queued_message_as_news_exit,
|
|
m_pane, TRUE);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
MSG_DeliverQueuedMailState::DeliverAsMail ()
|
|
{
|
|
URL_Struct *url;
|
|
char *to = m_to;
|
|
char *bcc = m_bcc;
|
|
char *buffer;
|
|
if (to) while (XP_IS_SPACE(*to)) to++;
|
|
if (bcc) while (XP_IS_SPACE(*bcc)) bcc++;
|
|
|
|
if (!to || !*to)
|
|
return DoFcc ();
|
|
|
|
m_awaitingDelivery = TRUE;
|
|
|
|
#define EXTRA_BYTES 9
|
|
/* 9 counts for "mailto:" + NULL terminated string + comma if we */
|
|
/* have bcc */
|
|
buffer = (char *) XP_ALLOC(EXTRA_BYTES + XP_STRLEN(to) +
|
|
(bcc ? XP_STRLEN(bcc)+1 : 0));
|
|
if (!buffer) return MK_OUT_OF_MEMORY;
|
|
XP_STRCPY(buffer, "mailto:");
|
|
XP_STRCAT (buffer, to);
|
|
if (bcc)
|
|
{
|
|
XP_STRCAT(buffer, ",");
|
|
XP_STRCAT(buffer, bcc);
|
|
}
|
|
|
|
url = NET_CreateURLStruct (buffer, NET_NORMAL_RELOAD);
|
|
XP_FREEIF (buffer);
|
|
if (!url) return MK_OUT_OF_MEMORY;
|
|
|
|
url->post_data = XP_STRDUP(m_tmpName);
|
|
url->post_data_size = XP_STRLEN(url->post_data);
|
|
url->post_data_is_file = TRUE;
|
|
url->method = URL_POST_METHOD;
|
|
url->fe_data = this;
|
|
url->internal_url = TRUE;
|
|
url->msg_pane = m_pane;
|
|
|
|
{
|
|
char buf[100];
|
|
const char *fmt = XP_GetString(MK_MSG_DELIVERING_MESSAGE_TO);
|
|
|
|
PR_snprintf(buf, sizeof(buf)-1, fmt, (long)m_msgNumber, to);
|
|
FE_Progress(m_context, buf);
|
|
}
|
|
|
|
/* We can ignore the return value of NET_GetURL() because we have
|
|
handled the error in msg_deliver_queued_message_as_mail_exit(). */
|
|
#if 0
|
|
NET_GetURL (url, FO_CACHE_AND_PRESENT, m_context,
|
|
msg_deliver_queued_message_as_mail_exit);
|
|
#else
|
|
MSG_UrlQueue::AddUrlToPane (url, msg_deliver_queued_message_as_mail_exit,
|
|
m_pane, TRUE);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
void MSG_DeliverQueuedMailState::msg_deliver_queued_message_as_news_exit (URL_Struct *url, int status,
|
|
MWContext * /*context*/)
|
|
{
|
|
MSG_DeliverQueuedMailState *state = (MSG_DeliverQueuedMailState *) url->fe_data;
|
|
state->DeliverAsNewsExit(url, status);
|
|
}
|
|
|
|
void MSG_DeliverQueuedMailState::DeliverAsNewsExit(URL_Struct *url, int status)
|
|
{
|
|
url->fe_data = 0;
|
|
if (m_status >= 0)
|
|
m_status = status;
|
|
|
|
if (status < 0)
|
|
{
|
|
char *error_msg = 0;
|
|
error_msg = url->error_msg;
|
|
url->error_msg = 0;
|
|
if (!error_msg)
|
|
error_msg = NET_ExplainErrorDetails (status, 0, 0, 0, 0);
|
|
Error (error_msg);
|
|
FREEIF(error_msg);
|
|
}
|
|
|
|
NET_FreeURLStruct (url);
|
|
|
|
if (m_status >= 0 && !m_deliveryFailed)
|
|
m_status = DeliverAsMail ();
|
|
else
|
|
DeliverDone ();
|
|
}
|
|
|
|
|
|
void
|
|
MSG_DeliverQueuedMailState::msg_deliver_queued_message_as_mail_exit (URL_Struct *url, int status,
|
|
MWContext * /*context*/)
|
|
{
|
|
MSG_DeliverQueuedMailState *state = (MSG_DeliverQueuedMailState *) url->fe_data;
|
|
state->DeliverAsMailExit(url, status);
|
|
}
|
|
|
|
void MSG_DeliverQueuedMailState::DeliverAsMailExit(URL_Struct *url, int status)
|
|
{
|
|
url->fe_data = 0;
|
|
if (m_status >= 0)
|
|
m_status = status;
|
|
|
|
if (status < 0)
|
|
{
|
|
char *error_msg = 0;
|
|
error_msg = url->error_msg;
|
|
url->error_msg = 0;
|
|
if (!error_msg)
|
|
error_msg = NET_ExplainErrorDetails (status, 0, 0, 0, 0);
|
|
Error (error_msg);
|
|
FREEIF(error_msg);
|
|
}
|
|
|
|
NET_FreeURLStruct (url);
|
|
|
|
if (m_status >= 0 && !m_deliveryFailed)
|
|
m_status = DoFcc ();
|
|
else
|
|
DeliverDone ();
|
|
}
|
|
|
|
/* statuc */ void
|
|
MSG_DeliverQueuedMailState::PostAppendToIMAPSentFolder(
|
|
URL_Struct *url,
|
|
int status,
|
|
MWContext * /* context */)
|
|
{
|
|
MSG_DeliverQueuedMailState *state=
|
|
(MSG_DeliverQueuedMailState*) url->fe_data;
|
|
XP_ASSERT(state);
|
|
|
|
if (state)
|
|
{
|
|
if (status < 0)
|
|
{
|
|
char *error_msg = 0;
|
|
error_msg = url->error_msg;
|
|
url->error_msg = 0;
|
|
if (!error_msg)
|
|
error_msg = NET_ExplainErrorDetails (status, 0, 0, 0,
|
|
0);
|
|
state->Error (error_msg);
|
|
FREEIF(error_msg);
|
|
}
|
|
else
|
|
{
|
|
if (state->m_imapFolderInfo)
|
|
{
|
|
if (!state->m_localFolderInfo)
|
|
state->m_localFolderInfo =
|
|
state->m_pane->GetMaster()->FindMailFolder(state->m_folderName, FALSE);
|
|
|
|
if (state->m_localFolderInfo)
|
|
state->m_localFolderInfo->UpdatePendingCounts(state->m_imapFolderInfo,
|
|
&state->m_msgKeys,
|
|
FALSE);
|
|
state->m_imapFolderInfo->SummaryChanged();
|
|
}
|
|
}
|
|
state->m_status = state->DeliverDone();
|
|
}
|
|
NET_FreeURLStruct(url);
|
|
}
|
|
|
|
/* static */ void
|
|
MSG_DeliverQueuedMailState::PostCreateIMAPSentFolder(URL_Struct *url,
|
|
int status,
|
|
MWContext *context)
|
|
{
|
|
MSG_DeliverQueuedMailState *state =
|
|
(MSG_DeliverQueuedMailState*) url->fe_data;
|
|
XP_ASSERT(state);
|
|
|
|
if (state)
|
|
{
|
|
if (status < 0)
|
|
{
|
|
char *error_msg = 0;
|
|
error_msg = url->error_msg;
|
|
url->error_msg = 0;
|
|
if (!error_msg)
|
|
error_msg = NET_ExplainErrorDetails (status, 0, 0, 0,
|
|
0);
|
|
state->Error (error_msg);
|
|
state->m_status = state->DeliverDone();
|
|
FREEIF(error_msg);
|
|
}
|
|
else
|
|
{
|
|
MSG_Master::PostCreateImapFolderUrlExitFunc (url,
|
|
status,
|
|
context);
|
|
|
|
char *folderName = IMAP_CreateOnlineSourceFolderNameFromUrl(
|
|
url->address);
|
|
char *hostName = NET_ParseURL(url->address, GET_HOST_PART);
|
|
state->m_imapFolderInfo =
|
|
state->m_pane->GetMaster()->FindImapMailFolder(hostName, folderName, NULL, FALSE);
|
|
FREEIF(hostName);
|
|
XP_ASSERT(state->m_imapFolderInfo);
|
|
|
|
if (state->m_imapFolderInfo)
|
|
{
|
|
state->m_imapFolderInfo->SetFlag(MSG_FOLDER_FLAG_SENTMAIL);
|
|
state->AppendToIMAPSentFolder();
|
|
}
|
|
else
|
|
state->m_status = state->DeliverDone();
|
|
}
|
|
}
|
|
NET_FreeURLStruct(url);
|
|
}
|
|
|
|
|
|
void
|
|
MSG_DeliverQueuedMailState::PostListIMAPSentFolder ( URL_Struct *url,
|
|
int status,
|
|
MWContext *)
|
|
{
|
|
MSG_DeliverQueuedMailState *state =
|
|
(MSG_DeliverQueuedMailState*) url->fe_data;
|
|
XP_ASSERT(state);
|
|
|
|
if (state)
|
|
{
|
|
if (status < 0)
|
|
{
|
|
char *error_msg = 0;
|
|
error_msg = url->error_msg;
|
|
url->error_msg = 0;
|
|
if (!error_msg)
|
|
error_msg = NET_ExplainErrorDetails (status, 0, 0, 0,
|
|
0);
|
|
state->Error (error_msg);
|
|
state->m_status = state->DeliverDone();
|
|
FREEIF(error_msg);
|
|
}
|
|
else
|
|
{
|
|
state->m_pane->SetIMAPListInProgress(FALSE);
|
|
if (state->m_pane->IMAPListMailboxExist())
|
|
{
|
|
state->AppendToIMAPSentFolder();
|
|
}
|
|
else
|
|
{
|
|
char *buf = NULL;
|
|
URL_Struct *url_struct = NULL;
|
|
char *host = NET_ParseURL(state->m_fcc, GET_HOST_PART);
|
|
char *name = NET_ParseURL(state->m_fcc, GET_PATH_PART);
|
|
|
|
// *** Create Imap magic folder
|
|
// *** then append message to the folder
|
|
if (!name || !*name)
|
|
{
|
|
XP_FREEIF(name);
|
|
name = PR_smprintf("/%s", SENT_FOLDER_NAME);
|
|
}
|
|
|
|
if (host && *host && name && *name)
|
|
{
|
|
buf = CreateImapMailboxCreateUrl
|
|
(host, name+1, kOnlineHierarchySeparatorUnknown);
|
|
if (buf)
|
|
{
|
|
url_struct = NET_CreateURLStruct(buf, NET_NORMAL_RELOAD);
|
|
if (url_struct)
|
|
{
|
|
url_struct->fe_data = state;
|
|
url_struct->internal_url = TRUE;
|
|
url_struct->msg_pane = state->m_pane;
|
|
state->m_pane->GetContext()->imapURLPane =
|
|
state->m_pane;
|
|
MSG_UrlQueue::AddUrlToPane
|
|
(url_struct, PostCreateIMAPSentFolder,
|
|
state->m_pane, TRUE);
|
|
}
|
|
XP_FREEIF(buf);
|
|
}
|
|
}
|
|
XP_FREEIF(host);
|
|
XP_FREEIF(name);
|
|
}
|
|
}
|
|
}
|
|
NET_FreeURLStruct(url);
|
|
}
|
|
|
|
|
|
void
|
|
MSG_DeliverQueuedMailState::ImapAppendAddBccHeadersIfNeeded( URL_Struct *url)
|
|
{
|
|
XP_ASSERT(url);
|
|
const char *bcc_headers = m_bcc;
|
|
char *post_data = NULL;
|
|
if (bcc_headers && *bcc_headers)
|
|
{
|
|
post_data = WH_TempName(xpFileToPost, "nsmail");
|
|
if (post_data)
|
|
{
|
|
XP_File dstFile = XP_FileOpen(post_data, xpFileToPost, XP_FILE_WRITE_BIN);
|
|
if (dstFile)
|
|
{
|
|
XP_File srcFile = XP_FileOpen(m_tmpName, xpFileToPost,
|
|
XP_FILE_READ_BIN);
|
|
if (srcFile)
|
|
{
|
|
char *tmpBuffer = (char *)XP_ALLOC(4096);
|
|
int bytesRead = 0;
|
|
if (tmpBuffer)
|
|
{
|
|
XP_FileWrite("Bcc: ", 5, dstFile);
|
|
XP_FileWrite(bcc_headers, XP_STRLEN(bcc_headers),
|
|
dstFile);
|
|
XP_FileWrite(CRLF, XP_STRLEN(CRLF), dstFile);
|
|
bytesRead = XP_FileRead(tmpBuffer, 4096, srcFile);
|
|
while (bytesRead > 0)
|
|
{
|
|
XP_FileWrite(tmpBuffer, bytesRead, dstFile);
|
|
bytesRead = XP_FileRead(tmpBuffer, 4096,
|
|
srcFile);
|
|
}
|
|
XP_FREE(tmpBuffer);
|
|
}
|
|
XP_FileClose(srcFile);
|
|
}
|
|
XP_FileClose(dstFile);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
post_data = XP_STRDUP(m_tmpName);
|
|
}
|
|
|
|
if (post_data)
|
|
{
|
|
url->post_data = post_data;
|
|
url->post_data_size = XP_STRLEN(post_data);
|
|
url->post_data_is_file = TRUE;
|
|
url->method = URL_POST_METHOD;
|
|
url->fe_data = this;
|
|
url->internal_url = TRUE;
|
|
url->msg_pane = m_pane;
|
|
m_pane->GetContext()->imapURLPane = m_pane;
|
|
|
|
MSG_UrlQueue::AddUrlToPane
|
|
(url, PostAppendToIMAPSentFolder, m_pane, TRUE);
|
|
}
|
|
else
|
|
{
|
|
NET_FreeURLStruct(url);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
MSG_DeliverQueuedMailState::AppendToIMAPSentFolder()
|
|
{
|
|
char *host = NET_ParseURL(m_fcc, GET_HOST_PART);
|
|
char *name = NET_ParseURL(m_fcc, GET_PATH_PART);
|
|
char *owner = NET_ParseURL(m_fcc, GET_USERNAME_PART);
|
|
|
|
if (!name || !*name)
|
|
{
|
|
XP_FREEIF(name);
|
|
name = PR_smprintf("/%s", SENT_FOLDER_NAME);
|
|
}
|
|
if (!owner || !*owner)
|
|
{
|
|
MSG_IMAPHost *imapHost = m_pane->GetMaster()->GetIMAPHost(host);
|
|
if (imapHost && imapHost->GetDefaultNamespacePrefixOfType(kPersonalNamespace))
|
|
StrAllocCopy(owner, imapHost->GetUserName());
|
|
}
|
|
|
|
m_imapFolderInfo =
|
|
m_pane->GetMaster()->FindImapMailFolder(host, name+1, owner, FALSE);
|
|
|
|
char *urlBuf = NULL;
|
|
URL_Struct *url = NULL;
|
|
|
|
if (m_imapFolderInfo)
|
|
{
|
|
MSG_Pane *urlPane = NULL;
|
|
|
|
if (!urlPane)
|
|
urlPane = m_pane;
|
|
// *** append message to IMAP Send folder
|
|
urlBuf =
|
|
CreateImapAppendMessageFromFileUrl(
|
|
m_imapFolderInfo->GetHostName(),
|
|
m_imapFolderInfo->GetOnlineName(),
|
|
m_imapFolderInfo->GetOnlineHierarchySeparator(),
|
|
FALSE);
|
|
if (urlBuf)
|
|
{
|
|
url = NET_CreateURLStruct (urlBuf, NET_NORMAL_RELOAD);
|
|
if (url)
|
|
{
|
|
ImapAppendAddBccHeadersIfNeeded(url);
|
|
}
|
|
XP_FREEIF(urlBuf);
|
|
}
|
|
}
|
|
else if (m_pane->IMAPListMailboxExist())
|
|
{
|
|
// m_pane->SetIMAPListMailboxExist(FALSE);
|
|
// *** append message to not subscribed IMAP Send folder
|
|
urlBuf =
|
|
CreateImapAppendMessageFromFileUrl(host, name,
|
|
kOnlineHierarchySeparatorUnknown,
|
|
FALSE);
|
|
if (urlBuf)
|
|
{
|
|
url = NET_CreateURLStruct (urlBuf, NET_NORMAL_RELOAD);
|
|
if (url)
|
|
{
|
|
ImapAppendAddBccHeadersIfNeeded(url);
|
|
}
|
|
XP_FREEIF(urlBuf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// *** List not subscribed IMAP Sent Folder
|
|
urlBuf =
|
|
CreateImapListUrl(host, name, kOnlineHierarchySeparatorUnknown);
|
|
if (urlBuf)
|
|
{
|
|
url = NET_CreateURLStruct(urlBuf, NET_NORMAL_RELOAD);
|
|
if (url)
|
|
{
|
|
url->fe_data = this;
|
|
url->internal_url = TRUE;
|
|
url->msg_pane = m_pane;
|
|
if (!m_context)
|
|
SetContext(m_pane->GetContext());
|
|
m_pane->GetContext()->imapURLPane = m_pane;
|
|
m_pane->SetIMAPListInProgress(TRUE);
|
|
MSG_UrlQueue::AddUrlToPane (url, PostListIMAPSentFolder,
|
|
m_pane, TRUE);
|
|
}
|
|
XP_FREEIF(urlBuf);
|
|
}
|
|
}
|
|
XP_FREEIF(host);
|
|
XP_FREEIF(name);
|
|
XP_FREEIF(owner);
|
|
}
|
|
|
|
int
|
|
MSG_DeliverQueuedMailState::DoFcc ()
|
|
{
|
|
const char *bcc = m_bcc;
|
|
const char *fcc = m_fcc;
|
|
if (bcc) while (XP_IS_SPACE(*bcc)) bcc++;
|
|
if (fcc) while (XP_IS_SPACE(*fcc)) fcc++;
|
|
|
|
if (fcc && *fcc)
|
|
{
|
|
// check if we are fccing to an an imap server
|
|
if (NET_URL_Type(fcc) == IMAP_TYPE_URL)
|
|
{
|
|
if (m_pane->GetMaster()->GetPrefs()->GetMailServerIsIMAP4())
|
|
{
|
|
AppendToIMAPSentFolder();
|
|
return m_status;
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int status = msg_DoFCC (m_pane,
|
|
m_tmpName, xpFileToPost,
|
|
fcc, xpMailFolder,
|
|
bcc, fcc);
|
|
if (status < 0)
|
|
Error (/* #### slightly wrong error */
|
|
XP_GetString (MK_MSG_COULDNT_OPEN_FCC_FILE));
|
|
else
|
|
{
|
|
// this is normally done in the DeliverDoneCB, but that doesn't seem
|
|
// to be used when delivering queued mail
|
|
MSG_FolderInfo *folder = m_pane->GetMaster()->FindMailFolder (fcc, FALSE /*create?*/);
|
|
if (folder)
|
|
folder->SummaryChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
m_status = DeliverDone ();
|
|
return m_status;
|
|
}
|
|
|
|
void MSG_DeliverQueuedMailState::Error(const char *error_msg)
|
|
{
|
|
XP_ASSERT( error_msg);
|
|
|
|
m_deliveryFailed = TRUE;
|
|
|
|
if (!error_msg)
|
|
{
|
|
m_done = TRUE;
|
|
}
|
|
else
|
|
{
|
|
char *s, *s2;
|
|
int L;
|
|
XP_Bool cont = FALSE;
|
|
|
|
s2 = XP_GetString(MK_MSG_QUEUED_DELIVERY_FAILED);
|
|
|
|
L = XP_STRLEN(error_msg) + XP_STRLEN(s2) + 1;
|
|
s = (char *) XP_ALLOC(L);
|
|
if (!s)
|
|
{
|
|
m_done = TRUE;
|
|
return;
|
|
}
|
|
PR_snprintf (s, L, s2, error_msg);
|
|
cont = FE_Confirm (m_context, s);
|
|
XP_FREE(s);
|
|
|
|
if (cont)
|
|
m_status = 0;
|
|
else
|
|
m_done = TRUE;
|
|
}
|
|
}
|
|
|
|
/* This function parses the headers, and also deletes from the header block
|
|
any headers which should not be delivered in mail, regardless of whether
|
|
they were present in the queue file. Such headers include: BCC, FCC,
|
|
Sender, X-Mozilla-Status, X-Mozilla-News-Host, and Content-Length.
|
|
(Content-Length is for the disk file only, and must not be allowed to
|
|
escape onto the network, since it depends on the local linebreak
|
|
representation. Arguably, we could allow Lines to escape, but it's not
|
|
required by NNTP.)
|
|
*/
|
|
int32 MSG_DeliverQueuedMailState::HackHeaders()
|
|
{
|
|
char *buf = m_headers;
|
|
char *buf_end = buf + m_headersFP;
|
|
|
|
FREEIF(m_to);
|
|
FREEIF(m_bcc);
|
|
FREEIF(m_newsgroups);
|
|
FREEIF(m_newshost);
|
|
m_flags = 0;
|
|
|
|
if (m_pane)
|
|
m_pane->SetRequestForReturnReceipt(FALSE);
|
|
|
|
while (buf < buf_end)
|
|
{
|
|
XP_Bool prune_p = FALSE;
|
|
XP_Bool do_flags_p = FALSE;
|
|
XP_Bool do_return_receipt_p = FALSE;
|
|
char *colon = XP_STRCHR (buf, ':');
|
|
char *end;
|
|
char *value = 0;
|
|
char **header = 0;
|
|
char *header_start = buf;
|
|
|
|
if (! colon)
|
|
break;
|
|
|
|
end = colon;
|
|
while (end > buf && (*end == ' ' || *end == '\t'))
|
|
end--;
|
|
|
|
switch (buf [0])
|
|
{
|
|
case 'B': case 'b':
|
|
if (!strncasecomp ("BCC", buf, end - buf))
|
|
{
|
|
header = &m_bcc;
|
|
prune_p = TRUE;
|
|
}
|
|
break;
|
|
case 'C': case 'c':
|
|
if (!strncasecomp ("CC", buf, end - buf))
|
|
header = &m_to;
|
|
else if (!strncasecomp (CONTENT_LENGTH, buf, end - buf))
|
|
prune_p = TRUE;
|
|
break;
|
|
case 'F': case 'f':
|
|
if (!strncasecomp ("FCC", buf, end - buf))
|
|
{
|
|
header = &m_fcc;
|
|
prune_p = TRUE;
|
|
}
|
|
break;
|
|
case 'L': case 'l':
|
|
if (!strncasecomp ("Lines", buf, end - buf))
|
|
prune_p = TRUE;
|
|
break;
|
|
case 'N': case 'n':
|
|
if (!strncasecomp ("Newsgroups", buf, end - buf))
|
|
header = &m_newsgroups;
|
|
break;
|
|
case 'S': case 's':
|
|
if (!strncasecomp ("Sender", buf, end - buf))
|
|
prune_p = TRUE;
|
|
break;
|
|
case 'T': case 't':
|
|
if (!strncasecomp ("To", buf, end - buf))
|
|
header = &m_to;
|
|
break;
|
|
case 'X': case 'x':
|
|
if (X_MOZILLA_STATUS2_LEN == end - buf &&
|
|
!strncasecomp(X_MOZILLA_STATUS2, buf, end - buf))
|
|
prune_p = TRUE;
|
|
else if (X_MOZILLA_STATUS_LEN == end - buf &&
|
|
!strncasecomp(X_MOZILLA_STATUS, buf, end - buf))
|
|
prune_p = do_flags_p = TRUE;
|
|
else if (!strncasecomp(X_MOZILLA_DRAFT_INFO, buf, end - buf))
|
|
prune_p = do_return_receipt_p = TRUE;
|
|
else if (!strncasecomp(X_MOZILLA_NEWSHOST, buf, end - buf))
|
|
{
|
|
prune_p = TRUE;
|
|
header = &m_newshost;
|
|
}
|
|
break;
|
|
}
|
|
|
|
buf = colon + 1;
|
|
while (*buf == ' ' || *buf == '\t')
|
|
buf++;
|
|
|
|
value = buf;
|
|
|
|
SEARCH_NEWLINE:
|
|
while (*buf != 0 && *buf != CR && *buf != LF)
|
|
buf++;
|
|
|
|
if (buf+1 >= buf_end)
|
|
;
|
|
/* If "\r\n " or "\r\n\t" is next, that doesn't terminate the header. */
|
|
else if (buf+2 < buf_end &&
|
|
(buf[0] == CR && buf[1] == LF) &&
|
|
(buf[2] == ' ' || buf[2] == '\t'))
|
|
{
|
|
buf += 3;
|
|
goto SEARCH_NEWLINE;
|
|
}
|
|
/* If "\r " or "\r\t" or "\n " or "\n\t" is next, that doesn't terminate
|
|
the header either. */
|
|
else if ((buf[0] == CR || buf[0] == LF) &&
|
|
(buf[1] == ' ' || buf[1] == '\t'))
|
|
{
|
|
buf += 2;
|
|
goto SEARCH_NEWLINE;
|
|
}
|
|
|
|
if (header)
|
|
{
|
|
int L = buf - value;
|
|
if (*header)
|
|
{
|
|
char *newh = (char*) XP_REALLOC ((*header),
|
|
XP_STRLEN(*header) + L + 10);
|
|
if (!newh) return MK_OUT_OF_MEMORY;
|
|
*header = newh;
|
|
newh = (*header) + XP_STRLEN (*header);
|
|
*newh++ = ',';
|
|
*newh++ = ' ';
|
|
XP_MEMCPY (newh, value, L);
|
|
newh [L] = 0;
|
|
}
|
|
else
|
|
{
|
|
*header = (char *) XP_ALLOC(L+1);
|
|
if (!*header) return MK_OUT_OF_MEMORY;
|
|
XP_MEMCPY ((*header), value, L);
|
|
(*header)[L] = 0;
|
|
}
|
|
}
|
|
else if (do_flags_p)
|
|
{
|
|
int i;
|
|
char *s = value;
|
|
XP_ASSERT(*s != ' ' && *s != '\t');
|
|
m_flags = 0;
|
|
for (i=0 ; i<4 ; i++) {
|
|
m_flags = (m_flags << 4) | UNHEX(*s);
|
|
s++;
|
|
}
|
|
}
|
|
else if (do_return_receipt_p)
|
|
{
|
|
int L = buf - value;
|
|
char *draftInfo = (char*) XP_ALLOC(L+1);
|
|
char *receipt = NULL;
|
|
if (!draftInfo) return MK_OUT_OF_MEMORY;
|
|
XP_MEMCPY(draftInfo, value, L);
|
|
*(draftInfo+L)=0;
|
|
receipt = XP_STRSTR(draftInfo, "receipt=");
|
|
if (receipt)
|
|
{
|
|
char *s = receipt+8;
|
|
int requestForReturnReceipt = 0;
|
|
sscanf(s, "%d", &requestForReturnReceipt);
|
|
if ((requestForReturnReceipt == 2 ||
|
|
requestForReturnReceipt == 3) && m_pane)
|
|
m_pane->SetRequestForReturnReceipt(TRUE);
|
|
}
|
|
XP_FREEIF(draftInfo);
|
|
}
|
|
|
|
if (*buf == CR || *buf == LF)
|
|
{
|
|
if (*buf == CR && buf[1] == LF)
|
|
buf++;
|
|
buf++;
|
|
}
|
|
|
|
if (prune_p)
|
|
{
|
|
char *to = header_start;
|
|
char *from = buf;
|
|
while (from < buf_end)
|
|
*to++ = *from++;
|
|
buf = header_start;
|
|
buf_end = to;
|
|
m_headersFP = buf_end - m_headers;
|
|
}
|
|
}
|
|
|
|
/* Print a message if this message isn't already expunged. */
|
|
if ((m_flags & MSG_FLAG_QUEUED) &&
|
|
(! (m_flags & MSG_FLAG_EXPUNGED)))
|
|
{
|
|
char buf[100];
|
|
const char *fmt = XP_GetString(MK_MSG_DELIVERING_MESSAGE);
|
|
|
|
m_msgNumber++;
|
|
PR_snprintf(buf, sizeof(buf)-1, fmt, (long) m_msgNumber);
|
|
FE_Progress(m_context, buf);
|
|
}
|
|
else if ((! (m_flags & MSG_FLAG_QUEUED)) &&
|
|
(! (m_flags & MSG_FLAG_EXPUNGED)))
|
|
{
|
|
/* Ugh! a non-expunged message without its queued bit set!
|
|
How did that get in here? Danger, danger. */
|
|
m_bogusMessageCount++;
|
|
}
|
|
|
|
/* Now m_headers contains only the headers we should ship.
|
|
Write them to the file;
|
|
*/
|
|
m_headers [m_headersFP++] = CR;
|
|
m_headers [m_headersFP++] = LF;
|
|
if (XP_FileWrite (m_headers, m_headersFP,
|
|
m_outfile) < m_headersFP) {
|
|
return MK_MIME_ERROR_WRITING_FILE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
#define msg_grow_headers(desired_size) \
|
|
(((desired_size) >= m_headersSize) ? \
|
|
msg_GrowBuffer ((desired_size), sizeof(char), 1024, \
|
|
&m_headers, &m_headersSize) \
|
|
: 0)
|
|
|
|
int32
|
|
MSG_DeliverQueuedMailState::DeliverQueuedLine(char *line, uint32 length)
|
|
{
|
|
uint32 flength = length;
|
|
|
|
m_bytesRead += length;
|
|
FE_SetProgressBarPercent(m_context,
|
|
((m_bytesRead * 100)
|
|
/ m_folderSize));
|
|
|
|
/* convert existing newline to CRLF */
|
|
if (length > 0 &&
|
|
(line[length-1] == CR ||
|
|
(line[length-1] == LF &&
|
|
(length < 2 || line[length-2] != CR))))
|
|
{
|
|
line[length-1] = CR;
|
|
line[length++] = LF;
|
|
}
|
|
|
|
if (line[0] == 'F' && msg_IsEnvelopeLine(line, length))
|
|
{
|
|
XP_ASSERT (!m_inhead); /* else folder corrupted */
|
|
|
|
if (!m_inhead &&
|
|
m_headersFP > 0)
|
|
{
|
|
m_status = DeliverQueuedMessage ();
|
|
if (m_status < 0) return m_status;
|
|
}
|
|
m_headersFP = 0;
|
|
m_headersPosition = 0;
|
|
m_inhead = TRUE;
|
|
}
|
|
else if (m_inhead)
|
|
{
|
|
if (m_headersPosition == 0)
|
|
{
|
|
/* This line is the first line in a header block.
|
|
Remember its position. */
|
|
m_headersPosition = m_position;
|
|
|
|
/* Also, since we're now processing the headers, clear out the
|
|
slots which we will parse data into, so that the values that
|
|
were used the last time around do not persist.
|
|
|
|
We must do that here, and not in the previous clause of this
|
|
`else' (the "I've just seen a `From ' line clause") because
|
|
that clause happens before delivery of the previous message is
|
|
complete, whereas this clause happens after the previous msg
|
|
has been delivered. If we did this up there, then only the
|
|
last message in the folder would ever be able to be both
|
|
mailed and posted (or fcc'ed.)
|
|
*/
|
|
FREEIF(m_to);
|
|
FREEIF(m_bcc);
|
|
FREEIF(m_newsgroups);
|
|
FREEIF(m_newshost);
|
|
FREEIF(m_fcc);
|
|
}
|
|
|
|
if (line[0] == CR || line[0] == LF || line[0] == 0)
|
|
{
|
|
/* End of headers. Now parse them; open the temp file;
|
|
and write the appropriate subset of the headers out. */
|
|
m_inhead = FALSE;
|
|
|
|
m_tmpName = WH_TempName (xpFileToPost, "nsqmail");
|
|
if (!m_tmpName)
|
|
return MK_OUT_OF_MEMORY;
|
|
m_outfile = XP_FileOpen (m_tmpName, xpFileToPost,
|
|
XP_FILE_WRITE_BIN);
|
|
if (!m_outfile)
|
|
return MK_MIME_ERROR_WRITING_FILE;
|
|
|
|
m_status = HackHeaders ();
|
|
if (m_status < 0) return m_status;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, this line belongs to a header. So append it to the
|
|
header data. */
|
|
|
|
if (!strncasecomp (line, X_MOZILLA_STATUS, X_MOZILLA_STATUS_LEN))
|
|
/* Notice the position of the flags. */
|
|
m_flagsPosition = m_position;
|
|
else if (m_headersFP == 0)
|
|
m_flagsPosition = 0;
|
|
|
|
m_status = msg_grow_headers (length + m_headersFP + 10);
|
|
if (m_status < 0) return m_status;
|
|
|
|
XP_MEMCPY (m_headers + m_headersFP, line, length);
|
|
m_headersFP += length;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* This is a body line. Write it to the file. */
|
|
XP_ASSERT (m_outfile);
|
|
if (m_outfile)
|
|
{
|
|
m_status = XP_FileWrite (line, length, m_outfile);
|
|
if (m_status < (int32) length) return MK_MIME_ERROR_WRITING_FILE;
|
|
}
|
|
}
|
|
|
|
m_position += flength;
|
|
return 0;
|
|
}
|
|
|