NS_IMETHODIMP nsMailDatabase::DeleteMessages(nsTArray<nsMsgKey>* nsMsgKeys, nsIDBChangeListener *instigator) { nsresult rv; if (!m_folderStream && m_folder) { PRBool isLocked; m_folder->GetLocked(&isLocked); if (isLocked) { NS_ASSERTION(PR_FALSE, "Some other operation is in progress"); return NS_MSG_FOLDER_BUSY; } rv = MsgGetFileStream(m_folderFile, getter_AddRefs(m_folderStream)); NS_ENSURE_SUCCESS(rv, rv); m_ownFolderStream = PR_TRUE; } rv = nsMsgDatabase::DeleteMessages(nsMsgKeys, instigator); if (m_ownFolderStream)//only if we own the stream, then we should close it { if (m_folderStream) { m_folderStream->Flush(); // this does a sync m_folderStream->Close(); } m_folderStream = nsnull; m_ownFolderStream = PR_FALSE; } SetFolderInfoValid(m_folderFile, 0, 0); return rv; }
// get output stream from header nsresult nsMsgMaildirStore::GetOutputStream(nsIMsgDBHdr *aHdr, nsCOMPtr<nsIOutputStream> &aOutputStream) { // file name is stored in message header property "storeToken" nsAutoCString fileName; aHdr->GetStringProperty("storeToken", getter_Copies(fileName)); if (fileName.IsEmpty()) return NS_ERROR_FAILURE; nsCOMPtr<nsIMsgFolder> folder; nsresult rv = aHdr->GetFolder(getter_AddRefs(folder)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIFile> folderPath; rv = folder->GetFilePath(getter_AddRefs(folderPath)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIFile> maildirFile; folderPath->Clone(getter_AddRefs(maildirFile)); maildirFile->Append(NS_LITERAL_STRING("cur")); maildirFile->AppendNative(fileName); return MsgGetFileStream(maildirFile, getter_AddRefs(aOutputStream)); }
NS_IMETHODIMP nsMailDatabase::GetFolderStream(nsIOutputStream **aFileStream) { NS_ENSURE_ARG_POINTER(aFileStream); if (!m_folderStream) { nsresult rv = MsgGetFileStream(m_folderFile, getter_AddRefs(m_folderStream)); NS_ENSURE_SUCCESS(rv, rv); m_ownFolderStream = PR_TRUE; } NS_IF_ADDREF(*aFileStream = m_folderStream); return NS_OK; }
// cache m_folderStream to make updating mozilla status flags fast NS_IMETHODIMP nsMailDatabase::StartBatch() { if (!m_folderStream && m_folder) //only if we create a stream, set m_ownFolderStream to true. { PRBool isLocked; m_folder->GetLocked(&isLocked); if (isLocked) { NS_ASSERTION(PR_FALSE, "Some other operation is in progress"); return NS_MSG_FOLDER_BUSY; } nsresult rv = MsgGetFileStream(m_folderFile, getter_AddRefs(m_folderStream)); NS_ENSURE_SUCCESS(rv, rv); m_ownFolderStream = PR_TRUE; } return NS_OK; }
nsresult nsMsgBrkMBoxStore::GetOutputStream(nsIArray *aHdrArray, nsCOMPtr<nsIOutputStream> &outputStream, nsCOMPtr<nsISeekableStream> &seekableStream, int64_t &restorePos) { nsresult rv; nsCOMPtr<nsIMsgDBHdr> msgHdr = do_QueryElementAt(aHdrArray, 0, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIMsgFolder> folder; msgHdr->GetFolder(getter_AddRefs(folder)); NS_ENSURE_SUCCESS(rv, rv); nsCString URI; folder->GetURI(URI); restorePos = -1; if (m_outputStreams.Get(URI, getter_AddRefs(outputStream))) { seekableStream = do_QueryInterface(outputStream); rv = seekableStream->Tell(&restorePos); if (NS_FAILED(rv)) { outputStream = nullptr; m_outputStreams.Remove(URI); } } nsCOMPtr<nsIFile> mboxFile; folder->GetFilePath(getter_AddRefs(mboxFile)); if (!outputStream) { rv = MsgGetFileStream(mboxFile, getter_AddRefs(outputStream)); seekableStream = do_QueryInterface(outputStream); if (NS_SUCCEEDED(rv)) m_outputStreams.Put(URI, outputStream); } return rv; }
NS_IMETHODIMP nsPop3Sink::IncorporateBegin(const char* uidlString, nsIURI* aURL, uint32_t flags, void** closure) { #ifdef DEBUG printf("Incorporate message begin:\n"); if (uidlString) printf("uidl string: %s\n", uidlString); #endif nsCOMPtr<nsIFile> path; m_folder->GetFilePath(getter_AddRefs(path)); nsresult rv; nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); if (pPrefBranch) { nsCOMPtr<nsIMsgIncomingServer> server; m_folder->GetServer(getter_AddRefs(server)); nsCString plugStoreContract; server->GetCharValue("storeContractID", plugStoreContract); // Maildir doesn't care about quaranting, but other stores besides berkeley // mailbox might. We should probably make this an attribute on the pluggable // store, though. if (plugStoreContract.Equals( NS_LITERAL_CSTRING("@mozilla.org/msgstore/berkeleystore;1"))) pPrefBranch->GetBoolPref("mailnews.downloadToTempFile", &m_downloadingToTempFile); } nsCOMPtr<nsIMsgDBHdr> newHdr; nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(m_popServer); if (!server) return NS_ERROR_UNEXPECTED; if (m_downloadingToTempFile) { // need to create an nsIOFileStream from a temp file... nsCOMPtr<nsIFile> tmpDownloadFile; rv = GetSpecialDirectoryWithFileName(NS_OS_TEMP_DIR, "newmsg", getter_AddRefs(tmpDownloadFile)); NS_ASSERTION(NS_SUCCEEDED(rv), "writing tmp pop3 download file: failed to append filename"); if (NS_FAILED(rv)) return rv; if (!m_tmpDownloadFile) { //need a unique tmp file to prevent dataloss in multiuser environment rv = tmpDownloadFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600); NS_ENSURE_SUCCESS(rv, rv); m_tmpDownloadFile = do_QueryInterface(tmpDownloadFile, &rv); } if (NS_SUCCEEDED(rv)) { rv = MsgGetFileStream(m_tmpDownloadFile, getter_AddRefs(m_outFileStream)); NS_ENSURE_SUCCESS(rv, rv); } } else { rv = server->GetMsgStore(getter_AddRefs(m_msgStore)); bool reusable; NS_ENSURE_SUCCESS(rv, rv); m_msgStore->GetNewMsgOutputStream(m_folder, getter_AddRefs(newHdr), &reusable, getter_AddRefs(m_outFileStream)); } // The following (!m_outFileStream etc) was added to make sure that we don't // write somewhere where for some reason or another we can't write to and // lose the messages. See bug 62480 if (!m_outFileStream) return NS_ERROR_OUT_OF_MEMORY; nsCOMPtr<nsISeekableStream> seekableOutStream = do_QueryInterface(m_outFileStream); // create a new mail parser if (!m_newMailParser) m_newMailParser = new nsParseNewMailState; NS_ENSURE_TRUE(m_newMailParser, NS_ERROR_OUT_OF_MEMORY); if (m_uidlDownload) m_newMailParser->DisableFilters(); nsCOMPtr <nsIMsgFolder> serverFolder; rv = GetServerFolder(getter_AddRefs(serverFolder)); if (NS_FAILED(rv)) return rv; rv = m_newMailParser->Init(serverFolder, m_folder, m_window, newHdr, m_outFileStream); // If we failed to initialize the parser, then just don't use it!!! // We can still continue without one. if (NS_FAILED(rv)) { m_newMailParser = nullptr; rv = NS_OK; } if (closure) *closure = (void*) this; nsCString outputString(GetDummyEnvelope()); rv = WriteLineToMailbox(outputString); NS_ENSURE_SUCCESS(rv, rv); // Write out account-key before UIDL so the code that looks for // UIDL will find the account first and know it can stop looking // once it finds the UIDL line. if (!m_accountKey.IsEmpty()) { outputString.AssignLiteral(HEADER_X_MOZILLA_ACCOUNT_KEY ": "); outputString.Append(m_accountKey); outputString.AppendLiteral(MSG_LINEBREAK); rv = WriteLineToMailbox(outputString); NS_ENSURE_SUCCESS(rv, rv); } if (uidlString) { outputString.AssignLiteral("X-UIDL: "); outputString.Append(uidlString); outputString.AppendLiteral(MSG_LINEBREAK); rv = WriteLineToMailbox(outputString); NS_ENSURE_SUCCESS(rv, rv); } // WriteLineToMailbox("X-Mozilla-Status: 8000" MSG_LINEBREAK); char *statusLine = PR_smprintf(X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, flags); outputString.Assign(statusLine); rv = WriteLineToMailbox(outputString); PR_smprintf_free(statusLine); NS_ENSURE_SUCCESS(rv, rv); rv = WriteLineToMailbox(NS_LITERAL_CSTRING("X-Mozilla-Status2: 00000000" MSG_LINEBREAK)); NS_ENSURE_SUCCESS(rv, rv); // leave space for 60 bytes worth of keys/tags rv = WriteLineToMailbox(NS_LITERAL_CSTRING(X_MOZILLA_KEYWORDS)); return NS_OK; }
NS_IMETHODIMP nsMsgBrkMBoxStore::GetNewMsgOutputStream(nsIMsgFolder *aFolder, nsIMsgDBHdr **aNewMsgHdr, bool *aReusable, nsIOutputStream **aResult) { NS_ENSURE_ARG_POINTER(aFolder); NS_ENSURE_ARG_POINTER(aNewMsgHdr); NS_ENSURE_ARG_POINTER(aReusable); NS_ENSURE_ARG_POINTER(aResult); #ifdef _DEBUG NS_ASSERTION(m_streamOutstandingFolder != aFolder, "didn't finish prev msg"); m_streamOutstandingFolder = aFolder; #endif *aReusable = true; nsCOMPtr<nsIFile> mboxFile; aFolder->GetFilePath(getter_AddRefs(mboxFile)); nsCOMPtr<nsIMsgDatabase> db; aFolder->GetMsgDatabase(getter_AddRefs(db)); if (!db && !*aNewMsgHdr) NS_WARNING("no db, and no message header"); bool exists; mboxFile->Exists(&exists); if (!exists) mboxFile->Create(nsIFile::NORMAL_FILE_TYPE, 0600); nsCString URI; aFolder->GetURI(URI); nsresult rv; nsCOMPtr<nsISeekableStream> seekable; if (m_outputStreams.Get(URI, aResult)) { seekable = do_QueryInterface(*aResult, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = seekable->Seek(nsISeekableStream::NS_SEEK_END, 0); if (NS_FAILED(rv)) { m_outputStreams.Remove(URI); NS_RELEASE(*aResult); } } if (!*aResult) { rv = MsgGetFileStream(mboxFile, aResult); NS_ASSERTION(NS_SUCCEEDED(rv), "failed opening offline store for output"); if (NS_FAILED(rv)) printf("failed opening offline store for %s\n", URI.get()); NS_ENSURE_SUCCESS(rv, rv); seekable = do_QueryInterface(*aResult, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = seekable->Seek(nsISeekableStream::NS_SEEK_END, 0); NS_ENSURE_SUCCESS(rv, rv); m_outputStreams.Put(URI, *aResult); } int64_t filePos; seekable->Tell(&filePos); if (db && !*aNewMsgHdr) { // if mbox is close to 4GB, auto-assign the msg key. nsMsgKey key = filePos > 0xFFFFFF00 ? nsMsgKey_None : (nsMsgKey) filePos; db->CreateNewHdr(key, aNewMsgHdr); } if (*aNewMsgHdr) { char storeToken[100]; PR_snprintf(storeToken, sizeof(storeToken), "%lld", filePos); (*aNewMsgHdr)->SetMessageOffset(filePos); (*aNewMsgHdr)->SetStringProperty("storeToken", storeToken); } return rv; }
nsresult nsMsgAttachmentHandler::ConvertToAppleEncoding(const nsCString &aFileURI, const nsCString &aFilePath, nsILocalFileMac *aSourceFile) { // convert the apple file to AppleDouble first, and then patch the // address in the url. //We need to retrieve the file type and creator... char fileInfo[32]; OSType type, creator; nsresult rv = aSourceFile->GetFileType(&type); if (NS_FAILED(rv)) return false; PR_snprintf(fileInfo, sizeof(fileInfo), "%X", type); m_xMacType = fileInfo; rv = aSourceFile->GetFileCreator(&creator); if (NS_FAILED(rv)) return false; PR_snprintf(fileInfo, sizeof(fileInfo), "%X", creator); m_xMacCreator = fileInfo; FSRef fsRef; aSourceFile->GetFSRef(&fsRef); bool sendResourceFork = HasResourceFork(&fsRef); // if we have a resource fork, check the filename extension, maybe we don't need the resource fork! if (sendResourceFork) { nsCOMPtr<nsIURL> fileUrl(do_CreateInstance(NS_STANDARDURL_CONTRACTID)); if (fileUrl) { rv = fileUrl->SetSpec(aFileURI); if (NS_SUCCEEDED(rv)) { nsCAutoString ext; rv = fileUrl->GetFileExtension(ext); if (NS_SUCCEEDED(rv) && !ext.IsEmpty()) { sendResourceFork = PL_strcasecmp(ext.get(), "TXT") && PL_strcasecmp(ext.get(), "JPG") && PL_strcasecmp(ext.get(), "GIF") && PL_strcasecmp(ext.get(), "TIF") && PL_strcasecmp(ext.get(), "HTM") && PL_strcasecmp(ext.get(), "HTML") && PL_strcasecmp(ext.get(), "ART") && PL_strcasecmp(ext.get(), "XUL") && PL_strcasecmp(ext.get(), "XML") && PL_strcasecmp(ext.get(), "CSS") && PL_strcasecmp(ext.get(), "JS"); } } } } // Only use appledouble if we aren't uuencoding. if( sendResourceFork ) { char *separator; separator = mime_make_separator("ad"); if (!separator) return NS_ERROR_OUT_OF_MEMORY; nsCOMPtr <nsIFile> tmpFile; nsresult rv = nsMsgCreateTempFile("appledouble", getter_AddRefs(tmpFile)); if (NS_SUCCEEDED(rv)) mEncodedWorkingFile = do_QueryInterface(tmpFile); if (!mEncodedWorkingFile) { PR_FREEIF(separator); return NS_ERROR_OUT_OF_MEMORY; } // // RICHIE_MAC - ok, here's the deal, we have a file that we need // to encode in appledouble encoding for the resource fork and put that // into the mEncodedWorkingFile location. Then, we need to patch the new file // spec into the array and send this as part of the 2 part appledouble/mime // encoded mime part. // AppleDoubleEncodeObject *obj = new (AppleDoubleEncodeObject); if (obj == NULL) { mEncodedWorkingFile = nsnull; PR_FREEIF(separator); return NS_ERROR_OUT_OF_MEMORY; } rv = MsgGetFileStream(mEncodedWorkingFile, getter_AddRefs(obj->fileStream)); if (NS_FAILED(rv) || !obj->fileStream) { PR_FREEIF(separator); delete obj; return NS_ERROR_OUT_OF_MEMORY; } PRInt32 bSize = AD_WORKING_BUFF_SIZE; char *working_buff = nsnull; while (!working_buff && (bSize >= 512)) { working_buff = (char *)PR_CALLOC(bSize); if (!working_buff) bSize /= 2; } if (!working_buff) { PR_FREEIF(separator); delete obj; return NS_ERROR_OUT_OF_MEMORY; } obj->buff = working_buff; obj->s_buff = bSize; // // Setup all the need information on the apple double encoder. // ap_encode_init(&(obj->ap_encode_obj), aFilePath.get(), separator); PRInt32 count; nsresult status = noErr; m_size = 0; while (status == noErr) { status = ap_encode_next(&(obj->ap_encode_obj), obj->buff, bSize, &count); if (status == noErr || status == errDone) { // // we got the encode data, so call the next stream to write it to the disk. // PRUint32 bytesWritten; obj->fileStream->Write(obj->buff, count, &bytesWritten); if (bytesWritten != (PRUint32) count) status = NS_MSG_ERROR_WRITING_FILE; } } ap_encode_end(&(obj->ap_encode_obj), (status >= 0)); // if this is true, ok, false abort if (obj->fileStream) obj->fileStream->Close(); PR_FREEIF(obj->buff); /* free the working buff. */ PR_FREEIF(obj); nsCOMPtr <nsIURI> fileURI; NS_NewFileURI(getter_AddRefs(fileURI), mEncodedWorkingFile); nsCOMPtr<nsIFileURL> theFileURL = do_QueryInterface(fileURI, &rv); NS_ENSURE_SUCCESS(rv,rv); nsCString newURLSpec; NS_ENSURE_SUCCESS(rv, rv); fileURI->GetSpec(newURLSpec); if (newURLSpec.IsEmpty()) { PR_FREEIF(separator); return NS_ERROR_OUT_OF_MEMORY; } if (NS_FAILED(nsMsgNewURL(getter_AddRefs(mURL), newURLSpec.get()))) { PR_FREEIF(separator); return NS_ERROR_OUT_OF_MEMORY; } // Now after conversion, also patch the types. char tmp[128]; PR_snprintf(tmp, sizeof(tmp), MULTIPART_APPLEDOUBLE ";\r\n boundary=\"%s\"", separator); PR_FREEIF(separator); m_type = tmp; } else { if ( sendResourceFork ) { // For now, just do the encoding, but in the old world we would ask the // user about doing this conversion printf("...we could ask the user about this conversion, but for now, nahh..\n"); } bool useDefault; char *macType, *macEncoding; if (m_type.IsEmpty() || m_type.LowerCaseEqualsLiteral(TEXT_PLAIN)) { # define TEXT_TYPE 0x54455854 /* the characters 'T' 'E' 'X' 'T' */ # define text_TYPE 0x74657874 /* the characters 't' 'e' 'x' 't' */ if (type != TEXT_TYPE && type != text_TYPE) { MacGetFileType(aSourceFile, &useDefault, &macType, &macEncoding); m_type = macType; } } // don't bother to set the types if we failed in getting the file info. } return NS_OK; }
// We let the caller close the file in case he's updating a lot of flags // and we don't want to open and close the file every time through. // As an experiment, try caching the fid in the db as m_folderFile. // If this is set, use it but don't return *pFid. void nsMailDatabase::UpdateFolderFlag(nsIMsgDBHdr *mailHdr, PRBool bSet, MsgFlags flag, nsIOutputStream **ppFileStream) { static char buf[50]; PRInt64 folderStreamPos = 0; //saves the folderStream pos in case we are sharing the stream with other code nsIOutputStream *fileStream = (m_folderStream) ? m_folderStream.get() : *ppFileStream; PRUint32 offset; (void)mailHdr->GetStatusOffset(&offset); nsCOMPtr <nsISeekableStream> seekableStream; nsresult rv; if (offset > 0) { if (fileStream == NULL) { rv = MsgGetFileStream(m_folderFile, &fileStream); if (NS_FAILED(rv)) return; seekableStream = do_QueryInterface(fileStream); } else if (!m_ownFolderStream) { m_folderStream->Flush(); seekableStream = do_QueryInterface(fileStream); seekableStream->Tell(&folderStreamPos); } else seekableStream = do_QueryInterface(m_folderStream); if (fileStream) { PRUint32 msgOffset; (void)mailHdr->GetMessageOffset(&msgOffset); PRUint32 statusPos = offset + msgOffset; PR_ASSERT(offset < 10000); seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, statusPos); buf[0] = '\0'; nsCOMPtr <nsIInputStream> inputStream = do_QueryInterface(fileStream); PRUint32 bytesRead; if (NS_SUCCEEDED(inputStream->Read(buf, X_MOZILLA_STATUS_LEN + 6, &bytesRead))) { buf[bytesRead] = '\0'; if (strncmp(buf, X_MOZILLA_STATUS, X_MOZILLA_STATUS_LEN) == 0 && strncmp(buf + X_MOZILLA_STATUS_LEN, ": ", 2) == 0 && strlen(buf) >= X_MOZILLA_STATUS_LEN + 6) { PRUint32 flags; PRUint32 bytesWritten; (void)mailHdr->GetFlags(&flags); if (!(flags & MSG_FLAG_EXPUNGED)) { int i; char *p = buf + X_MOZILLA_STATUS_LEN + 2; for (i=0, flags = 0; i<4; i++, p++) { flags = (flags << 4) | msg_UnHex(*p); } PRUint32 curFlags; (void)mailHdr->GetFlags(&curFlags); flags = (flags & MSG_FLAG_QUEUED) | (curFlags & ~MSG_FLAG_RUNTIME_ONLY); } else { flags &= ~MSG_FLAG_RUNTIME_ONLY; } seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, statusPos); // We are filing out x-mozilla-status flags here PR_snprintf(buf, sizeof(buf), X_MOZILLA_STATUS_FORMAT, flags & 0x0000FFFF); PRInt32 lineLen = PL_strlen(buf); PRUint32 status2Pos = statusPos + lineLen + MSG_LINEBREAK_LEN; fileStream->Write(buf, lineLen, &bytesWritten); // time to upate x-mozilla-status2 seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, status2Pos); if (NS_SUCCEEDED(inputStream->Read(buf, X_MOZILLA_STATUS2_LEN + 10, &bytesRead))) { if (strncmp(buf, X_MOZILLA_STATUS2, X_MOZILLA_STATUS2_LEN) == 0 && strncmp(buf + X_MOZILLA_STATUS2_LEN, ": ", 2) == 0 && strlen(buf) >= X_MOZILLA_STATUS2_LEN + 10) { PRUint32 dbFlags; (void)mailHdr->GetFlags(&dbFlags); dbFlags &= 0xFFFF0000; seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, status2Pos); PR_snprintf(buf, sizeof(buf), X_MOZILLA_STATUS2_FORMAT, dbFlags); fileStream->Write(buf, PL_strlen(buf), &bytesWritten); } } } else { #ifdef DEBUG printf("Didn't find %s where expected at position %ld\n" "instead, found %s.\n", X_MOZILLA_STATUS, (long) statusPos, buf); #endif SetReparse(PR_TRUE); } } else { #ifdef DEBUG printf("Couldn't read old status line at all at position %ld\n", (long) statusPos); #endif SetReparse(PR_TRUE); } } else { #ifdef DEBUG nsCString folderPath; m_folderFile->GetNativePath(folderPath); printf("Couldn't open mail folder for update%s!\n", folderPath.get()); #endif PR_ASSERT(PR_FALSE); } } if (!m_folderStream) *ppFileStream = fileStream; // This tells the caller that we opened the file, and please to close it. else if (!m_ownFolderStream) seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, folderStreamPos); }