From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- comm/mailnews/mime/cthandlers/glue/mimexpcom.cpp | 119 ++++ comm/mailnews/mime/cthandlers/glue/mimexpcom.h | 92 +++ comm/mailnews/mime/cthandlers/glue/moz.build | 17 + .../cthandlers/glue/nsMimeContentTypeHandler.cpp | 55 ++ .../cthandlers/glue/nsMimeContentTypeHandler.h | 46 ++ comm/mailnews/mime/cthandlers/moz.build | 10 + .../mime/cthandlers/pgpmime/components.conf | 21 + comm/mailnews/mime/cthandlers/pgpmime/moz.build | 24 + .../pgpmime/nsPgpMimeMimeContentTypeHandler.h | 22 + .../mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp | 672 +++++++++++++++++++++ .../mime/cthandlers/pgpmime/nsPgpMimeProxy.h | 73 +++ 11 files changed, 1151 insertions(+) create mode 100644 comm/mailnews/mime/cthandlers/glue/mimexpcom.cpp create mode 100644 comm/mailnews/mime/cthandlers/glue/mimexpcom.h create mode 100644 comm/mailnews/mime/cthandlers/glue/moz.build create mode 100644 comm/mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.cpp create mode 100644 comm/mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.h create mode 100644 comm/mailnews/mime/cthandlers/moz.build create mode 100644 comm/mailnews/mime/cthandlers/pgpmime/components.conf create mode 100644 comm/mailnews/mime/cthandlers/pgpmime/moz.build create mode 100644 comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeMimeContentTypeHandler.h create mode 100644 comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp create mode 100644 comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.h (limited to 'comm/mailnews/mime/cthandlers') diff --git a/comm/mailnews/mime/cthandlers/glue/mimexpcom.cpp b/comm/mailnews/mime/cthandlers/glue/mimexpcom.cpp new file mode 100644 index 0000000000..626dc043a4 --- /dev/null +++ b/comm/mailnews/mime/cthandlers/glue/mimexpcom.cpp @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsIMimeObjectClassAccess.h" +#include "nsCOMPtr.h" +#include "nsComponentManagerUtils.h" + +// {403B0540-B7C3-11d2-B35E-525400E2D63A} +#define NS_MIME_OBJECT_CLASS_ACCESS_CID \ + { \ + 0x403b0540, 0xb7c3, 0x11d2, { \ + 0xb3, 0x5e, 0x52, 0x54, 0x0, 0xe2, 0xd6, 0x3a \ + } \ + } +static NS_DEFINE_CID(kMimeObjectClassAccessCID, + NS_MIME_OBJECT_CLASS_ACCESS_CID); + +/* + * These calls are necessary to expose the object class hierarchy + * to externally developed content type handlers. + */ +extern "C" void* COM_GetmimeInlineTextClass(void) { + void* ptr = NULL; + + nsresult res; + nsCOMPtr objAccess = + do_CreateInstance(kMimeObjectClassAccessCID, &res); + if (NS_SUCCEEDED(res) && objAccess) objAccess->GetmimeInlineTextClass(&ptr); + + return ptr; +} + +extern "C" void* COM_GetmimeLeafClass(void) { + void* ptr = NULL; + + nsresult res; + nsCOMPtr objAccess = + do_CreateInstance(kMimeObjectClassAccessCID, &res); + if (NS_SUCCEEDED(res) && objAccess) objAccess->GetmimeLeafClass(&ptr); + + return ptr; +} + +extern "C" void* COM_GetmimeObjectClass(void) { + void* ptr = NULL; + + nsresult res; + nsCOMPtr objAccess = + do_CreateInstance(kMimeObjectClassAccessCID, &res); + if (NS_SUCCEEDED(res) && objAccess) objAccess->GetmimeObjectClass(&ptr); + + return ptr; +} + +extern "C" void* COM_GetmimeContainerClass(void) { + void* ptr = NULL; + + nsresult res; + nsCOMPtr objAccess = + do_CreateInstance(kMimeObjectClassAccessCID, &res); + if (NS_SUCCEEDED(res) && objAccess) objAccess->GetmimeContainerClass(&ptr); + + return ptr; +} + +extern "C" void* COM_GetmimeMultipartClass(void) { + void* ptr = NULL; + + nsresult res; + nsCOMPtr objAccess = + do_CreateInstance(kMimeObjectClassAccessCID, &res); + if (NS_SUCCEEDED(res) && objAccess) objAccess->GetmimeMultipartClass(&ptr); + + return ptr; +} + +extern "C" void* COM_GetmimeMultipartSignedClass(void) { + void* ptr = NULL; + + nsresult res; + nsCOMPtr objAccess = + do_CreateInstance(kMimeObjectClassAccessCID, &res); + if (NS_SUCCEEDED(res) && objAccess) + objAccess->GetmimeMultipartSignedClass(&ptr); + + return ptr; +} + +extern "C" int COM_MimeObject_write(void* mimeObject, char* data, + int32_t length, bool user_visible_p) { + int32_t rc = -1; + + nsresult res; + nsCOMPtr objAccess = + do_CreateInstance(kMimeObjectClassAccessCID, &res); + if (NS_SUCCEEDED(res) && objAccess) { + if (NS_SUCCEEDED(objAccess->MimeObjectWrite(mimeObject, data, length, + user_visible_p))) + rc = length; + else + rc = -1; + } + + return rc; +} + +extern "C" void* COM_MimeCreate(char* content_type, void* hdrs, void* opts) { + void* ptr = NULL; + + nsresult res; + nsCOMPtr objAccess = + do_CreateInstance(kMimeObjectClassAccessCID, &res); + if (NS_SUCCEEDED(res) && objAccess) + objAccess->MimeCreate(content_type, hdrs, opts, &ptr); + + return ptr; +} diff --git a/comm/mailnews/mime/cthandlers/glue/mimexpcom.h b/comm/mailnews/mime/cthandlers/glue/mimexpcom.h new file mode 100644 index 0000000000..343c7d0dc7 --- /dev/null +++ b/comm/mailnews/mime/cthandlers/glue/mimexpcom.h @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +/* + * This is the definitions for the Content Type Handler plugins to + * access internals of libmime via XP-COM calls + */ +#ifndef _MIMEXPCOM_H_ +#define _MIMEXPCOM_H_ + +/* + This header exposes functions that are necessary to access the + object hierarchy for the mime chart. The class hierarchy is: + + MimeObject (abstract) + | + |--- MimeContainer (abstract) + | | + | |--- MimeMultipart (abstract) + | | | + | | |--- MimeMultipartMixed + | | | + | | |--- MimeMultipartDigest + | | | + | | |--- MimeMultipartParallel + | | | + | | |--- MimeMultipartAlternative + | | | + | | |--- MimeMultipartRelated + | | | + | | |--- MimeMultipartAppleDouble + | | | + | | |--- MimeSunAttachment + | | | + | | |--- MimeMultipartSigned (abstract) + | | | + | | |--- MimeMultipartSigned + | | + | |--- MimeXlateed (abstract) + | | | + | | |--- MimeXlateed + | | + | |--- MimeMessage + | | + | |--- MimeUntypedText + | + |--- MimeLeaf (abstract) + | | + | |--- MimeInlineText (abstract) + | | | + | | |--- MimeInlineTextPlain + | | | + | | |--- MimeInlineTextHTML + | | | + | | |--- MimeInlineTextRichtext + | | | | + | | | |--- MimeInlineTextEnriched + | | | + | | |--- MimeInlineTextVCard + | | + | |--- MimeInlineImage + | | + | |--- MimeExternalObject + | + |--- MimeExternalBody + */ + +/* + * These functions are exposed by libmime to be used by content type + * handler plugins for processing stream data. + */ +/* + * This is the write call for outputting processed stream data. + */ +extern "C" int COM_MimeObject_write(void* mimeObject, const char* data, + int32_t length, bool user_visible_p); +/* + * The following group of calls expose the pointers for the object + * system within libmime. + */ +extern "C" void* COM_GetmimeInlineTextClass(void); +extern "C" void* COM_GetmimeLeafClass(void); +extern "C" void* COM_GetmimeObjectClass(void); +extern "C" void* COM_GetmimeContainerClass(void); +extern "C" void* COM_GetmimeMultipartClass(void); +extern "C" void* COM_GetmimeMultipartSignedClass(void); + +extern "C" void* COM_MimeCreate(char* content_type, void* hdrs, void* opts); + +#endif /* _MIMEXPCOM_H_ */ diff --git a/comm/mailnews/mime/cthandlers/glue/moz.build b/comm/mailnews/mime/cthandlers/glue/moz.build new file mode 100644 index 0000000000..4955981f3d --- /dev/null +++ b/comm/mailnews/mime/cthandlers/glue/moz.build @@ -0,0 +1,17 @@ +# vim: set filetype=python: +# 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/. + +EXPORTS += [ + "nsMimeContentTypeHandler.h", +] + +SOURCES += [ + "mimexpcom.cpp", + "nsMimeContentTypeHandler.cpp", +] + +FINAL_LIBRARY = "mail" + +Library("mimecthglue_s") diff --git a/comm/mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.cpp b/comm/mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.cpp new file mode 100644 index 0000000000..ace9c64d8c --- /dev/null +++ b/comm/mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 +#include "nscore.h" +#include "plstr.h" +#include "nsMimeContentTypeHandler.h" + +/* + * The following macros actually implement addref, release and + * query interface for our component. + */ +NS_IMPL_ISUPPORTS(nsMimeContentTypeHandler, nsIMimeContentTypeHandler) + +/* + * nsIMimeEmitter definitions.... + */ +nsMimeContentTypeHandler::nsMimeContentTypeHandler( + const char* aMimeType, MCTHCreateCTHClass callback) { + NS_ASSERTION( + aMimeType, + "nsMimeContentTypeHandler should be initialized with non-null mime type"); + NS_ASSERTION( + callback, + "nsMimeContentTypeHandler should be initialized with non-null callback"); + mimeType = PL_strdup(aMimeType); + realCreateContentTypeHandlerClass = callback; +} + +nsMimeContentTypeHandler::~nsMimeContentTypeHandler(void) { + if (mimeType) { + free(mimeType); + mimeType = 0; + } + realCreateContentTypeHandlerClass = 0; +} + +// Get the content type if necessary +nsresult nsMimeContentTypeHandler::GetContentType(char** contentType) { + *contentType = PL_strdup(mimeType); + return NS_OK; +} + +// Set the output stream for processed data. +nsresult nsMimeContentTypeHandler::CreateContentTypeHandlerClass( + const char* content_type, contentTypeHandlerInitStruct* initStruct, + MimeObjectClass** objClass) { + *objClass = realCreateContentTypeHandlerClass(content_type, initStruct); + if (!*objClass) + return NS_ERROR_OUT_OF_MEMORY; /* we couldn't allocate the object */ + else + return NS_OK; +} diff --git a/comm/mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.h b/comm/mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.h new file mode 100644 index 0000000000..2974e98f17 --- /dev/null +++ b/comm/mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +/* + * This interface is implemented by content type handlers that will be + * called upon by libmime to process various attachments types. The primary + * purpose of these handlers will be to represent the attached data in a + * viewable HTML format that is useful for the user + * + * Note: These will all register by their content type prefixed by the + * following: mimecth:text/vcard + * + * libmime will then use the XPCOM Component Manager to + * locate the appropriate Content Type handler + */ +#ifndef nsMimeContentTypeHandler_h_ +#define nsMimeContentTypeHandler_h_ + +#include "mozilla/Attributes.h" +#include "nsIMimeContentTypeHandler.h" + +typedef MimeObjectClass* (*MCTHCreateCTHClass)( + const char* content_type, contentTypeHandlerInitStruct* initStruct); + +class nsMimeContentTypeHandler : public nsIMimeContentTypeHandler { + public: + nsMimeContentTypeHandler(const char* aMimeType, MCTHCreateCTHClass callback); + + /* this macro defines QueryInterface, AddRef and Release for this class */ + NS_DECL_ISUPPORTS + + NS_IMETHOD GetContentType(char** contentType) override; + + NS_IMETHOD CreateContentTypeHandlerClass( + const char* content_type, contentTypeHandlerInitStruct* initStruct, + MimeObjectClass** objClass) override; + + private: + virtual ~nsMimeContentTypeHandler(); + char* mimeType; + MCTHCreateCTHClass realCreateContentTypeHandlerClass; +}; + +#endif /* nsMimeContentTypeHandler_h_ */ diff --git a/comm/mailnews/mime/cthandlers/moz.build b/comm/mailnews/mime/cthandlers/moz.build new file mode 100644 index 0000000000..7d61b9ebf5 --- /dev/null +++ b/comm/mailnews/mime/cthandlers/moz.build @@ -0,0 +1,10 @@ +# vim: set filetype=python: +# 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/. + +# pgpmime depends on glue. +DIRS += [ + "glue", + "pgpmime", +] diff --git a/comm/mailnews/mime/cthandlers/pgpmime/components.conf b/comm/mailnews/mime/cthandlers/pgpmime/components.conf new file mode 100644 index 0000000000..a1098a43f8 --- /dev/null +++ b/comm/mailnews/mime/cthandlers/pgpmime/components.conf @@ -0,0 +1,21 @@ +# 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/. + +Classes = [ + { + "cid": "{212f415f-f8b5-11d2-ffe0-00af19a7d144}", + "contract_ids": [ + "@mozilla.org/mimecth;1?type=multipart/encrypted", + ], + "legacy_constructor": "nsPgpMimeMimeContentTypeHandlerConstructor", + "headers": ["/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeMimeContentTypeHandler.h"], + }, + { + "cid": "{815c4fbe-0e7c-45b6-8324-f7044c7252ac}", + "contract_ids": ["@mozilla.org/mime/pgp-mime-decrypt;1"], + "type": "nsPgpMimeProxy", + "init_method": "Init", + "headers": ["/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.h"], + }, +] diff --git a/comm/mailnews/mime/cthandlers/pgpmime/moz.build b/comm/mailnews/mime/cthandlers/pgpmime/moz.build new file mode 100644 index 0000000000..7259395c5a --- /dev/null +++ b/comm/mailnews/mime/cthandlers/pgpmime/moz.build @@ -0,0 +1,24 @@ +# vim: set filetype=python: +# 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/. + +EXPORTS += [ + "nsPgpMimeProxy.h", +] + +SOURCES += [ + "nsPgpMimeProxy.cpp", +] + +FINAL_LIBRARY = "mail" + +Library("pgpmime_s") + +LOCAL_INCLUDES += [ + "../glue", +] + +XPCOM_MANIFESTS += [ + "components.conf", +] diff --git a/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeMimeContentTypeHandler.h b/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeMimeContentTypeHandler.h new file mode 100644 index 0000000000..bc8a432b08 --- /dev/null +++ b/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeMimeContentTypeHandler.h @@ -0,0 +1,22 @@ +/* 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 "nsMimeContentTypeHandler.h" +#include "nsPgpMimeProxy.h" + +extern "C" MimeObjectClass* MIME_PgpMimeCreateContentTypeHandlerClass( + const char* content_type, contentTypeHandlerInitStruct* initStruct); + +static nsresult nsPgpMimeMimeContentTypeHandlerConstructor(REFNSIID aIID, + void** aResult) { + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nullptr; + + RefPtr inst(new nsMimeContentTypeHandler( + "multipart/encrypted", &MIME_PgpMimeCreateContentTypeHandlerClass)); + + NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY); + + return inst->QueryInterface(aIID, aResult); +} diff --git a/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp b/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp new file mode 100644 index 0000000000..4382ed0c1a --- /dev/null +++ b/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp @@ -0,0 +1,672 @@ +/* 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 "nsPgpMimeProxy.h" +#include "nspr.h" +#include "plstr.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "mozilla/Components.h" +#include "nsIRequest.h" +#include "nsIStringBundle.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIURI.h" +#include "mimexpcom.h" +#include "nsMsgUtils.h" +#include "nsNetUtil.h" + +#include "mimecth.h" +#include "mimemoz2.h" +#include "nspr.h" +#include "plstr.h" +#include "nsIPgpMimeProxy.h" +#include "nsComponentManagerUtils.h" + +/** + * Overall description + * =================== + * + * There are three components involved here: MIME, a proxy object + * (nsPgpMimeProxy) and Enigmail (or any other add-on that registered a + * decryption object with + * "@mozilla.org/mime/pgp-mime-js-decrypt;1"). + * + * MIME creates and initialises the proxy object in nsPgpMimeProxy::Init(). This + * creates a decryption object, for example EnigmailMimeDecrypt. When MIME wants + * to decode something, it calls the Write() method of the proxy, which in turn + * calls OnDataAvailable() on the decryptor. The decryptor optains the encrypted + * data form the proxy via the proxy's Read() method. The decryptor decrypts the + * data and passes the result back to the proxy, using the OutputDecryptedData() + * method or by passing a stream to the proxy's OnDataAvailable() method, in + * which the proxy will read from that stream. The proxy knows how to interface + * with MIME and passes the data on using some function pointers it got given + * via nsPgpMimeProxy::SetMimeCallback(). + */ + +#define MIME_SUPERCLASS mimeEncryptedClass +MimeDefClass(MimeEncryptedPgp, MimeEncryptedPgpClass, mimeEncryptedPgpClass, + &MIME_SUPERCLASS); + +#define kCharMax 1024 + +extern "C" MimeObjectClass* MIME_PgpMimeCreateContentTypeHandlerClass( + const char* content_type, contentTypeHandlerInitStruct* initStruct) { + MimeObjectClass* objClass = (MimeObjectClass*)&mimeEncryptedPgpClass; + + initStruct->force_inline_display = false; + + return objClass; +} + +static void* MimePgpe_init(MimeObject*, + int (*output_fn)(const char*, int32_t, void*), + void*); +static int MimePgpe_write(const char*, int32_t, void*); +static int MimePgpe_eof(void*, bool); +static char* MimePgpe_generate(void*); +static void MimePgpe_free(void*); + +/* Returns a string describing the location of the part (like "2.5.3"). + This is not a full URL, just a part-number. + */ +static nsCString determineMimePart(MimeObject* obj); + +#define PGPMIME_PROPERTIES_URL "chrome://messenger/locale/pgpmime.properties" +#define PGPMIME_STR_NOT_SUPPORTED_ID "pgpNotAvailable" + +static void PgpMimeGetNeedsAddonString(nsCString& aResult) { + aResult.AssignLiteral("???"); + + nsCOMPtr stringBundleService = + mozilla::components::StringBundle::Service(); + + nsCOMPtr stringBundle; + nsresult rv = stringBundleService->CreateBundle(PGPMIME_PROPERTIES_URL, + getter_AddRefs(stringBundle)); + if (NS_FAILED(rv)) return; + + nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) return; + + nsString result; + rv = stringBundle->GetStringFromName(PGPMIME_STR_NOT_SUPPORTED_ID, result); + if (NS_FAILED(rv)) return; + aResult = NS_ConvertUTF16toUTF8(result); +} + +static int MimeEncryptedPgpClassInitialize(MimeEncryptedPgpClass* clazz) { + mozilla::DebugOnly oclass = (MimeObjectClass*)clazz; + NS_ASSERTION(!oclass->class_initialized, "oclass is not initialized"); + + MimeEncryptedClass* eclass = (MimeEncryptedClass*)clazz; + + eclass->crypto_init = MimePgpe_init; + eclass->crypto_write = MimePgpe_write; + eclass->crypto_eof = MimePgpe_eof; + eclass->crypto_generate_html = MimePgpe_generate; + eclass->crypto_free = MimePgpe_free; + + return 0; +} + +class MimePgpeData : public nsISupports { + public: + NS_DECL_ISUPPORTS + + int (*output_fn)(const char* buf, int32_t buf_size, void* output_closure); + void* output_closure; + MimeObject* self; + + nsCOMPtr mimeDecrypt; + + MimePgpeData() : output_fn(nullptr), output_closure(nullptr) {} + + private: + virtual ~MimePgpeData() {} +}; + +NS_IMPL_ISUPPORTS0(MimePgpeData) + +static void* MimePgpe_init(MimeObject* obj, + int (*output_fn)(const char* buf, int32_t buf_size, + void* output_closure), + void* output_closure) { + if (!(obj && obj->options && output_fn)) return nullptr; + + MimePgpeData* data = new MimePgpeData(); + NS_ENSURE_TRUE(data, nullptr); + + data->self = obj; + data->output_fn = output_fn; + data->output_closure = output_closure; + data->mimeDecrypt = nullptr; + + // Create proxy object. + nsresult rv; + data->mimeDecrypt = do_CreateInstance(NS_PGPMIMEPROXY_CONTRACTID, &rv); + if (NS_FAILED(rv)) return data; + + char* ct = MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE, false, false); + + rv = (ct ? data->mimeDecrypt->SetContentType(nsDependentCString(ct)) + : data->mimeDecrypt->SetContentType(EmptyCString())); + + PR_Free(ct); + + if (NS_FAILED(rv)) return nullptr; + + nsCString mimePart = determineMimePart(obj); + + rv = data->mimeDecrypt->SetMimePart(mimePart); + if (NS_FAILED(rv)) return nullptr; + + if (mimePart.EqualsLiteral("1.1") && obj->parent && + obj->parent->content_type && + !strcmp(obj->parent->content_type, "multipart/signed") && + ((MimeContainer*)obj->parent)->nchildren == 1) { + // Don't show status for the outer signature, it could be misleading, + // the signature could have been created by someone not knowing + // the contents of the inner encryption layer. + // Another reason is, we usually skip decrypting nested encrypted + // parts. However, we make an exception: If the outermost layer + // is a signature, and the signature wraps only a single encrypted + // message (no sibling MIME parts next to the encrypted part), + // then we allow decryption. (bug 1594253) + data->mimeDecrypt->SetAllowNestedDecrypt(true); + } + + mime_stream_data* msd = + (mime_stream_data*)(data->self->options->stream_closure); + nsIChannel* channel = msd->channel; + + nsCOMPtr uri; + if (channel) channel->GetURI(getter_AddRefs(uri)); + + if (!uri && obj && obj->options && obj->options->url) { + // Allow the PGP mime decrypt code to know what message we're + // working with, necessary for storing into the message DB + // (e.g. decrypted subject). Bug 1666005. + NS_NewURI(getter_AddRefs(uri), obj->options->url); + } + + // Initialise proxy object with MIME's output function, object and URI. + if (NS_FAILED( + data->mimeDecrypt->SetMimeCallback(output_fn, output_closure, uri))) + return nullptr; + + return data; +} + +static int MimePgpe_write(const char* buf, int32_t buf_size, + void* output_closure) { + MimePgpeData* data = (MimePgpeData*)output_closure; + + if (!data || !data->output_fn) return -1; + + if (!data->mimeDecrypt) return 0; + + return (NS_SUCCEEDED(data->mimeDecrypt->Write(buf, buf_size)) ? 0 : -1); +} + +static int MimePgpe_eof(void* output_closure, bool abort_p) { + MimePgpeData* data = (MimePgpeData*)output_closure; + + if (!data || !data->output_fn) return -1; + + if (NS_FAILED(data->mimeDecrypt->Finish())) return -1; + + data->mimeDecrypt->RemoveMimeCallback(); + data->mimeDecrypt = nullptr; + return 0; +} + +static char* MimePgpe_generate(void* output_closure) { + const char htmlMsg[] = "GEN MSG"; + char* msg = (char*)PR_MALLOC(strlen(htmlMsg) + 1); + if (msg) PL_strcpy(msg, htmlMsg); + + return msg; +} + +static void MimePgpe_free(void* output_closure) { + MimePgpeData* data = (MimePgpeData*)output_closure; + if (data->mimeDecrypt) { + data->mimeDecrypt->RemoveMimeCallback(); + data->mimeDecrypt = nullptr; + } +} + +/* Returns a string describing the location of the part (like "2.5.3"). + This is not a full URL, just a part-number. + */ +static nsCString determineMimePart(MimeObject* obj) { + char mimePartNum[20]; + MimeObject* kid; + MimeContainer* cont; + int32_t i; + + nsCString mimePart; + + while (obj->parent) { + cont = (MimeContainer*)obj->parent; + for (i = 0; i < cont->nchildren; i++) { + kid = cont->children[i]; + if (kid == obj) { + sprintf(mimePartNum, ".%d", i + 1); + mimePart.Insert(mimePartNum, 0); + } + } + obj = obj->parent; + } + + // remove leading "." + if (mimePart.Length() > 0) mimePart.Cut(0, 1); + + return mimePart; +} + +//////////////////////////////////////////////////////////////////////////// +NS_IMPL_ISUPPORTS(nsPgpMimeProxy, nsIPgpMimeProxy, nsIRequestObserver, + nsIStreamListener, nsIRequest, nsIInputStream) + +// nsPgpMimeProxy implementation +nsPgpMimeProxy::nsPgpMimeProxy() + : mInitialized(false), +#ifdef DEBUG + mOutputWasRemoved(false), +#endif + mOutputFun(nullptr), + mOutputClosure(nullptr), + mLoadFlags(LOAD_NORMAL), + mCancelStatus(NS_OK), + mAllowNestedDecrypt(false) { +} + +nsPgpMimeProxy::~nsPgpMimeProxy() { Finalize(); } + +nsresult nsPgpMimeProxy::Finalize() { return NS_OK; } + +NS_IMETHODIMP +nsPgpMimeProxy::SetMimeCallback(MimeDecodeCallbackFun outputFun, + void* outputClosure, nsIURI* myUri) { + if (!outputFun || !outputClosure) return NS_ERROR_NULL_POINTER; + + mOutputFun = outputFun; + mOutputClosure = outputClosure; + mInitialized = true; + mMessageURI = myUri; + + mStreamOffset = 0; + mByteBuf.Truncate(); + + if (mDecryptor) return mDecryptor->OnStartRequest((nsIRequest*)this); + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::RemoveMimeCallback() { + mOutputFun = nullptr; + mOutputClosure = nullptr; +#ifdef DEBUG + mOutputWasRemoved = true; +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::Init() { + mByteBuf.Truncate(); + + // Create add-on supplied decryption object. + nsresult rv; + mDecryptor = do_CreateInstance(PGPMIME_JS_DECRYPTOR_CONTRACTID, &rv); + if (NS_FAILED(rv)) mDecryptor = nullptr; + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::Write(const char* buf, uint32_t buf_size) { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + mByteBuf.Assign(buf, buf_size); + mStreamOffset = 0; + + // Pass data to the decryption object for decryption. + // The result is returned via OutputDecryptedData(). + if (mDecryptor) + return mDecryptor->OnDataAvailable((nsIRequest*)this, (nsIInputStream*)this, + 0, buf_size); + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::Finish() { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + if (mDecryptor) { + return mDecryptor->OnStopRequest((nsIRequest*)this, NS_OK); + } else { + if (!mOutputFun) return NS_ERROR_FAILURE; + + nsCString temp; + temp.AppendLiteral( + "Content-Type: text/html; Charset=utf-8\r\n\r\n"); + temp.AppendLiteral( + "
"); + temp.AppendLiteral("
"); + + nsCString tString; + PgpMimeGetNeedsAddonString(tString); + temp.Append(tString); + temp.AppendLiteral( + "

