diff options
Diffstat (limited to 'mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp')
-rw-r--r-- | mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp b/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp new file mode 100644 index 000000000..de4ec3174 --- /dev/null +++ b/mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp @@ -0,0 +1,634 @@ +/* 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 "nsStringGlue.h" +#include "mozilla/Services.h" +#include "nsIRequest.h" +#include "nsIStringBundle.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIURI.h" +#include "mimexpcom.h" +#include "nsMsgUtils.h" + +#include "nsMsgMimeCID.h" + +#include "mimecth.h" +#include "mimemoz2.h" +#include "nspr.h" +#include "plstr.h" +#include "nsIPgpMimeProxy.h" +#include "nsComponentManagerUtils.h" + +#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 u"pgpMimeNeedsAddon" +#define PGPMIME_URL_PREF "mail.pgpmime.addon_url" + +static void PgpMimeGetNeedsAddonString(nsCString &aResult) +{ + aResult.AssignLiteral("???"); + + nsCOMPtr<nsIStringBundleService> stringBundleService = + mozilla::services::GetStringBundleService(); + + nsCOMPtr<nsIStringBundle> stringBundle; + nsresult rv = stringBundleService->CreateBundle(PGPMIME_PROPERTIES_URL, + getter_AddRefs(stringBundle)); + if (NS_FAILED(rv)) + return; + + nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return; + + nsCString url; + if (NS_FAILED(prefs->GetCharPref("mail.pgpmime.addon_url", + getter_Copies(url)))) + return; + + NS_ConvertUTF8toUTF16 url16(url); + const char16_t *formatStrings[] = { url16.get() }; + + nsString result; + rv = stringBundle->FormatStringFromName(PGPMIME_STR_NOT_SUPPORTED_ID, + formatStrings, 1, getter_Copies(result)); + if (NS_FAILED(rv)) + return; + aResult = NS_ConvertUTF16toUTF8(result); +} + +static int +MimeEncryptedPgpClassInitialize(MimeEncryptedPgpClass *clazz) +{ + mozilla::DebugOnly<MimeObjectClass *> 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<nsIPgpMimeProxy> 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; + + 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; + + mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure); + nsIChannel *channel = msd->channel; + + nsCOMPtr<nsIURI> uri; + if (channel) + channel->GetURI(getter_AddRefs(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 = nullptr; + return 0; +} + +static char* +MimePgpe_generate(void *output_closure) +{ + const char htmlMsg[] = "<html><body><b>GEN MSG<b></body></html>"; + char* msg = (char *) PR_MALLOC(strlen(htmlMsg) + 1); + if (msg) + PL_strcpy(msg, htmlMsg); + + return msg; +} + +static void +MimePgpe_free(void *output_closure) +{ +} + +/* 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), + mDecryptor(nullptr), + mLoadGroup(nullptr), + mLoadFlags(LOAD_NORMAL), + mCancelStatus(NS_OK) +{ +} + +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; + + mStreamOffset = 0; + mByteBuf.Truncate(); + + if (mDecryptor) + return mDecryptor->OnStartRequest((nsIRequest*) this, myUri); + + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::Init() +{ + mByteBuf.Truncate(); + + nsresult rv; + nsCOMPtr<nsIPrefBranch> pbi(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return 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; + + if (mDecryptor) + return mDecryptor->OnDataAvailable((nsIRequest*) this, nullptr, (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, nullptr, NS_OK); + } + else { + nsCString temp; + temp.Append("Content-Type: text/html\r\nCharset: UTF-8\r\n\r\n<html><body>"); + temp.Append("<BR><text=\"#000000\" bgcolor=\"#FFFFFF\" link=\"#FF0000\" vlink=\"#800080\" alink=\"#0000FF\">"); + temp.Append("<center><table BORDER=1 ><tr><td><CENTER>"); + + nsCString tString; + PgpMimeGetNeedsAddonString(tString); + temp.Append(tString); + temp.Append("</CENTER></td></tr></table></center><BR></body></html>\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::GetMimePart(nsACString &aMimePart) +{ + aMimePart = mMimePart; + return NS_OK; +} + + +NS_IMETHODIMP +nsPgpMimeProxy::SetMimePart(const nsACString &aMimePart) +{ + mMimePart = aMimePart; + 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; +} + +// 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::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; +} + +/////////////////////////////////////////////////////////////////////////////// +// nsIStreamListener methods +/////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsPgpMimeProxy::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsPgpMimeProxy::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, + nsresult aStatus) +{ + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// nsIStreamListener method +/////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsPgpMimeProxy::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, + nsIInputStream *aInputStream, + uint64_t aSourceOffset, + uint32_t aLength) +{ + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + + NS_ENSURE_ARG(aInputStream); + + 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; +} |