Bug 239583 - mail lost when getting fetchmailed messages.

r=bienvenu@nventure.com, sr=mscott@mozilla.org, a=chofmann@mozilla.org
This commit is contained in:
pkw%us.ibm.com 2004-04-09 13:32:35 +00:00
Родитель f550d05efe
Коммит 91f9527d19
1 изменённых файлов: 175 добавлений и 192 удалений

Просмотреть файл

@ -70,6 +70,10 @@
#include "nsCOMPtr.h"
#include "nsMsgFolderFlags.h"
#include "nsILineInputStream.h"
#include "nsNetUtil.h"
#include "nsAutoPtr.h"
#include "prlog.h"
#if defined(PR_LOGGING)
//
@ -178,10 +182,9 @@ PRBool ObtainSpoolLock(const char *spoolnameStr,
nsresult rv;
// Create nsFileSpec and nsILocalFile for the spool.mozlock file
nsFileSpec tmplocspec(mozlockstr.get());
// Create nsILocalFile for the spool.mozlock file
nsCOMPtr<nsILocalFile> tmplocfile;
rv = NS_FileSpecToIFile(&tmplocspec, getter_AddRefs(tmplocfile));
rv = NS_NewNativeLocalFile(mozlockstr, PR_TRUE, getter_AddRefs(tmplocfile));
if (NS_FAILED(rv))
return PR_FALSE;
// THOUGHT: hmm, perhaps use MakeUnique to generate us a unique mozlock?
@ -189,7 +192,7 @@ PRBool ObtainSpoolLock(const char *spoolnameStr,
// step 1: create SPOOLNAME.mozlock
rv = tmplocfile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);
if ( NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
// can't create our .mozlock file... game over already
LOG(("Failed to create file %s\n", mozlockstr.get()));
return PR_FALSE;
@ -203,19 +206,17 @@ PRBool ObtainSpoolLock(const char *spoolnameStr,
int retry_count = 0;
do {
link_result =
link(mozlockstr.get(),lockstr.get());
link_result = link(mozlockstr.get(),lockstr.get());
retry_count++;
LOG(("Attempt %d of %d to create lock file", retry_count, seconds));
if ((seconds > 0) &&
(link_result == -1)) {
if (seconds > 0 && link_result == -1) {
// pause 1sec, waiting for .lock to go away
PRIntervalTime sleepTime = 1000; // 1 second
PR_Sleep(sleepTime);
}
} while ((link_result == -1) && (retry_count < seconds));
} while (link_result == -1 && retry_count < seconds);
LOG(("Link result: %d", link_result));
// step 3: remove .mozlock file, in any case
@ -245,10 +246,9 @@ PRBool YieldSpoolLock(const char *spoolnameStr)
nsresult rv;
// Create nsFileSpec and nsILocalFile for the spool.lock file
nsFileSpec locklocspec(lockstr.get());
// Create nsILocalFile for the spool.lock file
nsCOMPtr<nsILocalFile> locklocfile;
rv = NS_FileSpecToIFile(&locklocspec, getter_AddRefs(locklocfile));
rv = NS_NewNativeLocalFile(lockstr, PR_TRUE, getter_AddRefs(locklocfile));
if (NS_FAILED(rv))
return PR_FALSE;
@ -271,6 +271,48 @@ PRBool YieldSpoolLock(const char *spoolnameStr)
return PR_TRUE;
}
static nsresult
LocateSpoolFile(nsACString & spoolPath)
{
PRBool isFile;
nsresult rv;
nsCOMPtr<nsILocalFile> spoolFile;
rv = NS_NewNativeLocalFile(nsCString(), PR_TRUE, getter_AddRefs(spoolFile));
NS_ENSURE_SUCCESS(rv, rv);
char * mailEnv = PR_GetEnv("MAIL");
char * userEnv = PR_GetEnv("USER");
if (!userEnv)
userEnv = PR_GetEnv("USERNAME");
if (mailEnv) {
rv = spoolFile->InitWithNativePath(nsDependentCString(mailEnv));
NS_ENSURE_SUCCESS(rv, rv);
rv = spoolFile->IsFile(&isFile);
if (NS_SUCCEEDED(rv) && isFile)
spoolPath = mailEnv;
}
else if (userEnv) {
// Try to build the mailbox path from the username and a number
// of guessed spool directory paths.
nsCAutoString tmpPath;
PRUint32 i;
for (i = 0; i < NUM_DEFAULT_SPOOL_PATHS; i++) {
tmpPath = gDefaultSpoolPaths[i];
tmpPath += userEnv;
rv = spoolFile->InitWithNativePath(tmpPath);
NS_ENSURE_SUCCESS(rv, rv);
rv = spoolFile->IsFile(&isFile);
if (NS_SUCCEEDED(rv) && isFile) {
spoolPath = tmpPath;
break;
}
}
}
return rv;
}
nsresult
nsMovemailService::GetNewMail(nsIMsgWindow *aMsgWindow,
@ -287,196 +329,137 @@ nsMovemailService::GetNewMail(nsIMsgWindow *aMsgWindow,
if (!in_server)
return NS_MSG_INVALID_OR_MISSING_SERVER;
mMsgWindow = aMsgWindow;
nsCAutoString wholeboxname;
// Attempt to locate the mail spool file
nsCAutoString spoolPath;
rv = LocateSpoolFile(spoolPath);
if (NS_FAILED(rv) || spoolPath.IsEmpty()) {
Error(MOVEMAIL_SPOOL_FILE_NOT_FOUND, nsnull, 0);
return NS_ERROR_FAILURE;
}
// Create an input stream for the spool file
nsCOMPtr<nsILocalFile> spoolFile;
rv = NS_NewNativeLocalFile(spoolPath, PR_TRUE, getter_AddRefs(spoolFile));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInputStream> spoolInputStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(spoolInputStream), spoolFile);
if (NS_FAILED(rv)) {
const PRUnichar *params[] = {
NS_ConvertUTF8toUCS2(spoolPath).get()
};
Error(MOVEMAIL_CANT_OPEN_SPOOL_FILE, params, 1);
return rv;
}
// Get a line input interface for the spool file
nsCOMPtr<nsILineInputStream> lineInputStream =
do_QueryInterface(spoolInputStream, &rv);
if (!lineInputStream)
return rv;
nsCOMPtr<nsIFileSpec> mailDirectory;
rv = in_server->GetLocalPath(getter_AddRefs(mailDirectory));
NS_ENSURE_SUCCESS(rv, rv);
nsFileSpec fileSpec;
mailDirectory->GetFileSpec(&fileSpec);
fileSpec += "Inbox";
nsIOFileStream outFileStream(fileSpec);
outFileStream.seek(fileSpec.GetFileSize());
nsCOMPtr<nsIMsgFolder> serverFolder;
nsCOMPtr<nsIMsgFolder> inbox;
nsCOMPtr<nsIMsgFolder> rootMsgFolder;
// create a new mail parser
nsRefPtr<nsParseNewMailState> newMailParser = new nsParseNewMailState;
if (newMailParser == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
rv = in_server->GetRootFolder(getter_AddRefs(serverFolder));
NS_ENSURE_SUCCESS(rv, rv);
rootMsgFolder = do_QueryInterface(serverFolder, &rv);
if (!rootMsgFolder)
return rv;
PRUint32 numFolders;
rv = rootMsgFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, 1,
&numFolders,
getter_AddRefs(inbox));
NS_ENSURE_SUCCESS(rv, rv);
rv = newMailParser->Init(serverFolder, inbox,
fileSpec, &outFileStream, nsnull);
NS_ENSURE_SUCCESS(rv, rv);
in_server->SetServerBusy(PR_TRUE);
// FUN STUFF starts here
{
// we now quest for the mail spool file...
nsFileSpec spoolFileSpec;
PRBool foundSpoolFile = PR_FALSE;
// If $(MAIL) is set then we have things easy.
char * mailEnv = PR_GetEnv("MAIL");
char * userEnv = PR_GetEnv("USER");
if (!userEnv)
userEnv = PR_GetEnv("USERNAME");
if (mailEnv) {
wholeboxname = mailEnv;
spoolFileSpec = wholeboxname.get();
foundSpoolFile = (spoolFileSpec.Valid() && spoolFileSpec.IsFile());
} else if (userEnv) {
// Otherwise try to build the mailbox path from the
// username and a number of guessed spool directory
// paths.
int i;
for (i = 0; i < NUM_DEFAULT_SPOOL_PATHS && !foundSpoolFile; i++) {
wholeboxname = gDefaultSpoolPaths[i];
wholeboxname += userEnv;
spoolFileSpec = wholeboxname.get();
foundSpoolFile = (spoolFileSpec.Valid() && spoolFileSpec.IsFile());
}
}
if (!foundSpoolFile) {
Error(MOVEMAIL_SPOOL_FILE_NOT_FOUND, nsnull, 0);
return NS_ERROR_FAILURE;
}
nsInputFileStream spoolfile(spoolFileSpec);
if (!spoolfile.is_open() || spoolfile.failed()) {
const PRUnichar *params[] = {
NS_ConvertUTF8toUCS2(wholeboxname).get()
};
Error(MOVEMAIL_CANT_OPEN_SPOOL_FILE, params, 1);
return NS_ERROR_FAILURE;
}
// Try and obtain the lock for the spool file
if (!ObtainSpoolLock(wholeboxname.get(), 5)) {
nsAutoString lockFile = NS_ConvertUTF8toUCS2(wholeboxname);
lockFile += NS_LITERAL_STRING(".lock");
const PRUnichar *params[] = {
lockFile.get()
};
Error(MOVEMAIL_CANT_CREATE_LOCK, params, 1);
return NS_ERROR_FAILURE;
}
// Try and obtain the lock for the spool file
if (!ObtainSpoolLock(spoolPath.get(), 5)) {
nsAutoString lockFile = NS_ConvertUTF8toUCS2(spoolPath);
lockFile += NS_LITERAL_STRING(".lock");
const PRUnichar *params[] = {
lockFile.get()
};
Error(MOVEMAIL_CANT_CREATE_LOCK, params, 1);
return NS_ERROR_FAILURE;
}
#define READBUFSIZE 4096
char * buffer = (char*)PR_CALLOC(READBUFSIZE);
nsParseNewMailState *newMailParser = nsnull;
if (!buffer)
rv = NS_ERROR_OUT_OF_MEMORY;
else {
nsCOMPtr<nsIFileSpec> mailDirectory;
rv = in_server->GetLocalPath(getter_AddRefs(mailDirectory));
if (NS_FAILED(rv))
goto freebuff_and_unlock;
nsFileSpec fileSpec;
mailDirectory->GetFileSpec(&fileSpec);
fileSpec += "Inbox";
nsIOFileStream outFileStream(fileSpec);
outFileStream.seek(fileSpec.GetFileSize());
// create a new mail parser
newMailParser = new nsParseNewMailState;
NS_IF_ADDREF(newMailParser);
if (newMailParser == nsnull) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto freebuff_and_unlock;
}
nsCOMPtr <nsIMsgFolder> serverFolder;
rv = in_server->GetRootFolder(getter_AddRefs(serverFolder));
// MIDDLE of the FUN : consume the mailbox data.
PRBool isMore = PR_TRUE;
nsAutoString bufferUnicode;
nsCAutoString buffer;
if (NS_FAILED(rv))
goto freebuff_and_unlock;
nsCOMPtr<nsIMsgFolder> inbox;
nsCOMPtr<nsIMsgFolder> rootMsgFolder = do_QueryInterface(serverFolder);
if (!rootMsgFolder)
goto freebuff_and_unlock;
PRUint32 numFolders;
rv = rootMsgFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, 1,
&numFolders,
getter_AddRefs(inbox));
if (NS_FAILED(rv))
goto freebuff_and_unlock;
rv = newMailParser->Init(serverFolder, inbox,
fileSpec, &outFileStream, nsnull);
if (NS_FAILED(rv))
goto freebuff_and_unlock;
// MIDDLE of the FUN : consume the mailbox data.
{
int numlines = 0;
while (isMore &&
NS_SUCCEEDED(lineInputStream->ReadLine(bufferUnicode, &isMore)))
{
CopyUCS2toASCII(bufferUnicode, buffer);
// main parsing loop
while (!spoolfile.eof() &&
!spoolfile.failed() &&
spoolfile.is_open())
{
spoolfile.readline(buffer,
READBUFSIZE-(1+PL_strlen(MSG_LINEBREAK)));
// 'From' lines delimit messages
if ((numlines>0) &&
nsCRT::strncmp(buffer, "From ", 5) == 0) {
numlines = 0;
}
// If first string is empty and we're now at EOF
// (or, alternatively, we got a 'From' line and
// then the file mysteriously ended) then abort
// parsing.
if (numlines == 0 && !*buffer && spoolfile.eof()) {
LOG(("Empty spool file"));
break; // end the parsing loop right here
}
PL_strcpy(&buffer[PL_strlen(buffer)], MSG_LINEBREAK);
newMailParser->HandleLine(buffer, PL_strlen(buffer));
outFileStream << buffer;
numlines++;
if (numlines == 1 && !spoolfile.eof()) {
PL_strcpy(buffer, "X-Mozilla-Status: 8000"
MSG_LINEBREAK);
newMailParser->HandleLine(buffer,
PL_strlen(buffer));
outFileStream << buffer;
PL_strcpy(buffer, "X-Mozilla-Status2: 00000000"
MSG_LINEBREAK);
newMailParser->HandleLine(buffer,
PL_strlen(buffer));
outFileStream << buffer;
}
}
}
// END
outFileStream.flush(); // try this.
newMailParser->OnStopRequest(nsnull, nsnull, NS_OK);
newMailParser->SetDBFolderStream(nsnull); // stream is going away
if (outFileStream.is_open())
outFileStream.close();
// truncate the spool file here.
nsFileSpec filespecForTrunc(wholeboxname.get());
rv = filespecForTrunc.Truncate(0);
if (NS_FAILED(rv)) {
const PRUnichar *params[] = {
NS_ConvertUTF8toUCS2(wholeboxname).get()
};
Error(MOVEMAIL_CANT_TRUNCATE_SPOOL_FILE, params, 1);
}
if (spoolfile.is_open())
spoolfile.close();
// If first string is empty and we're now at EOF then abort parsing.
if (buffer.IsEmpty() && !isMore) {
LOG(("Empty spool file"));
break;
}
freebuff_and_unlock:
PR_Free(buffer);
NS_IF_RELEASE(newMailParser);
if (!YieldSpoolLock(wholeboxname.get())) {
nsAutoString spoolLock = NS_ConvertUTF8toUCS2(wholeboxname);
spoolLock += NS_LITERAL_STRING(".lock");
const PRUnichar *params[] = {
spoolLock.get()
};
Error(MOVEMAIL_CANT_DELETE_LOCK, params, 1);
buffer += MSG_LINEBREAK;
newMailParser->HandleLine(buffer.BeginWriting(), buffer.Length());
outFileStream << buffer.get();
// 'From' lines delimit messages
if (isMore && !PL_strncasecmp(buffer.get(), "From ", 5)) {
buffer = NS_LITERAL_CSTRING("X-Mozilla-Status: 8000" MSG_LINEBREAK);
newMailParser->HandleLine(buffer.BeginWriting(), buffer.Length());
outFileStream << buffer.get();
buffer = NS_LITERAL_CSTRING("X-Mozilla-Status2: 00000000" MSG_LINEBREAK);
newMailParser->HandleLine(buffer.BeginWriting(), buffer.Length());
outFileStream << buffer.get();
}
}
outFileStream.flush();
newMailParser->OnStopRequest(nsnull, nsnull, NS_OK);
newMailParser->SetDBFolderStream(nsnull); // stream is going away
if (outFileStream.is_open())
outFileStream.close();
// Truncate the spool file
rv = spoolFile->SetFileSize(0);
if (NS_FAILED(rv)) {
const PRUnichar *params[] = {
NS_ConvertUTF8toUCS2(spoolPath).get()
};
Error(MOVEMAIL_CANT_TRUNCATE_SPOOL_FILE, params, 1);
}
if (!YieldSpoolLock(spoolPath.get())) {
nsAutoString spoolLock = NS_ConvertUTF8toUCS2(spoolPath);
spoolLock += NS_LITERAL_STRING(".lock");
const PRUnichar *params[] = {
spoolLock.get()
};
Error(MOVEMAIL_CANT_DELETE_LOCK, params, 1);
}
in_server->SetServerBusy(PR_FALSE);
LOG(("GetNewMail returning rv=%d", rv));
@ -522,7 +505,7 @@ nsMovemailService::GetDefaultLocalPath(nsIFileSpec ** aResult)
rv = localFile->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return rv;
// Make the resulting nsIFileSpec
// TODO: Convert arg to nsILocalFile and avoid this