\r\n"); + + PR_SetError(0, 0); + int status = mOutputFun(temp.get(), temp.Length(), mOutputClosure); + if (status < 0) { + PR_SetError(status, 0); + mOutputFun = nullptr; + return NS_ERROR_FAILURE; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::GetDecryptor(nsIStreamListener** aDecryptor) { + NS_IF_ADDREF(*aDecryptor = mDecryptor); + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::SetDecryptor(nsIStreamListener* aDecryptor) { + mDecryptor = aDecryptor; + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::GetContentType(nsACString& aContentType) { + aContentType = mContentType; + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::SetContentType(const nsACString& aContentType) { + mContentType = aContentType; + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::GetMessageURI(nsIURI** aMessageURI) { + NS_IF_ADDREF(*aMessageURI = mMessageURI); + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::GetMimePart(nsACString& aMimePart) { + aMimePart = mMimePart; + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::SetMimePart(const nsACString& aMimePart) { + mMimePart = aMimePart; + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::SetAllowNestedDecrypt(bool aAllowNestedDecrypt) { + mAllowNestedDecrypt = aAllowNestedDecrypt; + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::GetAllowNestedDecrypt(bool* aAllowNestedDecrypt) { + *aAllowNestedDecrypt = mAllowNestedDecrypt; + return NS_OK; +} + +/** + * This method is called by the add-on-supplied decryption object. + * It passes the decrypted data back to the proxy which calls the + * output function is was initialised with. + */ +NS_IMETHODIMP +nsPgpMimeProxy::OutputDecryptedData(const char* buf, uint32_t buf_size) { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + NS_ENSURE_ARG(buf); + +#ifdef DEBUG + // If this assertion is hit, there might be a bug related to object + // lifetime, e.g. a JS MIME handler might live longer than the + // corresponding MIME data, e.g. bug 1665475. + NS_ASSERTION(!mOutputWasRemoved, "MIME data already destroyed"); +#endif + + if (!mOutputFun) return NS_ERROR_FAILURE; + + int status = mOutputFun(buf, buf_size, mOutputClosure); + if (status < 0) { + PR_SetError(status, 0); + mOutputFun = nullptr; + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// nsIRequest methods +/////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsPgpMimeProxy::GetName(nsACString& result) { + result = "pgpmimeproxy"; + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::IsPending(bool* result) { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + *result = NS_SUCCEEDED(mCancelStatus); + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::GetStatus(nsresult* status) { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + *status = mCancelStatus; + return NS_OK; +} + +NS_IMETHODIMP nsPgpMimeProxy::SetCanceledReason(const nsACString& aReason) { + return SetCanceledReasonImpl(aReason); +} + +NS_IMETHODIMP nsPgpMimeProxy::GetCanceledReason(nsACString& aReason) { + return GetCanceledReasonImpl(aReason); +} + +NS_IMETHODIMP nsPgpMimeProxy::CancelWithReason(nsresult aStatus, + const nsACString& aReason) { + return CancelWithReasonImpl(aStatus, aReason); +} + +// NOTE: We assume that OnStopRequest should not be called if +// request is canceled. This may be wrong! +NS_IMETHODIMP +nsPgpMimeProxy::Cancel(nsresult status) { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + // Need a non-zero status code to cancel + if (NS_SUCCEEDED(status)) return NS_ERROR_FAILURE; + + if (NS_SUCCEEDED(mCancelStatus)) mCancelStatus = status; + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::Suspend(void) { return NS_ERROR_NOT_IMPLEMENTED; } + +NS_IMETHODIMP +nsPgpMimeProxy::Resume(void) { return NS_ERROR_NOT_IMPLEMENTED; } + +NS_IMETHODIMP +nsPgpMimeProxy::GetLoadGroup(nsILoadGroup** aLoadGroup) { + NS_IF_ADDREF(*aLoadGroup = mLoadGroup); + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::SetLoadGroup(nsILoadGroup* aLoadGroup) { + mLoadGroup = aLoadGroup; + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::GetTRRMode(nsIRequest::TRRMode* aTRRMode) { + return GetTRRModeImpl(aTRRMode); +} + +NS_IMETHODIMP +nsPgpMimeProxy::SetTRRMode(nsIRequest::TRRMode aTRRMode) { + return SetTRRModeImpl(aTRRMode); +} + +NS_IMETHODIMP +nsPgpMimeProxy::GetLoadFlags(nsLoadFlags* aLoadFlags) { + *aLoadFlags = mLoadFlags; + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::SetLoadFlags(nsLoadFlags aLoadFlags) { + mLoadFlags = aLoadFlags; + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// nsIInputStream methods +/////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsPgpMimeProxy::Available(uint64_t* _retval) { + NS_ENSURE_ARG(_retval); + + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + *_retval = (mByteBuf.Length() > mStreamOffset) + ? mByteBuf.Length() - mStreamOffset + : 0; + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::Read(char* buf, uint32_t count, uint32_t* readCount) { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + if (!buf || !readCount) return NS_ERROR_NULL_POINTER; + + int32_t avail = (mByteBuf.Length() > mStreamOffset) + ? mByteBuf.Length() - mStreamOffset + : 0; + + uint32_t readyCount = ((uint32_t)avail > count) ? count : avail; + + if (readyCount) { + memcpy(buf, mByteBuf.get() + mStreamOffset, readyCount); + *readCount = readyCount; + } + + mStreamOffset += *readCount; + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::ReadSegments(nsWriteSegmentFun writer, void* aClosure, + uint32_t count, uint32_t* readCount) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPgpMimeProxy::IsNonBlocking(bool* aNonBlocking) { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + *aNonBlocking = true; + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::Close() { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + mStreamOffset = 0; + mByteBuf.Truncate(); + + return NS_OK; +} + +NS_IMETHODIMP nsPgpMimeProxy::StreamStatus() { return NS_OK; } + +/////////////////////////////////////////////////////////////////////////////// +// nsIStreamListener methods +/////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsPgpMimeProxy::OnStartRequest(nsIRequest* aRequest) { return NS_OK; } + +NS_IMETHODIMP +nsPgpMimeProxy::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) { + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// nsIStreamListener method +/////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsPgpMimeProxy::OnDataAvailable(nsIRequest* aRequest, + nsIInputStream* aInputStream, + uint64_t aSourceOffset, uint32_t aLength) { + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_ARG(aInputStream); + + if (!mOutputFun) return NS_ERROR_FAILURE; + + char buf[kCharMax]; + uint32_t readCount, readMax; + + while (aLength > 0) { + readMax = (aLength < kCharMax) ? aLength : kCharMax; + + nsresult rv; + rv = aInputStream->Read((char*)buf, readMax, &readCount); + NS_ENSURE_SUCCESS(rv, rv); + + int status = mOutputFun(buf, readCount, mOutputClosure); + if (status < 0) { + PR_SetError(status, 0); + mOutputFun = nullptr; + return NS_ERROR_FAILURE; + } + + aLength -= readCount; + } + + return NS_OK; +} diff --git a/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.h b/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.h new file mode 100644 index 0000000000..e115be2ddd --- /dev/null +++ b/comm/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.h @@ -0,0 +1,73 @@ +/* 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/. */ + +#ifndef _nsPgpmimeDecrypt_h_ +#define _nsPgpmimeDecrypt_h_ + +#include "mimecth.h" +#include "nsIPgpMimeProxy.h" +#include "nsCOMPtr.h" +#include "nsIStreamListener.h" +#include "nsIInputStream.h" +#include "nsILoadGroup.h" + +#define PGPMIME_JS_DECRYPTOR_CONTRACTID \ + "@mozilla.org/mime/pgp-mime-js-decrypt;1" + +typedef struct MimeEncryptedPgpClass MimeEncryptedPgpClass; +typedef struct MimeEncryptedPgp MimeEncryptedPgp; + +struct MimeEncryptedPgpClass { + MimeEncryptedClass encrypted; +}; + +struct MimeEncryptedPgp { + MimeEncrypted encrypted; +}; + +class nsPgpMimeProxy : public nsIPgpMimeProxy, + public nsIRequest, + public nsIInputStream { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIPGPMIMEPROXY + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIREQUEST + NS_DECL_NSIINPUTSTREAM + + nsPgpMimeProxy(); + + // Define a Create method to be used with a factory: + static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult); + + protected: + virtual ~nsPgpMimeProxy(); + bool mInitialized; + nsCOMPtr mDecryptor; + +#ifdef DEBUG + PRBool mOutputWasRemoved; +#endif + MimeDecodeCallbackFun mOutputFun; + void* mOutputClosure; + + nsCOMPtr mLoadGroup; + nsLoadFlags mLoadFlags; + nsresult mCancelStatus; + + uint32_t mStreamOffset; + nsCString mByteBuf; + nsCString mContentType; + nsCString mMimePart; + bool mAllowNestedDecrypt; + + nsCOMPtr mMessageURI; + nsresult Finalize(); +}; + +#define MimeEncryptedPgpClassInitializer(ITYPE, CSUPER) \ + { MimeEncryptedClassInitializer(ITYPE, CSUPER) } + +#endif -- cgit v1.2.3