summaryrefslogtreecommitdiffstats
path: root/mailnews/import/src/nsImportMimeEncode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/import/src/nsImportMimeEncode.cpp')
-rw-r--r--mailnews/import/src/nsImportMimeEncode.cpp411
1 files changed, 411 insertions, 0 deletions
diff --git a/mailnews/import/src/nsImportMimeEncode.cpp b/mailnews/import/src/nsImportMimeEncode.cpp
new file mode 100644
index 000000000..e13ea1f94
--- /dev/null
+++ b/mailnews/import/src/nsImportMimeEncode.cpp
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nscore.h"
+#include "nsImportMimeEncode.h"
+
+#include "ImportCharSet.h"
+#include "ImportTranslate.h"
+
+#define kNoState 0
+#define kStartState 1
+#define kEncodeState 2
+#define kDoneState 3
+
+#define kEncodeBufferSz (8192 * 8)
+
+nsImportMimeEncode::nsImportMimeEncode()
+{
+ m_pOut = nullptr;
+ m_state = kNoState;
+ m_bytesProcessed = 0;
+ m_pInputBuf = nullptr;
+}
+
+nsImportMimeEncode::~nsImportMimeEncode()
+{
+ delete [] m_pInputBuf;
+}
+
+void nsImportMimeEncode::EncodeFile(nsIFile *pInFile, ImportOutFile *pOut, const char *pFileName, const char *pMimeType)
+{
+ m_fileName = pFileName;
+ m_mimeType = pMimeType;
+
+ m_pMimeFile = pInFile;
+
+ m_pOut = pOut;
+ m_state = kStartState;
+}
+
+void nsImportMimeEncode::CleanUp(void)
+{
+ CleanUpEncodeScan();
+}
+
+bool nsImportMimeEncode::SetUpEncode(void)
+{
+ nsCString errStr;
+ if (!m_pInputBuf) {
+ m_pInputBuf = new uint8_t[kEncodeBufferSz];
+ }
+
+ m_appleSingle = false;
+
+#ifdef _MAC_IMPORT_CODE
+ // First let's see just what kind of beast we have?
+ // For files with only a data fork and a known mime type
+ // proceed with normal mime encoding just as on the PC.
+ // For unknown mime types and files with both forks,
+ // encode as AppleSingle format.
+ if (m_filePath.GetMacFileSize(UFileLocation::eResourceFork) || !pMimeType) {
+ m_appleSingle = TRUE;
+ m_mimeType = "application/applefile";
+ }
+#endif
+
+ if (!InitEncodeScan(m_appleSingle, m_pMimeFile, m_fileName.get(), m_pInputBuf, kEncodeBufferSz)) {
+ return false;
+ }
+
+ m_state = kEncodeState;
+ m_lineLen = 0;
+
+ // Write out the boundary header
+ bool bResult = true;
+ bResult = m_pOut->WriteStr("Content-type: ");
+ if (bResult)
+ bResult = m_pOut->WriteStr(m_mimeType.get());
+
+#ifdef _MAC_IMPORT_CODE
+ // include the type an creator here
+ if (bResult)
+ bResult = m_pOut->WriteStr("; x-mac-type=\"");
+ U8 hex[8];
+ LongToHexBytes(m_filePath.GetFileType(), hex);
+ if (bResult)
+ bResult = m_pOut->WriteData(hex, 8);
+ LongToHexBytes(m_filePath.GetFileCreator(), hex);
+ if (bResult)
+ bResult = m_pOut->WriteStr("\"; x-mac-creator=\"");
+ if (bResult)
+ bResult = m_pOut->WriteData(hex, 8);
+ if (bResult)
+ bResult = m_pOut->WriteStr("\"");
+#endif
+
+ /*
+ if (bResult)
+ bResult = m_pOut->WriteStr(gMimeTypeFileName);
+ */
+ if (bResult)
+ bResult = m_pOut->WriteStr(";\x0D\x0A");
+
+ nsCString fName;
+ bool trans = TranslateFileName(m_fileName, fName);
+ if (bResult)
+ bResult = WriteFileName(fName, trans, "name");
+ if (bResult)
+ bResult = m_pOut->WriteStr("Content-transfer-encoding: base64");
+ if (bResult)
+ bResult = m_pOut->WriteEol();
+ if (bResult)
+ bResult = m_pOut->WriteStr("Content-Disposition: attachment;\x0D\x0A");
+ if (bResult)
+ bResult = WriteFileName(fName, trans, "filename");
+ if (bResult)
+ bResult = m_pOut->WriteEol();
+
+ if (!bResult) {
+ CleanUp();
+ }
+
+ return bResult;
+}
+
+bool nsImportMimeEncode::DoWork(bool *pDone)
+{
+ *pDone = false;
+ switch(m_state) {
+ case kNoState:
+ return false;
+ break;
+ case kStartState:
+ return SetUpEncode();
+ break;
+ case kEncodeState:
+ if (!Scan(pDone)) {
+ CleanUp();
+ return false;
+ }
+ if (*pDone) {
+ *pDone = false;
+ m_state = kDoneState;
+ }
+ break;
+ case kDoneState:
+ CleanUp();
+ m_state = kNoState;
+ *pDone = true;
+ break;
+ }
+
+ return true;
+}
+
+static uint8_t gBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+bool nsImportMimeEncode::ScanBuffer(bool *pDone)
+{
+
+ uint32_t pos = m_pos;
+ uint32_t start = pos;
+ uint8_t * pChar = m_pBuf + pos;
+ uint32_t max = m_bytesInBuf;
+ uint8_t byte[4];
+ uint32_t lineLen = m_lineLen;
+
+ while ((pos + 2) < max) {
+ // Encode 3 bytes
+ byte[0] = gBase64[*pChar >> 2];
+ byte[1] = gBase64[(((*pChar) & 0x3)<< 4) | (((*(pChar + 1)) & 0xF0) >> 4)];
+ pChar++;
+ byte[2] = gBase64[(((*pChar) & 0xF) << 2) | (((*(pChar + 1)) & 0xC0) >>6)];
+ pChar++;
+ byte[3] = gBase64[(*pChar) & 0x3F];
+ if (!m_pOut->WriteData(byte, 4))
+ return false;
+ pos += 3;
+ pChar++;
+ lineLen += 4;
+ if (lineLen > 71) {
+ if (!m_pOut->WriteEol())
+ return false;
+ lineLen = 0;
+ }
+ }
+
+ if ((pos < max) && m_eof) {
+ // Get the last few bytes!
+ byte[0] = gBase64[*pChar >> 2];
+ pos++;
+ if (pos < max) {
+ byte[1] = gBase64[(((*pChar) & 0x3)<< 4) | (((*(pChar + 1)) & 0xF0) >> 4)];
+ pChar++;
+ pos++;
+ if (pos < max) {
+ // Should be dead code!! (Then why is it here doofus?)
+ byte[2] = gBase64[(((*pChar) & 0xF) << 2) | (((*(pChar + 1)) & 0xC0) >>6)];
+ pChar++;
+ byte[3] = gBase64[(*pChar) & 0x3F];
+ pos++;
+ }
+ else {
+ byte[2] = gBase64[(((*pChar) & 0xF) << 2)];
+ byte[3] = '=';
+ }
+ }
+ else {
+ byte[1] = gBase64[(((*pChar) & 0x3)<< 4)];
+ byte[2] = '=';
+ byte[3] = '=';
+ }
+
+ if (!m_pOut->WriteData(byte, 4))
+ return false;
+ if (!m_pOut->WriteEol())
+ return false;
+ }
+ else if (m_eof) {
+ /*
+ byte[0] = '=';
+ if (!m_pOut->WriteData(byte, 1))
+ return FALSE;
+ */
+ if (!m_pOut->WriteEol())
+ return false;
+ }
+
+ m_lineLen = (int) lineLen;
+ m_pos = pos;
+ m_bytesProcessed += (pos - start);
+ return true;
+}
+
+bool nsImportMimeEncode::TranslateFileName(nsCString& inFile, nsCString& outFile)
+{
+ const uint8_t * pIn = (const uint8_t *) inFile.get();
+ int len = inFile.Length();
+
+ while (len) {
+ if (!ImportCharSet::IsUSAscii(*pIn))
+ break;
+ len--;
+ pIn++;
+ }
+ if (len) {
+ // non US ascii!
+ // assume this string needs translating...
+ if (!ImportTranslate::ConvertString(inFile, outFile, true)) {
+ outFile = inFile;
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ else {
+ outFile = inFile;
+ return false;
+ }
+}
+
+bool nsImportMimeEncode::WriteFileName(nsCString& fName, bool wasTrans, const char *pTag)
+{
+ int tagNum = 0;
+ int idx = 0;
+ bool result = true;
+ int len;
+ nsCString numStr;
+
+ while ((((fName.Length() - idx) + strlen(pTag)) > 70) && result) {
+ len = 68 - strlen(pTag) - 5;
+ if (wasTrans) {
+ if (fName.CharAt(idx + len - 1) == '%')
+ len--;
+ else if (fName.CharAt(idx + len - 2) == '%')
+ len -= 2;
+ }
+
+ if (result)
+ result = m_pOut->WriteStr("\x09");
+ if (result)
+ result = m_pOut->WriteStr(pTag);
+ numStr = "*";
+ numStr.AppendInt(tagNum);
+ if (result)
+ result = m_pOut->WriteStr(numStr.get());
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("*=");
+ else if (result)
+ result = m_pOut->WriteStr("=\"");
+ if (result)
+ result = m_pOut->WriteData(((const uint8_t *)fName.get()) + idx, len);
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("\x0D\x0A");
+ else if (result)
+ result = m_pOut->WriteStr("\"\x0D\x0A");
+ idx += len;
+ tagNum++;
+ }
+
+ if (idx) {
+ if ((fName.Length() - idx) > 0) {
+ if (result)
+ result = m_pOut->WriteStr("\x09");
+ if (result)
+ result = m_pOut->WriteStr(pTag);
+ numStr = "*";
+ numStr.AppendInt(tagNum);
+ if (result)
+ result = m_pOut->WriteStr(numStr.get());
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("*=");
+ else if (result)
+ result = m_pOut->WriteStr("=\"");
+ if (result)
+ result = m_pOut->WriteData(((const uint8_t *)fName.get()) + idx, fName.Length() - idx);
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("\x0D\x0A");
+ else if (result)
+ result = m_pOut->WriteStr("\"\x0D\x0A");
+ }
+ }
+ else {
+ if (result)
+ result = m_pOut->WriteStr("\x09");
+ if (result)
+ result = m_pOut->WriteStr(pTag);
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("*=");
+ else if (result)
+ result = m_pOut->WriteStr("=\"");
+ if (result)
+ result = m_pOut->WriteStr(fName.get());
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("\x0D\x0A");
+ else if (result)
+ result = m_pOut->WriteStr("\"\x0D\x0A");
+ }
+
+ return result;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+nsIImportMimeEncodeImpl::nsIImportMimeEncodeImpl()
+{
+ m_pOut = nullptr;
+ m_pEncode = nullptr;
+}
+
+nsIImportMimeEncodeImpl::~nsIImportMimeEncodeImpl()
+{
+ if (m_pOut)
+ delete m_pOut;
+ if (m_pEncode)
+ delete m_pEncode;
+}
+
+NS_IMPL_ISUPPORTS(nsIImportMimeEncodeImpl, nsIImportMimeEncode)
+
+NS_METHOD nsIImportMimeEncodeImpl::EncodeFile(nsIFile *inFile, nsIFile *outFile, const char *fileName, const char *mimeType)
+{
+ return Initialize(inFile, outFile, fileName, mimeType);
+}
+
+NS_METHOD nsIImportMimeEncodeImpl::DoWork(bool *done, bool *_retval)
+{
+ if (done && _retval && m_pEncode) {
+ *_retval = m_pEncode->DoWork(done);
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+NS_METHOD nsIImportMimeEncodeImpl::NumBytesProcessed(int32_t *_retval)
+{
+ if (m_pEncode && _retval)
+ *_retval = m_pEncode->NumBytesProcessed();
+ return NS_OK;
+}
+
+NS_METHOD nsIImportMimeEncodeImpl::DoEncoding(bool *_retval)
+{
+ if (_retval && m_pEncode) {
+ bool done = false;
+ while (m_pEncode->DoWork(&done) && !done);
+ *_retval = done;
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+NS_METHOD nsIImportMimeEncodeImpl::Initialize(nsIFile *inFile, nsIFile *outFile, const char *fileName, const char *mimeType)
+{
+ delete m_pEncode;
+ delete m_pOut;
+
+ m_pOut = new ImportOutFile();
+ m_pOut->InitOutFile(outFile);
+
+ m_pEncode = new nsImportMimeEncode();
+ m_pEncode->EncodeFile(inFile, m_pOut, fileName, mimeType);
+
+ return NS_OK;
+}
+