Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

View file

@ -0,0 +1,132 @@
/* -*- 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/. */
#include "nsIComponentManager.h"
#include "nsIMimeObjectClassAccess.h"
#include "nsMsgMimeCID.h"
#include "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
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<nsIMimeObjectClassAccess> 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<nsIMimeObjectClassAccess> 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<nsIMimeObjectClassAccess> 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<nsIMimeObjectClassAccess> 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<nsIMimeObjectClassAccess> 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<nsIMimeObjectClassAccess> 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<nsIMimeObjectClassAccess> 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<nsIMimeObjectClassAccess> objAccess =
do_CreateInstance(kMimeObjectClassAccessCID, &res);
if (NS_SUCCEEDED(res) && objAccess)
objAccess->MimeCreate(content_type, hdrs, opts, &ptr);
return ptr;
}

View file

@ -0,0 +1,93 @@
/* -*- 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_ */

View file

@ -0,0 +1,18 @@
# 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')

View file

@ -0,0 +1,60 @@
/* -*- 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/. */
#include <stdio.h>
#include "nscore.h"
#include "plstr.h"
//#include "mimecth.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) {
NS_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;
}

View file

@ -0,0 +1,47 @@
/* -*- 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_ */

View file

@ -0,0 +1,12 @@
# 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',
'vcard',
'pgpmime',
]

View file

@ -0,0 +1,20 @@
# 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',
]

View file

@ -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;
}

View file

@ -0,0 +1,69 @@
/* 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 NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
protected:
virtual ~nsPgpMimeProxy();
bool mInitialized;
nsCOMPtr<nsIStreamListener> mDecryptor;
MimeDecodeCallbackFun mOutputFun;
void* mOutputClosure;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsLoadFlags mLoadFlags;
nsresult mCancelStatus;
uint32_t mStreamOffset;
nsCString mByteBuf;
nsCString mContentType;
nsCString mMimePart;
nsresult Finalize();
};
#define MimeEncryptedPgpClassInitializer(ITYPE,CSUPER) \
{ MimeEncryptedClassInitializer(ITYPE,CSUPER) }
#endif

View file

@ -0,0 +1,378 @@
/* -*- 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/. */
#include "mimevcrd.h"
#include "mimecth.h"
#include "mimexpcom.h"
#include "nsIMsgVCardService.h"
#include "nsINetUtil.h"
#include "nsMsgUtils.h"
#include "prmem.h"
#include "prprf.h"
#include "nsServiceManagerUtils.h"
static int MimeInlineTextVCard_parse_line (const char *, int32_t, MimeObject *);
static int MimeInlineTextVCard_parse_eof (MimeObject *, bool);
static int MimeInlineTextVCard_parse_begin (MimeObject *obj);
static int s_unique = 0;
static int BeginVCard (MimeObject *obj);
static int EndVCard (MimeObject *obj);
static int WriteOutVCard (MimeObject *obj, VObject* v);
static int GenerateVCardData(MimeObject * aMimeObj, VObject* aVcard);
static int OutputVcardAttribute(MimeObject *aMimeObj, VObject *aVcard, const char* id, nsACString& vCardOutput);
static int OutputBasicVcard(MimeObject *aMimeObj, VObject *aVcard, nsACString& vCardOutput);
typedef struct
{
const char *attributeName;
int resourceId;
} AttributeName;
#define kNumAttributes 12
#define MSGVCARDSERVICE_CONTRACT_ID "@mozilla.org/addressbook/msgvcardservice;1"
/* This is the object definition. Note: we will set the superclass
to NULL and manually set this on the class creation */
MimeDefClass(MimeInlineTextVCard, MimeInlineTextVCardClass,
mimeInlineTextVCardClass, NULL);
extern "C" MimeObjectClass *
MIME_VCardCreateContentTypeHandlerClass(const char *content_type,
contentTypeHandlerInitStruct *initStruct)
{
MimeObjectClass *clazz = (MimeObjectClass *)&mimeInlineTextVCardClass;
/*
* Must set the superclass by hand.
*/
if (!COM_GetmimeInlineTextClass())
return NULL;
clazz->superclass = (MimeObjectClass *)COM_GetmimeInlineTextClass();
initStruct->force_inline_display = true;
return clazz;
}
/*
* Implementation of VCard clazz
*/
static int
MimeInlineTextVCardClassInitialize(MimeInlineTextVCardClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
NS_ASSERTION(!oclass->class_initialized, "1.1 <rhp@netscape.com> 19 Mar 1999 12:11");
oclass->parse_begin = MimeInlineTextVCard_parse_begin;
oclass->parse_line = MimeInlineTextVCard_parse_line;
oclass->parse_eof = MimeInlineTextVCard_parse_eof;
return 0;
}
static int
MimeInlineTextVCard_parse_begin (MimeObject *obj)
{
int status = ((MimeObjectClass*)COM_GetmimeLeafClass())->parse_begin(obj);
MimeInlineTextVCardClass *clazz;
if (status < 0) return status;
if (!obj->output_p) return 0;
if (!obj->options || !obj->options->write_html_p) return 0;
/* This is a fine place to write out any HTML before the real meat begins.
In this sample code, we tell it to start a table. */
clazz = ((MimeInlineTextVCardClass *) obj->clazz);
/* initialize vcard string to empty; */
NS_MsgSACopy(&(clazz->vCardString), "");
obj->options->state->separator_suppressed_p = true;
return 0;
}
char *strcpySafe (char *dest, const char *src, size_t destLength)
{
char *result = strncpy (dest, src, --destLength);
dest[destLength] = '\0';
return result;
}
static int
MimeInlineTextVCard_parse_line (const char *line, int32_t length, MimeObject *obj)
{
// This routine gets fed each line of data, one at a time.
char* linestring;
MimeInlineTextVCardClass *clazz = ((MimeInlineTextVCardClass *) obj->clazz);
if (!obj->output_p) return 0;
if (!obj->options || !obj->options->output_fn) return 0;
if (!obj->options->write_html_p)
{
return COM_MimeObject_write(obj, line, length, true);
}
linestring = (char *) PR_MALLOC (length + 1);
memset(linestring, 0, (length + 1));
if (linestring)
{
strcpySafe((char *)linestring, line, length + 1);
NS_MsgSACat (&clazz->vCardString, linestring);
PR_Free (linestring);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
static int
MimeInlineTextVCard_parse_eof (MimeObject *obj, bool abort_p)
{
nsCOMPtr<nsIMsgVCardService> vCardService =
do_GetService(MSGVCARDSERVICE_CONTRACT_ID);
if (!vCardService)
return -1;
int status = 0;
MimeInlineTextVCardClass *clazz = ((MimeInlineTextVCardClass *) obj->clazz);
VObject *t, *v;
if (obj->closed_p) return 0;
/* Run parent method first, to flush out any buffered data. */
// status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
status = ((MimeObjectClass*)COM_GetmimeInlineTextClass())->parse_eof(obj, abort_p);
if (status < 0) return status;
// Don't quote vCards...
if ( (obj->options) &&
((obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting) ||
(obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting))
)
return 0;
if (!clazz->vCardString) return 0;
v = vCardService->Parse_MIME(clazz->vCardString, strlen(clazz->vCardString));
NS_ASSERTION(v, "parse of vCard failed");
if (clazz->vCardString) {
PR_Free ((char*) clazz->vCardString);
clazz->vCardString = NULL;
}
if (obj->output_p && obj->options && obj->options->write_html_p &&
obj->options->headers != MimeHeadersCitation) {
/* This is a fine place to write any closing HTML. In fact, you may
want all the writing to be here, and all of the above would just
collect data into datastructures, though that isn't very
"streaming". */
t = v;
while (v && status >= 0) {
/* write out html */
status = WriteOutVCard (obj, v);
/* parse next vcard incase they're embedded */
v = vCardService->NextVObjectInList(v);
}
(void)vCardService->CleanVObject(t);
}
if (status < 0)
return status;
return 0;
}
static int EndVCard (MimeObject *obj)
{
int status = 0;
/* Scribble HTML-ending stuff into the stream */
char htmlFooters[32];
PR_snprintf (htmlFooters, sizeof(htmlFooters), "</BODY>%s</HTML>%s", MSG_LINEBREAK, MSG_LINEBREAK);
status = COM_MimeObject_write(obj, htmlFooters, strlen(htmlFooters), false);
if (status < 0) return status;
return 0;
}
static int BeginVCard (MimeObject *obj)
{
int status = 0;
/* Scribble HTML-starting stuff into the stream */
char htmlHeaders[32];
s_unique++;
PR_snprintf (htmlHeaders, sizeof(htmlHeaders), "<HTML>%s<BODY>%s", MSG_LINEBREAK, MSG_LINEBREAK);
status = COM_MimeObject_write(obj, htmlHeaders, strlen(htmlHeaders), true);
if (status < 0) return status;
return 0;
}
static int WriteOutVCard (MimeObject * aMimeObj, VObject* aVcard)
{
BeginVCard (aMimeObj);
GenerateVCardData(aMimeObj, aVcard);
return EndVCard (aMimeObj);
}
static int GenerateVCardData(MimeObject * aMimeObj, VObject* aVcard)
{
// style is driven from CSS not here. Just layout the minimal vCard data
nsCString vCardOutput;
vCardOutput = "<table class=\"moz-vcard-table\"> <tr> "; // outer table plus the first (and only row) we use for this table
// we need to get an escaped vCard url to bind to our add to address book button
nsCOMPtr<nsIMsgVCardService> vCardService = do_GetService(MSGVCARDSERVICE_CONTRACT_ID);
if (!vCardService)
return -1;
nsAutoCString vCard;
nsAutoCString vEscCard;
int len = 0;
vCard.Adopt(vCardService->WriteMemoryVObjects(0, &len, aVcard, false));
MsgEscapeString(vCard, nsINetUtil::ESCAPE_XALPHAS, vEscCard);
// first cell in the outer table row is a clickable image which brings up the rich address book UI for the vcard
vCardOutput += "<td valign=\"top\"> <a class=\"moz-vcard-badge\" href=\"addbook:add?action=add?vcard=";
vCardOutput += vEscCard; // the href is the vCard
vCardOutput += "\"></a></td>";
// the 2nd cell in the outer table row is a nested table containing the actual vCard properties
vCardOutput += "<td> <table id=\"moz-vcard-properties-table\"> <tr> ";
OutputBasicVcard(aMimeObj, aVcard, vCardOutput);
// close the properties table
vCardOutput += "</table> </td> ";
// 2nd cell in the outer table is our vCard image
vCardOutput += "</tr> </table>";
// now write out the vCard
return COM_MimeObject_write(aMimeObj, (char *) vCardOutput.get(), vCardOutput.Length(), true);
}
static int OutputBasicVcard(MimeObject *aMimeObj, VObject *aVcard, nsACString& vCardOutput)
{
VObject *prop = NULL;
nsAutoCString urlstring;
nsAutoCString namestring;
nsAutoCString emailstring;
nsCOMPtr<nsIMsgVCardService> vCardService = do_GetService(MSGVCARDSERVICE_CONTRACT_ID);
if (!vCardService)
return -1;
/* get the name and email */
prop = vCardService->IsAPropertyOf(aVcard, VCFullNameProp);
if (prop)
{
if (VALUE_TYPE(prop))
{
if (VALUE_TYPE(prop) != VCVT_RAW)
namestring.Adopt(vCardService->FakeCString(prop));
else
namestring.Adopt(vCardService->VObjectAnyValue(prop));
if (!namestring.IsEmpty())
{
vCardOutput += "<td class=\"moz-vcard-title-property\"> ";
prop = vCardService->IsAPropertyOf(aVcard, VCURLProp);
if (prop)
{
urlstring.Adopt(vCardService->FakeCString(prop));
if (urlstring.IsEmpty())
vCardOutput += namestring;
else
{
char buf[512];
PR_snprintf(buf, 512, "<a href=""%s"" private>%s</a>", urlstring.get(), namestring.get());
vCardOutput.Append(buf);
}
}
else
vCardOutput += namestring;
/* get the email address */
prop = vCardService->IsAPropertyOf(aVcard, VCEmailAddressProp);
if (prop)
{
emailstring.Adopt(vCardService->FakeCString(prop));
if (!emailstring.IsEmpty())
{
char buf[512];
PR_snprintf(buf, 512, "&nbsp;&lt;<a href=""mailto:%s"" private>%s</a>&gt;", emailstring.get(), emailstring.get());
vCardOutput.Append(buf);
}
} // if email address property
vCardOutput += "</td> </tr> "; // end the cell for the name/email address
} // if we have a name property
}
} // if full name property
// now each basic property goes on its own line
// title
(void) OutputVcardAttribute (aMimeObj, aVcard, VCTitleProp, vCardOutput);
// org name and company name
prop = vCardService->IsAPropertyOf(aVcard, VCOrgProp);
if (prop)
{
OutputVcardAttribute (aMimeObj, prop, VCOrgUnitProp, vCardOutput);
OutputVcardAttribute (aMimeObj, prop, VCOrgNameProp, vCardOutput);
}
return 0;
}
static int OutputVcardAttribute(MimeObject *aMimeObj, VObject *aVcard, const char* id, nsACString& vCardOutput)
{
VObject *prop = NULL;
nsAutoCString string;
nsCOMPtr<nsIMsgVCardService> vCardService = do_GetService(MSGVCARDSERVICE_CONTRACT_ID);
if (!vCardService)
return -1;
prop = vCardService->IsAPropertyOf(aVcard, id);
if (prop)
if (VALUE_TYPE(prop))
{
if (VALUE_TYPE(prop) != VCVT_RAW)
string.Adopt(vCardService->FakeCString(prop));
else
string.Adopt(vCardService->VObjectAnyValue(prop));
if (!string.IsEmpty())
{
vCardOutput += "<tr> <td class=\"moz-vcard-property\">";
vCardOutput += string;
vCardOutput += "</td> </tr> ";
}
}
return 0;
}

View file

@ -0,0 +1,33 @@
/* -*- 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/. */
#ifndef _MIMEVCRD_H_
#define _MIMEVCRD_H_
#include "mimetext.h"
#include "nsCOMPtr.h"
/* The MimeInlineTextHTML class implements the text/x-vcard and (maybe?
someday?) the application/directory MIME content types.
*/
typedef struct MimeInlineTextVCardClass MimeInlineTextVCardClass;
typedef struct MimeInlineTextVCard MimeInlineTextVCard;
struct MimeInlineTextVCardClass {
MimeInlineTextClass text;
char *vCardString;
};
extern MimeInlineTextVCardClass mimeInlineTextVCardClass;
struct MimeInlineTextVCard {
MimeInlineText text;
};
#define MimeInlineTextVCardClassInitializer(ITYPE,CSUPER) \
{ MimeInlineTextClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEVCRD_H_ */

View file

@ -0,0 +1,14 @@
# 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/.
SOURCES += [
'mimevcrd.cpp',
]
FINAL_LIBRARY = 'mail'
LOCAL_INCLUDES += [
'../glue',
]

View file

@ -0,0 +1,21 @@
# 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 += [
'nsMimeEmitterCID.h',
]
SOURCES += [
'nsEmitterUtils.cpp',
'nsMimeBaseEmitter.cpp',
'nsMimeHtmlEmitter.cpp',
'nsMimePlainEmitter.cpp',
'nsMimeRawEmitter.cpp',
'nsMimeRebuffer.cpp',
'nsMimeXmlEmitter.cpp',
]
FINAL_LIBRARY = 'mail'

View file

@ -0,0 +1,67 @@
/* -*- 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/. */
#include "nsCOMPtr.h"
#include "prmem.h"
#include "plstr.h"
#include "nsMailHeaders.h"
#include "nsIMimeEmitter.h"
#include "nsIStringBundle.h"
#include "nsIServiceManager.h"
#include "nsIIOService.h"
#include "nsIURI.h"
#include "prprf.h"
extern "C" bool
EmitThisHeaderForPrefSetting(int32_t dispType, const char *header)
{
if (nsMimeHeaderDisplayTypes::AllHeaders == dispType)
return true;
if ((!header) || (!*header))
return false;
if (nsMimeHeaderDisplayTypes::MicroHeaders == dispType)
{
if (
(!strcmp(header, HEADER_SUBJECT)) ||
(!strcmp(header, HEADER_FROM)) ||
(!strcmp(header, HEADER_DATE))
)
return true;
else
return false;
}
if (nsMimeHeaderDisplayTypes::NormalHeaders == dispType)
{
if (
(!strcmp(header, HEADER_DATE)) ||
(!strcmp(header, HEADER_TO)) ||
(!strcmp(header, HEADER_SUBJECT)) ||
(!strcmp(header, HEADER_SENDER)) ||
(!strcmp(header, HEADER_RESENT_TO)) ||
(!strcmp(header, HEADER_RESENT_SENDER)) ||
(!strcmp(header, HEADER_RESENT_FROM)) ||
(!strcmp(header, HEADER_RESENT_CC)) ||
(!strcmp(header, HEADER_REPLY_TO)) ||
(!strcmp(header, HEADER_REFERENCES)) ||
(!strcmp(header, HEADER_NEWSGROUPS)) ||
(!strcmp(header, HEADER_MESSAGE_ID)) ||
(!strcmp(header, HEADER_FROM)) ||
(!strcmp(header, HEADER_FOLLOWUP_TO)) ||
(!strcmp(header, HEADER_CC)) ||
(!strcmp(header, HEADER_ORGANIZATION)) ||
(!strcmp(header, HEADER_REPLY_TO)) ||
(!strcmp(header, HEADER_BCC))
)
return true;
else
return false;
}
return true;
}

View file

@ -0,0 +1,14 @@
/* -*- 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/. */
#ifndef _nsEmitterUtils_h_
#define _nsEmitterUtils_h_
#include "prmem.h"
#include "plstr.h"
extern "C" bool EmitThisHeaderForPrefSetting(int32_t dispType, const char *header);
#endif // _nsEmitterUtils_h_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,147 @@
/* -*- 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/. */
#ifndef _nsMimeBaseEmitter_h_
#define _nsMimeBaseEmitter_h_
#include "prio.h"
#include "nsIMimeEmitter.h"
#include "nsMimeRebuffer.h"
#include "nsIStreamListener.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIAsyncInputStream.h"
#include "nsIURI.h"
#include "nsIChannel.h"
#include "nsIMimeMiscStatus.h"
#include "nsIPipe.h"
#include "nsIStringBundle.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsIMimeConverter.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIDateTimeFormat.h"
//
// The base emitter will serve as the place to do all of the caching,
// sorting, etc... of mail headers and bodies for this internally developed
// emitter library. The other emitter classes in this file (nsMimeHTMLEmitter, etc.)
// will only be concerned with doing output processing ONLY.
//
//
// Used for keeping track of the attachment information...
//
typedef struct {
char *displayName;
char *urlSpec;
char *contentType;
bool isExternalAttachment;
} attachmentInfoType;
//
// For header info...
//
typedef struct {
char *name;
char *value;
} headerInfoType;
class nsMimeBaseEmitter : public nsIMimeEmitter,
public nsIInterfaceRequestor
{
public:
nsMimeBaseEmitter ();
// nsISupports interface
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIMIMEEMITTER
NS_DECL_NSIINTERFACEREQUESTOR
// Utility output functions...
NS_IMETHOD UtilityWrite(const nsACString &buf);
NS_IMETHOD UtilityWriteCRLF(const char *buf);
// For string bundle usage...
char *MimeGetStringByName(const char *aHeaderName);
char *MimeGetStringByID(int32_t aID);
char *LocalizeHeaderName(const char *aHeaderName, const char *aDefaultName);
// For header processing...
const char *GetHeaderValue(const char *aHeaderName);
// To write out a stored header array as HTML
virtual nsresult WriteHeaderFieldHTMLPrefix(const nsACString &name);
virtual nsresult WriteHeaderFieldHTML(const char *field, const char *value);
virtual nsresult WriteHeaderFieldHTMLPostfix();
protected:
virtual ~nsMimeBaseEmitter();
// Internal methods...
void CleanupHeaderArray(nsTArray<headerInfoType*> *aArray);
// For header output...
nsresult DumpSubjectFromDate();
nsresult DumpToCC();
nsresult DumpRestOfHeaders();
nsresult OutputGenericHeader(const char *aHeaderVal);
nsresult WriteHelper(const nsACString &buf, uint32_t *countWritten);
// For string bundle usage...
nsCOMPtr<nsIStringBundle> m_stringBundle; // for translated strings
nsCOMPtr<nsIStringBundle> m_headerStringBundle; // for non-translated header strings
// For buffer management on output
MimeRebuffer *mBufferMgr;
// mscott
// don't ref count the streams....the emitter is owned by the converter
// which owns these streams...
//
nsIOutputStream *mOutStream;
nsIInputStream *mInputStream;
nsIStreamListener *mOutListener;
nsCOMPtr<nsIChannel> mChannel;
// For gathering statistics on processing...
uint32_t mTotalWritten;
uint32_t mTotalRead;
// Output control and info...
bool mDocHeader; // For header determination...
nsIURI *mURL; // the url for the data being processed...
int32_t mHeaderDisplayType; // The setting for header output...
nsCString mHTMLHeaders; // HTML Header Data...
// For attachment processing...
int32_t mAttachCount;
nsTArray<attachmentInfoType*> *mAttachArray;
attachmentInfoType *mCurrentAttachment;
// For header caching...
nsTArray<headerInfoType*> *mHeaderArray;
nsTArray<headerInfoType*> *mEmbeddedHeaderArray;
// For body caching...
bool mBodyStarted;
nsCString mBody;
bool mFirstHeaders;
// For the format being used...
int32_t mFormat;
// For I18N Conversion...
nsCOMPtr<nsIMimeConverter> mUnicodeConverter;
nsString mCharset;
nsCOMPtr<nsIDateTimeFormat> mDateFormatter;
nsresult GenerateDateString(const char * dateString, nsACString& formattedDate,
bool showDateForToday);
// The caller is expected to free the result of GetLocalizedDateString
char* GetLocalizedDateString(const char * dateString);
};
#endif /* _nsMimeBaseEmitter_h_ */

View file

@ -0,0 +1,51 @@
/* -*- 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/. */
#ifndef nsMimeEmitterCID_h__
#define nsMimeEmitterCID_h__
#include "nsISupports.h"
#include "nsIFactory.h"
#include "nsIComponentManager.h"
#define NS_MIME_EMITTER_CONTRACTID_PREFIX \
"@mozilla.org/messenger/mimeemitter;1?type="
#define NS_HTML_MIME_EMITTER_CONTRACTID \
NS_MIME_EMITTER_CONTRACTID_PREFIX "text/html"
// {F0A8AF16-DCCE-11d2-A411-00805F613C79}
#define NS_HTML_MIME_EMITTER_CID \
{ 0xf0a8af16, 0xdcce, 0x11d2, \
{ 0xa4, 0x11, 0x0, 0x80, 0x5f, 0x61, 0x3c, 0x79 } }
#define NS_XML_MIME_EMITTER_CONTRACTID \
NS_MIME_EMITTER_CONTRACTID_PREFIX "text/xml"
// {977E418F-E392-11d2-A2AC-00A024A7D144}
#define NS_XML_MIME_EMITTER_CID \
{ 0x977e418f, 0xe392, 0x11d2, \
{ 0xa2, 0xac, 0x0, 0xa0, 0x24, 0xa7, 0xd1, 0x44 } }
#define NS_RAW_MIME_EMITTER_CONTRACTID \
NS_MIME_EMITTER_CONTRACTID_PREFIX "raw"
// {F0A8AF16-DCFF-11d2-A411-00805F613C79}
#define NS_RAW_MIME_EMITTER_CID \
{ 0xf0a8af16, 0xdcff, 0x11d2, \
{ 0xa4, 0x11, 0x0, 0x80, 0x5f, 0x61, 0x3c, 0x79 } }
#define NS_XUL_MIME_EMITTER_CONTRACTID \
NS_MIME_EMITTER_CONTRACTID_PREFIX "application/vnd.mozilla.xul+xml"
// {FAA8AF16-DCFF-11d2-A411-00805F613C19}
#define NS_XUL_MIME_EMITTER_CID \
{ 0xfaa8af16, 0xdcff, 0x11d2, \
{ 0xa4, 0x11, 0x0, 0x80, 0x5f, 0x61, 0x3c, 0x19 } }
#define NS_PLAIN_MIME_EMITTER_CONTRACTID \
NS_MIME_EMITTER_CONTRACTID_PREFIX "text/plain"
// {E8892265-7653-46c5-A290-307F3404D0F3}
#define NS_PLAIN_MIME_EMITTER_CID \
{ 0xe8892265, 0x7653, 0x46c5, \
{ 0xa2, 0x90, 0x30, 0x7f, 0x34, 0x4, 0xd0, 0xf3 } }
#endif // nsMimeEmitterCID_h__

View file

@ -0,0 +1,543 @@
/* -*- 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/. */
#include "nsCOMPtr.h"
#include <stdio.h>
#include "nsMimeRebuffer.h"
#include "nsMimeHtmlEmitter.h"
#include "plstr.h"
#include "nsMailHeaders.h"
#include "nscore.h"
#include "nsEmitterUtils.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIMimeStreamConverter.h"
#include "nsIMsgWindow.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsMimeTypes.h"
#include "prtime.h"
#include "prprf.h"
#include "nsIStringEnumerator.h"
#include "nsServiceManagerUtils.h"
// hack: include this to fix opening news attachments.
#include "nsINntpUrl.h"
#include "nsComponentManagerUtils.h"
#include "nsIMimeConverter.h"
#include "nsMsgMimeCID.h"
#include "nsMsgUtils.h"
#include "nsAutoPtr.h"
#include "nsINetUtil.h"
#include "nsMemory.h"
#include "mozilla/Services.h"
#define VIEW_ALL_HEADERS 2
/**
* A helper class to implement nsIUTF8StringEnumerator
*/
class nsMimeStringEnumerator final : public nsIUTF8StringEnumerator {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIUTF8STRINGENUMERATOR
nsMimeStringEnumerator() : mCurrentIndex(0) {}
template<class T>
nsCString* Append(T value) { return mValues.AppendElement(value); }
protected:
~nsMimeStringEnumerator() {}
nsTArray<nsCString> mValues;
uint32_t mCurrentIndex; // consumers expect first-in first-out enumeration
};
NS_IMPL_ISUPPORTS(nsMimeStringEnumerator, nsIUTF8StringEnumerator)
NS_IMETHODIMP
nsMimeStringEnumerator::HasMore(bool *result)
{
NS_ENSURE_ARG_POINTER(result);
*result = mCurrentIndex < mValues.Length();
return NS_OK;
}
NS_IMETHODIMP
nsMimeStringEnumerator::GetNext(nsACString& result)
{
if (mCurrentIndex >= mValues.Length())
return NS_ERROR_UNEXPECTED;
result = mValues[mCurrentIndex++];
return NS_OK;
}
/*
* nsMimeHtmlEmitter definitions....
*/
nsMimeHtmlDisplayEmitter::nsMimeHtmlDisplayEmitter() : nsMimeBaseEmitter()
{
mFirst = true;
mSkipAttachment = false;
}
nsMimeHtmlDisplayEmitter::~nsMimeHtmlDisplayEmitter(void)
{
}
nsresult nsMimeHtmlDisplayEmitter::Init()
{
return NS_OK;
}
bool nsMimeHtmlDisplayEmitter::BroadCastHeadersAndAttachments()
{
// try to get a header sink if there is one....
nsCOMPtr<nsIMsgHeaderSink> headerSink;
nsresult rv = GetHeaderSink(getter_AddRefs(headerSink));
if (NS_SUCCEEDED(rv) && headerSink && mDocHeader)
return true;
else
return false;
}
nsresult
nsMimeHtmlDisplayEmitter::WriteHeaderFieldHTMLPrefix(const nsACString &name)
{
if (!BroadCastHeadersAndAttachments() || (mFormat == nsMimeOutput::nsMimeMessagePrintOutput))
return nsMimeBaseEmitter::WriteHeaderFieldHTMLPrefix(name);
else
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::WriteHeaderFieldHTML(const char *field, const char *value)
{
if (!BroadCastHeadersAndAttachments() || (mFormat == nsMimeOutput::nsMimeMessagePrintOutput))
return nsMimeBaseEmitter::WriteHeaderFieldHTML(field, value);
else
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::WriteHeaderFieldHTMLPostfix()
{
if (!BroadCastHeadersAndAttachments() || (mFormat == nsMimeOutput::nsMimeMessagePrintOutput))
return nsMimeBaseEmitter::WriteHeaderFieldHTMLPostfix();
else
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::GetHeaderSink(nsIMsgHeaderSink ** aHeaderSink)
{
nsresult rv = NS_OK;
if ( (mChannel) && (!mHeaderSink) )
{
nsCOMPtr<nsIURI> uri;
mChannel->GetURI(getter_AddRefs(uri));
if (uri)
{
nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(uri));
if (msgurl)
{
msgurl->GetMsgHeaderSink(getter_AddRefs(mHeaderSink));
if (!mHeaderSink) // if the url is not overriding the header sink, then just get the one from the msg window
{
nsCOMPtr<nsIMsgWindow> msgWindow;
msgurl->GetMsgWindow(getter_AddRefs(msgWindow));
if (msgWindow)
msgWindow->GetMsgHeaderSink(getter_AddRefs(mHeaderSink));
}
}
}
}
*aHeaderSink = mHeaderSink;
NS_IF_ADDREF(*aHeaderSink);
return rv;
}
nsresult nsMimeHtmlDisplayEmitter::BroadcastHeaders(nsIMsgHeaderSink * aHeaderSink, int32_t aHeaderMode, bool aFromNewsgroup)
{
// two string enumerators to pass out to the header sink
RefPtr<nsMimeStringEnumerator> headerNameEnumerator = new nsMimeStringEnumerator();
NS_ENSURE_TRUE(headerNameEnumerator, NS_ERROR_OUT_OF_MEMORY);
RefPtr<nsMimeStringEnumerator> headerValueEnumerator = new nsMimeStringEnumerator();
NS_ENSURE_TRUE(headerValueEnumerator, NS_ERROR_OUT_OF_MEMORY);
nsCString extraExpandedHeaders;
nsTArray<nsCString> extraExpandedHeadersArray;
nsAutoCString convertedDateString;
nsresult rv;
nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (pPrefBranch)
{
pPrefBranch->GetCharPref("mailnews.headers.extraExpandedHeaders", getter_Copies(extraExpandedHeaders));
// todo - should make this upper case
if (!extraExpandedHeaders.IsEmpty())
{
ToLowerCase(extraExpandedHeaders);
ParseString(extraExpandedHeaders, ' ', extraExpandedHeadersArray);
}
}
for (size_t i = 0; i < mHeaderArray->Length(); i++)
{
headerInfoType * headerInfo = mHeaderArray->ElementAt(i);
if ( (!headerInfo) || (!headerInfo->name) || (!(*headerInfo->name)) || (!headerInfo->value) || (!(*headerInfo->value)))
continue;
const char * headerValue = headerInfo->value;
// optimization: if we aren't in view all header view mode, we only show a small set of the total # of headers.
// don't waste time sending those out to the UI since the UI is going to ignore them anyway.
if (aHeaderMode != VIEW_ALL_HEADERS && (mFormat != nsMimeOutput::nsMimeMessageFilterSniffer))
{
nsDependentCString headerStr(headerInfo->name);
if (PL_strcasecmp("to", headerInfo->name) && PL_strcasecmp("from", headerInfo->name) &&
PL_strcasecmp("cc", headerInfo->name) && PL_strcasecmp("newsgroups", headerInfo->name) &&
PL_strcasecmp("bcc", headerInfo->name) && PL_strcasecmp("followup-to", headerInfo->name) &&
PL_strcasecmp("reply-to", headerInfo->name) && PL_strcasecmp("subject", headerInfo->name) &&
PL_strcasecmp("organization", headerInfo->name) && PL_strcasecmp("user-agent", headerInfo->name) &&
PL_strcasecmp("content-base", headerInfo->name) && PL_strcasecmp("sender", headerInfo->name) &&
PL_strcasecmp("date", headerInfo->name) && PL_strcasecmp("x-mailer", headerInfo->name) &&
PL_strcasecmp("content-type", headerInfo->name) && PL_strcasecmp("message-id", headerInfo->name) &&
PL_strcasecmp("x-newsreader", headerInfo->name) && PL_strcasecmp("x-mimeole", headerInfo->name) &&
PL_strcasecmp("references", headerInfo->name) && PL_strcasecmp("in-reply-to", headerInfo->name) &&
PL_strcasecmp("list-post", headerInfo->name) && PL_strcasecmp("delivered-to", headerInfo->name) &&
// make headerStr lower case because IndexOf is case-sensitive
(!extraExpandedHeadersArray.Length() || (ToLowerCase(headerStr),
!extraExpandedHeadersArray.Contains(headerStr))))
continue;
}
headerNameEnumerator->Append(headerInfo->name);
headerValueEnumerator->Append(headerValue);
// Add a localized version of the date header if we encounter it.
if (!PL_strcasecmp("Date", headerInfo->name))
{
headerNameEnumerator->Append("X-Mozilla-LocalizedDate");
GenerateDateString(headerValue, convertedDateString, false);
headerValueEnumerator->Append(convertedDateString);
}
}
aHeaderSink->ProcessHeaders(headerNameEnumerator, headerValueEnumerator, aFromNewsgroup);
return rv;
}
NS_IMETHODIMP nsMimeHtmlDisplayEmitter::WriteHTMLHeaders(const nsACString &name)
{
// if we aren't broadcasting headers OR printing...just do whatever
// our base class does...
if (mFormat == nsMimeOutput::nsMimeMessagePrintOutput)
{
return nsMimeBaseEmitter::WriteHTMLHeaders(name);
}
else if (!BroadCastHeadersAndAttachments() || !mDocHeader)
{
// This needs to be here to correct the output format if we are
// not going to broadcast headers to the XUL document.
if (mFormat == nsMimeOutput::nsMimeMessageBodyDisplay)
mFormat = nsMimeOutput::nsMimeMessagePrintOutput;
return nsMimeBaseEmitter::WriteHTMLHeaders(name);
}
else
mFirstHeaders = false;
bool bFromNewsgroups = false;
for (size_t j = 0; j < mHeaderArray->Length(); j++)
{
headerInfoType *headerInfo = mHeaderArray->ElementAt(j);
if (!(headerInfo && headerInfo->name && *headerInfo->name))
continue;
if (!PL_strcasecmp("Newsgroups", headerInfo->name))
{
bFromNewsgroups = true;
break;
}
}
// try to get a header sink if there is one....
nsCOMPtr<nsIMsgHeaderSink> headerSink;
nsresult rv = GetHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
{
int32_t viewMode = 0;
nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (pPrefBranch)
rv = pPrefBranch->GetIntPref("mail.show_headers", &viewMode);
rv = BroadcastHeaders(headerSink, viewMode, bFromNewsgroups);
} // if header Sink
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::EndHeader(const nsACString &name)
{
if (mDocHeader && (mFormat != nsMimeOutput::nsMimeMessageFilterSniffer))
{
UtilityWriteCRLF("<html>");
UtilityWriteCRLF("<head>");
const char * val = GetHeaderValue(HEADER_SUBJECT); // do not free this value
if (val)
{
char * subject = MsgEscapeHTML(val);
if (subject)
{
int32_t bufLen = strlen(subject) + 16;
char *buf = new char[bufLen];
if (!buf)
return NS_ERROR_OUT_OF_MEMORY;
PR_snprintf(buf, bufLen, "<title>%s</title>", subject);
UtilityWriteCRLF(buf);
delete [] buf;
free(subject);
}
}
// Stylesheet info!
UtilityWriteCRLF("<link rel=\"important stylesheet\" href=\"chrome://messagebody/skin/messageBody.css\">");
UtilityWriteCRLF("</head>");
UtilityWriteCRLF("<body>");
}
WriteHTMLHeaders(name);
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::StartAttachment(const nsACString &name,
const char *contentType,
const char *url,
bool aIsExternalAttachment)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMsgHeaderSink> headerSink;
rv = GetHeaderSink(getter_AddRefs(headerSink));
if (NS_SUCCEEDED(rv) && headerSink)
{
nsCString uriString;
nsCOMPtr<nsIMsgMessageUrl> msgurl (do_QueryInterface(mURL, &rv));
if (NS_SUCCEEDED(rv))
{
// HACK: news urls require us to use the originalSpec. Everyone
// else uses GetURI to get the RDF resource which describes the message.
nsCOMPtr<nsINntpUrl> nntpUrl (do_QueryInterface(mURL, &rv));
if (NS_SUCCEEDED(rv) && nntpUrl)
rv = msgurl->GetOriginalSpec(getter_Copies(uriString));
else
rv = msgurl->GetUri(getter_Copies(uriString));
}
// we need to convert the attachment name from UTF-8 to unicode before
// we emit it. The attachment name has already been rfc2047 processed
// upstream of us. (Namely, mime_decode_filename has been called, deferring
// to nsIMimeHeaderParam.decodeParameter.)
nsString unicodeHeaderValue;
CopyUTF8toUTF16(name, unicodeHeaderValue);
headerSink->HandleAttachment(contentType, url /* was escapedUrl */,
unicodeHeaderValue.get(), uriString.get(),
aIsExternalAttachment);
mSkipAttachment = false;
}
else if (mFormat == nsMimeOutput::nsMimeMessagePrintOutput)
{
// then we need to deal with the attachments in the body by inserting
// them into a table..
rv = StartAttachmentInBody(name, contentType, url);
}
else
{
// If we don't need or cannot broadcast attachment info, just ignore it
mSkipAttachment = true;
rv = NS_OK;
}
return rv;
}
// Attachment handling routines
// Ok, we are changing the way we handle these now...It used to be that we output
// HTML to make a clickable link, etc... but now, this should just be informational
// and only show up during printing
// XXX should they also show up during quoting?
nsresult
nsMimeHtmlDisplayEmitter::StartAttachmentInBody(const nsACString &name,
const char *contentType,
const char *url)
{
mSkipAttachment = false;
bool p7mExternal = false;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefs)
prefs->GetBoolPref("mailnews.p7m_external", &p7mExternal);
if ( (contentType) &&
((!p7mExternal && !strcmp(contentType, APPLICATION_XPKCS7_MIME)) ||
(!p7mExternal && !strcmp(contentType, APPLICATION_PKCS7_MIME)) ||
(!strcmp(contentType, APPLICATION_XPKCS7_SIGNATURE)) ||
(!strcmp(contentType, APPLICATION_PKCS7_SIGNATURE)) ||
(!strcmp(contentType, TEXT_VCARD)))
)
{
mSkipAttachment = true;
return NS_OK;
}
if (mFirst)
{
UtilityWrite("<br><fieldset class=\"mimeAttachmentHeader\">");
if (!name.IsEmpty())
{
nsresult rv;
nsCOMPtr<nsIStringBundleService> bundleSvc =
mozilla::services::GetStringBundleService();
NS_ENSURE_TRUE(bundleSvc, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleSvc->CreateBundle("chrome://messenger/locale/messenger.properties",
getter_AddRefs(bundle));
NS_ENSURE_SUCCESS(rv, rv);
nsString attachmentsHeader;
bundle->GetStringFromName(u"attachmentsPrintHeader",
getter_Copies(attachmentsHeader));
UtilityWrite("<legend class=\"mimeAttachmentHeaderName\">");
nsCString escapedName;
escapedName.Adopt(MsgEscapeHTML(NS_ConvertUTF16toUTF8(attachmentsHeader).get()));
UtilityWrite(escapedName.get());
UtilityWrite("</legend>");
}
UtilityWrite("</fieldset>");
UtilityWrite("<div class=\"mimeAttachmentWrap\">");
UtilityWrite("<table class=\"mimeAttachmentTable\">");
}
UtilityWrite("<tr>");
UtilityWrite("<td class=\"mimeAttachmentFile\">");
UtilityWrite(name);
UtilityWrite("</td>");
mFirst = false;
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::AddAttachmentField(const char *field, const char *value)
{
if (mSkipAttachment)
return NS_OK;
// Don't let bad things happen
if ( !value || !*value )
return NS_OK;
// Don't output this ugly header...
if (!strcmp(field, HEADER_X_MOZILLA_PART_URL))
return NS_OK;
nsCOMPtr<nsIMsgHeaderSink> headerSink;
nsresult rv = GetHeaderSink(getter_AddRefs(headerSink));
if (NS_SUCCEEDED(rv) && headerSink)
{
headerSink->AddAttachmentField(field, value);
}
else
{
// Currently, we only care about the part size.
if (strcmp(field, HEADER_X_MOZILLA_PART_SIZE))
return NS_OK;
uint64_t size = atoi(value);
nsAutoString sizeString;
rv = FormatFileSize(size, false, sizeString);
UtilityWrite("<td class=\"mimeAttachmentSize\">");
UtilityWrite(NS_ConvertUTF16toUTF8(sizeString).get());
UtilityWrite("</td>");
}
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::EndAttachment()
{
if (mSkipAttachment)
return NS_OK;
mSkipAttachment = false; // reset it for next attachment round
if (BroadCastHeadersAndAttachments())
return NS_OK;
if (mFormat == nsMimeOutput::nsMimeMessagePrintOutput)
UtilityWrite("</tr>");
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::EndAllAttachments()
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMsgHeaderSink> headerSink;
rv = GetHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
headerSink->OnEndAllAttachments();
if (mFormat == nsMimeOutput::nsMimeMessagePrintOutput)
{
UtilityWrite("</table>");
UtilityWrite("</div>");
}
return rv;
}
nsresult
nsMimeHtmlDisplayEmitter::WriteBody(const nsACString &buf,
uint32_t *amountWritten)
{
Write(buf, amountWritten);
return NS_OK;
}
nsresult
nsMimeHtmlDisplayEmitter::EndBody()
{
if (mFormat != nsMimeOutput::nsMimeMessageFilterSniffer)
{
UtilityWriteCRLF("</body>");
UtilityWriteCRLF("</html>");
}
nsCOMPtr<nsIMsgHeaderSink> headerSink;
nsresult rv = GetHeaderSink(getter_AddRefs(headerSink));
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl (do_QueryInterface(mURL, &rv));
if (headerSink)
headerSink->OnEndMsgHeaders(mailnewsUrl);
return NS_OK;
}

View file

@ -0,0 +1,64 @@
/* -*- 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/. */
#ifndef _nsMimeHtmlEmitter_h_
#define _nsMimeHtmlEmitter_h_
#include "mozilla/Attributes.h"
#include "prio.h"
#include "nsMimeBaseEmitter.h"
#include "nsMimeRebuffer.h"
#include "nsIStreamListener.h"
#include "nsIOutputStream.h"
#include "nsIInputStream.h"
#include "nsIURI.h"
#include "nsIChannel.h"
#include "nsIMimeMiscStatus.h"
#include "nsIMimeConverter.h"
class nsMimeHtmlDisplayEmitter : public nsMimeBaseEmitter {
public:
nsMimeHtmlDisplayEmitter ();
nsresult Init();
virtual ~nsMimeHtmlDisplayEmitter (void);
// Header handling routines.
NS_IMETHOD EndHeader(const nsACString &name) override;
// Attachment handling routines
NS_IMETHOD StartAttachment(const nsACString &name,
const char *contentType, const char *url,
bool aIsExternalAttachment) override;
NS_IMETHOD AddAttachmentField(const char *field, const char *value) override;
NS_IMETHOD EndAttachment() override;
NS_IMETHOD EndAllAttachments() override;
// Body handling routines
NS_IMETHOD WriteBody(const nsACString &buf, uint32_t *amountWritten) override;
NS_IMETHOD EndBody() override;
NS_IMETHOD WriteHTMLHeaders(const nsACString &name) override;
virtual nsresult WriteHeaderFieldHTMLPrefix(const nsACString &name
) override;
virtual nsresult WriteHeaderFieldHTML(const char *field,
const char *value) override;
virtual nsresult WriteHeaderFieldHTMLPostfix() override;
protected:
bool mFirst; // Attachment flag...
bool mSkipAttachment; // attachments we shouldn't show...
nsCOMPtr<nsIMsgHeaderSink> mHeaderSink;
nsresult GetHeaderSink(nsIMsgHeaderSink ** aHeaderSink);
bool BroadCastHeadersAndAttachments();
nsresult StartAttachmentInBody(const nsACString &name,
const char *contentType, const char *url);
nsresult BroadcastHeaders(nsIMsgHeaderSink * aHeaderSink, int32_t aHeaderMode, bool aFromNewsgroup);
};
#endif /* _nsMimeHtmlEmitter_h_ */

View file

@ -0,0 +1,64 @@
/* -*- 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/. */
#include <stdio.h>
#include "nsMimeRebuffer.h"
#include "nsMimePlainEmitter.h"
#include "plstr.h"
#include "nsMailHeaders.h"
#include "nscore.h"
#include "prmem.h"
#include "nsEmitterUtils.h"
#include "nsCOMPtr.h"
#include "nsUnicharUtils.h"
/*
* nsMimePlainEmitter definitions....
*/
nsMimePlainEmitter::nsMimePlainEmitter()
{
}
nsMimePlainEmitter::~nsMimePlainEmitter(void)
{
}
// Header handling routines.
nsresult
nsMimePlainEmitter::StartHeader(bool rootMailHeader, bool headerOnly, const char *msgID,
const char *outCharset)
{
mDocHeader = rootMailHeader;
return NS_OK;
}
nsresult
nsMimePlainEmitter::AddHeaderField(const char *field, const char *value)
{
if ( (!field) || (!value) )
return NS_OK;
UtilityWrite(field);
UtilityWrite(":\t");
UtilityWriteCRLF(value);
return NS_OK;
}
nsresult
nsMimePlainEmitter::EndHeader(const nsACString &name)
{
UtilityWriteCRLF("");
return NS_OK;
}
NS_IMETHODIMP
nsMimePlainEmitter::WriteBody(const nsACString &buf, uint32_t *amountWritten)
{
Write(buf, amountWritten);
return NS_OK;
}

View file

@ -0,0 +1,31 @@
/* -*- 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/. */
#ifndef _nsMimePlainEmitter_h_
#define _nsMimePlainEmitter_h_
#include "mozilla/Attributes.h"
#include "prio.h"
#include "nsMimeBaseEmitter.h"
#include "nsMimeRebuffer.h"
#include "nsIStreamListener.h"
#include "nsIOutputStream.h"
#include "nsIURI.h"
#include "nsIChannel.h"
class nsMimePlainEmitter : public nsMimeBaseEmitter {
public:
nsMimePlainEmitter ();
virtual ~nsMimePlainEmitter (void);
// Header handling routines.
NS_IMETHOD StartHeader(bool rootMailHeader, bool headerOnly, const char *msgID,
const char *outCharset) override;
NS_IMETHOD AddHeaderField(const char *field, const char *value) override;
NS_IMETHOD EndHeader(const nsACString &buf) override;
NS_IMETHOD WriteBody(const nsACString &buf, uint32_t *amountWritten) override;
};
#endif /* _nsMimePlainEmitter_h_ */

View file

@ -0,0 +1,34 @@
/* -*- 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/. */
#include "nsCOMPtr.h"
#include <stdio.h>
#include "nsMimeRebuffer.h"
#include "nsMimeRawEmitter.h"
#include "plstr.h"
#include "nsIMimeEmitter.h"
#include "nsMailHeaders.h"
#include "nscore.h"
#include "prmem.h"
#include "nsEmitterUtils.h"
/*
* nsMimeRawEmitter definitions....
*/
nsMimeRawEmitter::nsMimeRawEmitter()
{
}
nsMimeRawEmitter::~nsMimeRawEmitter(void)
{
}
NS_IMETHODIMP
nsMimeRawEmitter::WriteBody(const nsACString &buf, uint32_t *amountWritten)
{
Write(buf, amountWritten);
return NS_OK;
}

View file

@ -0,0 +1,29 @@
/* -*- 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/. */
#ifndef _nsMimeRawEmitter_h_
#define _nsMimeRawEmitter_h_
#include "mozilla/Attributes.h"
#include "prio.h"
#include "nsMimeBaseEmitter.h"
#include "nsMimeRebuffer.h"
#include "nsIStreamListener.h"
#include "nsIOutputStream.h"
#include "nsIURI.h"
#include "nsIChannel.h"
class nsMimeRawEmitter : public nsMimeBaseEmitter {
public:
nsMimeRawEmitter ();
virtual ~nsMimeRawEmitter (void);
NS_IMETHOD WriteBody(const nsACString &buf,
uint32_t *amountWritten) override;
protected:
};
#endif /* _nsMimeRawEmitter_h_ */

View file

@ -0,0 +1,50 @@
/* -*- 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/. */
#include <string.h>
#include "nsMimeRebuffer.h"
#include "prmem.h"
MimeRebuffer::MimeRebuffer(void)
{
}
MimeRebuffer::~MimeRebuffer(void)
{
}
uint32_t
MimeRebuffer::GetSize()
{
return mBuf.Length();
}
uint32_t
MimeRebuffer::IncreaseBuffer(const nsACString &addBuf)
{
mBuf.Append(addBuf);
return mBuf.Length();
}
uint32_t
MimeRebuffer::ReduceBuffer(uint32_t numBytes)
{
if (numBytes == 0)
return mBuf.Length();
if (numBytes >= mBuf.Length())
{
mBuf.Truncate();
return 0;
}
mBuf.Cut(0, numBytes);
return mBuf.Length();
}
nsACString &
MimeRebuffer::GetBuffer()
{
return mBuf;
}

View file

@ -0,0 +1,29 @@
/* -*- 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/. */
#ifndef _rebuffer_h_
#define _rebuffer_h_
#include <stdint.h>
#include "nsStringGlue.h"
//////////////////////////////////////////////////////////////
// A rebuffering class necessary for stream output buffering
//////////////////////////////////////////////////////////////
class MimeRebuffer {
public:
MimeRebuffer (void);
virtual ~MimeRebuffer (void);
uint32_t GetSize();
uint32_t IncreaseBuffer(const nsACString &addBuf);
uint32_t ReduceBuffer(uint32_t numBytes);
nsACString & GetBuffer();
protected:
nsCString mBuf;
};
#endif /* _rebuffer_h_ */

View file

@ -0,0 +1,184 @@
/* -*- 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/. */
#include <stdio.h>
#include "nsMimeRebuffer.h"
#include "nsMimeXmlEmitter.h"
#include "plstr.h"
#include "nsMailHeaders.h"
#include "nscore.h"
#include "prmem.h"
#include "nsEmitterUtils.h"
#include "nsCOMPtr.h"
#include "nsUnicharUtils.h"
#include "nsMsgUtils.h"
/*
* nsMimeXmlEmitter definitions....
*/
nsMimeXmlEmitter::nsMimeXmlEmitter()
{
}
nsMimeXmlEmitter::~nsMimeXmlEmitter(void)
{
}
// Note - this is teardown only...you should not write
// anything to the stream since these may be image data
// output streams, etc...
nsresult
nsMimeXmlEmitter::Complete()
{
char buf[16];
// Now write out the total count of attachments for this message
UtilityWrite("<mailattachcount>");
sprintf(buf, "%d", mAttachCount);
UtilityWrite(buf);
UtilityWrite("</mailattachcount>");
UtilityWrite("</message>");
return nsMimeBaseEmitter::Complete();
}
nsresult
nsMimeXmlEmitter::WriteXMLHeader(const char *msgID)
{
if ( (!msgID) || (!*msgID) )
msgID = "none";
char *newValue = MsgEscapeHTML(msgID);
if (!newValue)
return NS_ERROR_OUT_OF_MEMORY;
UtilityWrite("<?xml version=\"1.0\"?>");
UtilityWriteCRLF("<?xml-stylesheet href=\"chrome://messagebody/skin/messageBody.css\" type=\"text/css\"?>");
UtilityWrite("<message id=\"");
UtilityWrite(newValue);
UtilityWrite("\">");
mXMLHeaderStarted = true;
PR_FREEIF(newValue);
return NS_OK;
}
nsresult
nsMimeXmlEmitter::WriteXMLTag(const char *tagName, const char *value)
{
if ( (!value) || (!*value) )
return NS_OK;
char *upCaseTag = NULL;
char *newValue = MsgEscapeHTML(value);
if (!newValue)
return NS_OK;
nsCString newTagName(tagName);
newTagName.StripWhitespace();
ToUpperCase(newTagName);
upCaseTag = ToNewCString(newTagName);
UtilityWrite("<header field=\"");
UtilityWrite(upCaseTag);
UtilityWrite("\">");
// Here is where we are going to try to L10N the tagName so we will always
// get a field name next to an emitted header value. Note: Default will always
// be the name of the header itself.
//
UtilityWrite("<headerdisplayname>");
char *l10nTagName = LocalizeHeaderName(upCaseTag, tagName);
if ( (!l10nTagName) || (!*l10nTagName) )
UtilityWrite(tagName);
else
{
UtilityWrite(l10nTagName);
}
PR_FREEIF(l10nTagName);
UtilityWrite(": ");
UtilityWrite("</headerdisplayname>");
// Now write out the actual value itself and move on!
//
UtilityWrite(newValue);
UtilityWrite("</header>");
NS_Free(upCaseTag);
PR_FREEIF(newValue);
return NS_OK;
}
// Header handling routines.
nsresult
nsMimeXmlEmitter::StartHeader(bool rootMailHeader, bool headerOnly, const char *msgID,
const char *outCharset)
{
mDocHeader = rootMailHeader;
WriteXMLHeader(msgID);
UtilityWrite("<mailheader>");
return NS_OK;
}
nsresult
nsMimeXmlEmitter::AddHeaderField(const char *field, const char *value)
{
if ( (!field) || (!value) )
return NS_OK;
WriteXMLTag(field, value);
return NS_OK;
}
nsresult
nsMimeXmlEmitter::EndHeader(const nsACString &name)
{
UtilityWrite("</mailheader>");
return NS_OK;
}
// Attachment handling routines
nsresult
nsMimeXmlEmitter::StartAttachment(const nsACString &name,
const char *contentType,
const char *url,
bool aIsExternalAttachment)
{
char buf[128];
++mAttachCount;
sprintf(buf, "<mailattachment id=\"%d\">", mAttachCount);
UtilityWrite(buf);
AddAttachmentField(HEADER_PARM_FILENAME, PromiseFlatCString(name).get());
return NS_OK;
}
nsresult
nsMimeXmlEmitter::AddAttachmentField(const char *field, const char *value)
{
WriteXMLTag(field, value);
return NS_OK;
}
nsresult
nsMimeXmlEmitter::EndAttachment()
{
UtilityWrite("</mailattachment>");
return NS_OK;
}

View file

@ -0,0 +1,47 @@
/* -*- 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/. */
#ifndef _nsMimeXmlEmitter_h_
#define _nsMimeXmlEmitter_h_
#include "mozilla/Attributes.h"
#include "prio.h"
#include "nsMimeBaseEmitter.h"
#include "nsMimeRebuffer.h"
#include "nsIStreamListener.h"
#include "nsIOutputStream.h"
#include "nsIURI.h"
#include "nsIChannel.h"
class nsMimeXmlEmitter : public nsMimeBaseEmitter {
public:
nsMimeXmlEmitter ();
virtual ~nsMimeXmlEmitter (void);
NS_IMETHOD Complete() override;
// Header handling routines.
NS_IMETHOD StartHeader(bool rootMailHeader, bool headerOnly, const char *msgID,
const char *outCharset) override;
NS_IMETHOD AddHeaderField(const char *field, const char *value) override;
NS_IMETHOD EndHeader(const nsACString &buf) override;
// Attachment handling routines
NS_IMETHOD StartAttachment(const nsACString &name,
const char *contentType, const char *url,
bool aIsExternalAttachment) override;
NS_IMETHOD AddAttachmentField(const char *field, const char *value) override;
NS_IMETHOD EndAttachment() override;
NS_IMETHOD WriteXMLHeader(const char *msgID);
NS_IMETHOD WriteXMLTag(const char *tagName, const char *value);
protected:
// For header determination...
bool mXMLHeaderStarted;
int32_t mAttachCount;
};
#endif /* _nsMimeXmlEmitter_h_ */

View file

@ -0,0 +1,19 @@
Copyright (c) 2013 Joshua Cranmer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,59 @@
Code Layout
===========
JSMime is a MIME parsing and composition library that is written completely in
JavaScript using ES6 functionality and WebAPIs (where such APIs exist). There
are a few features for which a standardized WebAPI does not exist; for these,
external JavaScript libraries are used.
The MIME parser consists of three logical phases of translation:
1. Build the MIME (and pseudo-MIME) tree.
2. Convert the MIME tree into a list of body parts and attachments.
3. Use the result to drive a displayed version of the message.
The first stage is located in `mimeparser.js`. The latter stages have yet to be
implemented.
Dependencies
============
This code depends on the following ES6 features and Web APIs:
* ES6 generators
* ES6 Map and Set
* ES6 @@iterator support (especially for Map and Set)
* ES6 let
* ES6 let-destructuring
* ES6 const
* Typed arrays (predominantly Uint8Array)
* btoa, atob (found on global Windows or WorkerScopes)
* TextDecoder
Versions and API stability
==========================
As APIs require some use and experimentation to get a feel for what works best,
the APIs may change between successive version updates as uses indicate
substandard or error-prone APIs. Therefore, there will be no guarantee of API
stability until version 1.0 is released.
This code is being initially developed as an effort to replace the MIME library
within Thunderbird. New versions will be released as needed to bring new support
into the Thunderbird codebase; version 1.0 will correspond to the version where
feature-parity with the old MIME library is reached. The set of features which
will be added before 1.0 are the following:
* S/MIME encryption and decryption
* PGP encryption and decryption
* IMAP parts-on-demand support
* Support for text/plain to HTML conversion for display
* Support for HTML downgrading and sanitization for display
* Support for all major multipart types
* Ability to convert HTML documents to text/plain and multipart/related
* Support for building outgoing messages
* Support for IDN and EAI
* yEnc and uuencode decoding support
* Support for date and Message-ID/References-like headers
Other features than these may be added before version 1.0 is released (most
notably TNEF decoding support), but they are not considered necessary to release
a version 1.0.

File diff suppressed because it is too large Load diff

15
mailnews/mime/moz.build Normal file
View file

@ -0,0 +1,15 @@
# 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/.
DIRS += [
'public',
'src',
'emitters',
'cthandlers',
]
EXTRA_JS_MODULES.jsmime += [
'jsmime/jsmime.js',
]

View file

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 MimeEncoder_h__
#define MimeEncoder_h__
#include "nscore.h"
namespace mozilla {
namespace mailnews {
/// A class for encoding the bodies of MIME parts.
class MimeEncoder {
public:
virtual ~MimeEncoder() {}
/// A callback for writing the encoded output
typedef nsresult (*OutputCallback)
(const char *buf, int32_t size, void *closure);
/// Encodes the string in the buffer and sends it to the callback
virtual nsresult Write(const char *buffer, int32_t size) = 0;
/// Flush all pending data when no more data exists
virtual nsresult Flush() { return NS_OK; }
/// Get an encoder that outputs Base64-encoded data
static MimeEncoder *GetBase64Encoder(OutputCallback callback, void *closure);
/// Get an encoder that outputs quoted-printable data
static MimeEncoder *GetQPEncoder(OutputCallback callback, void *closure);
protected:
MimeEncoder(OutputCallback callback, void *closure);
OutputCallback mCallback;
void *mClosure;
uint32_t mCurrentColumn;
};
} // namespace mailnews
} // namespace mozilla
#endif

View file

@ -0,0 +1,174 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 MimeHeaderParser_h__
#define MimeHeaderParser_h__
#include "nsCOMArray.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
class msgIAddressObject;
namespace mozilla {
namespace mailnews {
/**
* This is used to signal that the input header value has already been decoded
* according to RFC 2047 and is in UTF-16 form.
*/
nsCOMArray<msgIAddressObject> DecodedHeader(const nsAString &aHeader);
/**
* This is used to signal that the input header value needs to be decoded
* according to RFC 2047. The charset parameter indicates the charset to assume
* that non-ASCII data is in; if the value is null (the default), then the
* charset is assumed to be UTF-8.
*/
nsCOMArray<msgIAddressObject> EncodedHeader(const nsACString &aHeader,
const char *aCharset = nullptr);
namespace detail {
void DoConversion(const nsTArray<nsString> &aUTF16, nsTArray<nsCString> &aUTF8);
};
/**
* This is a class designed for use as temporaries so that methods can pass
* an nsTArray<nsCString> into methods that expect nsTArray<nsString> for out
* parameters (this does not work for in-parameters).
*
* It works by internally providing an nsTArray<nsString> which it uses for its
* external API operations. If the user requests an array of nsCString elements
* instead, it converts the UTF-16 array to a UTF-8 array on destruction.
*/
template <uint32_t N = 5>
class UTF16ArrayAdapter
{
public:
UTF16ArrayAdapter(nsTArray<nsCString> &aUTF8Array)
: mUTF8Array(aUTF8Array) {}
~UTF16ArrayAdapter() { detail::DoConversion(mUTF16Array, mUTF8Array); }
operator nsTArray<nsString>&() { return mUTF16Array; }
private:
nsTArray<nsCString> &mUTF8Array;
AutoTArray<nsString, N> mUTF16Array;
};
/**
* Given a name and an email, both encoded in UTF-8, produce a string suitable
* for writing in an email header by quoting where necessary.
*
* If name is not empty, the output string will be name <email>. If it is empty,
* the output string is just the email. Note that this DOES NOT do any RFC 2047
* encoding.
*/
void MakeMimeAddress(const nsACString &aName, const nsACString &aEmail,
nsACString &full);
/**
* Given a name and an email, produce a string suitable for writing in an email
* header by quoting where necessary.
*
* If name is not empty, the output string will be name <email>. If it is empty,
* the output string is just the email. Note that this DOES NOT do any RFC 2047
* encoding.
*/
void MakeMimeAddress(const nsAString &aName, const nsAString &aEmail,
nsAString &full);
/**
* Given a name and an email, both encoded in UTF-8, produce a string suitable
* for displaying in UI.
*
* If name is not empty, the output string will be name <email>. If it is empty,
* the output string is just the email.
*/
void MakeDisplayAddress(const nsAString &aName, const nsAString &aEmail,
nsAString &full);
/**
* Returns a copy of the input which may have had some addresses removed.
* Addresses are removed if they are already in either of the supplied
* address lists.
*
* Addresses are considered to be the same if they contain the same email
* address parts, ignoring case. Display names or comments are not compared.
*
* @param aHeader The addresses to remove duplicates from.
* @param aOtherEmails Other addresses that the duplicate removal process also
* checks for duplicates against. Addresses in this list
* will not be added to the result.
* @return The original header with duplicate addresses removed.
*/
void RemoveDuplicateAddresses(const nsACString &aHeader,
const nsACString &aOtherEmails,
nsACString &result);
/**
* Given a message header, extract all names and email addresses found in that
* header into the two arrays.
*/
void ExtractAllAddresses(const nsCOMArray<msgIAddressObject> &aHeader,
nsTArray<nsString> &names, nsTArray<nsString> &emails);
/**
* Given a raw message header value, extract display names for every address
* found in the header.
*/
void ExtractDisplayAddresses(const nsCOMArray<msgIAddressObject> &aHeader,
nsTArray<nsString> &addresses);
/**
* Given a raw message header value, extract all the email addresses into an
* array.
*
* Duplicate email addresses are not removed from the output list.
*/
void ExtractEmails(const nsCOMArray<msgIAddressObject> &aHeader,
nsTArray<nsString> &emails);
/**
* Given a raw message header value, extract the first name/email address found
* in the header. This is essentially equivalent to grabbing the first entry of
* ExtractAllAddresses.
*/
void ExtractFirstAddress(const nsCOMArray<msgIAddressObject> &aHeader,
nsACString &name, nsACString &email);
/**
* Given an RFC 2047-decoded message header value, extract the first name/email
* address found in the header. This is essentially equivalent to grabbing the
* first entry of ExtractAllAddresses.
*/
void ExtractFirstAddress(const nsCOMArray<msgIAddressObject> &aHeader,
nsAString &name, nsACString &email);
/**
* Given a raw message header value, extract the first email address found in
* the header.
*/
void ExtractEmail(const nsCOMArray<msgIAddressObject> &aHeader,
nsACString &email);
/**
* Given a raw message header value, extract and clean up the first display
* name found in the header. If there is no display name, the email address is
* used instead.
*/
void ExtractName(const nsCOMArray<msgIAddressObject> &aHeader,
nsACString &name);
/**
* Given an RFC 2047-decoded message header value, extract the first display
* name found in the header. If there is no display name, the email address is
* returned instead.
*/
void ExtractName(const nsCOMArray<msgIAddressObject> &aDecodedHeader,
nsAString &name);
} // namespace mailnews
} // namespace mozilla
#endif

View file

@ -0,0 +1,36 @@
# 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/.
XPIDL_SOURCES += [
'msgIStructuredHeaders.idl',
'nsICMSDecoder.idl',
'nsICMSEncoder.idl',
'nsICMSMessage.idl',
'nsICMSMessage2.idl',
'nsICMSMessageErrors.idl',
'nsICMSSecureMessage.idl',
'nsIMimeConverter.idl',
'nsIMimeEmitter.idl',
'nsIMimeHeaders.idl',
'nsIMimeMiscStatus.idl',
'nsIMimeStreamConverter.idl',
'nsIMsgHeaderParser.idl',
'nsIPgpMimeProxy.idl',
'nsISimpleMimeConverter.idl',
]
XPIDL_MODULE = 'mime'
EXPORTS += [
'nsIMimeContentTypeHandler.h',
'nsIMimeObjectClassAccess.h',
'nsMailHeaders.h',
'nsMsgMimeCID.h',
]
EXPORTS.mozilla.mailnews += [
'MimeEncoder.h',
'MimeHeaderParser.h',
]

View file

@ -0,0 +1,209 @@
/* 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 "nsISupports.idl"
%{C++
#include "nsCOMArray.h"
#define NS_ISTRUCTUREDHEADERS_CONTRACTID \
"@mozilla.org/messenger/structuredheaders;1"
%}
interface msgIAddressObject;
interface nsIUTF8StringEnumerator;
/**
* A collection of MIME headers that are stored in a rich, structured format.
*
* The structured forms defined in this method use the structured decoder and
* encoder functionality found in jsmime to interconvert between the raw string
* forms found in the actual message text and the structured forms supported by
* this interface. Extensions can register their own custom structured headers
* by listing the source URL of their code under the category
* "custom-mime-encoder".
*
* The alternative modes of access for specific headers are expected to only
* work for the headers for which that mode of access is the correct one. For
* example, retrieving the "To" header from getUnstructuredHeader would fail,
* since the To header is not an unstructured header but an addressing header.
* They are provided mostly as a convenience to C++ which is much less able to
* utilize a fully generic format.
*
* With the exception of mismatched headers, the methods do not throw an
* exception if the header is missing but rather return an appropriate default
* value as indicated in their documentation.
*/
[scriptable, uuid(e109bf4f-788f-47ba-bfa8-1236ede05597)]
interface msgIStructuredHeaders : nsISupports {
/**
* Retrieve the value of the header stored in this set of headers. If the
* header is not present, then undefined is returned.
*
* @param aHeaderName The name of the header to retrieve.
*/
jsval getHeader(in string aHeaderName);
/**
* Return true if and only if the given header is already set.
*
* @param aHeaderName The name of the header to retrieve.
*/
bool hasHeader(in string aHeaderName);
/**
* Retrieve the value of the header as if it is an unstructured header. Such
* headers include most notably the Subject header. If the header is not
* present, then null is returned. This is reflected in C++ as an empty string
* with IsVoid() set to true (distinguishing it from a header that is present
* but contains an empty string).
*
* @param aHeaderName The name of the header to retrieve.
*/
AString getUnstructuredHeader(in string aHeaderName);
/**
* Retrieve the value of the header if it is an addressing header, such as the
* From or To headers. If the header is not present, then an empty array is
* returned.
*
* @param aHeaderName The name of the header to retrieve.
* @param aPreserveGroups If false (the default), then the result is a flat
* list of addresses, with all group annotations
* removed.
* If true, then some address objects may represent
* groups in the header, preserving the original header
* structure.
*/
void getAddressingHeader(in string aHeaderName,
[optional] in boolean aPreserveGroups, [optional] out unsigned long count,
[array, size_is(count), retval] out msgIAddressObject addresses);
/**
* Retrieve a raw version of the header value as would be represented in MIME.
* This form does not include the header name and colon, trailing whitespace,
* nor embedded CRLF pairs in the case of very long header names.
*
* @param aHeaderName The name of the header to retrieve.
*/
AUTF8String getRawHeader(in string aHeaderName);
/**
* Retrieve an enumerator of the names of all headers in this set of headers.
* The header names returned may be in different cases depending on the
* precise implementation of this interface, so implementations should not
* rely on an exact kind of case being returned.
*/
readonly attribute nsIUTF8StringEnumerator headerNames;
/**
* Retrieve the MIME representation of all of the headers.
*
* The header values are emitted in an ASCII form, unless internationalized
* email addresses are involved. The extra CRLF indicating the end of headers
* is not included in this representation.
*
* This accessor is provided mainly for the benefit of C++ consumers of this
* interface, since the JSMime headeremitter functionality allows more
* fine-grained customization of the results.
*/
AUTF8String buildMimeText();
%{C++
/**
* A special variant of getAddressingHeader that is specialized better for C++
* users of this API.
*/
nsresult GetAddressingHeader(const char *aPropertyName,
nsCOMArray<msgIAddressObject> &addrs,
bool aPreserveGroups = false)
{
msgIAddressObject **addrPtr;
uint32_t length;
nsresult rv = GetAddressingHeader(aPropertyName, aPreserveGroups, &length,
&addrPtr);
NS_ENSURE_SUCCESS(rv, rv);
addrs.Adopt(addrPtr, length);
return NS_OK;
}
%}
};
/**
* An interface that enhances msgIStructuredHeaders by allowing the values of
* headers to be modified.
*/
[scriptable, uuid(5dcbbef6-2356-45d8-86d7-b3e73f9c9a0c)]
interface msgIWritableStructuredHeaders : msgIStructuredHeaders {
/**
* Store the given value for the given header, overwriting any previous value
* that was stored for said header.
*
* @param aHeaderName The name of the header to store.
* @param aValue The rich, structured value of the header to store.
*/
void setHeader(in string aHeaderName, in jsval aValue);
/**
* Forget any previous value that was stored for the given header.
*
* @param aHeaderName The name of the header to delete.
*/
void deleteHeader(in string aHeaderName);
/**
* Copy all of the structured values from another set of structured headers to
* the current one, overwriting any values that may have been specified
* locally. Note that the copy is a shallow copy of the value.
*
* @param aOtherHeaders A set of header values to be copied.
*/
void addAllHeaders(in msgIStructuredHeaders aOtherHeaders);
/**
* Set the value of the header as if it were an unstructured header. Such
* headers include most notably the Subject header.
*
* @param aHeaderName The name of the header to store.
* @param aValue The value to store.
*/
void setUnstructuredHeader(in string aHeaderName, in AString aValue);
/**
* Set the value of the header as if it were an addressing header, such as the
* From or To headers.
*
* @param aHeaderName The name of the header to store.
*/
void setAddressingHeader(in string aHeaderName,
[array, size_is(aCount)] in msgIAddressObject aAddresses,
in unsigned long aCount);
/**
* Store the value of the header using a raw version as would be represented
* in MIME. So as to handle 8-bit headers properly, the charset needs to be
* specified, although it may be null.
*
* @param aHeaderName The name of the header to store.
* @param aValue The raw MIME header value to store.
* @param aCharset The expected charset of aValue.
*/
void setRawHeader(in string aHeaderName, in ACString aValue,
in string aCharset);
%{C++
/**
* A special variant of setAddressingHeader that is specialized better for C++
* users of this API.
*/
nsresult SetAddressingHeader(const char *aPropertyName,
const nsCOMArray<msgIAddressObject> &addrs)
{
return SetAddressingHeader(aPropertyName,
const_cast<nsCOMArray<msgIAddressObject>&>(addrs).Elements(),
addrs.Length());
}
%}
};

View file

@ -0,0 +1,29 @@
/* -*- 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 "nsISupports.idl"
%{ C++
typedef void (*NSSCMSContentCallback)(void *arg, const char *buf, unsigned long len);
#define NS_CMSDECODER_CONTRACTID "@mozilla.org/nsCMSDecoder;1"
%}
native NSSCMSContentCallback(NSSCMSContentCallback);
interface nsICMSMessage;
/**
* nsICMSDecoder
* Interface to decode an CMS message
*/
[uuid(c7c7033b-f341-4065-aadd-7eef55ce0dda)]
interface nsICMSDecoder : nsISupports
{
void start(in NSSCMSContentCallback cb, in voidPtr arg);
void update(in string aBuf, in long aLen);
void finish(out nsICMSMessage msg);
};

View file

@ -0,0 +1,30 @@
/* -*- 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 "nsISupports.idl"
%{ C++
typedef void (*NSSCMSContentCallback)(void *arg, const char *buf, unsigned long len);
#define NS_CMSENCODER_CONTRACTID "@mozilla.org/nsCMSEncoder;1"
%}
native NSSCMSContentCallback(NSSCMSContentCallback);
interface nsICMSMessage;
/**
* nsICMSEncoder
* Interface to Encode an CMS message
*/
[uuid(17dc4fb4-e379-4e56-a4a4-57cdcc74816f)]
interface nsICMSEncoder : nsISupports
{
void start(in nsICMSMessage aMsg, in NSSCMSContentCallback cb, in voidPtr arg);
void update(in string aBuf, in long aLen);
void finish();
void encode(in nsICMSMessage aMsg);
};

View file

@ -0,0 +1,39 @@
/* -*- 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 "nsISupports.idl"
%{ C++
#define NS_CMSMESSAGE_CONTRACTID "@mozilla.org/nsCMSMessage;1"
%}
[ptr] native UnsignedCharPtr(unsigned char);
interface nsIX509Cert;
interface nsIArray;
/**
* nsICMSMessage
* Interface to a CMS Message
*/
[uuid(c6d51c22-73e9-4dad-86b9-bde584e33c63)]
interface nsICMSMessage : nsISupports
{
void contentIsSigned(out boolean aSigned);
void contentIsEncrypted(out boolean aEncrypted);
void getSignerCommonName(out string aName);
void getSignerEmailAddress(out string aEmail);
void getSignerCert(out nsIX509Cert scert);
void getEncryptionCert(out nsIX509Cert ecert);
void verifySignature();
void verifyDetachedSignature(in UnsignedCharPtr aDigestData, in unsigned long aDigestDataLen);
void CreateEncrypted(in nsIArray aRecipientCerts);
/* The parameter aDigestType must be one of the values in nsICryptoHash */
void CreateSigned(in nsIX509Cert scert, in nsIX509Cert ecert,
in UnsignedCharPtr aDigestData,
in unsigned long aDigestDataLen, in int16_t aDigestType);
};

View file

@ -0,0 +1,64 @@
/* 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 "nsISupports.idl"
interface nsISMimeVerificationListener;
[ptr] native UnsignedCharPtr(unsigned char);
/*
* This interface is currently not marked scriptable,
* because its verification functions are meant to look like those
* in nsICMSMessage. At the time the ptr type is eliminated in both
* interfaces, both should be made scriptable.
*/
[uuid(b21a3636-2287-4b9f-9a22-25f245981ef0)]
interface nsICMSMessage2 : nsISupports
{
/**
* Async version of nsICMSMessage::VerifySignature.
* Code will be executed on a background thread and
* availability of results will be notified using a
* call to nsISMimeVerificationListener.
*/
void asyncVerifySignature(in nsISMimeVerificationListener listener);
/**
* Async version of nsICMSMessage::VerifyDetachedSignature.
* Code will be executed on a background thread and
* availability of results will be notified using a
* call to nsISMimeVerificationListener.
*
* We are using "native unsigned char" ptr, because the function
* signatures of this one and nsICMSMessage::verifyDetachedSignature
* should be the identical. Cleaning up nsICMSMessages needs to be
* postponed, because this async version is needed on MOZILLA_1_8_BRANCH.
*
* Once both interfaces get cleaned up, the function signature should
* look like:
* [array, length_is(aDigestDataLen)]
* in octet aDigestData,
* in unsigned long aDigestDataLen);
*/
void asyncVerifyDetachedSignature(in nsISMimeVerificationListener listener,
in UnsignedCharPtr aDigestData,
in unsigned long aDigestDataLen);
};
[uuid(5226d698-0773-4f25-b94c-7944b3fc01d3)]
interface nsISMimeVerificationListener : nsISupports {
/**
* Notify that results are ready, that have been requested
* using nsICMSMessage2::asyncVerify[Detached]Signature()
*
* verificationResultCode matches synchronous result code from
* nsICMSMessage::verify[Detached]Signature
*/
void notify(in nsICMSMessage2 verifiedMessage,
in nsresult verificationResultCode);
};

View file

@ -0,0 +1,35 @@
/* -*- 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 "nsISupports.idl"
/**
* nsICMSMessageErrors
* Scriptable error constants for nsICMSMessage
*/
[scriptable,uuid(267f1a5b-88f7-413b-bc49-487e745282f1)]
interface nsICMSMessageErrors : nsISupports
{
const long SUCCESS = 0;
const long GENERAL_ERROR = 1;
const long VERIFY_NOT_SIGNED = 1024;
const long VERIFY_NO_CONTENT_INFO = 1025;
const long VERIFY_BAD_DIGEST = 1026;
const long VERIFY_NOCERT = 1028;
const long VERIFY_UNTRUSTED = 1029;
const long VERIFY_ERROR_UNVERIFIED = 1031;
const long VERIFY_ERROR_PROCESSING = 1032;
const long VERIFY_BAD_SIGNATURE = 1033;
const long VERIFY_DIGEST_MISMATCH = 1034;
const long VERIFY_UNKNOWN_ALGO = 1035;
const long VERIFY_UNSUPPORTED_ALGO = 1036;
const long VERIFY_MALFORMED_SIGNATURE = 1037;
const long VERIFY_HEADER_MISMATCH = 1038;
const long VERIFY_NOT_YET_ATTEMPTED = 1039;
const long VERIFY_CERT_WITHOUT_ADDRESS = 1040;
const long ENCRYPT_NO_BULK_ALG = 1056;
const long ENCRYPT_INCOMPLETE = 1057;
};

View file

@ -0,0 +1,42 @@
/* -*- 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 "nsISupports.idl"
interface nsIX509Cert;
/**
* nsICMSManager (service)
* Interface to access users certificate store
*/
[scriptable, uuid(17103436-0111-4819-a751-0fc4aa6e3d79)]
interface nsICMSSecureMessage : nsISupports
{
/**
* getCertByPrefID - a BASE64 string representing a user's
* certificate (or NULL if there isn't one)
*/
string getCertByPrefID(in string certID);
/**
* decodeCert - decode a BASE64 string into an X509Certificate object
*/
nsIX509Cert decodeCert(in string value);
/**
* sendMessage - send a text message to the recipient indicated
* by the base64-encoded cert.
*/
string sendMessage(in string msg, in string cert);
/**
* receiveMessage - receive an encrypted (enveloped) message
*/
string receiveMessage(in string msg);
};
%{C++
#define NS_CMSSECUREMESSAGE_CONTRACTID "@mozilla.org/nsCMSSecureMessage;1"
%}

View file

@ -0,0 +1,65 @@
/* -*- 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 nsIMimeContentTypeHandler_h_
#define nsIMimeContentTypeHandler_h_
typedef struct {
bool force_inline_display;
} contentTypeHandlerInitStruct;
#include "nsISupports.h"
#include "mimecth.h"
// {20DABD99-F8B5-11d2-8EE0-00A024A7D144}
#define NS_IMIME_CONTENT_TYPE_HANDLER_IID \
{ 0x20dabd99, 0xf8b5, 0x11d2, \
{ 0x8e, 0xe0, 0x0, 0xa0, 0x24, 0xa7, 0xd1, 0x44 } }
// {20DABDA1-F8B5-11d2-8EE0-00A024A7D144}
#define NS_VCARD_CONTENT_TYPE_HANDLER_CID \
{ 0x20dabda1, 0xf8b5, 0x11d2, \
{ 0x8e, 0xe0, 0x0, 0xa0, 0x24, 0xa7, 0xd1, 0x44 } }
#define NS_SMIME_CONTENT_TYPE_HANDLER_CID \
{ 0x20dabdac, 0xf8b5, 0x11d2, \
{ 0xFF, 0xe0, 0x0, 0xa0, 0x24, 0xa7, 0xd1, 0x44 } }
#define NS_SIGNED_CONTENT_TYPE_HANDLER_CID \
{ 0x20dabdac, 0xf8b5, 0x11d2, \
{ 0xFF, 0xe0, 0x0, 0xaf, 0x19, 0xa7, 0xd1, 0x44 } }
#define NS_PGPMIME_CONTENT_TYPE_HANDLER_CID \
{ 0x212f415f, 0xf8b5, 0x11d2, \
{ 0xFF, 0xe0, 0x0, 0xaf, 0x19, 0xa7, 0xd1, 0x44 } }
class nsIMimeContentTypeHandler : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMIME_CONTENT_TYPE_HANDLER_IID)
NS_IMETHOD GetContentType(char **contentType) = 0;
NS_IMETHOD CreateContentTypeHandlerClass(const char *content_type,
contentTypeHandlerInitStruct *initStruct,
MimeObjectClass **objClass) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMimeContentTypeHandler,
NS_IMIME_CONTENT_TYPE_HANDLER_IID)
#endif /* nsIMimeContentTypeHandler_h_ */

View file

@ -0,0 +1,75 @@
/* -*- 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 "nsISupports.idl"
/**
* Encode/decode mail headers (via libmime).
*/
[scriptable, uuid(0d3f5531-2dbe-40d3-9280-f6ac45a6f5e0)]
interface nsIMimeConverter : nsISupports {
/**
* Suggested byte length limit for use when calling encodeMimePartIIStr_UTF8.
*/
const long MIME_ENCODED_WORD_SIZE = 72;
const long MAX_CHARSET_NAME_LENGTH = 64;
/**
* Encode a UTF-8 string into a form containing only ASCII characters using
* RFC 2047 encoded words where necessary.
*
* Note that, although allowed for the present time, encoding to charsets
* other than UTF-8 is considered deprecated.
*
* @param aHeader UTF-8 header to encode.
* @param aAddressingHeader Is the header a list of email addresses?
* @param aMailCharset Charset to use when encoding (see above for note).
* @param aFieldNameLen Header field name length (ex: "From: " = 6)
* @param aMaxLineLen Maximum length of an individual line. Use
* MIME_ENCODED_WORD_SIZE for best results.
*
* @return The encoded header.
*/
AUTF8String encodeMimePartIIStr_UTF8(in AUTF8String aHeader,
in boolean aAddressingHeader,
in string aMailCharset,
in long aFieldNameLen,
in long aMaxLineLen);
/**
* Decode a MIME header to UTF-8 if conversion is required. Marked as
* noscript because the return value may contain non-ASCII characters.
*
* @param header A (possibly encoded) header to decode.
* @param default_charset The charset to apply to un-labeled non-UTF-8 data.
* @param override_charset If true, default_charset is used instead of any
* charset labeling other than UTF-8.
* @param eatContinuations If true, unfold headers.
*
* @return UTF-8 encoded value if conversion was required, nullptr if no
* conversion was required.
*/
AUTF8String decodeMimeHeaderToUTF8(in ACString header,
in string default_charset,
in boolean override_charset,
in boolean eatContinuations);
/**
* Decode a MIME header to UTF-16.
*
* @param header A (possibly encoded) header to decode.
* @param default_charset The charset to apply to un-labeled non-UTF-8 data.
* @param override_charset If true, default_charset is used instead of any
* charset labeling other than UTF-8.
* @param eatContinuations If true, unfold headers.
*
* @return UTF-16 encoded value as an AString.
*/
AString decodeMimeHeader(in string header,
in string default_charset,
in boolean override_charset,
in boolean eatContinuations);
};

View file

@ -0,0 +1,81 @@
/* -*- 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 "nsISupports.idl"
#include "nsrootidl.idl"
interface nsIOutputStream;
interface nsIInputStream;
interface nsIURI;
interface nsIStreamListener;
interface nsIChannel;
[scriptable, uuid(eb9beb09-44de-4ad2-a560-f572b1afd534)]
interface nsMimeHeaderDisplayTypes
{
const long MicroHeaders = 0;
const long NormalHeaders = 1;
const long AllHeaders = 2;
};
%{C++
#define NS_IMIME_MISC_STATUS_KEY "@mozilla.org/MimeMiscStatus;1?type="
%}
[scriptable, uuid(7a57166f-2891-4122-9a74-6c3fab0caac3)]
interface nsIMimeEmitter : nsISupports {
// Output listener to allow access to it from mime.
attribute nsIStreamListener outputListener;
// These will be called to start and stop the total operation.
void initialize(in nsIURI url, in nsIChannel aChannel, in long aFormat);
void complete();
// Set the output stream/listener for processed data.
void setPipe(in nsIInputStream inputStream, in nsIOutputStream outStream);
// Header handling routines.
void startHeader(in boolean rootMailHeader, in boolean headerOnly,
[const] in string msgID, [const] in string outCharset);
void addHeaderField([const] in string field, [const] in string value);
void addAllHeaders(in ACString allheaders);
/**
* Write the HTML Headers for the current attachment.
* Note: Book case this with an EndHeader call.
*
* @param name The name of this attachment.
*/
void writeHTMLHeaders([const] in AUTF8String name);
/**
* Finish writing the headers for the current attachment.
*
* @param name The name of this attachment.
*/
void endHeader([const] in AUTF8String name);
void updateCharacterSet([const] in string aCharset);
// Attachment handling routines.
void startAttachment([const] in AUTF8String name,
[const] in string contentType,
[const] in string url, in boolean aNotDownloaded);
void addAttachmentField([const] in string field, [const] in string value);
void endAttachment();
void endAllAttachments();
// Body handling routines.
void startBody(in boolean bodyOnly, [const] in string msgID, [const] in string outCharset);
void writeBody([const] in AUTF8String buf, out uint32_t amountWritten);
void endBody();
// Generic write routine. This is necessary for output that
// libmime needs to pass through without any particular parsing
// involved (i.e. decoded images, HTML Body Text, etc...
void write([const] in ACString buf, out uint32_t amountWritten);
void utilityWrite([const] in string buf);
};

View file

@ -0,0 +1,41 @@
/* -*- 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 "msgIStructuredHeaders.idl"
%{C++
#define NS_IMIMEHEADERS_CONTRACTID \
"@mozilla.org/messenger/mimeheaders;1"
%}
/**
* An interface that can extract individual headers from a body of headers.
*/
[scriptable, uuid(a9222679-b991-4786-8314-f8819c3a2ba3)]
interface nsIMimeHeaders : msgIStructuredHeaders {
/// Feed in the text of headers
void initialize(in ACString allHeaders);
/**
* Get the text of a header.
*
* Leading and trailing whitespace from headers will be stripped from the
* return value. If getAllOfThem is set to true, then the returned string will
* have all of the values of the header, in order, joined with the ',\r\n\t'.
*
* If the header is not present, then the returned value is NULL.
*/
ACString extractHeader(in string headerName, in boolean getAllOfThem);
/**
* The current text of all header data.
*
* Unlike the asMimeText property, this result preserves the original
* representation of the header text, including alternative line endings or
* custom, non-8-bit text. For instances of this interface, this attribute is
* usually preferable to asMimeText.
*/
readonly attribute ACString allHeaders;
};

View file

@ -0,0 +1,76 @@
/* -*- 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 "nsISupports.idl"
#include "nsrootidl.idl"
interface nsIChannel;
interface nsIMsgMailNewsUrl;
interface nsIUTF8StringEnumerator;
interface nsIMsgDBHdr;
interface nsIURI;
interface nsIWritablePropertyBag2;
[scriptable, uuid(4644FB25-5255-11d3-82B8-444553540002)]
interface nsIMimeMiscStatus : nsISupports{
string GetWindowXULandJS();
string GetGlobalXULandJS();
string GetIndividualXUL(in string aName, in string aHeader, in string aEmail);
long GetMiscStatus(in string aName, in string aEmail);
string GetImageURL(in long aStatus);
};
// this is a simple interface which allows someone to listen to all the headers
// that are discovered by mime. We can use this when displaying a message to update
// the msg header in JS.
[scriptable, uuid(e0e821f0-cecf-4cb3-be5b-ee58b6868343)]
interface nsIMsgHeaderSink : nsISupports
{
// You must finish consuming the iterators before returning from processHeaders. aHeaderNames and aHeaderValues will ALWAYS have the same
// number of elements in them
void processHeaders(in nsIUTF8StringEnumerator aHeaderNames, in nsIUTF8StringEnumerator aHeaderValues, in boolean dontCollectAddress);
void handleAttachment(in string contentType, in string url, in wstring displayName, in string uri,
in boolean aNotDownloaded);
/**
* Add a metadata field to the current attachment, e.g. "X-Mozilla-PartSize".
*
* @param field The field to add
* @param value The value of the field
*/
void addAttachmentField(in string field, in string value);
void onEndAllAttachments();
// onEndMsgHeaders is called after libmime is done processing a message. At this point it is safe for
// elements like the UI to update junk status, process return receipts, etc.
void onEndMsgHeaders(in nsIMsgMailNewsUrl url);
// onEndMsgDownload is triggered when layout says it is actually done rendering
// the message body in the UI.
void onEndMsgDownload(in nsIMsgMailNewsUrl url);
attribute nsISupports securityInfo;
/**
* onMsgHasRemoteContent is called each time content policy encounters remote
* content that it will block from loading.
* @param aMsgHdr header of the message the content is located in
* @param aContentURI location that will be blocked.
* @param aCanOverride can the blocking be overridden or not
*/
void onMsgHasRemoteContent(in nsIMsgDBHdr aMsgHdr, in nsIURI aContentURI, in boolean aCanOverride);
readonly attribute nsIMsgDBHdr dummyMsgHeader;
// used as a hook for extension mime content handlers to store data that can later
// be accessed by other parts of the code, e.g., UI code.
// TODO - Should replace securityInfo
readonly attribute nsIWritablePropertyBag2 properties;
// When streaming a new message, properties should be reset, so that there are
// not previous values lurking around.
void resetProperties();
};

View file

@ -0,0 +1,49 @@
/* -*- 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 libmime. This interface is used by
* a Content-Type handler "Plug In" (i.e. vCard) for accessing various
* internal information about the object class system of libmime. When
* libmime progresses to a C++ object class, this would probably change.
*/
#ifndef nsIMimeObjectClassAccess_h_
#define nsIMimeObjectClassAccess_h_
// {C09EDB23-B7AF-11d2-B35E-525400E2D63A}
#define NS_IMIME_OBJECT_CLASS_ACCESS_IID \
{ 0xc09edb23, 0xb7af, 0x11d2, \
{ 0xb3, 0x5e, 0x52, 0x54, 0x0, 0xe2, 0xd6, 0x3a } }
class nsIMimeObjectClassAccess : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMIME_OBJECT_CLASS_ACCESS_IID)
// These methods are all implemented by libmime to be used by
// content type handler plugins for processing stream data.
// This is the write call for outputting processed stream data.
NS_IMETHOD MimeObjectWrite(void *mimeObject,
char *data,
int32_t length,
bool user_visible_p) = 0;
// The following group of calls expose the pointers for the object
// system within libmime.
NS_IMETHOD GetmimeInlineTextClass(void **ptr) = 0;
NS_IMETHOD GetmimeLeafClass(void **ptr) = 0;
NS_IMETHOD GetmimeObjectClass(void **ptr) = 0;
NS_IMETHOD GetmimeContainerClass(void **ptr) = 0;
NS_IMETHOD GetmimeMultipartClass(void **ptr) = 0;
NS_IMETHOD GetmimeMultipartSignedClass(void **ptr) = 0;
NS_IMETHOD GetmimeEncryptedClass(void **ptr) = 0;
NS_IMETHOD MimeCreate(char* content_type, void * hdrs, void * opts, void **ptr) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMimeObjectClassAccess,
NS_IMIME_OBJECT_CLASS_ACCESS_IID)
#endif /* nsIMimeObjectClassAccess_h_ */

View file

@ -0,0 +1,93 @@
/* -*- 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 "nsISupports.idl"
#include "nsrootidl.idl"
#include "nsIMimeHeaders.idl"
#include "nsIMsgIdentity.idl"
#include "nsIMsgHdr.idl"
interface nsIURI;
typedef long nsMimeOutputType;
[scriptable, uuid(fdc2956e-d558-43fb-bfdd-fb9511229aa5)]
interface nsMimeOutput
{
const long nsMimeMessageSplitDisplay = 0;
const long nsMimeMessageHeaderDisplay = 1;
const long nsMimeMessageBodyDisplay = 2;
const long nsMimeMessageQuoting = 3;
const long nsMimeMessageBodyQuoting = 4;
const long nsMimeMessageRaw = 5;
const long nsMimeMessageDraftOrTemplate = 6;
const long nsMimeMessageEditorTemplate = 7;
const long nsMimeMessagePrintOutput = 9;
const long nsMimeMessageSaveAs = 10;
const long nsMimeMessageSource = 11;
const long nsMimeMessageFilterSniffer = 12;
const long nsMimeMessageDecrypt = 13;
const long nsMimeMessageAttach = 14;
const long nsMimeUnknown = 15;
};
[scriptable, uuid(FA81CAA0-6261-11d3-8311-00805F2A0107)]
interface nsIMimeStreamConverterListener : nsISupports{
void onHeadersReady(in nsIMimeHeaders headers);
};
/**
* This interface contains mailnews mime specific information for stream
* converters. Most of the code is just stuff that has been moved out
* of nsIStreamConverter.idl to make it more generic.
*/
[scriptable, uuid(d894c833-29c5-495b-880c-9a9f847bfdc9)]
interface nsIMimeStreamConverter : nsISupports {
/**
* Set the desired mime output type on the converer.
*/
void SetMimeOutputType(in nsMimeOutputType aType);
void GetMimeOutputType(out nsMimeOutputType aOutFormat);
/**
* This is needed by libmime for MHTML link processing...the url is the URL
* string associated with this input stream.
*/
void SetStreamURI(in nsIURI aURI);
/**
* Used to extract headers while parsing a message.
*/
void SetMimeHeadersListener(in nsIMimeStreamConverterListener listener, in nsMimeOutputType aType);
/**
* This is used for forward inline, both as a filter action, and from the UI.
*/
attribute boolean forwardInline;
/**
* This is used for a forward inline filter action. When streaming is done,
* we won't open a compose window with the editor contents.
*/
attribute boolean forwardInlineFilter;
/**
* Address for the forward inline filter to forward the message to.
*/
attribute AString forwardToAddress;
/**
* Use the opposite compose format, used for forward inline.
*/
attribute boolean overrideComposeFormat;
/**
* This is used for OpenDraft, OpenEditorTemplate and Forward inline (which use OpenDraft)
*/
attribute nsIMsgIdentity identity;
attribute string originalMsgURI;
attribute nsIMsgDBHdr origMsgHdr;
};

View file

@ -0,0 +1,235 @@
/* -*- 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 "nsISupports.idl"
%{C++
#define NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID \
"@mozilla.org/messenger/headerparser;1"
%}
/**
* A structured representation of an address.
*
* This is meant to correspond to the address production from RFC 5322. As a
* result, an instance of this interface is either a single mailbox or a group
* of mailboxes. The difference between the two forms is in which attribute is
* undefined: mailboxes leave the members attribute undefined while groups leave
* the email attribute undefined.
*
* For example, an address like "John Doe <jdoe@machine.example>" will, when
* parsed, result in an instance with the name attribute set to "John Doe", the
* email attribute set to "jdoe@machine.example", and the members variable left
* undefined.
*
* A group like "undisclosed-recipients:;" will, when parsed, result in an
* instance with the name attribute set to "undisclosed-recipients", the email
* attribute left defined, and the members variable set to an empty array.
*
* In general, the attributes of this interface are always meant to be in a form
* suitable for display purposes, and not in a form usable for MIME emission. In
* particular, email addresses could be fully internationalized and non-ASCII,
* RFC 2047-encoded words may appear in names, and the name or email parameters
* are unquoted.
*/
[scriptable, uuid(b19f5636-ebc4-470e-b46c-98b5fc7e88c9)]
interface msgIAddressObject : nsISupports {
/// The name of the mailbox or group.
readonly attribute AString name;
/// The email of the mailbox.
readonly attribute AString email;
/**
* The member mailboxes of this group, which may be an empty list.
*
* Due to the limitations of XPIDL, the type of this attribute cannot be
* properly reflected. It is actually an array of msgIAddressObject instances,
* although it is instead undefined if this object does not represent a group.
*/
readonly attribute jsval group;
/// Return a string form of this object that is suitable for display.
AString toString();
};
/**
* A utility service for manipulating addressing headers in email messages.
*
* This interface is designed primarily for use from JavaScript code; code in
* C++ should use the methods in MimeHeaderParser.h instead, as it is better
* designed to take advantage of C++'s features, particularly with respect to
* arrays.
*
* There are two methods for parsing MIME headers, one for RFC 2047-decoded
* strings, and one for non-RFC 2047-decoded strings.
*
* In general, this API attempts to preserve the format of addresses as
* faithfully as possible. No case normalization is performed at any point.
* However, internationalized email addresses generally need extra processing to
* work properly, so while this API should handle them without issues, consumers
* of this API may fail to work properly when presented with such addresses. To
* ease use for such cases, future versions of the API may incorporate necessary
* normalization steps to make oblivious consumers more likely to work properly.
*/
[scriptable, uuid(af2f9dd1-0226-4835-b981-a4f88b5e97cc)]
interface nsIMsgHeaderParser : nsISupports {
/**
* Parse an address-based header that has not yet been 2047-decoded.
*
* The result of this method is an array of objects described in the above
* comment. Note that the header is a binary string that will be decoded as if
* passed into nsIMimeConverter.
*
* @param aEncodedHeader The RFC 2047-encoded header to parse.
* @param aHeaderCharset The charset to assume for raw octets.
* @param aPreserveGroups If false (the default), the result is a flat array
* of mailbox objects, containing no group objects.
* @return An array corresponding to the header description.
*/
void parseEncodedHeader(in ACString aEncodedHeader,
in string aHeaderCharset,
[optional] in bool aPreserveGroups,
[optional] out unsigned long length,
[retval, array, size_is(length)]
out msgIAddressObject addresses);
/**
* Parse an address-based header that has been 2047-decoded.
*
* The result of this method is an array of objects described in the above
* comment. Note that the header is a binary string that will be decoded as if
* passed into nsIMimeConverter.
*
* @param aDecodedHeader The non-RFC 2047-encoded header to parse.
* @param aPreserveGroups If false (the default), the result is a flat array
* of mailbox objects, containing no group objects.
* @return An array corresponding to the header description.
*/
void parseDecodedHeader(in AString aDecodedHeader,
[optional] in bool aPreserveGroups,
[optional] out unsigned long length,
[retval, array, size_is(length)]
out msgIAddressObject addresses);
/**
* Given an array of addresses, make a MIME header suitable for emission.
*
* The return value of this method is not directly suitable for use in a MIME
* message but rather needs to be passed through nsIMimeConverter first to
* have RFC-2047 encoding applied and the resulting output wrapped to adhere
* to maximum line length formats.
*
* @param aAddresses An array corresponding to the header description.
* @param aLength The length of said array of addresses.
* @return A string that is suitable for writing in a MIME message.
*/
AString makeMimeHeader([array, size_is(aLength)]
in msgIAddressObject aAddresses,
in unsigned long aLength);
/**
* Return the first address in the list in a format suitable for display.
*
* This is largely a convience method for handling From headers (or similar),
* which are expected to only have a single element in them. It is exactly
* equivalent to saying (parseDecodedHeader(decodedHeader))[0].toString().
*
* @param decodedHeader The non-RFC 2047-encoded header to parse.
* @return The first address, suitable for display.
*/
AString extractFirstName(in AString aDecodedHeader);
/**
* Returns a copy of the input which may have had some addresses removed.
* Addresses are removed if they are already in either of the supplied
* address lists.
*
* Addresses are considered to be the same if they contain the same email
* part (case-insensitive). Since the email part should never be RFC
* 2047-encoded, this method should work whether or not the header is
* RFC 2047-encoded.
*
* @param aAddrs The addresses to remove duplicates from.
* @param aOtherAddrs Other addresses that the duplicate removal process also
* checks for duplicates against. Addresses in this list
* will not be added to the result.
* @return The original header with duplicate addresses removed.
*/
AUTF8String removeDuplicateAddresses(in AUTF8String aAddrs,
[optional] in AUTF8String aOtherAddrs);
/// Return a structured mailbox object having the given name and email.
msgIAddressObject makeMailboxObject(in AString aName, in AString aEmail);
/// Return a structured group object having the given name and members.
msgIAddressObject makeGroupObject(in AString aName,
[array, size_is(aLength)] in msgIAddressObject aMembers,
in unsigned long aLength);
/**
* Return an array of structured mailbox objects for the given display name
* string.
*
* The string is expected to be a comma-separated sequence of strings that
* would be produced by msgIAddressObject::toString(). For example, the string
* "Bond, James <agent007@mi5.invalid>" would produce one address object,
* while the string "webmaster@nowhere.invalid, child@nowhere.invalid" would
* produce two address objects.
*
* Note that the input string is RFC 2231 and RFC 2047 decoded but no UTF-8
* decoding takes place.
*/
void makeFromDisplayAddress(in AString aDisplayAddresses,
[optional] out unsigned long count,
[retval, array, size_is(count)] out msgIAddressObject addresses);
[deprecated] void parseHeadersWithArray(in wstring aLine,
[array, size_is(count)] out wstring aEmailAddresses,
[array, size_is(count)] out wstring aNames,
[array, size_is(count)] out wstring aFullNames,
[retval] out unsigned long count);
/**
* Given a string which contains a list of Header addresses, returns a
* comma-separated list of just the `mailbox' portions.
*
* @param aLine The header line to parse.
* @return A comma-separated list of just the mailbox parts
* of the email-addresses.
*/
[deprecated] ACString extractHeaderAddressMailboxes(in ACString aLine);
/**
* Given a string which contains a list of Header addresses, returns a
* comma-separated list of just the `user name' portions. If any of
* the addresses doesn't have a name, then the mailbox is used instead.
*
* @param aLine The header line to parse.
* @return A comma-separated list of just the name parts
* of the addresses.
*/
[deprecated] AUTF8String extractHeaderAddressNames(in AUTF8String aLine);
/*
* Like extractHeaderAddressNames, but only returns the first name in the
* header if there is one. This function will return unquoted strings suitable
* for display.
*
* @param aLine The header line to parse.
* @return The first name found in the list.
*/
[deprecated] AUTF8String extractHeaderAddressName(in AUTF8String aLine);
/**
* Given a name and email address, produce a string that is suitable for
* emitting in a MIME header (after applying RFC 2047 encoding).
*
* @note This is a temporary method.
*/
[deprecated] AString makeMimeAddress(in AString aName, in AString aEmail);
};

View file

@ -0,0 +1,69 @@
/* 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 "nsIStreamListener.idl"
#include "nsIURI.idl"
%{C++
typedef int (*MimeDecodeCallbackFun)(const char *buf, int32_t buf_size, void *output_closure);
#define NS_PGPMIMEPROXY_CLASSNAME "PGP/Mime Decryption"
#define NS_PGPMIMEPROXY_CONTRACTID "@mozilla.org/mime/pgp-mime-decrypt;1"
#define NS_PGPMIMEPROXY_CID \
{ /* 6b7e094f-536b-40dc-b3a4-e3d729205ce1 */ \
0x6b7e094f, 0x536b, 0x40dc, \
{0xb3, 0xa4, 0xe3, 0xd7, 0x29, 0x20, 0x5c, 0xe1 } }
%}
native MimeDecodeCallbackFun(MimeDecodeCallbackFun);
/**
* nsIPgpMimeProxy is a proxy for a (JS-)addon for OpenPGP/MIME decryption
*/
[scriptable, uuid(6b7e094f-536b-40dc-b3a4-e3d729205ce1)]
interface nsIPgpMimeProxy : nsIStreamListener
{
/**
* set the decoder callback into mimelib
*/
[noscript] void setMimeCallback(in MimeDecodeCallbackFun outputFun,
in voidPtr outputClosure,
in nsIURI myUri);
/**
* init function
*/
void init();
/**
* process encoded data received from mimelib
*/
void write(in string buf, in unsigned long count);
/**
* finish writing (EOF) from mimelib
*/
void finish();
/**
* the listener that receives the OpenPGP/MIME data stream and decrypts
* the message
*/
attribute nsIStreamListener decryptor;
attribute ACString contentType;
/**
* The particular part number of the multipart object we are working on. The
* numbering is the same as in URLs that use the form "...?part=1.1.2".
*
* The value stored in mimePart is only the number, e.g. "1" or "1.1.2"
*/
attribute ACString mimePart;
};
///////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 20; 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 "nsISupports.idl"
interface nsIURI;
[scriptable, uuid(FC6E8234-BBF3-44A1-9802-5F023A929173)]
interface nsISimpleMimeConverter : nsISupports
{
// uri of message getting displayed
attribute nsIURI uri;
AUTF8String convertToHTML(in ACString contentType,
in AUTF8String data);
};
%{C++
#define NS_SIMPLEMIMECONVERTERS_CATEGORY "simple-mime-converters"
%}

View file

@ -0,0 +1,90 @@
/* -*- 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 allows any module to access the encoder/decoder
* routines for RFC822 headers. This will allow any mail/news module
* to call on these routines.
*/
#ifndef nsMailHeaders_h_
#define nsMailHeaders_h_
/*
* These are the defines for standard header field names.
*/
#define HEADER_BCC "BCC"
#define HEADER_CC "CC"
#define HEADER_CONTENT_BASE "Content-Base"
#define HEADER_CONTENT_LOCATION "Content-Location"
#define HEADER_CONTENT_ID "Content-ID"
#define HEADER_CONTENT_DESCRIPTION "Content-Description"
#define HEADER_CONTENT_DISPOSITION "Content-Disposition"
#define HEADER_CONTENT_ENCODING "Content-Encoding"
#define HEADER_CONTENT_LANGUAGE "Content-Language"
#define HEADER_CONTENT_LENGTH "Content-Length"
#define HEADER_CONTENT_NAME "Content-Name"
#define HEADER_CONTENT_TRANSFER_ENCODING "Content-Transfer-Encoding"
#define HEADER_CONTENT_TYPE "Content-Type"
#define HEADER_DATE "Date"
#define HEADER_DISTRIBUTION "Distribution"
#define HEADER_FCC "FCC"
#define HEADER_FOLLOWUP_TO "Followup-To"
#define HEADER_FROM "From"
#define HEADER_STATUS "Status"
#define HEADER_LINES "Lines"
#define HEADER_LIST_POST "List-Post"
#define HEADER_MAIL_FOLLOWUP_TO "Mail-Followup-To"
#define HEADER_MAIL_REPLY_TO "Mail-Reply-To"
#define HEADER_MESSAGE_ID "Message-ID"
#define HEADER_MIME_VERSION "MIME-Version"
#define HEADER_NEWSGROUPS "Newsgroups"
#define HEADER_ORGANIZATION "Organization"
#define HEADER_REFERENCES "References"
#define HEADER_REPLY_TO "Reply-To"
#define HEADER_RESENT_COMMENTS "Resent-Comments"
#define HEADER_RESENT_DATE "Resent-Date"
#define HEADER_RESENT_FROM "Resent-From"
#define HEADER_RESENT_MESSAGE_ID "Resent-Message-ID"
#define HEADER_RESENT_SENDER "Resent-Sender"
#define HEADER_RESENT_TO "Resent-To"
#define HEADER_RESENT_CC "Resent-CC"
#define HEADER_SENDER "Sender"
#define HEADER_SUBJECT "Subject"
#define HEADER_TO "To"
#define HEADER_APPROVED_BY "Approved-By"
#define HEADER_X_MAILER "X-Mailer"
#define HEADER_USER_AGENT "User-Agent"
#define HEADER_X_NEWSREADER "X-Newsreader"
#define HEADER_X_POSTING_SOFTWARE "X-Posting-Software"
#define HEADER_X_MOZILLA_STATUS "X-Mozilla-Status"
#define HEADER_X_MOZILLA_STATUS2 "X-Mozilla-Status2"
#define HEADER_X_MOZILLA_NEWSHOST "X-Mozilla-News-Host"
#define HEADER_X_MOZILLA_DRAFT_INFO "X-Mozilla-Draft-Info"
#define HEADER_X_UIDL "X-UIDL"
#define HEADER_XREF "XREF"
#define HEADER_X_SUN_CHARSET "X-Sun-Charset"
#define HEADER_X_SUN_CONTENT_LENGTH "X-Sun-Content-Length"
#define HEADER_X_SUN_CONTENT_LINES "X-Sun-Content-Lines"
#define HEADER_X_SUN_DATA_DESCRIPTION "X-Sun-Data-Description"
#define HEADER_X_SUN_DATA_NAME "X-Sun-Data-Name"
#define HEADER_X_SUN_DATA_TYPE "X-Sun-Data-Type"
#define HEADER_X_SUN_ENCODING_INFO "X-Sun-Encoding-Info"
#define HEADER_X_PRIORITY "X-Priority"
#define HEADER_PARM_CHARSET "charset"
#define HEADER_PARM_START "start"
#define HEADER_PARM_BOUNDARY "BOUNDARY"
#define HEADER_PARM_FILENAME "FILENAME"
#define HEADER_PARM_NAME "NAME"
#define HEADER_PARM_TYPE "TYPE"
#define HEADER_X_MOZILLA_PART_URL "X-Mozilla-PartURL"
#define HEADER_X_MOZILLA_PART_SIZE "X-Mozilla-PartSize"
#define HEADER_X_MOZILLA_PART_DOWNLOADED "X-Mozilla-PartDownloaded"
#define HEADER_X_MOZILLA_CLOUD_PART "X-Mozilla-Cloud-Part"
#define HEADER_X_MOZILLA_IDENTITY_KEY "X-Identity-Key"
#define HEADER_X_MOZILLA_ACCOUNT_KEY "X-Account-Key"
#define HEADER_X_MOZILLA_KEYWORDS "X-Mozilla-Keys"
#endif /* nsMailHeaders_h_ */

View file

@ -0,0 +1,33 @@
/* -*- 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/. */
#ifndef nsMessageMimeCID_h__
#define nsMessageMimeCID_h__
#define NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID \
NS_ISTREAMCONVERTER_KEY "?from=message/rfc822&to=application/vnd.mozilla.xul+xml"
#define NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID1 \
NS_ISTREAMCONVERTER_KEY "?from=message/rfc822&to=text/html"
#define NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID2 \
NS_ISTREAMCONVERTER_KEY "?from=message/rfc822&to=*/*"
#define NS_MAILNEWS_MIME_STREAM_CONVERTER_CID \
{ /* FAF4F9A6-60AD-11d3-989A-001083010E9B */ \
0xfaf4f9a6, 0x60ad, 0x11d3, { 0x98, 0x9a, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b } }
#define NS_MIME_CONVERTER_CONTRACTID \
"@mozilla.org/messenger/mimeconverter;1"
// {403B0540-B7C3-11d2-B35E-525400E2D63A}
#define NS_MIME_OBJECT_CLASS_ACCESS_CID \
{ 0x403b0540, 0xb7c3, 0x11d2, \
{ 0xb3, 0x5e, 0x52, 0x54, 0x0, 0xe2, 0xd6, 0x3a } }
#define NS_MIME_OBJECT_CONTRACTID \
"@mozilla.org/messenger/mimeobject;1"
#endif // nsMessageMimeCID_h__

View file

@ -0,0 +1,229 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "mozilla/mailnews/MimeHeaderParser.h"
#include "mozilla/mailnews/Services.h"
#include "mozilla/DebugOnly.h"
#include "nsMemory.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIMimeConverter.h"
#include "nsIMsgHeaderParser.h"
namespace mozilla {
namespace mailnews {
void detail::DoConversion(const nsTArray<nsString> &aUTF16Array,
nsTArray<nsCString> &aUTF8Array)
{
uint32_t count = aUTF16Array.Length();
aUTF8Array.SetLength(count);
for (uint32_t i = 0; i < count; ++i)
CopyUTF16toUTF8(aUTF16Array[i], aUTF8Array[i]);
}
void MakeMimeAddress(const nsACString &aName, const nsACString &aEmail,
nsACString &full)
{
nsAutoString utf16Address;
MakeMimeAddress(NS_ConvertUTF8toUTF16(aName), NS_ConvertUTF8toUTF16(aEmail),
utf16Address);
CopyUTF16toUTF8(utf16Address, full);
}
void MakeMimeAddress(const nsAString &aName, const nsAString &aEmail,
nsAString &full)
{
nsCOMPtr<nsIMsgHeaderParser> headerParser(services::GetHeaderParser());
nsCOMPtr<msgIAddressObject> address;
headerParser->MakeMailboxObject(aName, aEmail, getter_AddRefs(address));
msgIAddressObject *obj = address;
headerParser->MakeMimeHeader(&obj, 1, full);
}
void MakeDisplayAddress(const nsAString &aName, const nsAString &aEmail,
nsAString &full)
{
nsCOMPtr<nsIMsgHeaderParser> headerParser(services::GetHeaderParser());
nsCOMPtr<msgIAddressObject> object;
headerParser->MakeMailboxObject(aName, aEmail, getter_AddRefs(object));
object->ToString(full);
}
void RemoveDuplicateAddresses(const nsACString &aHeader,
const nsACString &aOtherEmails,
nsACString &result)
{
nsCOMPtr<nsIMsgHeaderParser> headerParser(services::GetHeaderParser());
headerParser->RemoveDuplicateAddresses(aHeader, aOtherEmails, result);
}
/////////////////////////////////////////////
// These are the core shim methods we need //
/////////////////////////////////////////////
nsCOMArray<msgIAddressObject> DecodedHeader(const nsAString &aHeader)
{
nsCOMArray<msgIAddressObject> retval;
if (aHeader.IsEmpty()) {
return retval;
}
nsCOMPtr<nsIMsgHeaderParser> headerParser(services::GetHeaderParser());
msgIAddressObject **addresses = nullptr;
uint32_t length;
nsresult rv = headerParser->ParseDecodedHeader(aHeader, false,
&length, &addresses);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Javascript jsmime returned an error!");
if (NS_SUCCEEDED(rv) && length > 0 && addresses) {
retval.Adopt(addresses, length);
}
return retval;
}
nsCOMArray<msgIAddressObject> EncodedHeader(const nsACString &aHeader,
const char *aCharset)
{
nsCOMArray<msgIAddressObject> retval;
if (aHeader.IsEmpty()) {
return retval;
}
nsCOMPtr<nsIMsgHeaderParser> headerParser(services::GetHeaderParser());
msgIAddressObject **addresses = nullptr;
uint32_t length;
nsresult rv = headerParser->ParseEncodedHeader(aHeader, aCharset,
false, &length, &addresses);
MOZ_ASSERT(NS_SUCCEEDED(rv), "This should never fail!");
if (NS_SUCCEEDED(rv) && length > 0 && addresses) {
retval.Adopt(addresses, length);
}
return retval;
}
void ExtractAllAddresses(const nsCOMArray<msgIAddressObject> &aHeader,
nsTArray<nsString> &names, nsTArray<nsString> &emails)
{
uint32_t count = aHeader.Length();
// Prefill arrays before we start
names.SetLength(count);
emails.SetLength(count);
for (uint32_t i = 0; i < count; i++)
{
aHeader[i]->GetName(names[i]);
aHeader[i]->GetEmail(emails[i]);
}
if (count == 1 && names[0].IsEmpty() && emails[0].IsEmpty())
{
names.Clear();
emails.Clear();
}
}
void ExtractDisplayAddresses(const nsCOMArray<msgIAddressObject> &aHeader,
nsTArray<nsString> &displayAddrs)
{
uint32_t count = aHeader.Length();
displayAddrs.SetLength(count);
for (uint32_t i = 0; i < count; i++)
aHeader[i]->ToString(displayAddrs[i]);
if (count == 1 && displayAddrs[0].IsEmpty())
displayAddrs.Clear();
}
/////////////////////////////////////////////////
// All of these are based on the above methods //
/////////////////////////////////////////////////
void ExtractEmails(const nsCOMArray<msgIAddressObject> &aHeader,
nsTArray<nsString> &emails)
{
nsTArray<nsString> names;
ExtractAllAddresses(aHeader, names, emails);
}
void ExtractEmail(const nsCOMArray<msgIAddressObject> &aHeader,
nsACString &email)
{
AutoTArray<nsString, 1> names;
AutoTArray<nsString, 1> emails;
ExtractAllAddresses(aHeader, names, emails);
if (emails.Length() > 0)
CopyUTF16toUTF8(emails[0], email);
else
email.Truncate();
}
void ExtractFirstAddress(const nsCOMArray<msgIAddressObject> &aHeader,
nsACString &name, nsACString &email)
{
AutoTArray<nsString, 1> names, emails;
ExtractAllAddresses(aHeader, names, emails);
if (names.Length() > 0)
{
CopyUTF16toUTF8(names[0], name);
CopyUTF16toUTF8(emails[0], email);
}
else
{
name.Truncate();
email.Truncate();
}
}
void ExtractFirstAddress(const nsCOMArray<msgIAddressObject> &aHeader,
nsAString &name, nsACString &email)
{
AutoTArray<nsString, 1> names, emails;
ExtractAllAddresses(aHeader, names, emails);
if (names.Length() > 0)
{
name = names[0];
CopyUTF16toUTF8(emails[0], email);
}
else
{
name.Truncate();
email.Truncate();
}
}
void ExtractName(const nsCOMArray<msgIAddressObject> &aHeader, nsACString &name)
{
nsCString email;
ExtractFirstAddress(aHeader, name, email);
if (name.IsEmpty())
name = email;
}
void ExtractName(const nsCOMArray<msgIAddressObject> &aHeader, nsAString &name)
{
AutoTArray<nsString, 1> names;
AutoTArray<nsString, 1> emails;
ExtractAllAddresses(aHeader, names, emails);
if (names.Length() > 0)
{
if (names[0].IsEmpty())
name = emails[0];
else
name = names[0];
}
else
{
name.Truncate();
}
}
} // namespace mailnews
} // namespace mozilla

View file

@ -0,0 +1,108 @@
/* -*- 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/. */
#include "comi18n.h"
#include "nsIStringCharsetDetector.h"
#include "nsMsgUtils.h"
#include "nsICharsetConverterManager.h"
#include "nsIMIMEHeaderParam.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsMsgMimeCID.h"
#include "nsIMimeConverter.h"
////////////////////////////////////////////////////////////////////////////////
// BEGIN PUBLIC INTERFACE
extern "C" {
void MIME_DecodeMimeHeader(const char *header, const char *default_charset,
bool override_charset, bool eatContinuations,
nsACString &result)
{
nsresult rv;
nsCOMPtr <nsIMimeConverter> mimeConverter =
do_GetService(NS_MIME_CONVERTER_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
result.Truncate();
return;
}
mimeConverter->DecodeMimeHeaderToUTF8(nsDependentCString(header),
default_charset, override_charset,
eatContinuations, result);
}
// UTF-8 utility functions.
//detect charset soly based on aBuf. return in aCharset
nsresult
MIME_detect_charset(const char *aBuf, int32_t aLength, const char** aCharset)
{
nsresult res = NS_ERROR_UNEXPECTED;
nsString detector_name;
*aCharset = nullptr;
NS_GetLocalizedUnicharPreferenceWithDefault(nullptr, "intl.charset.detector", EmptyString(), detector_name);
if (!detector_name.IsEmpty()) {
nsAutoCString detector_contractid;
detector_contractid.AssignLiteral(NS_STRCDETECTOR_CONTRACTID_BASE);
detector_contractid.Append(NS_ConvertUTF16toUTF8(detector_name));
nsCOMPtr<nsIStringCharsetDetector> detector = do_CreateInstance(detector_contractid.get(), &res);
if (NS_SUCCEEDED(res)) {
nsDetectionConfident oConfident;
res = detector->DoIt(aBuf, aLength, aCharset, oConfident);
if (NS_SUCCEEDED(res) && (eBestAnswer == oConfident || eSureAnswer == oConfident)) {
return NS_OK;
}
}
}
return res;
}
//Get unicode decoder(from inputcharset to unicode) for aInputCharset
nsresult
MIME_get_unicode_decoder(const char* aInputCharset, nsIUnicodeDecoder **aDecoder)
{
nsresult res;
// get charset converters.
nsCOMPtr<nsICharsetConverterManager> ccm =
do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res);
if (NS_SUCCEEDED(res)) {
// create a decoder (conv to unicode), ok if failed if we do auto detection
if (!*aInputCharset || !PL_strcasecmp("us-ascii", aInputCharset))
res = ccm->GetUnicodeDecoderRaw("ISO-8859-1", aDecoder);
else
// GetUnicodeDecoderInternal in order to support UTF-7 messages
//
// XXX this means that even HTML messages in UTF-7 will be decoded
res = ccm->GetUnicodeDecoderInternal(aInputCharset, aDecoder);
}
return res;
}
//Get unicode encoder(from unicode to inputcharset) for aOutputCharset
nsresult
MIME_get_unicode_encoder(const char* aOutputCharset, nsIUnicodeEncoder **aEncoder)
{
nsresult res;
// get charset converters.
nsCOMPtr<nsICharsetConverterManager> ccm =
do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res);
if (NS_SUCCEEDED(res) && *aOutputCharset) {
// create a encoder (conv from unicode)
res = ccm->GetUnicodeEncoder(aOutputCharset, aEncoder);
}
return res;
}
} /* end of extern "C" */
// END PUBLIC INTERFACE

View file

@ -0,0 +1,42 @@
/* -*- 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/. */
#ifndef _COMI18N_LOADED_H_
#define _COMI18N_LOADED_H_
#include "msgCore.h"
class nsIUnicodeDecoder;
class nsIUnicodeEncoder;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Decode MIME header to UTF-8.
* Uses MIME_ConvertCharset if the decoded string needs a conversion.
*
*
* @param header [IN] A header to decode.
* @param default_charset [IN] Default charset to apply to ulabeled non-UTF-8 8bit data
* @param override_charset [IN] If true, default_charset used instead of any charset labeling other than UTF-8
* @param eatContinuations [IN] If true, unfold headers
* @param result [OUT] Decoded buffer
*/
void MIME_DecodeMimeHeader(const char *header, const char *default_charset,
bool override_charset, bool eatContinuations,
nsACString &result);
nsresult MIME_detect_charset(const char *aBuf, int32_t aLength, const char** aCharset);
nsresult MIME_get_unicode_decoder(const char* aInputCharset, nsIUnicodeDecoder **aDecoder);
nsresult MIME_get_unicode_encoder(const char* aOutputCharset, nsIUnicodeEncoder **aEncoder);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif // _COMI18N_LOADED_H_

View file

@ -0,0 +1,29 @@
/* 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/. */
function parseNewsgroups(headers) {
let ng = [];
for (let header of headers) {
ng = ng.concat(header.split(/\s*,\s*/));
}
return ng;
}
function emitNewsgroups(groups) {
// Don't encode the newsgroups names in RFC 2047...
if (groups.length == 1)
this.addText(groups[0], false);
else {
this.addText(groups[0], false);
for (let i = 1; i < groups.length; i++) {
this.addText(",", false); // only comma, no space!
this.addText(groups[i], false);
}
}
}
jsmime.headerparser.addStructuredDecoder("Newsgroups", parseNewsgroups);
jsmime.headerparser.addStructuredDecoder("Followup-To", parseNewsgroups);
jsmime.headeremitter.addStructuredEncoder("Newsgroups", emitNewsgroups);
jsmime.headeremitter.addStructuredEncoder("Followup-To", emitNewsgroups);

View file

@ -0,0 +1,90 @@
/* 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/. */
// vim:set ts=2 sw=2 sts=2 et ft=javascript:
Components.utils.import("resource://gre/modules/Services.jsm");
/**
* This file exports the JSMime code, polyfilling code as appropriate for use in
* Gecko.
*/
// Load the core MIME parser. Since it doesn't define EXPORTED_SYMBOLS, we must
// use the subscript loader instead.
Services.scriptloader.loadSubScript("resource:///modules/jsmime/jsmime.js");
var EXPORTED_SYMBOLS = ["jsmime"];
// A polyfill to support non-encoding-spec charsets. Since the only converter
// available to us from JavaScript has a very, very weak and inflexible API, we
// choose to rely on the regular text decoder unless absolutely necessary.
// support non-encoding-spec charsets.
function FakeTextDecoder(label="UTF-8", options = {}) {
this._reset(label);
// So nsIScriptableUnicodeConverter only gives us fatal=false, unless we are
// using UTF-8, where we only get fatal=true. The internals of said class tell
// us to use a C++-only class if we need better behavior.
}
FakeTextDecoder.prototype = {
_reset: function (label) {
this._encoder = Components.classes[
"@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
this._encoder.isInternal = true;
let manager = Components.classes[
"@mozilla.org/charset-converter-manager;1"]
.createInstance(Components.interfaces.nsICharsetConverterManager);
this._encoder.charset = manager.getCharsetAlias(label);
},
get encoding() { return this._encoder.charset; },
decode: function (input, options = {}) {
let more = 'stream' in options ? options.stream : false;
let result = "";
if (input !== undefined) {
let data = new Uint8Array(input);
result = this._encoder.convertFromByteArray(data, data.length);
}
// This isn't quite right--it won't handle errors if there are a few
// remaining bytes in the buffer, but it's the best we can do.
if (!more)
this._reset(this.encoding);
return result;
},
};
var RealTextDecoder = TextDecoder;
function FallbackTextDecoder(charset, options) {
try {
return new RealTextDecoder(charset, options);
} catch (e) {
return new FakeTextDecoder(charset, options);
}
}
TextDecoder = FallbackTextDecoder;
// The following code loads custom MIME encoders.
var CATEGORY_NAME = "custom-mime-encoder";
Services.obs.addObserver(function (subject, topic, data) {
subject = subject.QueryInterface(Components.interfaces.nsISupportsCString)
.data;
if (data == CATEGORY_NAME) {
let url = catman.getCategoryEntry(CATEGORY_NAME, subject);
Services.scriptloader.loadSubScript(url, {}, "UTF-8");
}
}, "xpcom-category-entry-added", false);
var catman = Components.classes["@mozilla.org/categorymanager;1"]
.getService(Components.interfaces.nsICategoryManager);
var entries = catman.enumerateCategory(CATEGORY_NAME);
while (entries.hasMoreElements()) {
let string = entries.getNext()
.QueryInterface(Components.interfaces.nsISupportsCString)
.data;
let url = catman.getCategoryEntry(CATEGORY_NAME, string);
Services.scriptloader.loadSubScript(url, {}, "UTF-8");
}

View file

@ -0,0 +1,7 @@
; 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/.
LIBRARY mime.dll
EXPORTS

View file

@ -0,0 +1,512 @@
/* 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/. */
Components.utils.import("resource://gre/modules/Deprecated.jsm");
Components.utils.import("resource:///modules/jsmime.jsm");
Components.utils.import("resource:///modules/mimeParser.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function HeaderHandler() {
this.value = "";
this.deliverData = function (str) { this.value += str; };
this.deliverEOF = function () {};
}
function StringEnumerator(iterator) {
this._iterator = iterator;
this._next = undefined;
}
StringEnumerator.prototype = {
QueryInterface: XPCOMUtils.generateQI([
Components.interfaces.nsIUTF8StringEnumerator]),
_setNext: function () {
if (this._next !== undefined)
return;
this._next = this._iterator.next();
},
hasMore: function () {
this._setNext();
return !this._next.done;
},
getNext: function () {
this._setNext();
let result = this._next;
this._next = undefined;
if (result.done)
throw Components.results.NS_ERROR_UNEXPECTED;
return result.value;
}
};
/**
* If we get XPConnect-wrapped objects for msgIAddressObjects, we will have
* properties defined for 'group' that throws off jsmime. This function converts
* the addresses into the form that jsmime expects.
*/
function fixXpconnectAddresses(addrs) {
return addrs.map((addr) => {
// This is ideally !addr.group, but that causes a JS strict warning, if
// group is not in addr, since that's enabled in all chrome code now.
if (!('group' in addr) || addr.group === undefined || addr.group === null) {
return MimeAddressParser.prototype.makeMailboxObject(addr.name,
addr.email);
} else {
return MimeAddressParser.prototype.makeGroupObject(addr.name,
fixXpconnectAddresses(addr.group));
}
});
}
/**
* This is a base handler for supporting msgIStructuredHeaders, since we have
* two implementations that need the readable aspects of the interface.
*/
function MimeStructuredHeaders() {
}
MimeStructuredHeaders.prototype = {
getHeader: function (aHeaderName) {
let name = aHeaderName.toLowerCase();
return this._headers.get(name);
},
hasHeader: function (aHeaderName) {
return this._headers.has(aHeaderName.toLowerCase());
},
getUnstructuredHeader: function (aHeaderName) {
let result = this.getHeader(aHeaderName);
if (result === undefined || typeof result == "string")
return result;
throw Components.results.NS_ERROR_ILLEGAL_VALUE;
},
getAddressingHeader: function (aHeaderName, aPreserveGroups, count) {
let addrs = this.getHeader(aHeaderName);
if (addrs === undefined) {
addrs = [];
} else if (!Array.isArray(addrs)) {
throw Components.results.NS_ERROR_ILLEGAL_VALUE;
}
return fixArray(addrs, aPreserveGroups, count);
},
getRawHeader: function (aHeaderName) {
let result = this.getHeader(aHeaderName);
if (result === undefined)
return result;
let value = jsmime.headeremitter.emitStructuredHeader(aHeaderName,
result, {});
// Strip off the header name and trailing whitespace before returning...
value = value.substring(aHeaderName.length + 2).trim();
// ... as well as embedded newlines.
value = value.replace(/\r\n/g, '');
return value;
},
get headerNames() {
return new StringEnumerator(this._headers.keys());
},
buildMimeText: function () {
if (this._headers.size == 0) {
return "";
}
let handler = new HeaderHandler();
let emitter = jsmime.headeremitter.makeStreamingEmitter(handler, {
useASCII: true
});
for (let [value, header] of this._headers) {
emitter.addStructuredHeader(value, header);
}
emitter.finish();
return handler.value;
},
};
function MimeHeaders() {
}
MimeHeaders.prototype = {
__proto__: MimeStructuredHeaders.prototype,
classDescription: "Mime headers implementation",
classID: Components.ID("d1258011-f391-44fd-992e-c6f4b461a42f"),
contractID: "@mozilla.org/messenger/mimeheaders;1",
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIMimeHeaders,
Components.interfaces.msgIStructuredHeaders]),
initialize: function MimeHeaders_initialize(allHeaders) {
this._headers = MimeParser.extractHeaders(allHeaders);
},
extractHeader: function MimeHeaders_extractHeader(header, getAll) {
if (!this._headers)
throw Components.results.NS_ERROR_NOT_INITIALIZED;
// Canonicalized to lower-case form
header = header.toLowerCase();
if (!this._headers.has(header))
return null;
var values = this._headers.getRawHeader(header);
if (getAll)
return values.join(",\r\n\t");
else
return values[0];
},
get allHeaders() {
return this._headers.rawHeaderText;
}
};
function MimeWritableStructuredHeaders() {
this._headers = new Map();
}
MimeWritableStructuredHeaders.prototype = {
__proto__: MimeStructuredHeaders.prototype,
classID: Components.ID("c560806a-425f-4f0f-bf69-397c58c599a7"),
QueryInterface: XPCOMUtils.generateQI([
Components.interfaces.msgIStructuredHeaders,
Components.interfaces.msgIWritableStructuredHeaders]),
setHeader: function (aHeaderName, aValue) {
this._headers.set(aHeaderName.toLowerCase(), aValue);
},
deleteHeader: function (aHeaderName) {
this._headers.delete(aHeaderName.toLowerCase());
},
addAllHeaders: function (aHeaders) {
let headerList = aHeaders.headerNames;
while (headerList.hasMore()) {
let header = headerList.getNext();
this.setHeader(header, aHeaders.getHeader(header));
}
},
setUnstructuredHeader: function (aHeaderName, aValue) {
this.setHeader(aHeaderName, aValue);
},
setAddressingHeader: function (aHeaderName, aAddresses, aCount) {
this.setHeader(aHeaderName, fixXpconnectAddresses(aAddresses));
},
setRawHeader: function (aHeaderName, aValue, aCharset) {
aValue = jsmime.headerparser.convert8BitHeader(aValue, aCharset);
try {
this.setHeader(aHeaderName,
jsmime.headerparser.parseStructuredHeader(aHeaderName, aValue));
} catch (e) {
// This means we don't have a structured encoder. Just assume it's a raw
// string value then.
this.setHeader(aHeaderName, aValue);
}
}
};
// These are prototypes for nsIMsgHeaderParser implementation
var Mailbox = {
toString: function () {
return this.name ? this.name + " <" + this.email + ">" : this.email;
}
};
var EmailGroup = {
toString: function () {
return this.name + ": " + this.group.map(x => x.toString()).join(", ");
}
};
// A helper method for parse*Header that takes into account the desire to
// preserve group and also tweaks the output to support the prototypes for the
// XPIDL output.
function fixArray(addresses, preserveGroups, count) {
function resetPrototype(obj, prototype) {
let prototyped = Object.create(prototype);
for (let key of Object.getOwnPropertyNames(obj)) {
if (typeof obj[key] == "string") {
prototyped[key] = obj[key].replace(/\x00/g, '');
} else {
prototyped[key] = obj[key];
}
}
return prototyped;
}
let outputArray = [];
for (let element of addresses) {
if ('group' in element) {
// Fix up the prototypes of the group and the list members
element = resetPrototype(element, EmailGroup);
element.group = element.group.map(e => resetPrototype(e, Mailbox));
// Add to the output array
if (preserveGroups)
outputArray.push(element);
else
outputArray = outputArray.concat(element.group);
} else {
element = resetPrototype(element, Mailbox);
outputArray.push(element);
}
}
if (count)
count.value = outputArray.length;
return outputArray;
}
function MimeAddressParser() {
}
MimeAddressParser.prototype = {
classID: Components.ID("96bd8769-2d0e-4440-963d-22b97fb3ba77"),
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIMsgHeaderParser]),
parseEncodedHeader: function (aHeader, aCharset, aPreserveGroups, count) {
aHeader = aHeader || "";
let value = MimeParser.parseHeaderField(aHeader,
MimeParser.HEADER_ADDRESS | MimeParser.HEADER_OPTION_ALL_I18N, aCharset);
return fixArray(value, aPreserveGroups, count);
},
parseDecodedHeader: function (aHeader, aPreserveGroups, count) {
aHeader = aHeader || "";
let value = MimeParser.parseHeaderField(aHeader, MimeParser.HEADER_ADDRESS);
return fixArray(value, aPreserveGroups, count);
},
makeMimeHeader: function (addresses, length) {
addresses = fixXpconnectAddresses(addresses);
// Don't output any necessary continuations, so make line length as large as
// possible first.
let options = {
softMargin: 900,
hardMargin: 900,
useASCII: false // We don't want RFC 2047 encoding here.
};
let handler = new HeaderHandler();
let emitter = new jsmime.headeremitter.makeStreamingEmitter(handler,
options);
emitter.addAddresses(addresses);
emitter.finish(true);
return handler.value.replace(/\r\n( |$)/g, '');
},
extractFirstName: function (aHeader) {
let address = this.parseDecodedHeader(aHeader, false)[0];
return address.name || address.email;
},
removeDuplicateAddresses: function (aAddrs, aOtherAddrs) {
// This is actually a rather complicated algorithm, especially if we want to
// preserve group structure. Basically, we use a set to identify which
// headers we have seen and therefore want to remove. To work in several
// various forms of edge cases, we need to normalize the entries in that
// structure.
function normalize(email) {
// XXX: This algorithm doesn't work with IDN yet. It looks like we have to
// convert from IDN then do lower case, but I haven't confirmed yet.
return email.toLowerCase();
}
// The filtration function, which removes email addresses that are
// duplicates of those we have already seen.
function filterAccept(e) {
if ('email' in e) {
// If we've seen the address, don't keep this one; otherwise, add it to
// the list.
let key = normalize(e.email);
if (allAddresses.has(key))
return false;
allAddresses.add(key);
} else {
// Groups -> filter out all the member addresses.
e.group = e.group.filter(filterAccept);
}
return true;
}
// First, collect all of the emails to forcibly delete.
let allAddresses = new Set();
for (let element of this.parseDecodedHeader(aOtherAddrs, false)) {
allAddresses.add(normalize(element.email));
}
// The actual data to filter
let filtered = this.parseDecodedHeader(aAddrs, true).filter(filterAccept);
return this.makeMimeHeader(filtered);
},
makeMailboxObject: function (aName, aEmail) {
let object = Object.create(Mailbox);
object.name = aName;
object.email = aEmail ? aEmail.trim() : aEmail;
return object;
},
makeGroupObject: function (aName, aMembers) {
let object = Object.create(EmailGroup);
object.name = aName;
object.group = aMembers;
return object;
},
makeFromDisplayAddress: function (aDisplay, count) {
// The basic idea is to split on every comma, so long as there is a
// preceding @.
let output = [];
while (aDisplay.length) {
let at = aDisplay.indexOf('@');
let comma = aDisplay.indexOf(',', at + 1);
let addr;
if (comma > 0) {
addr = aDisplay.substr(0, comma);
aDisplay = aDisplay.substr(comma + 1);
} else {
addr = aDisplay;
aDisplay = "";
}
output.push(this._makeSingleAddress(addr.trimLeft()));
}
if (count)
count.value = output.length;
return output;
},
/// Construct a single email address from a name <local@domain> token.
_makeSingleAddress: function (aDisplayName) {
if (aDisplayName.includes('<')) {
let lbracket = aDisplayName.lastIndexOf('<');
let rbracket = aDisplayName.lastIndexOf('>');
return this.makeMailboxObject(
lbracket == 0 ? '' : aDisplayName.slice(0, lbracket).trim(),
aDisplayName.slice(lbracket + 1, rbracket));
} else {
return this.makeMailboxObject('', aDisplayName);
}
},
// What follows is the deprecated API that will be removed shortly.
parseHeadersWithArray: function (aHeader, aAddrs, aNames, aFullNames) {
let addrs = [], names = [], fullNames = [];
// Parse header, but without HEADER_OPTION_ALLOW_RAW.
let value = MimeParser.parseHeaderField(aHeader || "",
MimeParser.HEADER_ADDRESS |
MimeParser.HEADER_OPTION_DECODE_2231 |
MimeParser.HEADER_OPTION_DECODE_2047,
undefined);
let allAddresses = fixArray(value, false);
// Don't index the dummy empty address.
if (aHeader.trim() == "")
allAddresses = [];
for (let address of allAddresses) {
addrs.push(address.email);
names.push(address.name || null);
fullNames.push(address.toString());
}
aAddrs.value = addrs;
aNames.value = names;
aFullNames.value = fullNames;
return allAddresses.length;
},
extractHeaderAddressMailboxes: function (aLine) {
return this.parseDecodedHeader(aLine).map(addr => addr.email).join(", ");
},
extractHeaderAddressNames: function (aLine) {
return this.parseDecodedHeader(aLine).map(addr => addr.name || addr.email)
.join(", ");
},
extractHeaderAddressName: function (aLine) {
let addrs = this.parseDecodedHeader(aLine).map(addr =>
addr.name || addr.email);
return addrs.length == 0 ? "" : addrs[0];
},
makeMimeAddress: function (aName, aEmail) {
let object = this.makeMailboxObject(aName, aEmail);
return this.makeMimeHeader([object]);
},
};
function MimeConverter() {
}
MimeConverter.prototype = {
classID: Components.ID("93f8c049-80ed-4dda-9000-94ad8daba44c"),
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIMimeConverter]),
encodeMimePartIIStr_UTF8: function (aHeader, aStructured, aCharset,
aFieldNameLen, aLineLength) {
// The JSMime encoder only works in UTF-8, so if someone requests to not do
// it, they need to change their code.
if (aCharset.toLowerCase() != "utf-8") {
Deprecated.warning("Encoding to non-UTF-8 values is obsolete",
"http://bugzilla.mozilla.org/show_bug.cgi?id=790855");
}
// Compute the encoding options. The way our API is structured in this
// method is really horrendous and does not align with the way that JSMime
// handles it. Instead, we'll need to create a fake header to take into
// account the aFieldNameLen parameter.
let fakeHeader = '-'.repeat(aFieldNameLen);
let options = {
softMargin: aLineLength,
useASCII: true,
};
let handler = new HeaderHandler();
let emitter = new jsmime.headeremitter.makeStreamingEmitter(handler,
options);
// Add the text to the be encoded.
emitter.addHeaderName(fakeHeader);
if (aStructured) {
// Structured really means "this is an addressing header"
let addresses = MimeParser.parseHeaderField(aHeader,
MimeParser.HEADER_ADDRESS | MimeParser.HEADER_OPTION_DECODE_2047);
// This happens in one of our tests if there is a "bare" email but no
// @ sign. Without it, the result disappears since our emission code
// assumes that an empty email is not worth emitting.
if (addresses.length === 1 && addresses[0].email === "" &&
addresses[0].name !== "") {
addresses[0].email = addresses[0].name;
addresses[0].name = "";
}
emitter.addAddresses(addresses);
} else {
emitter.addUnstructured(aHeader);
}
// Compute the output. We need to strip off the fake prefix added earlier
// and the extra CRLF at the end.
emitter.finish(true);
let value = handler.value;
value = value.replace(new RegExp(fakeHeader + ":\\s*"), "");
return value.substring(0, value.length - 2);
},
decodeMimeHeader: function (aHeader, aDefaultCharset, aOverride, aUnfold) {
let value = MimeParser.parseHeaderField(aHeader,
MimeParser.HEADER_UNSTRUCTURED | MimeParser.HEADER_OPTION_ALL_I18N,
aDefaultCharset);
if (aUnfold) {
value = value.replace(/[\r\n]\t/g, ' ')
.replace(/[\r\n]/g, '');
}
return value;
},
// This is identical to the above, except for factors that are handled by the
// xpconnect conversion process
decodeMimeHeaderToUTF8: function () {
return this.decodeMimeHeader.apply(this, arguments);
},
};
var components = [MimeHeaders, MimeWritableStructuredHeaders, MimeAddressParser,
MimeConverter];
var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);

View file

@ -0,0 +1,258 @@
/* 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/. */
// vim:set ts=2 sw=2 sts=2 et ft=javascript:
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/jsmime.jsm");
var EXPORTED_SYMBOLS = ["MimeParser"];
// Emitter helpers, for internal functions later on.
var ExtractHeadersEmitter = {
startPart: function (partNum, headers) {
if (partNum == '') {
this.headers = headers;
}
}
};
var ExtractHeadersAndBodyEmitter = {
body: '',
startPart: ExtractHeadersEmitter.startPart,
deliverPartData: function (partNum, data) {
if (partNum == '')
this.body += data;
}
};
var Ci = Components.interfaces;
var Cc = Components.classes;
/// Sets appropriate default options for chrome-privileged environments
function setDefaultParserOptions(opts) {
if (!("onerror" in opts)) {
opts.onerror = Components.utils.reportError;
}
}
var MimeParser = {
/**
* Triggers an asynchronous parse of the given input.
*
* The input is an input stream; the stream will be read until EOF and then
* closed upon completion. Both blocking and nonblocking streams are
* supported by this implementation, but it is still guaranteed that the first
* callback will not happen before this method returns.
*
* @param input An input stream of text to parse.
* @param emitter The emitter to receive callbacks on.
* @param opts A set of options for the parser.
*/
parseAsync: function MimeParser_parseAsync(input, emitter, opts) {
// Normalize the input into an input stream.
if (!(input instanceof Ci.nsIInputStream)) {
throw new Error("input is not a recognizable type!");
}
// We need a pump for the listener
var pump = Cc["@mozilla.org/network/input-stream-pump;1"]
.createInstance(Ci.nsIInputStreamPump);
pump.init(input, -1, -1, 0, 0, true);
// Make a stream listener with the given emitter and use it to read from
// the pump.
var parserListener = MimeParser.makeStreamListenerParser(emitter, opts);
pump.asyncRead(parserListener, null);
},
/**
* Triggers an synchronous parse of the given input.
*
* The input is a string that is immediately parsed, calling all functions on
* the emitter before this function returns.
*
* @param input A string or input stream of text to parse.
* @param emitter The emitter to receive callbacks on.
* @param opts A set of options for the parser.
*/
parseSync: function MimeParser_parseSync(input, emitter, opts) {
// We only support string parsing if we are trying to do this parse
// synchronously.
if (typeof input != "string") {
throw new Error("input is not a recognizable type!");
}
setDefaultParserOptions(opts);
var parser = new jsmime.MimeParser(emitter, opts);
parser.deliverData(input);
parser.deliverEOF();
return;
},
/**
* Returns a stream listener that feeds data into a parser.
*
* In addition to the functions on the emitter that the parser may use, the
* generated stream listener will also make calls to onStartRequest and
* onStopRequest on the emitter (if they exist).
*
* @param emitter The emitter to receive callbacks on.
* @param opts A set of options for the parser.
*/
makeStreamListenerParser: function MimeParser_makeSLParser(emitter, opts) {
var StreamListener = {
onStartRequest: function SLP_onStartRequest(aRequest, aContext) {
try {
if ("onStartRequest" in emitter)
emitter.onStartRequest(aRequest, aContext);
} finally {
this._parser.resetParser();
}
},
onStopRequest: function SLP_onStopRequest(aRequest, aContext, aStatus) {
this._parser.deliverEOF();
if ("onStopRequest" in emitter)
emitter.onStopRequest(aRequest, aContext, aStatus);
},
onDataAvailable: function SLP_onData(aRequest, aContext, aStream,
aOffset, aCount) {
var scriptIn = Cc["@mozilla.org/scriptableinputstream;1"]
.createInstance(Ci.nsIScriptableInputStream);
scriptIn.init(aStream);
// Use readBytes instead of read to handle embedded NULs properly.
this._parser.deliverData(scriptIn.readBytes(aCount));
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener,
Ci.nsIRequestObserver])
};
setDefaultParserOptions(opts);
StreamListener._parser = new jsmime.MimeParser(emitter, opts);
return StreamListener;
},
/**
* Returns a new raw MIME parser.
*
* Prefer one of the other methods where possible, since the input here must
* be driven manually.
*
* @param emitter The emitter to receive callbacks on.
* @param opts A set of options for the parser.
*/
makeParser: function MimeParser_makeParser(emitter, opts) {
setDefaultParserOptions(opts);
return new jsmime.MimeParser(emitter, opts);
},
/**
* Returns a dictionary of headers for the given input.
*
* The input is any type of input that would be accepted by parseSync. What
* is returned is a JS object that represents the headers of the entire
* envelope as would be received by startPart when partNum is the empty
* string.
*
* @param input A string of text to parse.
*/
extractHeaders: function MimeParser_extractHeaders(input) {
var emitter = Object.create(ExtractHeadersEmitter);
MimeParser.parseSync(input, emitter, {pruneat: '', bodyformat: 'none'});
return emitter.headers;
},
/**
* Returns the headers and body for the given input message.
*
* The return value is an array whose first element is the dictionary of
* headers (as would be returned by extractHeaders) and whose second element
* is a binary string of the entire body of the message.
*
* @param input A string of text to parse.
*/
extractHeadersAndBody: function MimeParser_extractHeaders(input) {
var emitter = Object.create(ExtractHeadersAndBodyEmitter);
MimeParser.parseSync(input, emitter, {pruneat: '', bodyformat: 'raw'});
return [emitter.headers, emitter.body];
},
// Parameters for parseHeaderField
/**
* Parse the header as if it were unstructured.
*
* This results in the same string if no other options are specified. If other
* options are specified, this causes the string to be modified appropriately.
*/
HEADER_UNSTRUCTURED: 0x00,
/**
* Parse the header as if it were in the form text; attr=val; attr=val.
*
* Such headers include Content-Type, Content-Disposition, and most other
* headers used by MIME as opposed to messages.
*/
HEADER_PARAMETER: 0x02,
/**
* Parse the header as if it were a sequence of mailboxes.
*/
HEADER_ADDRESS: 0x03,
/**
* This decodes parameter values according to RFC 2231.
*
* This flag means nothing if HEADER_PARAMETER is not specified.
*/
HEADER_OPTION_DECODE_2231: 0x10,
/**
* This decodes the inline encoded-words that are in RFC 2047.
*/
HEADER_OPTION_DECODE_2047: 0x20,
/**
* This converts the header from a raw string to proper Unicode.
*/
HEADER_OPTION_ALLOW_RAW: 0x40,
/// Convenience for all three of the above.
HEADER_OPTION_ALL_I18N: 0x70,
/**
* Parse a header field according to the specification given by flags.
*
* Permissible flags begin with one of the HEADER_* flags, which may be or'd
* with any of the HEADER_OPTION_* flags to modify the result appropriately.
*
* If the option HEADER_OPTION_ALLOW_RAW is passed, the charset parameter, if
* present, is the charset to fallback to if the header is not decodable as
* UTF-8 text. If HEADER_OPTION_ALLOW_RAW is passed but the charset parameter
* is not provided, then no fallback decoding will be done. If
* HEADER_OPTION_ALLOW_RAW is not passed, then no attempt will be made to
* convert charsets.
*
* @param text The value of a MIME or message header to parse.
* @param flags A set of flags that controls interpretation of the header.
* @param charset A default charset to assume if no information may be found.
*/
parseHeaderField: function MimeParser_parseHeaderField(text, flags, charset) {
// If we have a raw string, convert it to Unicode first
if (flags & MimeParser.HEADER_OPTION_ALLOW_RAW)
text = jsmime.headerparser.convert8BitHeader(text, charset);
// The low 4 bits indicate the type of the header we are parsing. All of the
// higher-order bits are flags.
switch (flags & 0x0f) {
case MimeParser.HEADER_UNSTRUCTURED:
if (flags & MimeParser.HEADER_OPTION_DECODE_2047)
text = jsmime.headerparser.decodeRFC2047Words(text);
return text;
case MimeParser.HEADER_PARAMETER:
return jsmime.headerparser.parseParameterHeader(text,
(flags & MimeParser.HEADER_OPTION_DECODE_2047) != 0,
(flags & MimeParser.HEADER_OPTION_DECODE_2231) != 0);
case MimeParser.HEADER_ADDRESS:
return jsmime.headerparser.parseAddressingHeader(text,
(flags & MimeParser.HEADER_OPTION_DECODE_2047) != 0);
default:
throw "Illegal type of header field";
}
},
};

View file

@ -0,0 +1,150 @@
/* -*- 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/. */
/* Most of this code is copied from mimethsa. If you find a bug here, check that class, too. */
/* This runs the entire HTML document through the Mozilla HTML parser, and
then outputs it as string again. This ensures that the HTML document is
syntactically correct and complete and all tags and attributes are closed.
That prevents "MIME in the middle" attacks like efail.de.
The base problem is that we concatenate different MIME parts in the output
and render them all together as a single HTML document in the display.
The better solution would be to put each MIME part into its own <iframe type="content">.
during rendering. Unfortunately, we'd need <iframe seamless> for that.
That would remove the need for this workaround, and stop even more attack classes.
*/
#include "mimeTextHTMLParsed.h"
#include "prmem.h"
#include "prlog.h"
#include "msgCore.h"
#include "nsIDOMParser.h"
#include "nsIDOMDocument.h"
#include "nsIDocument.h"
#include "nsIDocumentEncoder.h"
#include "mozilla/ErrorResult.h"
#include "nsIPrefBranch.h"
#include "mimethtm.h"
#define MIME_SUPERCLASS mimeInlineTextHTMLClass
MimeDefClass(MimeInlineTextHTMLParsed, MimeInlineTextHTMLParsedClass,
mimeInlineTextHTMLParsedClass, &MIME_SUPERCLASS);
static int MimeInlineTextHTMLParsed_parse_line(const char *, int32_t,
MimeObject *);
static int MimeInlineTextHTMLParsed_parse_begin(MimeObject *obj);
static int MimeInlineTextHTMLParsed_parse_eof(MimeObject *, bool);
static void MimeInlineTextHTMLParsed_finalize(MimeObject *obj);
static int
MimeInlineTextHTMLParsedClassInitialize(MimeInlineTextHTMLParsedClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *)clazz;
NS_ASSERTION(!oclass->class_initialized, "problem with superclass");
oclass->parse_line = MimeInlineTextHTMLParsed_parse_line;
oclass->parse_begin = MimeInlineTextHTMLParsed_parse_begin;
oclass->parse_eof = MimeInlineTextHTMLParsed_parse_eof;
oclass->finalize = MimeInlineTextHTMLParsed_finalize;
return 0;
}
static int
MimeInlineTextHTMLParsed_parse_begin(MimeObject *obj)
{
MimeInlineTextHTMLParsed *me = (MimeInlineTextHTMLParsed *)obj;
me->complete_buffer = new nsString();
int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
if (status < 0)
return status;
return 0;
}
static int
MimeInlineTextHTMLParsed_parse_eof(MimeObject *obj, bool abort_p)
{
if (obj->closed_p)
return 0;
int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
if (status < 0)
return status;
MimeInlineTextHTMLParsed *me = (MimeInlineTextHTMLParsed *)obj;
// We have to cache all lines and parse the whole document at once.
// There's a useful sounding function parseFromStream(), but it only allows XML
// mimetypes, not HTML. Methinks that's because the HTML soup parser
// needs the entire doc to make sense of the gibberish that people write.
if (!me || !me->complete_buffer)
return 0;
nsString& rawHTML = *(me->complete_buffer);
if (rawHTML.IsEmpty())
return 0;
nsString parsed;
nsresult rv;
// Parse the HTML source.
nsCOMPtr<nsIDOMDocument> document;
nsCOMPtr<nsIDOMParser> parser = do_GetService(NS_DOMPARSER_CONTRACTID);
rv = parser->ParseFromString(rawHTML.get(), "text/html",
getter_AddRefs(document));
NS_ENSURE_SUCCESS(rv, -1);
// Serialize it back to HTML source again.
nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance(
"@mozilla.org/layout/documentEncoder;1?type=text/html");
uint32_t aFlags = nsIDocumentEncoder::OutputRaw |
nsIDocumentEncoder::OutputDisallowLineBreaking;
rv = encoder->Init(document, NS_LITERAL_STRING("text/html"), aFlags);
NS_ENSURE_SUCCESS(rv, -1);
rv = encoder->EncodeToString(parsed);
NS_ENSURE_SUCCESS(rv, -1);
// Write it out.
NS_ConvertUTF16toUTF8 resultCStr(parsed);
MimeInlineTextHTML_insert_lang_div(obj, resultCStr);
MimeInlineTextHTML_remove_plaintext_tag(obj, resultCStr);
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_line(
resultCStr.BeginWriting(), resultCStr.Length(), obj);
rawHTML.Truncate();
return status;
}
void
MimeInlineTextHTMLParsed_finalize(MimeObject *obj)
{
MimeInlineTextHTMLParsed *me = (MimeInlineTextHTMLParsed *)obj;
if (me && me->complete_buffer)
{
obj->clazz->parse_eof(obj, false);
delete me->complete_buffer;
me->complete_buffer = NULL;
}
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(obj);
}
static int
MimeInlineTextHTMLParsed_parse_line(const char *line, int32_t length,
MimeObject *obj)
{
MimeInlineTextHTMLParsed *me = (MimeInlineTextHTMLParsed *)obj;
if (!me || !(me->complete_buffer))
return -1;
nsCString linestr(line, length);
NS_ConvertUTF8toUTF16 line_ucs2(linestr.get());
if (length && line_ucs2.IsEmpty())
CopyASCIItoUTF16(linestr, line_ucs2);
(me->complete_buffer)->Append(line_ucs2);
return 0;
}

View file

@ -0,0 +1,28 @@
/* -*- 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/. */
#ifndef _MIMETEXTHTMLPARSED_H_
#define _MIMETEXTHTMLPARSED_H_
#include "mimethtm.h"
typedef struct MimeInlineTextHTMLParsedClass MimeInlineTextHTMLParsedClass;
typedef struct MimeInlineTextHTMLParsed MimeInlineTextHTMLParsed;
struct MimeInlineTextHTMLParsedClass {
MimeInlineTextHTMLClass html;
};
extern MimeInlineTextHTMLParsedClass mimeInlineTextHTMLParsedClass;
struct MimeInlineTextHTMLParsed {
MimeInlineTextHTML html;
nsString *complete_buffer; // Gecko parser expects wide strings
};
#define MimeInlineTextHTMLParsedClassInitializer(ITYPE,CSUPER) \
{ MimeInlineTextHTMLClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMETEXTHTMLPARSED_H_ */

View file

@ -0,0 +1,249 @@
/* -*- 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 Original Code has been modified by IBM Corporation. Modifications made by IBM
* described herein are Copyright (c) International Business Machines Corporation, 2000.
* Modifications to Mozilla code or documentation identified per MPL Section 3.3
*
* Date Modified by Description of modification
* 04/20/2000 IBM Corp. OS/2 VisualAge build.
*/
/*
* mimebuf.c - libmsg like buffer handling routines for libmime
*/
#include "prmem.h"
#include "plstr.h"
#include "prlog.h"
#include "msgCore.h"
#include "nsMimeStringResources.h"
extern "C" int
mime_GrowBuffer (uint32_t desired_size, uint32_t element_size, uint32_t quantum,
char **buffer, int32_t *size)
{
if ((uint32_t) *size <= desired_size)
{
char *new_buf;
uint32_t increment = desired_size - *size;
if (increment < quantum) /* always grow by a minimum of N bytes */
increment = quantum;
new_buf = (*buffer
? (char *) PR_Realloc (*buffer, (*size + increment)
* (element_size / sizeof(char)))
: (char *) PR_MALLOC ((*size + increment)
* (element_size / sizeof(char))));
if (! new_buf)
return MIME_OUT_OF_MEMORY;
*buffer = new_buf;
*size += increment;
}
return 0;
}
/* The opposite of mime_LineBuffer(): takes small buffers and packs them
up into bigger buffers before passing them along.
Pass in a desired_buffer_size 0 to tell it to flush (for example, in
in the very last call to this function.)
*/
extern "C" int
mime_ReBuffer (const char *net_buffer, int32_t net_buffer_size,
uint32_t desired_buffer_size,
char **bufferP, int32_t *buffer_sizeP, uint32_t *buffer_fpP,
int32_t (*per_buffer_fn) (char *buffer, uint32_t buffer_size,
void *closure),
void *closure)
{
int status = 0;
if (desired_buffer_size >= (uint32_t) (*buffer_sizeP))
{
status = mime_GrowBuffer (desired_buffer_size, sizeof(char), 1024,
bufferP, buffer_sizeP);
if (status < 0) return status;
}
do
{
int32_t size = *buffer_sizeP - *buffer_fpP;
if (size > net_buffer_size)
size = net_buffer_size;
if (size > 0)
{
memcpy ((*bufferP) + (*buffer_fpP), net_buffer, size);
(*buffer_fpP) += size;
net_buffer += size;
net_buffer_size -= size;
}
if (*buffer_fpP > 0 &&
*buffer_fpP >= desired_buffer_size)
{
status = (*per_buffer_fn) ((*bufferP), (*buffer_fpP), closure);
*buffer_fpP = 0;
if (status < 0) return status;
}
}
while (net_buffer_size > 0);
return 0;
}
static int
convert_and_send_buffer(char* buf, int length, bool convert_newlines_p,
int32_t (* per_line_fn) (char *line,
uint32_t line_length,
void *closure),
void *closure)
{
/* Convert the line terminator to the native form.
*/
char* newline;
#if (MSG_LINEBREAK_LEN == 2)
/***
* This is a patch to support a mail DB corruption cause by earlier version that lead to a crash.
* What happened is that the line terminator is CR+NULL+LF. Therefore, we first process a line
* terminated by CR then a second line that contains only NULL+LF. We need to ignore this second
* line. See bug http://bugzilla.mozilla.org/show_bug.cgi?id=61412 for more information.
***/
if (length == 2 && buf[0] == 0x00 && buf[1] == '\n')
return 0;
#endif
NS_ASSERTION(buf && length > 0, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (!buf || length <= 0) return -1;
newline = buf + length;
NS_ASSERTION(newline[-1] == '\r' || newline[-1] == '\n', "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (newline[-1] != '\r' && newline[-1] != '\n') return -1;
if (!convert_newlines_p)
{
}
#if (MSG_LINEBREAK_LEN == 1)
else if ((newline - buf) >= 2 &&
newline[-2] == '\r' &&
newline[-1] == '\n')
{
/* CRLF -> CR or LF */
buf [length - 2] = MSG_LINEBREAK[0];
length--;
}
else if (newline > buf + 1 &&
newline[-1] != MSG_LINEBREAK[0])
{
/* CR -> LF or LF -> CR */
buf [length - 1] = MSG_LINEBREAK[0];
}
#else
else if (((newline - buf) >= 2 && newline[-2] != '\r') ||
((newline - buf) >= 1 && newline[-1] != '\n'))
{
/* LF -> CRLF or CR -> CRLF */
length++;
buf[length - 2] = MSG_LINEBREAK[0];
buf[length - 1] = MSG_LINEBREAK[1];
}
#endif
return (*per_line_fn)(buf, length, closure);
}
extern "C" int
mime_LineBuffer (const char *net_buffer, int32_t net_buffer_size,
char **bufferP, int32_t *buffer_sizeP, uint32_t *buffer_fpP,
bool convert_newlines_p,
int32_t (* per_line_fn) (char *line, uint32_t line_length,
void *closure),
void *closure)
{
int status = 0;
if (*buffer_fpP > 0 && *bufferP && (*bufferP)[*buffer_fpP - 1] == '\r' &&
net_buffer_size > 0 && net_buffer[0] != '\n') {
/* The last buffer ended with a CR. The new buffer does not start
with a LF. This old buffer should be shipped out and discarded. */
NS_ASSERTION((uint32_t) *buffer_sizeP > *buffer_fpP, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if ((uint32_t) *buffer_sizeP <= *buffer_fpP) return -1;
status = convert_and_send_buffer(*bufferP, *buffer_fpP,
convert_newlines_p,
per_line_fn, closure);
if (status < 0) return status;
*buffer_fpP = 0;
}
while (net_buffer_size > 0)
{
const char *net_buffer_end = net_buffer + net_buffer_size;
const char *newline = 0;
const char *s;
for (s = net_buffer; s < net_buffer_end; s++)
{
/* Move forward in the buffer until the first newline.
Stop when we see CRLF, CR, or LF, or the end of the buffer.
*But*, if we see a lone CR at the *very end* of the buffer,
treat this as if we had reached the end of the buffer without
seeing a line terminator. This is to catch the case of the
buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
*/
if (*s == '\r' || *s == '\n')
{
newline = s;
if (newline[0] == '\r')
{
if (s == net_buffer_end - 1)
{
/* CR at end - wait for the next character. */
newline = 0;
break;
}
else if (newline[1] == '\n')
/* CRLF seen; swallow both. */
newline++;
}
newline++;
break;
}
}
/* Ensure room in the net_buffer and append some or all of the current
chunk of data to it. */
{
const char *end = (newline ? newline : net_buffer_end);
uint32_t desired_size = (end - net_buffer) + (*buffer_fpP) + 1;
if (desired_size >= (uint32_t) (*buffer_sizeP))
{
status = mime_GrowBuffer (desired_size, sizeof(char), 1024,
bufferP, buffer_sizeP);
if (status < 0) return status;
}
memcpy ((*bufferP) + (*buffer_fpP), net_buffer, (end - net_buffer));
(*buffer_fpP) += (end - net_buffer);
(*bufferP)[*buffer_fpP] = '\0';
}
/* Now *bufferP contains either a complete line, or as complete
a line as we have read so far.
If we have a line, process it, and then remove it from `*bufferP'.
Then go around the loop again, until we drain the incoming data.
*/
if (!newline)
return 0;
status = convert_and_send_buffer(*bufferP, *buffer_fpP,
convert_newlines_p,
per_line_fn, closure);
if (status < 0)
return status;
net_buffer_size -= (newline - net_buffer);
net_buffer = newline;
(*buffer_fpP) = 0;
}
return 0;
}

View file

@ -0,0 +1,39 @@
/* -*- 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 Original Code has been modified by IBM Corporation. Modifications made by IBM
* described herein are Copyright (c) International Business Machines Corporation, 2000.
* Modifications to Mozilla code or documentation identified per MPL Section 3.3
*
* Date Modified by Description of modification
* 04/20/2000 IBM Corp. OS/2 VisualAge build.
*/
#ifndef _MIMEBUF_H_
#define _MIMEBUF_H_
extern "C" int mime_GrowBuffer (uint32_t desired_size,
uint32_t element_size, uint32_t quantum,
char **buffer, int32_t *size);
extern "C" int mime_LineBuffer (const char *net_buffer, int32_t net_buffer_size,
char **bufferP, int32_t *buffer_sizeP,
int32_t *buffer_fpP,
bool convert_newlines_p,
int32_t (* per_line_fn) (char *line, int32_t
line_length, void *closure),
void *closure);
extern "C" int mime_ReBuffer (const char *net_buffer, int32_t net_buffer_size,
uint32_t desired_buffer_size,
char **bufferP, uint32_t *buffer_sizeP,
uint32_t *buffer_fpP,
int32_t (*per_buffer_fn) (char *buffer,
uint32_t buffer_size,
void *closure),
void *closure);
#endif /* _MIMEBUF_H_ */

View file

@ -0,0 +1,716 @@
/* -*- 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 "nsICMSMessage.h"
#include "nsICMSMessage2.h"
#include "nsICMSMessageErrors.h"
#include "nsICMSDecoder.h"
#include "mimecms.h"
#include "mimemsig.h"
#include "nspr.h"
#include "mimemsg.h"
#include "mimemoz2.h"
#include "nsIURI.h"
#include "nsIMsgWindow.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsIMimeMiscStatus.h"
#include "nsIMsgSMIMEHeaderSink.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsIX509Cert.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsProxyRelease.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
using namespace mozilla::mailnews;
#define MIME_SUPERCLASS mimeEncryptedClass
MimeDefClass(MimeEncryptedCMS, MimeEncryptedCMSClass,
mimeEncryptedCMSClass, &MIME_SUPERCLASS);
static void *MimeCMS_init(MimeObject *, int (*output_fn) (const char *, int32_t, void *), void *);
static int MimeCMS_write (const char *, int32_t, void *);
static int MimeCMS_eof (void *, bool);
static char * MimeCMS_generate (void *);
static void MimeCMS_free (void *);
extern int SEC_ERROR_CERT_ADDR_MISMATCH;
static int MimeEncryptedCMSClassInitialize(MimeEncryptedCMSClass *clazz)
{
#ifdef DEBUG
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
NS_ASSERTION(!oclass->class_initialized, "1.2 <mscott@netscape.com> 01 Nov 2001 17:59");
#endif
MimeEncryptedClass *eclass = (MimeEncryptedClass *) clazz;
eclass->crypto_init = MimeCMS_init;
eclass->crypto_write = MimeCMS_write;
eclass->crypto_eof = MimeCMS_eof;
eclass->crypto_generate_html = MimeCMS_generate;
eclass->crypto_free = MimeCMS_free;
return 0;
}
typedef struct MimeCMSdata
{
int (*output_fn) (const char *buf, int32_t buf_size, void *output_closure);
void *output_closure;
nsCOMPtr<nsICMSDecoder> decoder_context;
nsCOMPtr<nsICMSMessage> content_info;
bool ci_is_encrypted;
char *sender_addr;
bool decoding_failed;
uint32_t decoded_bytes;
MimeObject *self;
bool parent_is_encrypted_p;
bool parent_holds_stamp_p;
nsCOMPtr<nsIMsgSMIMEHeaderSink> smimeHeaderSink;
MimeCMSdata()
:output_fn(nullptr),
output_closure(nullptr),
ci_is_encrypted(false),
sender_addr(nullptr),
decoding_failed(false),
decoded_bytes(0),
self(nullptr),
parent_is_encrypted_p(false),
parent_holds_stamp_p(false)
{
}
~MimeCMSdata()
{
if(sender_addr)
PR_Free(sender_addr);
// Do an orderly release of nsICMSDecoder and nsICMSMessage //
if (decoder_context)
{
nsCOMPtr<nsICMSMessage> cinfo;
decoder_context->Finish(getter_AddRefs(cinfo));
}
}
} MimeCMSdata;
/* SEC_PKCS7DecoderContentCallback for SEC_PKCS7DecoderStart() */
static void MimeCMS_content_callback (void *arg, const char *buf, unsigned long length)
{
int status;
MimeCMSdata *data = (MimeCMSdata *) arg;
if (!data) return;
if (!data->output_fn)
return;
PR_SetError(0,0);
status = data->output_fn (buf, length, data->output_closure);
if (status < 0)
{
PR_SetError(status, 0);
data->output_fn = 0;
return;
}
data->decoded_bytes += length;
}
bool MimeEncryptedCMS_encrypted_p (MimeObject *obj)
{
bool encrypted;
if (!obj) return false;
if (mime_typep(obj, (MimeObjectClass *) &mimeEncryptedCMSClass))
{
MimeEncrypted *enc = (MimeEncrypted *) obj;
MimeCMSdata *data = (MimeCMSdata *) enc->crypto_closure;
if (!data || !data->content_info) return false;
data->content_info->ContentIsEncrypted(&encrypted);
return encrypted;
}
return false;
}
bool MimeCMSHeadersAndCertsMatch(nsICMSMessage *content_info,
nsIX509Cert *signerCert,
const char *from_addr,
const char *from_name,
const char *sender_addr,
const char *sender_name,
bool *signing_cert_without_email_address)
{
nsCString cert_addr;
bool match = true;
bool foundFrom = false;
bool foundSender = false;
/* Find the name and address in the cert.
*/
if (content_info)
{
// Extract any address contained in the cert.
// This will be used for testing, whether the cert contains no addresses at all.
content_info->GetSignerEmailAddress (getter_Copies(cert_addr));
}
if (signing_cert_without_email_address)
*signing_cert_without_email_address = cert_addr.IsEmpty();
/* Now compare them --
consider it a match if the address in the cert matches the
address in the From field (or as a fallback, the Sender field)
*/
/* If there is no addr in the cert at all, it can not match and we fail. */
if (cert_addr.IsEmpty())
{
match = false;
}
else
{
if (signerCert)
{
if (from_addr && *from_addr)
{
NS_ConvertASCIItoUTF16 ucs2From(from_addr);
if (NS_FAILED(signerCert->ContainsEmailAddress(ucs2From, &foundFrom)))
{
foundFrom = false;
}
}
else if (sender_addr && *sender_addr)
{
NS_ConvertASCIItoUTF16 ucs2Sender(sender_addr);
if (NS_FAILED(signerCert->ContainsEmailAddress(ucs2Sender, &foundSender)))
{
foundSender = false;
}
}
}
if (!foundSender && !foundFrom)
{
match = false;
}
}
return match;
}
class nsSMimeVerificationListener : public nsISMimeVerificationListener
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSISMIMEVERIFICATIONLISTENER
nsSMimeVerificationListener(const char *aFromAddr, const char *aFromName,
const char *aSenderAddr, const char *aSenderName,
nsIMsgSMIMEHeaderSink *aHeaderSink, int32_t aMimeNestingLevel);
protected:
virtual ~nsSMimeVerificationListener() {}
/**
* It is safe to declare this implementation as thread safe,
* despite not using a lock to protect the members.
* Because of the way the object will be used, we don't expect a race.
* After construction, the object is passed to another thread,
* but will no longer be accessed on the original thread.
* The other thread is unable to access/modify self's data members.
* When the other thread is finished, it will call into the "Notify"
* callback. Self's members will be accessed on the other thread,
* but this is fine, because there is no race with the original thread.
* Race-protection for XPCOM reference counting is sufficient.
*/
bool mSinkIsNull;
nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> mHeaderSink;
int32_t mMimeNestingLevel;
nsCString mFromAddr;
nsCString mFromName;
nsCString mSenderAddr;
nsCString mSenderName;
};
class SignedStatusRunnable : public mozilla::Runnable
{
public:
SignedStatusRunnable(const nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> &aSink, int32_t aNestingLevel,
int32_t aSignatureStatus, nsIX509Cert *aSignerCert);
NS_DECL_NSIRUNNABLE
protected:
nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> m_sink;
int32_t m_nestingLevel;
int32_t m_signatureStatus;
nsCOMPtr<nsIX509Cert> m_signerCert;
};
SignedStatusRunnable::SignedStatusRunnable(const nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> &aSink,
int32_t aNestingLevel,
int32_t aSignatureStatus,
nsIX509Cert *aSignerCert) :
m_sink(aSink), m_nestingLevel(aNestingLevel),
m_signatureStatus(aSignatureStatus), m_signerCert(aSignerCert)
{
}
NS_IMETHODIMP SignedStatusRunnable::Run()
{
return m_sink->SignedStatus(m_nestingLevel, m_signatureStatus, m_signerCert);
}
nsresult ProxySignedStatus(const nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> &aSink,
int32_t aNestingLevel,
int32_t aSignatureStatus,
nsIX509Cert *aSignerCert)
{
RefPtr<SignedStatusRunnable> signedStatus =
new SignedStatusRunnable(aSink, aNestingLevel, aSignatureStatus, aSignerCert);
return NS_DispatchToMainThread(signedStatus, NS_DISPATCH_SYNC);
}
NS_IMPL_ISUPPORTS(nsSMimeVerificationListener, nsISMimeVerificationListener)
nsSMimeVerificationListener::nsSMimeVerificationListener(const char *aFromAddr, const char *aFromName,
const char *aSenderAddr, const char *aSenderName,
nsIMsgSMIMEHeaderSink *aHeaderSink, int32_t aMimeNestingLevel)
{
mHeaderSink = new nsMainThreadPtrHolder<nsIMsgSMIMEHeaderSink>(aHeaderSink);
mSinkIsNull = !aHeaderSink;
mMimeNestingLevel = aMimeNestingLevel;
mFromAddr = aFromAddr;
mFromName = aFromName;
mSenderAddr = aSenderAddr;
mSenderName = aSenderName;
}
NS_IMETHODIMP nsSMimeVerificationListener::Notify(nsICMSMessage2 *aVerifiedMessage,
nsresult aVerificationResultCode)
{
// Only continue if we have a valid pointer to the UI
NS_ENSURE_FALSE(mSinkIsNull, NS_OK);
NS_ENSURE_TRUE(aVerifiedMessage, NS_ERROR_FAILURE);
nsCOMPtr<nsICMSMessage> msg = do_QueryInterface(aVerifiedMessage);
NS_ENSURE_TRUE(msg, NS_ERROR_FAILURE);
nsCOMPtr<nsIX509Cert> signerCert;
msg->GetSignerCert(getter_AddRefs(signerCert));
int32_t signature_status = nsICMSMessageErrors::GENERAL_ERROR;
if (NS_FAILED(aVerificationResultCode))
{
if (NS_ERROR_MODULE_SECURITY == NS_ERROR_GET_MODULE(aVerificationResultCode))
signature_status = NS_ERROR_GET_CODE(aVerificationResultCode);
else if (NS_ERROR_NOT_IMPLEMENTED == aVerificationResultCode)
signature_status = nsICMSMessageErrors::VERIFY_ERROR_PROCESSING;
}
else
{
bool signing_cert_without_email_address;
bool good_p = MimeCMSHeadersAndCertsMatch(msg, signerCert,
mFromAddr.get(), mFromName.get(),
mSenderAddr.get(), mSenderName.get(),
&signing_cert_without_email_address);
if (!good_p)
{
if (signing_cert_without_email_address)
signature_status = nsICMSMessageErrors::VERIFY_CERT_WITHOUT_ADDRESS;
else
signature_status = nsICMSMessageErrors::VERIFY_HEADER_MISMATCH;
}
else
signature_status = nsICMSMessageErrors::SUCCESS;
}
ProxySignedStatus(mHeaderSink, mMimeNestingLevel, signature_status, signerCert);
return NS_OK;
}
int MIMEGetRelativeCryptoNestLevel(MimeObject *obj)
{
/*
the part id of any mimeobj is mime_part_address(obj)
our currently displayed crypto part is obj
the part shown as the toplevel object in the current window is
obj->options->part_to_load
possibly stored in the toplevel object only ???
but hopefully all nested mimeobject point to the same displayooptions
we need to find out the nesting level of our currently displayed crypto object
wrt the shown part in the toplevel window
*/
// if we are showing the toplevel message, aTopMessageNestLevel == 0
int aTopMessageNestLevel = 0;
MimeObject *aTopShownObject = nullptr;
if (obj && obj->options->part_to_load) {
bool aAlreadyFoundTop = false;
for (MimeObject *walker = obj; walker; walker = walker->parent) {
if (aAlreadyFoundTop) {
if (!mime_typep(walker, (MimeObjectClass *) &mimeEncryptedClass)
&& !mime_typep(walker, (MimeObjectClass *) &mimeMultipartSignedClass)) {
++aTopMessageNestLevel;
}
}
if (!aAlreadyFoundTop && !strcmp(mime_part_address(walker), walker->options->part_to_load)) {
aAlreadyFoundTop = true;
aTopShownObject = walker;
}
if (!aAlreadyFoundTop && !walker->parent) {
// The mime part part_to_load is not a parent of the
// the crypto mime part passed in to this function as parameter obj.
// That means the crypto part belongs to another branch of the mime tree.
return -1;
}
}
}
bool CryptoObjectIsChildOfTopShownObject = false;
if (!aTopShownObject) {
// no sub part specified, top message is displayed, and
// our crypto object is definitively a child of it
CryptoObjectIsChildOfTopShownObject = true;
}
// if we are the child of the topmost message, aCryptoPartNestLevel == 1
int aCryptoPartNestLevel = 0;
if (obj) {
for (MimeObject *walker = obj; walker; walker = walker->parent) {
// Crypto mime objects are transparent wrt nesting.
if (!mime_typep(walker, (MimeObjectClass *) &mimeEncryptedClass)
&& !mime_typep(walker, (MimeObjectClass *) &mimeMultipartSignedClass)) {
++aCryptoPartNestLevel;
}
if (aTopShownObject && walker->parent == aTopShownObject) {
CryptoObjectIsChildOfTopShownObject = true;
}
}
}
if (!CryptoObjectIsChildOfTopShownObject) {
return -1;
}
return aCryptoPartNestLevel - aTopMessageNestLevel;
}
static void *MimeCMS_init(MimeObject *obj,
int (*output_fn) (const char *buf, int32_t buf_size, void *output_closure),
void *output_closure)
{
MimeCMSdata *data;
nsresult rv;
if (!(obj && obj->options && output_fn)) return 0;
data = new MimeCMSdata;
if (!data) return 0;
data->self = obj;
data->output_fn = output_fn;
data->output_closure = output_closure;
PR_SetError(0, 0);
data->decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
delete data;
return 0;
}
rv = data->decoder_context->Start(MimeCMS_content_callback, data);
if (NS_FAILED(rv))
{
delete data;
return 0;
}
// XXX Fix later XXX //
data->parent_holds_stamp_p =
(obj->parent &&
(mime_crypto_stamped_p(obj->parent) ||
mime_typep(obj->parent, (MimeObjectClass *) &mimeEncryptedClass)));
data->parent_is_encrypted_p =
(obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));
/* If the parent of this object is a crypto-blob, then it's the grandparent
who would have written out the headers and prepared for a stamp...
(This shit sucks.)
*/
if (data->parent_is_encrypted_p &&
!data->parent_holds_stamp_p &&
obj->parent && obj->parent->parent)
data->parent_holds_stamp_p =
mime_crypto_stamped_p (obj->parent->parent);
mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);
if (msd)
{
nsIChannel *channel = msd->channel; // note the lack of ref counting...
if (channel)
{
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIMsgWindow> msgWindow;
nsCOMPtr<nsIMsgHeaderSink> headerSink;
nsCOMPtr<nsIMsgMailNewsUrl> msgurl;
nsCOMPtr<nsISupports> securityInfo;
channel->GetURI(getter_AddRefs(uri));
if (uri)
{
nsAutoCString urlSpec;
rv = uri->GetSpec(urlSpec);
// We only want to update the UI if the current mime transaction
// is intended for display.
// If the current transaction is intended for background processing,
// we can learn that by looking at the additional header=filter
// string contained in the URI.
//
// If we find something, we do not set smimeHeaderSink,
// which will prevent us from giving UI feedback.
//
// If we do not find header=filter, we assume the result of the
// processing will be shown in the UI.
if (!strstr(urlSpec.get(), "?header=filter") &&
!strstr(urlSpec.get(), "&header=filter") &&
!strstr(urlSpec.get(), "?header=attach") &&
!strstr(urlSpec.get(), "&header=attach"))
{
msgurl = do_QueryInterface(uri);
if (msgurl)
msgurl->GetMsgWindow(getter_AddRefs(msgWindow));
if (msgWindow)
msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
if (securityInfo)
data->smimeHeaderSink = do_QueryInterface(securityInfo);
}
}
} // if channel
} // if msd
return data;
}
static int
MimeCMS_write (const char *buf, int32_t buf_size, void *closure)
{
MimeCMSdata *data = (MimeCMSdata *) closure;
nsresult rv;
if (!data || !data->output_fn || !data->decoder_context) return -1;
PR_SetError(0, 0);
rv = data->decoder_context->Update(buf, buf_size);
data->decoding_failed = NS_FAILED(rv);
return 0;
}
void MimeCMSGetFromSender(MimeObject *obj,
nsCString &from_addr,
nsCString &from_name,
nsCString &sender_addr,
nsCString &sender_name)
{
MimeHeaders *msg_headers = 0;
/* Find the headers of the MimeMessage which is the parent (or grandparent)
of this object (remember, crypto objects nest.) */
MimeObject *o2 = obj;
msg_headers = o2->headers;
while (o2 &&
o2->parent &&
!mime_typep(o2->parent, (MimeObjectClass *) &mimeMessageClass))
{
o2 = o2->parent;
msg_headers = o2->headers;
}
if (!msg_headers)
return;
/* Find the names and addresses in the From and/or Sender fields.
*/
nsCString s;
/* Extract the name and address of the "From:" field. */
s.Adopt(MimeHeaders_get(msg_headers, HEADER_FROM, false, false));
if (!s.IsEmpty())
ExtractFirstAddress(EncodedHeader(s), from_name, from_addr);
/* Extract the name and address of the "Sender:" field. */
s.Adopt(MimeHeaders_get(msg_headers, HEADER_SENDER, false, false));
if (!s.IsEmpty())
ExtractFirstAddress(EncodedHeader(s), sender_name, sender_addr);
}
void MimeCMSRequestAsyncSignatureVerification(nsICMSMessage *aCMSMsg,
const char *aFromAddr, const char *aFromName,
const char *aSenderAddr, const char *aSenderName,
nsIMsgSMIMEHeaderSink *aHeaderSink, int32_t aMimeNestingLevel,
unsigned char* item_data, uint32_t item_len)
{
nsCOMPtr<nsICMSMessage2> msg2 = do_QueryInterface(aCMSMsg);
if (!msg2)
return;
RefPtr<nsSMimeVerificationListener> listener =
new nsSMimeVerificationListener(aFromAddr, aFromName, aSenderAddr, aSenderName,
aHeaderSink, aMimeNestingLevel);
if (!listener)
return;
if (item_data)
msg2->AsyncVerifyDetachedSignature(listener, item_data, item_len);
else
msg2->AsyncVerifySignature(listener);
}
static int
MimeCMS_eof (void *crypto_closure, bool abort_p)
{
MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
nsresult rv;
int32_t status = nsICMSMessageErrors::SUCCESS;
if (!data || !data->output_fn || !data->decoder_context) {
return -1;
}
int aRelativeNestLevel = MIMEGetRelativeCryptoNestLevel(data->self);
/* Hand an EOF to the crypto library. It may call data->output_fn.
(Today, the crypto library has no flushing to do, but maybe there
will be someday.)
We save away the value returned and will use it later to emit a
blurb about whether the signature validation was cool.
*/
PR_SetError(0, 0);
rv = data->decoder_context->Finish(getter_AddRefs(data->content_info));
if (NS_FAILED(rv))
status = nsICMSMessageErrors::GENERAL_ERROR;
data->decoder_context = nullptr;
nsCOMPtr<nsIX509Cert> certOfInterest;
if (!data->smimeHeaderSink)
return 0;
if (aRelativeNestLevel < 0)
return 0;
int32_t maxNestLevel = 0;
data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel);
if (aRelativeNestLevel > maxNestLevel)
return 0;
if (data->decoding_failed)
status = nsICMSMessageErrors::GENERAL_ERROR;
if (!data->content_info)
{
if (!data->decoded_bytes)
{
// We were unable to decode any data.
status = nsICMSMessageErrors::GENERAL_ERROR;
}
else
{
// Some content got decoded, but we failed to decode
// the final summary, probably we got truncated data.
status = nsICMSMessageErrors::ENCRYPT_INCOMPLETE;
}
// Although a CMS message could be either encrypted or opaquely signed,
// what we see is most likely encrypted, because if it were
// signed only, we probably would have been able to decode it.
data->ci_is_encrypted = true;
}
else
{
rv = data->content_info->ContentIsEncrypted(&data->ci_is_encrypted);
if (NS_SUCCEEDED(rv) && data->ci_is_encrypted) {
data->content_info->GetEncryptionCert(getter_AddRefs(certOfInterest));
}
else {
// Existing logic in mimei assumes, if !ci_is_encrypted, then it is signed.
// Make sure it indeed is signed.
bool testIsSigned;
rv = data->content_info->ContentIsSigned(&testIsSigned);
if (NS_FAILED(rv) || !testIsSigned) {
// Neither signed nor encrypted?
// We are unable to understand what we got, do not try to indicate S/Mime status.
return 0;
}
nsCString from_addr;
nsCString from_name;
nsCString sender_addr;
nsCString sender_name;
MimeCMSGetFromSender(data->self,
from_addr, from_name,
sender_addr, sender_name);
MimeCMSRequestAsyncSignatureVerification(data->content_info,
from_addr.get(), from_name.get(),
sender_addr.get(), sender_name.get(),
data->smimeHeaderSink, aRelativeNestLevel,
nullptr, 0);
}
}
if (data->ci_is_encrypted)
{
data->smimeHeaderSink->EncryptionStatus(
aRelativeNestLevel,
status,
certOfInterest
);
}
return 0;
}
static void
MimeCMS_free (void *crypto_closure)
{
MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
if (!data) return;
delete data;
}
static char *
MimeCMS_generate (void *crypto_closure)
{
return nullptr;
}

View file

@ -0,0 +1,36 @@
/* -*- 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/. */
#ifndef _MIMECMS_H_
#define _MIMECMS_H_
#include "mimecryp.h"
class nsICMSMessage;
/* The MimeEncryptedCMS class implements a type of MIME object where the
object is passed through a CMS decryption engine to decrypt or verify
signatures. That module returns a new MIME object, which is then presented
to the user. See mimecryp.h for details of the general mechanism on which
this is built.
*/
typedef struct MimeEncryptedCMSClass MimeEncryptedCMSClass;
typedef struct MimeEncryptedCMS MimeEncryptedCMS;
struct MimeEncryptedCMSClass {
MimeEncryptedClass encrypted;
};
extern MimeEncryptedCMSClass mimeEncryptedCMSClass;
struct MimeEncryptedCMS {
MimeEncrypted encrypted; /* superclass variables */
};
#define MimeEncryptedCMSClassInitializer(ITYPE,CSUPER) \
{ MimeEncryptedClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEPKCS_H_ */

View file

@ -0,0 +1,74 @@
/* -*- 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/. */
#include "mimei.h"
#include "mimeobj.h" /* MimeObject (abstract) */
#include "mimecont.h" /* |--- MimeContainer (abstract) */
#include "mimemult.h" /* | |--- MimeMultipart (abstract) */
#include "mimemsig.h" /* | | |--- MimeMultipartSigned (abstract)*/
#include "mimetext.h" /* | |--- MimeInlineText (abstract) */
#include "mimecryp.h"
#include "mimecth.h"
/*
* These calls are necessary to expose the object class hierarchy
* to externally developed content type handlers.
*/
extern "C" void *
XPCOM_GetmimeInlineTextClass(void)
{
return (void *) &mimeInlineTextClass;
}
extern "C" void *
XPCOM_GetmimeLeafClass(void)
{
return (void *) &mimeLeafClass;
}
extern "C" void *
XPCOM_GetmimeObjectClass(void)
{
return (void *) &mimeObjectClass;
}
extern "C" void *
XPCOM_GetmimeContainerClass(void)
{
return (void *) &mimeContainerClass;
}
extern "C" void *
XPCOM_GetmimeMultipartClass(void)
{
return (void *) &mimeMultipartClass;
}
extern "C" void *
XPCOM_GetmimeMultipartSignedClass(void)
{
return (void *) &mimeMultipartSignedClass;
}
extern "C" void *
XPCOM_GetmimeEncryptedClass(void)
{
return (void *) &mimeEncryptedClass;
}
extern "C" int
XPCOM_MimeObject_write(void *mimeObject,
char *data,
int32_t length,
bool user_visible_p)
{
return MIME_MimeObject_write((MimeObject *)mimeObject, data,
length, user_visible_p);
}
extern "C" void *
XPCOM_Mime_create(char *content_type, void* hdrs, void* opts)
{
return mime_create(content_type, (MimeHeaders *)hdrs, (MimeDisplayOptions *)opts);
}

View file

@ -0,0 +1,38 @@
/* -*- 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/. */
/*
* XP-COM Bridges for C function calls
*/
#ifndef _MIMECOM_H_
#define _MIMECOM_H_
#include <stdint.h>
/*
* 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 XPCOM_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 *XPCOM_GetmimeInlineTextClass(void);
extern "C" void *XPCOM_GetmimeLeafClass(void);
extern "C" void *XPCOM_GetmimeObjectClass(void);
extern "C" void *XPCOM_GetmimeContainerClass(void);
extern "C" void *XPCOM_GetmimeMultipartClass(void);
extern "C" void *XPCOM_GetmimeMultipartSignedClass(void);
extern "C" void *XPCOM_GetmimeEncryptedClass(void);
extern "C" void *XPCOM_Mime_create(char *content_type, void* hdrs, void* opts);
#endif /* _MIMECOM_H_ */

View file

@ -0,0 +1,218 @@
/* -*- 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/. */
#include "prmem.h"
#include "plstr.h"
#include "prlog.h"
#include "prio.h"
#include "mimecont.h"
#include "nsMimeStringResources.h"
#define MIME_SUPERCLASS mimeObjectClass
MimeDefClass(MimeContainer, MimeContainerClass,
mimeContainerClass, &MIME_SUPERCLASS);
static int MimeContainer_initialize (MimeObject *);
static void MimeContainer_finalize (MimeObject *);
static int MimeContainer_add_child (MimeObject *, MimeObject *);
static int MimeContainer_parse_eof (MimeObject *, bool);
static int MimeContainer_parse_end (MimeObject *, bool);
static bool MimeContainer_displayable_inline_p (MimeObjectClass *clazz,
MimeHeaders *hdrs);
#if defined(DEBUG) && defined(XP_UNIX)
static int MimeContainer_debug_print (MimeObject *, PRFileDesc *, int32_t depth);
#endif
static int
MimeContainerClassInitialize(MimeContainerClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) &clazz->object;
NS_ASSERTION(!oclass->class_initialized, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
oclass->initialize = MimeContainer_initialize;
oclass->finalize = MimeContainer_finalize;
oclass->parse_eof = MimeContainer_parse_eof;
oclass->parse_end = MimeContainer_parse_end;
oclass->displayable_inline_p = MimeContainer_displayable_inline_p;
clazz->add_child = MimeContainer_add_child;
#if defined(DEBUG) && defined(XP_UNIX)
oclass->debug_print = MimeContainer_debug_print;
#endif
return 0;
}
static int
MimeContainer_initialize (MimeObject *object)
{
/* This is an abstract class; it shouldn't be directly instantiated. */
NS_ASSERTION(object->clazz != (MimeObjectClass *) &mimeContainerClass, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
}
static void
MimeContainer_finalize (MimeObject *object)
{
MimeContainer *cont = (MimeContainer *) object;
/* Do this first so that children have their parse_eof methods called
in forward order (0-N) but are destroyed in backward order (N-0)
*/
if (!object->closed_p)
object->clazz->parse_eof (object, false);
if (!object->parsed_p)
object->clazz->parse_end (object, false);
if (cont->children)
{
int i;
for (i = cont->nchildren-1; i >= 0; i--)
{
MimeObject *kid = cont->children[i];
if (kid)
mime_free(kid);
cont->children[i] = 0;
}
PR_FREEIF(cont->children);
cont->nchildren = 0;
}
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
}
static int
MimeContainer_parse_eof (MimeObject *object, bool abort_p)
{
MimeContainer *cont = (MimeContainer *) object;
int status;
/* We must run all of this object's parent methods first, to get all the
data flushed down its stream, so that the children's parse_eof methods
can access it. We do not access *this* object again after doing this,
only its children.
*/
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(object, abort_p);
if (status < 0) return status;
if (cont->children)
{
int i;
for (i = 0; i < cont->nchildren; i++)
{
MimeObject *kid = cont->children[i];
if (kid && !kid->closed_p)
{
int lstatus = kid->clazz->parse_eof(kid, abort_p);
if (lstatus < 0) return lstatus;
}
}
}
return 0;
}
static int
MimeContainer_parse_end (MimeObject *object, bool abort_p)
{
MimeContainer *cont = (MimeContainer *) object;
int status;
/* We must run all of this object's parent methods first, to get all the
data flushed down its stream, so that the children's parse_eof methods
can access it. We do not access *this* object again after doing this,
only its children.
*/
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_end(object, abort_p);
if (status < 0) return status;
if (cont->children)
{
int i;
for (i = 0; i < cont->nchildren; i++)
{
MimeObject *kid = cont->children[i];
if (kid && !kid->parsed_p)
{
int lstatus = kid->clazz->parse_end(kid, abort_p);
if (lstatus < 0) return lstatus;
}
}
}
return 0;
}
static int
MimeContainer_add_child (MimeObject *parent, MimeObject *child)
{
MimeContainer *cont = (MimeContainer *) parent;
MimeObject **old_kids, **new_kids;
NS_ASSERTION(parent && child, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (!parent || !child) return -1;
old_kids = cont->children;
new_kids = (MimeObject **)PR_MALLOC(sizeof(MimeObject *) * (cont->nchildren + 1));
if (!new_kids) return MIME_OUT_OF_MEMORY;
if (cont->nchildren > 0)
memcpy(new_kids, old_kids, sizeof(MimeObject *) * cont->nchildren);
new_kids[cont->nchildren] = child;
PR_Free(old_kids);
cont->children = new_kids;
cont->nchildren++;
child->parent = parent;
/* Copy this object's options into the child. */
child->options = parent->options;
return 0;
}
static bool
MimeContainer_displayable_inline_p (MimeObjectClass *clazz, MimeHeaders *hdrs)
{
return true;
}
#if defined(DEBUG) && defined(XP_UNIX)
static int
MimeContainer_debug_print (MimeObject *obj, PRFileDesc *stream, int32_t depth)
{
MimeContainer *cont = (MimeContainer *) obj;
int i;
char *addr = mime_part_address(obj);
for (i=0; i < depth; i++)
PR_Write(stream, " ", 2);
/*
PR_Write(stream, "<%s %s (%d kid%s) 0x%08X>\n",
obj->clazz->class_name,
addr ? addr : "???",
cont->nchildren, (cont->nchildren == 1 ? "" : "s"),
(uint32_t) cont);
*/
PR_FREEIF(addr);
/*
if (cont->nchildren > 0)
fprintf(stream, "\n");
*/
for (i = 0; i < cont->nchildren; i++)
{
MimeObject *kid = cont->children[i];
int status = kid->clazz->debug_print (kid, stream, depth+1);
if (status < 0) return status;
}
/*
if (cont->nchildren > 0)
fprintf(stream, "\n");
*/
return 0;
}
#endif

View file

@ -0,0 +1,43 @@
/* -*- 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/. */
#ifndef _MIMECONT_H_
#define _MIMECONT_H_
#include "mimeobj.h"
/* MimeContainer is the class for the objects representing all MIME
types which can contain other MIME objects within them. In addition
to the methods inherited from MimeObject, it provides one method:
int add_child (MimeObject *parent, MimeObject *child)
Given a parent (a subclass of MimeContainer) this method adds the
child (any MIME object) to the parent's list of children.
The MimeContainer `finalize' method will finalize the children as well.
*/
typedef struct MimeContainerClass MimeContainerClass;
typedef struct MimeContainer MimeContainer;
struct MimeContainerClass {
MimeObjectClass object;
int (*add_child) (MimeObject *parent, MimeObject *child);
};
extern MimeContainerClass mimeContainerClass;
struct MimeContainer {
MimeObject object; /* superclass variables */
MimeObject **children; /* list of contained objects */
int32_t nchildren; /* how many */
};
#define MimeContainerClassInitializer(ITYPE,CSUPER) \
{ MimeObjectClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMECONT_H_ */

View file

@ -0,0 +1,571 @@
/* -*- 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 "mimecryp.h"
#include "mimemoz2.h"
#include "nsMimeTypes.h"
#include "nsMimeStringResources.h"
#include "mimebuf.h"
#include "prmem.h"
#include "plstr.h"
#include "prlog.h"
#include "mimemult.h"
#include "nsIMimeConverter.h" // for MimeConverterOutputCallback
#define MIME_SUPERCLASS mimeContainerClass
MimeDefClass(MimeEncrypted, MimeEncryptedClass, mimeEncryptedClass,
&MIME_SUPERCLASS);
static int MimeEncrypted_initialize (MimeObject *);
static void MimeEncrypted_finalize (MimeObject *);
static int MimeEncrypted_parse_begin (MimeObject *);
static int MimeEncrypted_parse_buffer (const char *, int32_t, MimeObject *);
static int MimeEncrypted_parse_line (const char *, int32_t, MimeObject *);
static int MimeEncrypted_parse_decoded_buffer (const char *, int32_t, MimeObject *);
static int MimeEncrypted_parse_eof (MimeObject *, bool);
static int MimeEncrypted_parse_end (MimeObject *, bool);
static int MimeEncrypted_add_child (MimeObject *, MimeObject *);
static int MimeHandleDecryptedOutput (const char *, int32_t, void *);
static int MimeHandleDecryptedOutputLine (char *, int32_t, MimeObject *);
static int MimeEncrypted_close_headers (MimeObject *);
static int MimeEncrypted_emit_buffered_child(MimeObject *);
static int
MimeEncryptedClassInitialize(MimeEncryptedClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
MimeContainerClass *cclass = (MimeContainerClass *) clazz;
NS_ASSERTION(!oclass->class_initialized, "1.2 <mscott@netscape.com> 01 Nov 2001 17:59");
oclass->initialize = MimeEncrypted_initialize;
oclass->finalize = MimeEncrypted_finalize;
oclass->parse_begin = MimeEncrypted_parse_begin;
oclass->parse_buffer = MimeEncrypted_parse_buffer;
oclass->parse_line = MimeEncrypted_parse_line;
oclass->parse_eof = MimeEncrypted_parse_eof;
oclass->parse_end = MimeEncrypted_parse_end;
cclass->add_child = MimeEncrypted_add_child;
clazz->parse_decoded_buffer = MimeEncrypted_parse_decoded_buffer;
return 0;
}
static int
MimeEncrypted_initialize (MimeObject *obj)
{
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj);
}
static int
MimeEncrypted_parse_begin (MimeObject *obj)
{
MimeEncrypted *enc = (MimeEncrypted *) obj;
MimeDecoderData *(*fn) (MimeConverterOutputCallback, void*) = 0;
if (enc->crypto_closure)
return -1;
enc->crypto_closure = (((MimeEncryptedClass *) obj->clazz)->crypto_init) (obj, MimeHandleDecryptedOutput, obj);
if (!enc->crypto_closure)
return -1;
/* (Mostly duplicated from MimeLeaf, see comments in mimecryp.h.)
Initialize a decoder if necessary.
*/
if (!obj->encoding)
;
else if (!PL_strcasecmp(obj->encoding, ENCODING_BASE64))
fn = &MimeB64DecoderInit;
else if (!PL_strcasecmp(obj->encoding, ENCODING_QUOTED_PRINTABLE))
{
enc->decoder_data =
MimeQPDecoderInit (/* The (MimeConverterOutputCallback) cast is to turn the
`void' argument into `MimeObject'. */
((MimeConverterOutputCallback)
((MimeEncryptedClass *)obj->clazz)->parse_decoded_buffer),
obj);
if (!enc->decoder_data)
return MIME_OUT_OF_MEMORY;
}
else if (!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE) ||
!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE2) ||
!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE4))
fn = &MimeUUDecoderInit;
else if (!PL_strcasecmp(obj->encoding, ENCODING_YENCODE))
fn = &MimeYDecoderInit;
if (fn)
{
enc->decoder_data =
fn (/* The (MimeConverterOutputCallback) cast is to turn the `void'
argument into `MimeObject'. */
((MimeConverterOutputCallback)
((MimeEncryptedClass *)obj->clazz)->parse_decoded_buffer),
obj);
if (!enc->decoder_data)
return MIME_OUT_OF_MEMORY;
}
return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
}
static int
MimeEncrypted_parse_buffer (const char *buffer, int32_t size, MimeObject *obj)
{
/* (Duplicated from MimeLeaf, see comments in mimecryp.h.)
*/
MimeEncrypted *enc = (MimeEncrypted *) obj;
if (obj->closed_p) return -1;
/* Don't consult output_p here, since at this point we're behaving as a
simple container object -- the output_p decision should be made by
the child of this object. */
if (enc->decoder_data)
return MimeDecoderWrite (enc->decoder_data, buffer, size, nullptr);
else
return ((MimeEncryptedClass *)obj->clazz)->parse_decoded_buffer (buffer,
size,
obj);
}
static int
MimeEncrypted_parse_line (const char *line, int32_t length, MimeObject *obj)
{
NS_ERROR("This method shouldn't ever be called.");
return -1;
}
static int
MimeEncrypted_parse_decoded_buffer (const char *buffer, int32_t size, MimeObject *obj)
{
MimeEncrypted *enc = (MimeEncrypted *) obj;
return
((MimeEncryptedClass *) obj->clazz)->crypto_write (buffer, size,
enc->crypto_closure);
}
static int
MimeEncrypted_parse_eof (MimeObject *obj, bool abort_p)
{
int status = 0;
MimeEncrypted *enc = (MimeEncrypted *) obj;
if (obj->closed_p) return 0;
NS_ASSERTION(!obj->parsed_p, "1.2 <mscott@netscape.com> 01 Nov 2001 17:59");
/* (Duplicated from MimeLeaf, see comments in mimecryp.h.)
Close off the decoder, to cause it to give up any buffered data that
it is still holding.
*/
if (enc->decoder_data)
{
int status = MimeDecoderDestroy(enc->decoder_data, false);
enc->decoder_data = 0;
if (status < 0) return status;
}
/* If there is still data in the ibuffer, that means that the last
*decrypted* line of this part didn't end in a newline; so push it out
anyway (this means that the parse_line method will be called with a
string with no trailing newline, which isn't the usual case.) */
if (!abort_p &&
obj->ibuffer_fp > 0)
{
int status = MimeHandleDecryptedOutputLine (obj->ibuffer,
obj->ibuffer_fp, obj);
obj->ibuffer_fp = 0;
if (status < 0)
{
obj->closed_p = true;
return status;
}
}
/* Now run the superclass's parse_eof, which (because we've already taken
care of ibuffer in a way appropriate for this class, immediately above)
will ony set closed_p to true.
*/
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof (obj, abort_p);
if (status < 0) return status;
/* Now close off the underlying crypto module. At this point, the crypto
module has all of the input. (DecoderDestroy called parse_decoded_buffer
which called crypto_write, with the last of the data.)
*/
if (enc->crypto_closure)
{
status =
((MimeEncryptedClass *) obj->clazz)->crypto_eof (enc->crypto_closure,
abort_p);
if (status < 0 && !abort_p)
return status;
}
/* Now we have the entire child part in the part buffer.
We are now able to verify its signature, emit a blurb, and then
emit the part.
*/
if (abort_p)
return 0;
else
return MimeEncrypted_emit_buffered_child (obj);
}
static int
MimeEncrypted_parse_end (MimeObject *obj, bool abort_p)
{
return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_end (obj, abort_p);
}
static void
MimeEncrypted_cleanup (MimeObject *obj, bool finalizing_p)
{
MimeEncrypted *enc = (MimeEncrypted *) obj;
if (enc->part_buffer)
{
MimePartBufferDestroy(enc->part_buffer);
enc->part_buffer = 0;
}
if (finalizing_p && enc->crypto_closure)
{
/* Don't free these until this object is really going away -- keep them
around for the lifetime of the MIME object, so that we can get at the
security info of sub-parts of the currently-displayed message. */
((MimeEncryptedClass *) obj->clazz)->crypto_free (enc->crypto_closure);
enc->crypto_closure = 0;
}
/* (Duplicated from MimeLeaf, see comments in mimecryp.h.)
Free the decoder data, if it's still around. */
if (enc->decoder_data)
{
MimeDecoderDestroy(enc->decoder_data, true);
enc->decoder_data = 0;
}
if (enc->hdrs)
{
MimeHeaders_free(enc->hdrs);
enc->hdrs = 0;
}
}
static void
MimeEncrypted_finalize (MimeObject *obj)
{
MimeEncrypted_cleanup (obj, true);
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize (obj);
}
static int
MimeHandleDecryptedOutput (const char *buf, int32_t buf_size,
void *output_closure)
{
/* This method is invoked by the underlying decryption module.
The module is assumed to return a MIME object, and its associated
headers. For example, if a text/plain document was encrypted,
the encryption module would return the following data:
Content-Type: text/plain
Decrypted text goes here.
This function will then extract a header block (up to the first
blank line, as usual) and will then handle the included data as
appropriate.
*/
MimeObject *obj = (MimeObject *) output_closure;
/* Is it truly safe to use ibuffer here? I think so... */
return mime_LineBuffer (buf, buf_size,
&obj->ibuffer, &obj->ibuffer_size, &obj->ibuffer_fp,
true,
((int (*) (char *, int32_t, void *))
/* This cast is to turn void into MimeObject */
MimeHandleDecryptedOutputLine),
obj);
}
static int
MimeHandleDecryptedOutputLine (char *line, int32_t length, MimeObject *obj)
{
/* Largely the same as MimeMessage_parse_line (the other MIME container
type which contains exactly one child.)
*/
MimeEncrypted *enc = (MimeEncrypted *) obj;
int status = 0;
if (!line || !*line) return -1;
/* If we're supposed to write this object, but aren't supposed to convert
it to HTML, simply pass it through unaltered. */
if (obj->output_p &&
obj->options &&
!obj->options->write_html_p &&
obj->options->output_fn)
return MimeObject_write(obj, line, length, true);
/* If we already have a child object in the buffer, then we're done parsing
headers, and all subsequent lines get passed to the inferior object
without further processing by us. (Our parent will stop feeding us
lines when this MimeMessage part is out of data.)
*/
if (enc->part_buffer)
return MimePartBufferWrite (enc->part_buffer, line, length);
/* Otherwise we don't yet have a child object in the buffer, which means
we're not done parsing our headers yet.
*/
if (!enc->hdrs)
{
enc->hdrs = MimeHeaders_new();
if (!enc->hdrs) return MIME_OUT_OF_MEMORY;
}
status = MimeHeaders_parse_line(line, length, enc->hdrs);
if (status < 0) return status;
/* If this line is blank, we're now done parsing headers, and should
examine our content-type to create our "body" part.
*/
if (*line == '\r' || *line == '\n')
{
status = MimeEncrypted_close_headers(obj);
if (status < 0) return status;
}
return 0;
}
static int
MimeEncrypted_close_headers (MimeObject *obj)
{
MimeEncrypted *enc = (MimeEncrypted *) obj;
// Notify the JS Mime Emitter that this was an encrypted part that it should
// hopefully not analyze for indexing...
if (obj->options->notify_nested_bodies)
mimeEmitterAddHeaderField(obj->options, "x-jsemitter-encrypted", "1");
if (enc->part_buffer) return -1;
enc->part_buffer = MimePartBufferCreate();
if (!enc->part_buffer)
return MIME_OUT_OF_MEMORY;
return 0;
}
static int
MimeEncrypted_add_child (MimeObject *parent, MimeObject *child)
{
MimeContainer *cont = (MimeContainer *) parent;
if (!parent || !child) return -1;
/* Encryption containers can only have one child. */
if (cont->nchildren != 0) return -1;
return ((MimeContainerClass*)&MIME_SUPERCLASS)->add_child (parent, child);
}
static int
MimeEncrypted_emit_buffered_child(MimeObject *obj)
{
MimeEncrypted *enc = (MimeEncrypted *) obj;
int status = 0;
char *ct = 0;
MimeObject *body;
NS_ASSERTION(enc->crypto_closure, "1.2 <mscott@netscape.com> 01 Nov 2001 17:59");
/* Emit some HTML saying whether the signature was cool.
But don't emit anything if in FO_QUOTE_MESSAGE mode.
Also, don't emit anything if the enclosed object is itself a signed
object -- in the case of an encrypted object which contains a signed
object, we only emit the HTML once (since the normal way of encrypting
and signing is to nest the signature inside the crypto envelope.)
*/
if (enc->crypto_closure &&
obj->options &&
obj->options->headers != MimeHeadersCitation &&
obj->options->write_html_p &&
obj->options->output_fn)
// && !mime_crypto_object_p(enc->hdrs, true, obj->options)) // XXX fix later XXX //
{
char *html;
#if 0 // XXX Fix this later XXX //
char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
(enc->crypto_closure));
if (!html) return -1; /* MK_OUT_OF_MEMORY? */
status = MimeObject_write(obj, html, strlen(html), false);
PR_FREEIF(html);
if (status < 0) return status;
#endif
/* Now that we have written out the crypto stamp, the outermost header
block is well and truly closed. If this is in fact the outermost
message, then run the post_header_html_fn now.
*/
if (obj->options &&
obj->options->state &&
obj->options->generate_post_header_html_fn &&
!obj->options->state->post_header_html_run_p)
{
MimeHeaders *outer_headers = nullptr;
MimeObject *p;
for (p = obj; p->parent; p = p->parent)
outer_headers = p->headers;
NS_ASSERTION(obj->options->state->first_data_written_p, "1.2 <mscott@netscape.com> 01 Nov 2001 17:59");
html = obj->options->generate_post_header_html_fn(NULL,
obj->options->html_closure,
outer_headers);
obj->options->state->post_header_html_run_p = true;
if (html)
{
status = MimeObject_write(obj, html, strlen(html), false);
PR_FREEIF(html);
if (status < 0) return status;
}
}
}
else if (enc->crypto_closure &&
obj->options &&
obj->options->decrypt_p)
{
/* Do this just to cause `mime_set_crypto_stamp' to be called, and to
cause the various `decode_error' and `verify_error' slots to be set:
we don't actually use the returned HTML, because we're not emitting
HTML. It's maybe not such a good thing that the determination of
whether it was encrypted or not is tied up with generating HTML,
but oh well. */
char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
(enc->crypto_closure));
PR_FREEIF(html);
}
if (enc->hdrs)
ct = MimeHeaders_get (enc->hdrs, HEADER_CONTENT_TYPE, true, false);
body = mime_create((ct ? ct : TEXT_PLAIN), enc->hdrs, obj->options);
#ifdef MIME_DRAFTS
if (obj->options->decompose_file_p) {
if (mime_typep (body, (MimeObjectClass*) &mimeMultipartClass) )
obj->options->is_multipart_msg = true;
else if (obj->options->decompose_file_init_fn)
obj->options->decompose_file_init_fn(obj->options->stream_closure,
enc->hdrs);
}
#endif /* MIME_DRAFTS */
PR_FREEIF(ct);
if (!body) return MIME_OUT_OF_MEMORY;
status = ((MimeContainerClass *) obj->clazz)->add_child (obj, body);
if (status < 0)
{
mime_free(body);
return status;
}
/* Now that we've added this new object to our list of children,
start its parser going. */
status = body->clazz->parse_begin(body);
if (status < 0) return status;
/* If this object (or the parent) is being output, then by definition
the child is as well. (This is only necessary because this is such
a funny sort of container...)
*/
if (!body->output_p &&
(obj->output_p ||
(obj->parent && obj->parent->output_p)))
body->output_p = true;
/* If the body is being written raw (not as HTML) then make sure to
write its headers as well. */
if (body->output_p && obj->output_p && !obj->options->write_html_p)
{
status = MimeObject_write(body, "", 0, false); /* initialize */
if (status < 0) return status;
status = MimeHeaders_write_raw_headers(body->headers, obj->options,
false);
if (status < 0) return status;
}
if (enc->part_buffer) /* part_buffer is 0 for 0-length encrypted data. */
{
#ifdef MIME_DRAFTS
if (obj->options->decompose_file_p && !obj->options->is_multipart_msg)
{
status = MimePartBufferRead(enc->part_buffer,
/* The (MimeConverterOutputCallback) cast is to turn the `void'
argument into `MimeObject'. */
((MimeConverterOutputCallback)
obj->options->decompose_file_output_fn),
obj->options->stream_closure);
}
else
{
#endif /* MIME_DRAFTS */
status = MimePartBufferRead(enc->part_buffer,
/* The (MimeConverterOutputCallback) cast is to turn the `void'
argument into `MimeObject'. */
((MimeConverterOutputCallback) body->clazz->parse_buffer),
body);
#ifdef MIME_DRAFTS
}
#endif /* MIME_DRAFTS */
}
if (status < 0) return status;
/* The child has been fully processed. Close it off.
*/
status = body->clazz->parse_eof(body, false);
if (status < 0) return status;
status = body->clazz->parse_end(body, false);
if (status < 0) return status;
#ifdef MIME_DRAFTS
if (obj->options->decompose_file_p && !obj->options->is_multipart_msg)
obj->options->decompose_file_close_fn(obj->options->stream_closure);
#endif /* MIME_DRAFTS */
/* Put out a separator after every encrypted object. */
status = MimeObject_write_separator(obj);
if (status < 0) return status;
MimeEncrypted_cleanup (obj, false);
return 0;
}

View file

@ -0,0 +1,140 @@
/* -*- 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/. */
#ifndef _MIMECRYP_H_
#define _MIMECRYP_H_
#include "mimecont.h"
// #include "mimeenc.h"
#include "modmimee.h"
#include "mimepbuf.h"
/* The MimeEncrypted class implements a type of MIME object where the object
is passed to some other routine, which then returns a new MIME object.
This is the basis of a decryption module.
Oddly, this class behaves both as a container and as a leaf: it acts as a
container in that it parses out data in order to eventually present a
contained object; however, it acts as a leaf in that this container may
itself have a Content-Transfer-Encoding applied to its body. This violates
the cardinal rule of MIME containers, which is that encodings don't nest,
and therefore containers can't have encodings. But, the fact that the
S/MIME spec doesn't follow the groundwork laid down by previous MIME specs
isn't something we can do anything about at this point...
Therefore, this class duplicates some of the work done by the MimeLeaf
class, to meet its dual goals of container-hood and leaf-hood. (We could
alternately have made this class be a subclass of leaf, and had it duplicate
the effort of MimeContainer, but that seemed like the harder approach.)
The MimeEncrypted class provides the following methods:
void *crypto_init(MimeObject *obj,
int (*output_fn) (const char *data, int32 data_size,
void *output_closure),
void *output_closure)
This is called with the MimeObject representing the encrypted data.
The obj->headers should be used to initialize the decryption engine.
NULL indicates failure; otherwise, an opaque closure object should
be returned.
output_fn is what the decryption module should use to write a new MIME
object (the decrypted data.) output_closure should be passed along to
every call to the output routine.
The data sent to output_fn should begin with valid MIME headers indicating
the type of the data. For example, if decryption resulted in a text
document, the data fed through to the output_fn might minimally look like
Content-Type: text/plain
This is the decrypted data.
It is only two lines long.
Of course, the data may be of any MIME type, including multipart/mixed.
Any returned MIME object will be recursively processed and presented
appropriately. (This also imples that encrypted objects may nest, and
thus that the underlying decryption module must be reentrant.)
int crypto_write (const char *data, int32 data_size, void *crypto_closure)
This is called with the raw encrypted data. This data might not come
in line-based chunks: if there was a Content-Transfer-Encoding applied
to the data (base64 or quoted-printable) then it will have been decoded
first (handing binary data to the filter_fn.) `crypto_closure' is the
object that `crypto_init' returned. This may return negative on error.
int crypto_eof (void *crypto_closure, bool abort_p)
This is called when no more data remains. It may call `output_fn' again
to flush out any buffered data. If `abort_p' is true, then it may choose
to discard any data rather than processing it, as we're terminating
abnormally.
char * crypto_generate_html (void *crypto_closure)
This is called after `crypto_eof' but before `crypto_free'. The crypto
module should return a newly-allocated string of HTML code which
explains the status of the decryption to the user (whether the signature
checked out, etc.)
void crypto_free (void *crypto_closure)
This will be called when we're all done, after `crypto_eof' and
`crypto_emit_html'. It is intended to free any data represented
by the crypto_closure. output_fn may not be called.
int (*parse_decoded_buffer) (const char *buf, int32 size, MimeObject *obj)
This method, of the same name as one in MimeLeaf, is a part of the
afforementioned leaf/container hybridization. This method is invoked
with the content-transfer-decoded body of this part (without line
buffering.) The default behavior of this method is to simply invoke
`crypto_write' on the data with which it is called. It's unlikely that
a subclass will need to specialize this.
*/
typedef struct MimeEncryptedClass MimeEncryptedClass;
typedef struct MimeEncrypted MimeEncrypted;
struct MimeEncryptedClass {
MimeContainerClass container;
/* Duplicated from MimeLeaf, see comments above.
This is the callback that is handed to the decoder. */
int (*parse_decoded_buffer) (const char *buf, int32_t size, MimeObject *obj);
/* Callbacks used by decryption module. */
void * (*crypto_init) (MimeObject *obj,
int (*output_fn) (const char *data, int32_t data_size,
void *output_closure),
void *output_closure);
int (*crypto_write) (const char *data, int32_t data_size,
void *crypto_closure);
int (*crypto_eof) (void *crypto_closure, bool abort_p);
char * (*crypto_generate_html) (void *crypto_closure);
void (*crypto_free) (void *crypto_closure);
};
extern MimeEncryptedClass mimeEncryptedClass;
struct MimeEncrypted {
MimeContainer container; /* superclass variables */
void *crypto_closure; /* Opaque data used by decryption module. */
MimeDecoderData *decoder_data; /* Opaque data for the Transfer-Encoding
decoder. */
MimeHeaders *hdrs; /* Headers of the enclosed object (including
the type of the *decrypted* data.) */
MimePartBufferData *part_buffer; /* The data of the decrypted enclosed
object (see mimepbuf.h) */
};
#define MimeEncryptedClassInitializer(ITYPE,CSUPER) \
{ MimeContainerClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMECRYP_H_ */

View file

@ -0,0 +1,51 @@
/* -*- 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/. */
#include "mimecth.h"
/*
* These calls are necessary to expose the object class hierarchy
* to externally developed content type handlers.
*/
MimeInlineTextClass *
MIME_GetmimeInlineTextClass(void)
{
return &mimeInlineTextClass;
}
MimeLeafClass *
MIME_GetmimeLeafClass(void)
{
return &mimeLeafClass;
}
MimeObjectClass *
MIME_GetmimeObjectClass(void)
{
return &mimeObjectClass;
}
MimeContainerClass *
MIME_GetmimeContainerClass(void)
{
return &mimeContainerClass;
}
MimeMultipartClass *
MIME_GetmimeMultipartClass(void)
{
return &mimeMultipartClass;
}
MimeMultipartSignedClass *
MIME_GetmimeMultipartSignedClass(void)
{
return &mimeMultipartSignedClass;
}
MimeEncryptedClass *
MIME_GetmimeEncryptedClass(void)
{
return &mimeEncryptedClass;
}

135
mailnews/mime/src/mimecth.h Normal file
View file

@ -0,0 +1,135 @@
/* -*- 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 for
* libmime. This will allow developers the dynamically add the ability
* for libmime to render new content types in the MHTML rendering of
* HTML messages.
*/
#ifndef _MIMECTH_H_
#define _MIMECTH_H_
#include "mimei.h"
#include "mimeobj.h" /* MimeObject (abstract) */
#include "mimecont.h" /* |--- MimeContainer (abstract) */
#include "mimemult.h" /* | |--- MimeMultipart (abstract) */
#include "mimemsig.h" /* | | |--- MimeMultipartSigned (abstract)*/
#include "mimetext.h" /* | |--- MimeInlineText (abstract) */
#include "mimecryp.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
*/
#include "nsIMimeContentTypeHandler.h"
/*
* 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 int MIME_MimeObject_write(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 MimeInlineTextClass *MIME_GetmimeInlineTextClass(void);
extern MimeLeafClass *MIME_GetmimeLeafClass(void);
extern MimeObjectClass *MIME_GetmimeObjectClass(void);
extern MimeContainerClass *MIME_GetmimeContainerClass(void);
extern MimeMultipartClass *MIME_GetmimeMultipartClass(void);
extern MimeMultipartSignedClass *MIME_GetmimeMultipartSignedClass(void);
extern MimeEncryptedClass *MIME_GetmimeEncryptedClass(void);
/*
* These are the functions that need to be implemented by the
* content type handler plugin. They will be called by by libmime
* when the module is loaded at runtime.
*/
/*
* MIME_GetContentType() is called by libmime to identify the content
* type handled by this plugin.
*/
extern "C"
char *MIME_GetContentType(void);
/*
* This will create the MimeObjectClass object to be used by the libmime
* object system.
*/
extern "C"
MimeObjectClass *MIME_CreateContentTypeHandlerClass(const char *content_type,
contentTypeHandlerInitStruct *initStruct);
/*
* Typedefs for libmime to use when locating and calling the above
* defined functions.
*/
typedef char * (*mime_get_ct_fn_type)(void);
typedef MimeObjectClass * (*mime_create_class_fn_type)
(const char *, contentTypeHandlerInitStruct *);
#endif /* _MIMECTH_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,509 @@
/* -*- 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/. */
#include "nsCOMPtr.h"
#include "nsIURL.h"
#include "mimeebod.h"
#include "prmem.h"
#include "plstr.h"
#include "prlog.h"
#include "prio.h"
#include "msgCore.h"
#include "nsMimeStringResources.h"
#include "mimemoz2.h"
#include "nsComponentManagerUtils.h"
#include "nsMsgUtils.h"
#include "nsINetUtil.h"
#include <ctype.h>
#define MIME_SUPERCLASS mimeObjectClass
MimeDefClass(MimeExternalBody, MimeExternalBodyClass,
mimeExternalBodyClass, &MIME_SUPERCLASS);
#ifdef XP_MACOSX
extern MimeObjectClass mimeMultipartAppleDoubleClass;
#endif
static int MimeExternalBody_initialize (MimeObject *);
static void MimeExternalBody_finalize (MimeObject *);
static int MimeExternalBody_parse_line (const char *, int32_t, MimeObject *);
static int MimeExternalBody_parse_eof (MimeObject *, bool);
static bool MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz,
MimeHeaders *hdrs);
#if 0
#if defined(DEBUG) && defined(XP_UNIX)
static int MimeExternalBody_debug_print (MimeObject *, PRFileDesc *, int32_t);
#endif
#endif /* 0 */
static int
MimeExternalBodyClassInitialize(MimeExternalBodyClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
NS_ASSERTION(!oclass->class_initialized, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
oclass->initialize = MimeExternalBody_initialize;
oclass->finalize = MimeExternalBody_finalize;
oclass->parse_line = MimeExternalBody_parse_line;
oclass->parse_eof = MimeExternalBody_parse_eof;
oclass->displayable_inline_p = MimeExternalBody_displayable_inline_p;
#if 0
#if defined(DEBUG) && defined(XP_UNIX)
oclass->debug_print = MimeExternalBody_debug_print;
#endif
#endif /* 0 */
return 0;
}
static int
MimeExternalBody_initialize (MimeObject *object)
{
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
}
static void
MimeExternalBody_finalize (MimeObject *object)
{
MimeExternalBody *bod = (MimeExternalBody *) object;
if (bod->hdrs)
{
MimeHeaders_free(bod->hdrs);
bod->hdrs = 0;
}
PR_FREEIF(bod->body);
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
}
static int
MimeExternalBody_parse_line (const char *line, int32_t length, MimeObject *obj)
{
MimeExternalBody *bod = (MimeExternalBody *) obj;
int status = 0;
NS_ASSERTION(line && *line, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (!line || !*line) return -1;
if (!obj->output_p) return 0;
/* If we're supposed to write this object, but aren't supposed to convert
it to HTML, simply pass it through unaltered. */
if (obj->options &&
!obj->options->write_html_p &&
obj->options->output_fn)
return MimeObject_write(obj, line, length, true);
/* If we already have a `body' then we're done parsing headers, and all
subsequent lines get tacked onto the body. */
if (bod->body)
{
int L = strlen(bod->body);
char *new_str = (char *)PR_Realloc(bod->body, L + length + 1);
if (!new_str) return MIME_OUT_OF_MEMORY;
bod->body = new_str;
memcpy(bod->body + L, line, length);
bod->body[L + length] = 0;
return 0;
}
/* Otherwise we don't yet have a body, which means we're not done parsing
our headers.
*/
if (!bod->hdrs)
{
bod->hdrs = MimeHeaders_new();
if (!bod->hdrs) return MIME_OUT_OF_MEMORY;
}
status = MimeHeaders_parse_line(line, length, bod->hdrs);
if (status < 0) return status;
/* If this line is blank, we're now done parsing headers, and should
create a dummy body to show that. Gag.
*/
if (*line == '\r' || *line == '\n')
{
bod->body = strdup("");
if (!bod->body) return MIME_OUT_OF_MEMORY;
}
return 0;
}
char *
MimeExternalBody_make_url(const char *ct,
const char *at, const char *lexp, const char *size,
const char *perm, const char *dir, const char *mode,
const char *name, const char *url, const char *site,
const char *svr, const char *subj, const char *body)
{
char *s;
uint32_t slen;
if (!at)
{
return 0;
}
else if (!PL_strcasecmp(at, "ftp") || !PL_strcasecmp(at, "anon-ftp"))
{
if (!site || !name)
return 0;
slen = strlen(name) + strlen(site) + (dir ? strlen(dir) : 0) + 20;
s = (char *) PR_MALLOC(slen);
if (!s) return 0;
PL_strncpyz(s, "ftp://", slen);
PL_strcatn(s, slen, site);
PL_strcatn(s, slen, "/");
if (dir) PL_strcatn(s, slen, (dir[0] == '/' ? dir+1 : dir));
if (s[strlen(s)-1] != '/')
PL_strcatn(s, slen, "/");
PL_strcatn(s, slen, name);
return s;
}
else if (!PL_strcasecmp(at, "local-file") || !PL_strcasecmp(at, "afs"))
{
if (!name)
return 0;
#ifdef XP_UNIX
if (!PL_strcasecmp(at, "afs")) /* only if there is a /afs/ directory */
{
nsCOMPtr <nsIFile> fs = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
bool exists = false;
if (fs)
{
fs->InitWithNativePath(NS_LITERAL_CSTRING("/afs/."));
fs->Exists(&exists);
}
if (!exists)
return 0;
}
#else /* !XP_UNIX */
return 0; /* never, if not Unix. */
#endif /* !XP_UNIX */
slen = (strlen(name) * 3 + 20);
s = (char *) PR_MALLOC(slen);
if (!s) return 0;
PL_strncpyz(s, "file:", slen);
nsCString s2;
MsgEscapeString(nsDependentCString(name), nsINetUtil::ESCAPE_URL_PATH, s2);
PL_strcatn(s, slen, s2.get());
return s;
}
else if (!PL_strcasecmp(at, "mail-server"))
{
if (!svr)
return 0;
slen = (strlen(svr)*4 + (subj ? strlen(subj)*4 : 0) +
(body ? strlen(body)*4 : 0) + 25); // dpv xxx: why 4x? %xx escaping should be 3x
s = (char *) PR_MALLOC(slen);
if (!s) return 0;
PL_strncpyz(s, "mailto:", slen);
nsCString s2;
MsgEscapeString(nsDependentCString(svr), nsINetUtil::ESCAPE_XALPHAS, s2);
PL_strcatn(s, slen, s2.get());
if (subj)
{
MsgEscapeString(nsDependentCString(subj), nsINetUtil::ESCAPE_XALPHAS, s2);
PL_strcatn(s, slen, "?subject=");
PL_strcatn(s, slen, s2.get());
}
if (body)
{
MsgEscapeString(nsDependentCString(body), nsINetUtil::ESCAPE_XALPHAS, s2);
PL_strcatn(s, slen, (subj ? "&body=" : "?body="));
PL_strcatn(s, slen, s2.get());
}
return s;
}
else if (!PL_strcasecmp(at, "url")) /* RFC 2017 */
{
if (url)
return strdup(url); /* it's already quoted and everything */
else
return 0;
}
else
return 0;
}
static int
MimeExternalBody_parse_eof (MimeObject *obj, bool abort_p)
{
int status = 0;
MimeExternalBody *bod = (MimeExternalBody *) obj;
if (obj->closed_p) return 0;
/* Run parent method first, to flush out any buffered data. */
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
if (status < 0) return status;
#ifdef XP_MACOSX
if (obj->parent && mime_typep(obj->parent,
(MimeObjectClass*) &mimeMultipartAppleDoubleClass))
goto done;
#endif /* XP_MACOSX */
if (!abort_p &&
obj->output_p &&
obj->options &&
obj->options->write_html_p)
{
bool all_headers_p = obj->options->headers == MimeHeadersAll;
MimeDisplayOptions *newopt = obj->options; /* copy it */
char *ct = MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE,
false, false);
char *at, *lexp, *size, *perm;
char *url, *dir, *mode, *name, *site, *svr, *subj;
char *h = 0, *lname = 0, *lurl = 0, *body = 0;
MimeHeaders *hdrs = 0;
if (!ct) return MIME_OUT_OF_MEMORY;
at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
lexp = MimeHeaders_get_parameter(ct, "expiration", NULL, NULL);
size = MimeHeaders_get_parameter(ct, "size", NULL, NULL);
perm = MimeHeaders_get_parameter(ct, "permission", NULL, NULL);
dir = MimeHeaders_get_parameter(ct, "directory", NULL, NULL);
mode = MimeHeaders_get_parameter(ct, "mode", NULL, NULL);
name = MimeHeaders_get_parameter(ct, "name", NULL, NULL);
site = MimeHeaders_get_parameter(ct, "site", NULL, NULL);
svr = MimeHeaders_get_parameter(ct, "server", NULL, NULL);
subj = MimeHeaders_get_parameter(ct, "subject", NULL, NULL);
url = MimeHeaders_get_parameter(ct, "url", NULL, NULL);
PR_FREEIF(ct);
/* the *internal* content-type */
ct = MimeHeaders_get(bod->hdrs, HEADER_CONTENT_TYPE,
true, false);
uint32_t hlen = ((at ? strlen(at) : 0) +
(lexp ? strlen(lexp) : 0) +
(size ? strlen(size) : 0) +
(perm ? strlen(perm) : 0) +
(dir ? strlen(dir) : 0) +
(mode ? strlen(mode) : 0) +
(name ? strlen(name) : 0) +
(site ? strlen(site) : 0) +
(svr ? strlen(svr) : 0) +
(subj ? strlen(subj) : 0) +
(ct ? strlen(ct) : 0) +
(url ? strlen(url) : 0) + 100);
h = (char *) PR_MALLOC(hlen);
if (!h)
{
status = MIME_OUT_OF_MEMORY;
goto FAIL;
}
/* If there's a URL parameter, remove all whitespace from it.
(The URL parameter to one of these headers is stored with
lines broken every 40 characters or less; it's assumed that
all significant whitespace was URL-hex-encoded, and all the
rest of it was inserted just to keep the lines short.)
*/
if (url)
{
char *in, *out;
for (in = url, out = url; *in; in++)
if (!IS_SPACE(*in))
*out++ = *in;
*out = 0;
}
hdrs = MimeHeaders_new();
if (!hdrs)
{
status = MIME_OUT_OF_MEMORY;
goto FAIL;
}
# define FROB(STR,VAR) \
if (VAR) \
{ \
PL_strncpyz(h, STR ": ", hlen); \
PL_strcatn(h, hlen, VAR); \
PL_strcatn(h, hlen, MSG_LINEBREAK); \
status = MimeHeaders_parse_line(h, strlen(h), hdrs); \
if (status < 0) goto FAIL; \
}
FROB("Access-Type", at);
FROB("URL", url);
FROB("Site", site);
FROB("Server", svr);
FROB("Directory", dir);
FROB("Name", name);
FROB("Type", ct);
FROB("Size", size);
FROB("Mode", mode);
FROB("Permission", perm);
FROB("Expiration", lexp);
FROB("Subject", subj);
# undef FROB
PL_strncpyz(h, MSG_LINEBREAK, hlen);
status = MimeHeaders_parse_line(h, strlen(h), hdrs);
if (status < 0) goto FAIL;
lurl = MimeExternalBody_make_url(ct, at, lexp, size, perm, dir, mode,
name, url, site, svr, subj, bod->body);
if (lurl)
{
lname = MimeGetStringByID(MIME_MSG_LINK_TO_DOCUMENT);
}
else
{
lname = MimeGetStringByID(MIME_MSG_DOCUMENT_INFO);
all_headers_p = true;
}
all_headers_p = true; /* #### just do this all the time? */
if (bod->body && all_headers_p)
{
char *s = bod->body;
while (IS_SPACE(*s)) s++;
if (*s)
{
char *s2;
const char *pre = "<P><PRE>";
const char *suf = "</PRE>";
int32_t i;
for(i = strlen(s)-1; i >= 0 && IS_SPACE(s[i]); i--)
s[i] = 0;
s2 = MsgEscapeHTML(s);
if (!s2) goto FAIL;
body = (char *) PR_MALLOC(strlen(pre) + strlen(s2) +
strlen(suf) + 1);
if (!body)
{
NS_Free(s2);
goto FAIL;
}
PL_strcpy(body, pre);
PL_strcat(body, s2);
PL_strcat(body, suf);
}
}
newopt->fancy_headers_p = true;
newopt->headers = (all_headers_p ? MimeHeadersAll : MimeHeadersSome);
FAIL:
if (hdrs)
MimeHeaders_free(hdrs);
PR_FREEIF(h);
PR_FREEIF(lname);
PR_FREEIF(lurl);
PR_FREEIF(body);
PR_FREEIF(ct);
PR_FREEIF(at);
PR_FREEIF(lexp);
PR_FREEIF(size);
PR_FREEIF(perm);
PR_FREEIF(dir);
PR_FREEIF(mode);
PR_FREEIF(name);
PR_FREEIF(url);
PR_FREEIF(site);
PR_FREEIF(svr);
PR_FREEIF(subj);
}
#ifdef XP_MACOSX
done:
#endif
return status;
}
#if 0
#if defined(DEBUG) && defined(XP_UNIX)
static int
MimeExternalBody_debug_print (MimeObject *obj, PRFileDesc *stream, int32_t depth)
{
MimeExternalBody *bod = (MimeExternalBody *) obj;
int i;
char *ct, *ct2;
char *addr = mime_part_address(obj);
if (obj->headers)
ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, false, false);
if (bod->hdrs)
ct2 = MimeHeaders_get (bod->hdrs, HEADER_CONTENT_TYPE, false, false);
for (i=0; i < depth; i++)
PR_Write(stream, " ", 2);
/***
fprintf(stream,
"<%s %s\n"
"\tcontent-type: %s\n"
"\tcontent-type: %s\n"
"\tBody:%s\n\t0x%08X>\n\n",
obj->clazz->class_name,
addr ? addr : "???",
ct ? ct : "<none>",
ct2 ? ct2 : "<none>",
bod->body ? bod->body : "<none>",
(uint32_t) obj);
***/
PR_FREEIF(addr);
PR_FREEIF(ct);
PR_FREEIF(ct2);
return 0;
}
#endif
#endif /* 0 */
static bool
MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz,
MimeHeaders *hdrs)
{
char *ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, false, false);
char *at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL);
bool inline_p = false;
if (!at)
;
else if (!PL_strcasecmp(at, "ftp") ||
!PL_strcasecmp(at, "anon-ftp") ||
!PL_strcasecmp(at, "local-file") ||
!PL_strcasecmp(at, "mail-server") ||
!PL_strcasecmp(at, "url"))
inline_p = true;
#ifdef XP_UNIX
else if (!PL_strcasecmp(at, "afs")) /* only if there is a /afs/ directory */
{
nsCOMPtr <nsIFile> fs = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
bool exists = false;
if (fs)
{
fs->InitWithNativePath(NS_LITERAL_CSTRING("/afs/."));
fs->Exists(&exists);
}
if (!exists)
return 0;
inline_p = true;
}
#endif /* XP_UNIX */
PR_FREEIF(ct);
PR_FREEIF(at);
return inline_p;
}

View file

@ -0,0 +1,37 @@
/* -*- 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/. */
#ifndef _MIMEEBOD_H_
#define _MIMEEBOD_H_
#include "mimeobj.h"
/* The MimeExternalBody class implements the message/external-body MIME type.
(This is not to be confused with MimeExternalObject, which implements the
handler for application/octet-stream and other types with no more specific
handlers.)
*/
typedef struct MimeExternalBodyClass MimeExternalBodyClass;
typedef struct MimeExternalBody MimeExternalBody;
struct MimeExternalBodyClass {
MimeObjectClass object;
};
extern MimeExternalBodyClass mimeExternalBodyClass;
struct MimeExternalBody {
MimeObject object; /* superclass variables */
MimeHeaders *hdrs; /* headers within this external-body, which
describe the network data which this body
is a pointer to. */
char *body; /* The "phantom body" of this link. */
};
#define MimeExternalBodyClassInitializer(ITYPE,CSUPER) \
{ MimeObjectClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEEBOD_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
/* -*- 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/. */
#include "nsCOMPtr.h"
#include "mimeeobj.h"
#include "prmem.h"
#include "plstr.h"
#include "prlog.h"
#include "nsMimeStringResources.h"
#include "mimemoz2.h"
#include "mimemapl.h"
#include "nsMimeTypes.h"
#define MIME_SUPERCLASS mimeLeafClass
MimeDefClass(MimeExternalObject, MimeExternalObjectClass,
mimeExternalObjectClass, &MIME_SUPERCLASS);
static int MimeExternalObject_initialize (MimeObject *);
static void MimeExternalObject_finalize (MimeObject *);
static int MimeExternalObject_parse_begin (MimeObject *);
static int MimeExternalObject_parse_buffer (const char *, int32_t, MimeObject *);
static int MimeExternalObject_parse_line (const char *, int32_t, MimeObject *);
static int MimeExternalObject_parse_decoded_buffer (const char*, int32_t, MimeObject*);
static bool MimeExternalObject_displayable_inline_p (MimeObjectClass *clazz,
MimeHeaders *hdrs);
static int
MimeExternalObjectClassInitialize(MimeExternalObjectClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
MimeLeafClass *lclass = (MimeLeafClass *) clazz;
NS_ASSERTION(!oclass->class_initialized, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
oclass->initialize = MimeExternalObject_initialize;
oclass->finalize = MimeExternalObject_finalize;
oclass->parse_begin = MimeExternalObject_parse_begin;
oclass->parse_buffer = MimeExternalObject_parse_buffer;
oclass->parse_line = MimeExternalObject_parse_line;
oclass->displayable_inline_p = MimeExternalObject_displayable_inline_p;
lclass->parse_decoded_buffer = MimeExternalObject_parse_decoded_buffer;
return 0;
}
static int
MimeExternalObject_initialize (MimeObject *object)
{
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
}
static void
MimeExternalObject_finalize (MimeObject *object)
{
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
}
static int
MimeExternalObject_parse_begin (MimeObject *obj)
{
int status;
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
if (status < 0) return status;
// If we're writing this object, and we're doing it in raw form, then
// now is the time to inform the backend what the type of this data is.
//
if (obj->output_p &&
obj->options &&
!obj->options->write_html_p &&
!obj->options->state->first_data_written_p)
{
status = MimeObject_output_init(obj, 0);
if (status < 0) return status;
NS_ASSERTION(obj->options->state->first_data_written_p, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
}
//
// If we're writing this object as HTML, do all the work now -- just write
// out a table with a link in it. (Later calls to the `parse_buffer' method
// will simply discard the data of the object itself.)
//
if (obj->options &&
obj->output_p &&
obj->options->write_html_p &&
obj->options->output_fn)
{
MimeDisplayOptions newopt = *obj->options; // copy it
char *id = 0;
char *id_url = 0;
char *id_name = 0;
nsCString id_imap;
bool all_headers_p = obj->options->headers == MimeHeadersAll;
id = mime_part_address (obj);
if (obj->options->missing_parts)
id_imap.Adopt(mime_imap_part_address (obj));
if (! id) return MIME_OUT_OF_MEMORY;
if (obj->options && obj->options->url)
{
const char *url = obj->options->url;
if (!id_imap.IsEmpty() && id)
{
// if this is an IMAP part.
id_url = mime_set_url_imap_part(url, id_imap.get(), id);
}
else
{
// This is just a normal MIME part as usual.
id_url = mime_set_url_part(url, id, true);
}
if (!id_url)
{
PR_Free(id);
return MIME_OUT_OF_MEMORY;
}
}
if (!strcmp (id, "0"))
{
PR_Free(id);
id = MimeGetStringByID(MIME_MSG_ATTACHMENT);
}
else
{
const char *p = "Part ";
uint32_t slen = strlen(p) + strlen(id) + 1;
char *s = (char *)PR_MALLOC(slen);
if (!s)
{
PR_Free(id);
PR_Free(id_url);
return MIME_OUT_OF_MEMORY;
}
// we have a valid id
if (id)
id_name = mime_find_suggested_name_of_part(id, obj);
PL_strncpyz(s, p, slen);
PL_strcatn(s, slen, id);
PR_Free(id);
id = s;
}
if (all_headers_p &&
// Don't bother showing all headers on this part if it's the only
// part in the message: in that case, we've already shown these
// headers.
obj->options->state &&
obj->options->state->root == obj->parent)
all_headers_p = false;
newopt.fancy_headers_p = true;
newopt.headers = (all_headers_p ? MimeHeadersAll : MimeHeadersSome);
/******
RICHIE SHERRY
GOTTA STILL DO THIS FOR QUOTING!
status = MimeHeaders_write_attachment_box (obj->headers, &newopt,
obj->content_type,
obj->encoding,
id_name? id_name : id, id_url, 0)
*****/
// obj->options really owns the storage for this.
newopt.part_to_load = nullptr;
newopt.default_charset = nullptr;
PR_FREEIF(id);
PR_FREEIF(id_url);
PR_FREEIF(id_name);
if (status < 0) return status;
}
return 0;
}
static int
MimeExternalObject_parse_buffer (const char *buffer, int32_t size, MimeObject *obj)
{
NS_ASSERTION(!obj->closed_p, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (obj->closed_p) return -1;
// Currently, we always want to stream, in order to determine the size of the
// MIME object.
/* The data will be base64-decoded and passed to
MimeExternalObject_parse_decoded_buffer. */
return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_buffer(buffer, size, obj);
}
static int
MimeExternalObject_parse_decoded_buffer (const char *buf, int32_t size,
MimeObject *obj)
{
/* This is called (by MimeLeafClass->parse_buffer) with blocks of data
that have already been base64-decoded. This will only be called in
the case where we're not emitting HTML, and want access to the raw
data itself.
We override the `parse_decoded_buffer' method provided by MimeLeaf
because, unlike most children of MimeLeaf, we do not want to line-
buffer the decoded data -- we want to simply pass it along to the
backend, without going through our `parse_line' method.
*/
/* Don't do a roundtrip through XPConnect when we're only interested in
* metadata and size. This includes when we are writing HTML (otherwise, the
* contents of binary attachments will just get dumped into messages when
* reading them) and the JS emitter (which doesn't care about attachment data
* at all). 0 means ok, the caller just checks for negative return value.
*/
if (obj->options && (obj->options->metadata_only ||
obj->options->write_html_p))
return 0;
else
return MimeObject_write(obj, buf, size, true);
}
static int
MimeExternalObject_parse_line (const char *line, int32_t length, MimeObject *obj)
{
NS_ERROR("This method should never be called (externals do no line buffering).");
return -1;
}
static bool
MimeExternalObject_displayable_inline_p (MimeObjectClass *clazz,
MimeHeaders *hdrs)
{
return false;
}

View file

@ -0,0 +1,34 @@
/* -*- 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/. */
#ifndef _MIMEEOBJ_H_
#define _MIMEEOBJ_H_
#include "mimeleaf.h"
/* The MimeExternalObject class represents MIME parts which contain data
which cannot be displayed inline -- application/octet-stream and any
other type that is not otherwise specially handled. (This is not to
be confused with MimeExternalBody, which is the handler for the
message/external-object MIME type only.)
*/
typedef struct MimeExternalObjectClass MimeExternalObjectClass;
typedef struct MimeExternalObject MimeExternalObject;
struct MimeExternalObjectClass {
MimeLeafClass leaf;
};
extern "C" MimeExternalObjectClass mimeExternalObjectClass;
struct MimeExternalObject {
MimeLeaf leaf;
};
#define MimeExternalObjectClassInitializer(ITYPE,CSUPER) \
{ MimeLeafClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEEOBJ_H_ */

View file

@ -0,0 +1,399 @@
/* -*- 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/. */
/* mimefilt.c --- test harness for libmime.a
This program reads a message from stdin and writes the output of the MIME
parser on stdout.
Parameters can be passed to the parser through the usual URL mechanism:
mimefilt BASE-URL?headers=all&rot13 < in > out
Some parameters can't be affected that way, so some additional switches
may be passed on the command line after the URL:
-fancy whether fancy headers should be generated (default)
-no-fancy opposite; this uses the headers used in the cases of
FO_SAVE_AS_TEXT or FO_QUOTE_MESSAGE
-html whether we should convert to HTML (like FO_PRESENT);
this is the default if no ?part= is specified.
-raw don't convert to HTML (FO_SAVE_AS);
this is the default if a ?part= is specified.
-outline at the end, print a debugging overview of the MIME structure
Before any output comes a blurb listing the content-type, charset, and
various other info that would have been put in the generated URL struct.
It's printed to the beginning of the output because otherwise this out-
of-band data would have been lost. (So the output of this program is,
in fact, a raw HTTP response.)
*/
#include "mimemsg.h"
#include "prglobal.h"
#include "key.h"
#include "cert.h"
#include "secrng.h"
#include "secmod.h"
#include "pk11func.h"
#include "nsMimeStringResources.h"
#ifndef XP_UNIX
ERROR! This is a unix-only file for the "mimefilt" standalone program.
This does not go into libmime.a.
#endif
static char *
test_file_type (const char *filename, void *stream_closure)
{
const char *suf = PL_strrchr(filename, '.');
if (!suf)
return 0;
suf++;
if (!PL_strcasecmp(suf, "txt") ||
!PL_strcasecmp(suf, "text"))
return strdup("text/plain");
else if (!PL_strcasecmp(suf, "htm") ||
!PL_strcasecmp(suf, "html"))
return strdup("text/html");
else if (!PL_strcasecmp(suf, "gif"))
return strdup("image/gif");
else if (!PL_strcasecmp(suf, "svg"))
return strdup("image/svg+xml");
else if (!PL_strcasecmp(suf, "jpg") ||
!PL_strcasecmp(suf, "jpeg"))
return strdup("image/jpeg");
else if (!PL_strcasecmp(suf, "pjpg") ||
!PL_strcasecmp(suf, "pjpeg"))
return strdup("image/pjpeg");
else if (!PL_strcasecmp(suf, "xbm"))
return strdup("image/x-xbitmap");
else if (!PL_strcasecmp(suf, "xpm"))
return strdup("image/x-xpixmap");
else if (!PL_strcasecmp(suf, "xwd"))
return strdup("image/x-xwindowdump");
else if (!PL_strcasecmp(suf, "bmp"))
return strdup("image/x-MS-bmp");
else if (!PL_strcasecmp(suf, "au"))
return strdup("audio/basic");
else if (!PL_strcasecmp(suf, "aif") ||
!PL_strcasecmp(suf, "aiff") ||
!PL_strcasecmp(suf, "aifc"))
return strdup("audio/x-aiff");
else if (!PL_strcasecmp(suf, "ps"))
return strdup("application/postscript");
else
return 0;
}
static int
test_output_fn(char *buf, int32_t size, void *closure)
{
FILE *out = (FILE *) closure;
if (out)
return fwrite(buf, sizeof(*buf), size, out);
else
return 0;
}
static int
test_output_init_fn (const char *type,
const char *charset,
const char *name,
const char *x_mac_type,
const char *x_mac_creator,
void *stream_closure)
{
FILE *out = (FILE *) stream_closure;
fprintf(out, "CONTENT-TYPE: %s", type);
if (charset)
fprintf(out, "; charset=\"%s\"", charset);
if (name)
fprintf(out, "; name=\"%s\"", name);
if (x_mac_type || x_mac_creator)
fprintf(out, "; x-mac-type=\"%s\"; x-mac-creator=\"%s\"",
x_mac_type ? x_mac_type : "",
x_mac_creator ? x_mac_type : "");
fprintf(out, CRLF CRLF);
return 0;
}
static void *
test_image_begin(const char *image_url, const char *content_type,
void *stream_closure)
{
return ((void *) strdup(image_url));
}
static void
test_image_end(void *image_closure, int status)
{
char *url = (char *) image_closure;
if (url) PR_Free(url);
}
static char *
test_image_make_image_html(void *image_data)
{
char *url = (char *) image_data;
#if 0
const char *prefix = "<P><CENTER><IMG SRC=\"";
const char *suffix = "\"></CENTER><P>";
#else
const char *prefix = ("<P><CENTER><TABLE BORDER=2 CELLPADDING=20"
" BGCOLOR=WHITE>"
"<TR><TD ALIGN=CENTER>"
"an inlined image would have gone here for<BR>");
const char *suffix = "</TD></TR></TABLE></CENTER><P>";
#endif
uint32_t buflen = strlen (prefix) + strlen (suffix) + strlen (url) + 20;
char *buf = (char *) PR_MALLOC (buflen);
if (!buf) return 0;
*buf = 0;
PL_strcatn (buf, buflen, prefix);
PL_strcatn (buf, buflen, url);
PL_strcatn (buf, buflen, suffix);
return buf;
}
static int test_image_write_buffer(const char *buf, int32_t size, void *image_closure)
{
return 0;
}
static char *
test_passwd_prompt (PK11SlotInfo *slot, void *wincx)
{
char buf[2048], *s;
fprintf(stdout, "#### Password required: ");
s = fgets(buf, sizeof(buf)-1, stdin);
if (!s) return s;
if (s[strlen(s)-1] == '\r' ||
s[strlen(s)-1] == '\n')
s[strlen(s)-1] = '\0';
return s;
}
int
test(FILE *in, FILE *out,
const char *url,
bool fancy_headers_p,
bool html_p,
bool outline_p,
bool dexlate_p,
bool variable_width_plaintext_p)
{
int status = 0;
MimeObject *obj = 0;
MimeDisplayOptions *opt = new MimeDisplayOptions;
// memset(opt, 0, sizeof(*opt));
if (dexlate_p) html_p = false;
opt->fancy_headers_p = fancy_headers_p;
opt->headers = MimeHeadersSome;
opt->rot13_p = false;
status = mime_parse_url_options(url, opt);
if (status < 0)
{
PR_Free(opt);
return MIME_OUT_OF_MEMORY;
}
opt->url = url;
opt->write_html_p = html_p;
opt->dexlate_p = dexlate_p;
opt->output_init_fn = test_output_init_fn;
opt->output_fn = test_output_fn;
opt->charset_conversion_fn= 0;
opt->rfc1522_conversion_p = false;
opt->file_type_fn = test_file_type;
opt->stream_closure = out;
opt->image_begin = test_image_begin;
opt->image_end = test_image_end;
opt->make_image_html = test_image_make_image_html;
opt->image_write_buffer = test_image_write_buffer;
opt->variable_width_plaintext_p = variable_width_plaintext_p;
obj = mime_new ((MimeObjectClass *)&mimeMessageClass,
(MimeHeaders *) NULL,
MESSAGE_RFC822);
if (!obj)
{
PR_Free(opt);
return MIME_OUT_OF_MEMORY;
}
obj->options = opt;
status = obj->class->initialize(obj);
if (status >= 0)
status = obj->class->parse_begin(obj);
if (status < 0)
{
PR_Free(opt);
PR_Free(obj);
return MIME_OUT_OF_MEMORY;
}
while (1)
{
char buf[255];
int size = fread(buf, sizeof(*buf), sizeof(buf), stdin);
if (size <= 0) break;
status = obj->class->parse_buffer(buf, size, obj);
if (status < 0)
{
mime_free(obj);
PR_Free(opt);
return status;
}
}
status = obj->class->parse_eof(obj, false);
if (status >= 0)
status = obj->class->parse_end(obj, false);
if (status < 0)
{
mime_free(obj);
PR_Free(opt);
return status;
}
if (outline_p)
{
fprintf(out, "\n\n"
"###############################################################\n");
obj->class->debug_print(obj, stderr, 0);
fprintf(out,
"###############################################################\n");
}
mime_free (obj);
PR_Free(opt);
return 0;
}
static char *
test_cdb_name_cb (void *arg, int vers)
{
static char f[1024];
if (vers <= 4)
sprintf(f, "%s/.netscape/cert.db", getenv("HOME"));
else
sprintf(f, "%s/.netscape/cert%d.db", getenv("HOME"), vers);
return f;
}
static char *
test_kdb_name_cb (void *arg, int vers)
{
static char f[1024];
if (vers <= 2)
sprintf(f, "%s/.netscape/key.db", getenv("HOME"));
else
sprintf(f, "%s/.netscape/key%d.db", getenv("HOME"), vers);
return f;
}
extern void SEC_Init(void);
int
main (int argc, char **argv)
{
int32_t i = 1;
char *url = "";
bool fancy_p = true;
bool html_p = true;
bool outline_p = false;
bool dexlate_p = false;
char filename[1000];
CERTCertDBHandle *cdb_handle;
SECKEYKeyDBHandle *kdb_handle;
PR_Init("mimefilt", 24, 1, 0);
cdb_handle = (CERTCertDBHandle *) calloc(1, sizeof(*cdb_handle));
if (SECSuccess != CERT_OpenCertDB(cdb_handle, false, test_cdb_name_cb, NULL))
CERT_OpenVolatileCertDB(cdb_handle);
CERT_SetDefaultCertDB(cdb_handle);
RNG_RNGInit();
kdb_handle = SECKEY_OpenKeyDB(false, test_kdb_name_cb, NULL);
SECKEY_SetDefaultKeyDB(kdb_handle);
PK11_SetPasswordFunc(test_passwd_prompt);
sprintf(filename, "%s/.netscape/secmodule.db", getenv("HOME"));
SECMOD_init(filename);
SEC_Init();
if (i < argc)
{
if (argv[i][0] == '-')
url = strdup("");
else
url = argv[i++];
}
if (url &&
(PL_strstr(url, "?part=") ||
PL_strstr(url, "&part=")))
html_p = false;
while (i < argc)
{
if (!strcmp(argv[i], "-fancy"))
fancy_p = true;
else if (!strcmp(argv[i], "-no-fancy"))
fancy_p = false;
else if (!strcmp(argv[i], "-html"))
html_p = true;
else if (!strcmp(argv[i], "-raw"))
html_p = false;
else if (!strcmp(argv[i], "-outline"))
outline_p = true;
else if (!strcmp(argv[i], "-dexlate"))
dexlate_p = true;
else
{
fprintf(stderr,
"usage: %s [ URL [ -fancy | -no-fancy | -html | -raw | -outline | -dexlate ]]\n"
" < message/rfc822 > output\n",
(PL_strrchr(argv[0], '/') ?
PL_strrchr(argv[0], '/') + 1 :
argv[0]));
i = 1;
goto FAIL;
}
i++;
}
i = test(stdin, stdout, url, fancy_p, html_p, outline_p, dexlate_p, true);
fprintf(stdout, "\n");
fflush(stdout);
FAIL:
CERT_ClosePermCertDB(cdb_handle);
SECKEY_CloseKeyDB(kdb_handle);
exit(i);
}

View file

@ -0,0 +1,888 @@
/* -*- 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/. */
#include "nsCOMPtr.h"
#include "msgCore.h"
#include "mimei.h"
#include "prmem.h"
#include "prlog.h"
#include "plstr.h"
#include "mimebuf.h"
#include "mimemoz2.h"
#include "nsIMimeEmitter.h"
#include "nsMsgMessageFlags.h"
#include "comi18n.h"
#include "nsMailHeaders.h"
#include "msgCore.h"
#include "nsMimeStringResources.h"
#include "mimemoz2.h"
#include "nsMsgI18N.h"
#include "mimehdrs.h"
#include "nsIMIMEHeaderParam.h"
#include "nsNetCID.h"
#include "nsServiceManagerUtils.h"
#include "nsMemory.h"
#include <ctype.h>
#include "nsMsgUtils.h"
// Forward declares...
int32_t MimeHeaders_build_heads_list(MimeHeaders *hdrs);
void
MimeHeaders_convert_header_value(MimeDisplayOptions *opt, nsCString &value,
bool convert_charset_only)
{
if (value.IsEmpty())
return;
if (convert_charset_only)
{
nsAutoCString output;
ConvertRawBytesToUTF8(value, opt->default_charset, output);
value.Assign(output);
return;
}
if (opt && opt->rfc1522_conversion_p)
{
nsAutoCString temporary;
MIME_DecodeMimeHeader(value.get(), opt->default_charset,
opt->override_charset, true, temporary);
if (!temporary.IsEmpty())
{
value = temporary;
}
}
else
{
// This behavior, though highly unusual, was carefully preserved
// from the previous implementation. It may be that this is dead
// code, in which case opt->rfc1522_conversion_p is no longer
// needed.
value.Truncate();
}
}
MimeHeaders *
MimeHeaders_new (void)
{
MimeHeaders *hdrs = (MimeHeaders *) PR_MALLOC(sizeof(MimeHeaders));
if (!hdrs) return 0;
memset(hdrs, 0, sizeof(*hdrs));
hdrs->done_p = false;
return hdrs;
}
void
MimeHeaders_free (MimeHeaders *hdrs)
{
if (!hdrs) return;
PR_FREEIF(hdrs->all_headers);
PR_FREEIF(hdrs->heads);
PR_FREEIF(hdrs->obuffer);
PR_FREEIF(hdrs->munged_subject);
hdrs->obuffer_fp = 0;
hdrs->obuffer_size = 0;
# ifdef DEBUG__
{
int i, size = sizeof(*hdrs);
uint32_t *array = (uint32_t*) hdrs;
for (i = 0; i < (size / sizeof(*array)); i++)
array[i] = (uint32_t) 0xDEADBEEF;
}
# endif /* DEBUG */
PR_Free(hdrs);
}
int
MimeHeaders_parse_line (const char *buffer, int32_t size, MimeHeaders *hdrs)
{
int status = 0;
int desired_size;
NS_ASSERTION(hdrs, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
if (!hdrs) return -1;
/* Don't try and feed me more data after having fed me a blank line... */
NS_ASSERTION(!hdrs->done_p, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
if (hdrs->done_p) return -1;
if (!buffer || size == 0 || *buffer == '\r' || *buffer == '\n')
{
/* If this is a blank line, we're done.
*/
hdrs->done_p = true;
return MimeHeaders_build_heads_list(hdrs);
}
/* Tack this data on to the end of our copy.
*/
desired_size = hdrs->all_headers_fp + size + 1;
if (desired_size >= hdrs->all_headers_size)
{
status = mime_GrowBuffer (desired_size, sizeof(char), 255,
&hdrs->all_headers, &hdrs->all_headers_size);
if (status < 0) return status;
}
memcpy(hdrs->all_headers+hdrs->all_headers_fp, buffer, size);
hdrs->all_headers_fp += size;
return 0;
}
MimeHeaders *
MimeHeaders_copy (MimeHeaders *hdrs)
{
MimeHeaders *hdrs2;
if (!hdrs) return 0;
hdrs2 = (MimeHeaders *) PR_MALLOC(sizeof(*hdrs));
if (!hdrs2) return 0;
memset(hdrs2, 0, sizeof(*hdrs2));
if (hdrs->all_headers)
{
hdrs2->all_headers = (char *) PR_MALLOC(hdrs->all_headers_fp);
if (!hdrs2->all_headers)
{
PR_Free(hdrs2);
return 0;
}
memcpy(hdrs2->all_headers, hdrs->all_headers, hdrs->all_headers_fp);
hdrs2->all_headers_fp = hdrs->all_headers_fp;
hdrs2->all_headers_size = hdrs->all_headers_fp;
}
hdrs2->done_p = hdrs->done_p;
if (hdrs->heads)
{
int i;
hdrs2->heads = (char **) PR_MALLOC(hdrs->heads_size
* sizeof(*hdrs->heads));
if (!hdrs2->heads)
{
PR_FREEIF(hdrs2->all_headers);
PR_Free(hdrs2);
return 0;
}
hdrs2->heads_size = hdrs->heads_size;
for (i = 0; i < hdrs->heads_size; i++)
{
hdrs2->heads[i] = (hdrs2->all_headers +
(hdrs->heads[i] - hdrs->all_headers));
}
}
return hdrs2;
}
int
MimeHeaders_build_heads_list(MimeHeaders *hdrs)
{
char *s;
char *end;
int i;
NS_ASSERTION(hdrs, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (!hdrs) return -1;
NS_ASSERTION(hdrs->done_p && !hdrs->heads, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (!hdrs->done_p || hdrs->heads)
return -1;
if (hdrs->all_headers_fp == 0)
{
/* Must not have been any headers (we got the blank line right away.) */
PR_FREEIF (hdrs->all_headers);
hdrs->all_headers_size = 0;
return 0;
}
/* At this point, we might as well realloc all_headers back down to the
minimum size it must be (it could be up to 1k bigger.) But don't
bother if we're only off by a tiny bit. */
NS_ASSERTION(hdrs->all_headers_fp <= hdrs->all_headers_size, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (hdrs->all_headers_fp + 60 <= hdrs->all_headers_size)
{
char *ls = (char *)PR_Realloc(hdrs->all_headers, hdrs->all_headers_fp);
if (ls) /* can this ever fail? we're making it smaller... */
{
hdrs->all_headers = ls; /* in case it got relocated */
hdrs->all_headers_size = hdrs->all_headers_fp;
}
}
/* First go through and count up the number of headers in the block.
*/
end = hdrs->all_headers + hdrs->all_headers_fp;
for (s = hdrs->all_headers; s < end; s++)
{
if (s < (end-1) && s[0] == '\r' && s[1] == '\n') /* CRLF -> LF */
s++;
if ((s[0] == '\r' || s[0] == '\n') && /* we're at a newline, and */
(s >= (end-1) || /* we're at EOF, or */
!(s[1] == ' ' || s[1] == '\t'))) /* next char is nonwhite */
hdrs->heads_size++;
}
/* Now allocate storage for the pointers to each of those headers.
*/
hdrs->heads = (char **) PR_MALLOC((hdrs->heads_size + 1) * sizeof(char *));
if (!hdrs->heads)
return MIME_OUT_OF_MEMORY;
memset(hdrs->heads, 0, (hdrs->heads_size + 1) * sizeof(char *));
/* Now make another pass through the headers, and this time, record the
starting position of each header.
*/
i = 0;
hdrs->heads[i++] = hdrs->all_headers;
s = hdrs->all_headers;
while (s < end)
{
SEARCH_NEWLINE:
while (s < end && *s != '\r' && *s != '\n')
s++;
if (s >= end)
break;
/* If "\r\n " or "\r\n\t" is next, that doesn't terminate the header. */
else if (s+2 < end &&
(s[0] == '\r' && s[1] == '\n') &&
(s[2] == ' ' || s[2] == '\t'))
{
s += 3;
goto SEARCH_NEWLINE;
}
/* If "\r " or "\r\t" or "\n " or "\n\t" is next, that doesn't terminate
the header either. */
else if (s+1 < end &&
(s[0] == '\r' || s[0] == '\n') &&
(s[1] == ' ' || s[1] == '\t'))
{
s += 2;
goto SEARCH_NEWLINE;
}
/* At this point, `s' points before a header-terminating newline.
Move past that newline, and store that new position in `heads'.
*/
if (*s == '\r')
s++;
if (s >= end)
break;
if (*s == '\n')
s++;
if (s < end)
{
NS_ASSERTION(! (i > hdrs->heads_size), "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (i > hdrs->heads_size)
return -1;
hdrs->heads[i++] = s;
}
}
return 0;
}
char *
MimeHeaders_get (MimeHeaders *hdrs, const char *header_name,
bool strip_p, bool all_p)
{
int i;
int name_length;
char *result = 0;
if (!hdrs) return 0;
NS_ASSERTION(header_name, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (!header_name) return 0;
/* Specifying strip_p and all_p at the same time doesn't make sense... */
NS_ASSERTION(!(strip_p && all_p), "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
/* One shouldn't be trying to read headers when one hasn't finished
parsing them yet... but this can happen if the message ended
prematurely, and has no body at all (as opposed to a null body,
which is more normal.) So, if we try to read from the headers,
let's assume that the headers are now finished. If they aren't
in fact finished, then a later attempt to write to them will assert.
*/
if (!hdrs->done_p)
{
int status;
hdrs->done_p = true;
status = MimeHeaders_build_heads_list(hdrs);
if (status < 0) return 0;
}
if (!hdrs->heads) /* Must not have been any headers. */
{
NS_ASSERTION(hdrs->all_headers_fp == 0, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
return 0;
}
name_length = strlen(header_name);
for (i = 0; i < hdrs->heads_size; i++)
{
char *head = hdrs->heads[i];
char *end = (i == hdrs->heads_size-1
? hdrs->all_headers + hdrs->all_headers_fp
: hdrs->heads[i+1]);
char *colon, *ocolon;
NS_ASSERTION(head, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (!head) continue;
/* Quick hack to skip over BSD Mailbox delimiter. */
if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5))
continue;
/* Find the colon. */
for (colon = head; colon < end; colon++)
if (*colon == ':') break;
if (colon >= end) continue;
/* Back up over whitespace before the colon. */
ocolon = colon;
for (; colon > head && IS_SPACE(colon[-1]); colon--)
;
/* If the strings aren't the same length, it doesn't match. */
if (name_length != colon - head )
continue;
/* If the strings differ, it doesn't match. */
if (PL_strncasecmp(header_name, head, name_length))
continue;
/* Otherwise, we've got a match. */
{
char *contents = ocolon + 1;
char *s;
/* Skip over whitespace after colon. */
while (contents < end && IS_SPACE(contents[0])) {
/* Mac or Unix style line break, followed by space or tab. */
if (contents < (end - 1) &&
(contents[0] == '\r' || contents[0] == '\n') &&
(contents[1] == ' ' || contents[1] == '\t'))
contents += 2;
/* Windows style line break, followed by space or tab. */
else if (contents < (end - 2) &&
contents[0] == '\r' && contents[1] == '\n' &&
(contents[2] == ' ' || contents[2] == '\t'))
contents += 3;
/* Any space or tab. */
else if (contents[0] == ' ' || contents[0] == '\t')
contents++;
/* If we get here, it's because this character is a line break
followed by non-whitespace, or a line break followed by
another line break
*/
else {
end = contents;
break;
}
}
/* If we're supposed to strip at the first token, pull `end' back to
the first whitespace or ';' after the first token.
*/
if (strip_p)
{
for (s = contents;
s < end && *s != ';' && *s != ',' && !IS_SPACE(*s);
s++)
;
end = s;
}
/* Now allocate some storage.
If `result' already has a value, enlarge it.
Otherwise, just allocate a block.
`s' gets set to the place where the new data goes.
*/
if (!result)
{
result = (char *) PR_MALLOC(end - contents + 1);
if (!result)
return 0;
s = result;
}
else
{
int32_t L = strlen(result);
s = (char *) PR_Realloc(result, (L + (end - contents + 10)));
if (!s)
{
PR_Free(result);
return 0;
}
result = s;
s = result + L;
/* Since we are tacking more data onto the end of the header
field, we must make it be a well-formed continuation line,
by separating the old and new data with CR-LF-TAB.
*/
*s++ = ','; /* #### only do this for addr headers? */
*s++ = MSG_LINEBREAK[0];
# if (MSG_LINEBREAK_LEN == 2)
*s++ = MSG_LINEBREAK[1];
# endif
*s++ = '\t';
}
/* Take off trailing whitespace... */
while (end > contents && IS_SPACE(end[-1]))
end--;
if (end > contents)
{
/* Now copy the header's contents in...
*/
memcpy(s, contents, end - contents);
s[end - contents] = 0;
}
else
{
s[0] = 0;
}
/* If we only wanted the first occurence of this header, we're done. */
if (!all_p) break;
}
}
if (result && !*result) /* empty string */
{
PR_Free(result);
return 0;
}
return result;
}
char *
MimeHeaders_get_parameter (const char *header_value, const char *parm_name,
char **charset, char **language)
{
if (!header_value || !parm_name || !*header_value || !*parm_name)
return nullptr;
nsresult rv;
nsCOMPtr <nsIMIMEHeaderParam> mimehdrpar =
do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
if (NS_FAILED(rv))
return nullptr;
nsCString result;
rv = mimehdrpar->GetParameterInternal(header_value, parm_name, charset,
language, getter_Copies(result));
return NS_SUCCEEDED(rv) ? PL_strdup(result.get()) : nullptr;
}
#define MimeHeaders_write(HDRS,OPT,DATA,LENGTH) \
MimeOptions_write((HDRS), (OPT), (DATA), (LENGTH), true);
#define MimeHeaders_grow_obuffer(hdrs, desired_size) \
((((long) (desired_size)) >= ((long) (hdrs)->obuffer_size)) ? \
mime_GrowBuffer ((desired_size), sizeof(char), 255, \
&(hdrs)->obuffer, &(hdrs)->obuffer_size) \
: 0)
int
MimeHeaders_write_all_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt, bool attachment)
{
int status = 0;
int i;
bool wrote_any_p = false;
NS_ASSERTION(hdrs, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (!hdrs)
return -1;
/* One shouldn't be trying to read headers when one hasn't finished
parsing them yet... but this can happen if the message ended
prematurely, and has no body at all (as opposed to a null body,
which is more normal.) So, if we try to read from the headers,
let's assume that the headers are now finished. If they aren't
in fact finished, then a later attempt to write to them will assert.
*/
if (!hdrs->done_p)
{
hdrs->done_p = true;
status = MimeHeaders_build_heads_list(hdrs);
if (status < 0) return 0;
}
char *charset = nullptr;
if (opt->format_out == nsMimeOutput::nsMimeMessageSaveAs)
{
if (opt->override_charset)
charset = PL_strdup(opt->default_charset);
else
{
char *contentType = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, false, false);
if (contentType)
charset = MimeHeaders_get_parameter(contentType, HEADER_PARM_CHARSET, nullptr, nullptr);
PR_FREEIF(contentType);
}
}
for (i = 0; i < hdrs->heads_size; i++)
{
char *head = hdrs->heads[i];
char *end = (i == hdrs->heads_size-1
? hdrs->all_headers + hdrs->all_headers_fp
: hdrs->heads[i+1]);
char *colon, *ocolon;
char *contents = end;
/* Hack for BSD Mailbox delimiter. */
if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5))
{
/* For now, we don't really want this header to be output so
we are going to just continue */
continue;
/* colon = head + 4; contents = colon + 1; */
}
else
{
/* Find the colon. */
for (colon = head; colon < end && *colon != ':'; colon++)
;
/* Back up over whitespace before the colon. */
ocolon = colon;
for (; colon > head && IS_SPACE(colon[-1]); colon--)
;
contents = ocolon + 1;
}
/* Skip over whitespace after colon. */
while (contents < end && IS_SPACE(*contents))
contents++;
/* Take off trailing whitespace... */
while (end > contents && IS_SPACE(end[-1]))
end--;
nsAutoCString name(Substring(head, colon));
nsAutoCString hdr_value;
if ( (end - contents) > 0 )
{
hdr_value = Substring(contents, end);
}
// MW Fixme: more?
bool convert_charset_only =
MsgLowerCaseEqualsLiteral(name, "to") || MsgLowerCaseEqualsLiteral(name, "from") ||
MsgLowerCaseEqualsLiteral(name, "cc") || MsgLowerCaseEqualsLiteral(name, "bcc") ||
MsgLowerCaseEqualsLiteral(name, "reply-to") || MsgLowerCaseEqualsLiteral(name, "sender");
MimeHeaders_convert_header_value(opt, hdr_value, convert_charset_only);
// if we're saving as html, we need to convert headers from utf8 to message charset, if any
if (opt->format_out == nsMimeOutput::nsMimeMessageSaveAs && charset)
{
nsAutoCString convertedStr;
if (NS_SUCCEEDED(ConvertFromUnicode(charset, NS_ConvertUTF8toUTF16(hdr_value),
convertedStr)))
{
hdr_value = convertedStr;
}
}
if (attachment) {
if (NS_FAILED(mimeEmitterAddAttachmentField(opt, name.get(), hdr_value.get())))
status = -1;
}
else {
if (NS_FAILED(mimeEmitterAddHeaderField(opt, name.get(), hdr_value.get())))
status = -1;
}
if (status < 0) return status;
if (!wrote_any_p)
wrote_any_p = (status > 0);
}
mimeEmitterAddAllHeaders(opt, hdrs->all_headers, hdrs->all_headers_fp);
PR_FREEIF(charset);
return 1;
}
/* Strip CR+LF runs within (original).
Since the string at (original) can only shrink,
this conversion is done in place. (original)
is returned. */
extern "C" char *
MIME_StripContinuations(char *original)
{
char *p1, *p2;
/* If we were given a null string, return it as is */
if (!original) return NULL;
/* Start source and dest pointers at the beginning */
p1 = p2 = original;
while (*p2) {
/* p2 runs ahead at (CR and/or LF) */
if ((p2[0] == '\r') || (p2[0] == '\n'))
p2++;
else if (p2 > p1)
*p1++ = *p2++;
else {
p1++;
p2++;
}
}
*p1 = '\0';
return original;
}
extern int16_t INTL_DefaultMailToWinCharSetID(int16_t csid);
/* Given text purporting to be a qtext header value, strip backslashes that
may be escaping other chars in the string. */
char *
mime_decode_filename(const char *name, const char *charset,
MimeDisplayOptions *opt)
{
nsresult rv;
nsCOMPtr <nsIMIMEHeaderParam> mimehdrpar =
do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
if (NS_FAILED(rv))
return nullptr;
nsAutoCString result;
rv = mimehdrpar->DecodeParameter(nsDependentCString(name), charset,
opt ? opt->default_charset : nullptr,
opt ? opt->override_charset : false,
result);
return NS_SUCCEEDED(rv) ? PL_strdup(result.get()) : nullptr;
}
/* Pull the name out of some header or another. Order is:
Content-Disposition: XXX; filename=NAME (RFC 1521/1806)
Content-Type: XXX; name=NAME (RFC 1341)
Content-Name: NAME (no RFC, but seen to occur)
X-Sun-Data-Name: NAME (no RFC, but used by MailTool)
*/
char *
MimeHeaders_get_name(MimeHeaders *hdrs, MimeDisplayOptions *opt)
{
char *s = 0, *name = 0, *cvt = 0;
char *charset = nullptr; // for RFC2231 support
s = MimeHeaders_get(hdrs, HEADER_CONTENT_DISPOSITION, false, false);
if (s)
{
name = MimeHeaders_get_parameter(s, HEADER_PARM_FILENAME, &charset, NULL);
PR_Free(s);
}
if (! name)
{
s = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, false, false);
if (s)
{
free(charset);
name = MimeHeaders_get_parameter(s, HEADER_PARM_NAME, &charset, NULL);
PR_Free(s);
}
}
if (! name)
name = MimeHeaders_get (hdrs, HEADER_CONTENT_NAME, false, false);
if (! name)
name = MimeHeaders_get (hdrs, HEADER_X_SUN_DATA_NAME, false, false);
if (name)
{
/* First remove continuation delimiters (CR+LF+space), then
remove escape ('\\') characters, then attempt to decode
mime-2 encoded-words. The latter two are done in
mime_decode_filename.
*/
MIME_StripContinuations(name);
/* Argh. What we should do if we want to be robust is to decode qtext
in all appropriate headers. Unfortunately, that would be too scary
at this juncture. So just decode qtext/mime2 here. */
cvt = mime_decode_filename(name, charset, opt);
free(charset);
if (cvt && cvt != name)
{
PR_Free(name);
name = cvt;
}
}
return name;
}
#ifdef XP_UNIX
/* This piece of junk is so that I can use BBDB with Mozilla.
= Put bbdb-srv.perl on your path.
= Put bbdb-srv.el on your lisp path.
= Make sure gnudoit (comes with xemacs) is on your path.
= Put (gnuserv-start) in ~/.emacs
= setenv NS_MSG_DISPLAY_HOOK bbdb-srv.perl
*/
void
MimeHeaders_do_unix_display_hook_hack(MimeHeaders *hdrs)
{
static const char *cmd = 0;
if (!cmd)
{
/* The first time we're invoked, look up the command in the
environment. Use "" as the `no command' tag. */
cmd = getenv("NS_MSG_DISPLAY_HOOK");
if (!cmd)
cmd = "";
}
/* Invoke "cmd" at the end of a pipe, and give it the headers on stdin.
The command is expected to be safe from hostile input!!
*/
if (cmd && *cmd)
{
FILE *fp = popen(cmd, "w");
if (fp)
{
fwrite(hdrs->all_headers, 1, hdrs->all_headers_fp, fp);
pclose(fp);
}
}
}
#endif /* XP_UNIX */
static void
MimeHeaders_compact (MimeHeaders *hdrs)
{
NS_ASSERTION(hdrs, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
if (!hdrs) return;
PR_FREEIF(hdrs->obuffer);
hdrs->obuffer_fp = 0;
hdrs->obuffer_size = 0;
/* These really shouldn't have gotten out of whack again. */
NS_ASSERTION(hdrs->all_headers_fp <= hdrs->all_headers_size &&
hdrs->all_headers_fp + 100 > hdrs->all_headers_size, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
}
/* Writes the headers as text/plain.
This writes out a blank line after the headers, unless
dont_write_content_type is true, in which case the header-block
is not closed off, and none of the Content- headers are written.
*/
int
MimeHeaders_write_raw_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt,
bool dont_write_content_type)
{
int status;
if (hdrs && !hdrs->done_p)
{
hdrs->done_p = true;
status = MimeHeaders_build_heads_list(hdrs);
if (status < 0) return 0;
}
if (!dont_write_content_type)
{
char nl[] = MSG_LINEBREAK;
if (hdrs)
{
status = MimeHeaders_write(hdrs, opt, hdrs->all_headers,
hdrs->all_headers_fp);
if (status < 0) return status;
}
status = MimeHeaders_write(hdrs, opt, nl, strlen(nl));
if (status < 0) return status;
}
else if (hdrs)
{
int32_t i;
for (i = 0; i < hdrs->heads_size; i++)
{
char *head = hdrs->heads[i];
char *end = (i == hdrs->heads_size-1
? hdrs->all_headers + hdrs->all_headers_fp
: hdrs->heads[i+1]);
NS_ASSERTION(head, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
if (!head) continue;
/* Don't write out any Content- header. */
if (!PL_strncasecmp(head, "Content-", 8))
continue;
/* Write out this (possibly multi-line) header. */
status = MimeHeaders_write(hdrs, opt, head, end - head);
if (status < 0) return status;
}
}
if (hdrs)
MimeHeaders_compact(hdrs);
return 0;
}
// XXX Fix this XXX //
char *
MimeHeaders_open_crypto_stamp(void)
{
return nullptr;
}
char *
MimeHeaders_finish_open_crypto_stamp(void)
{
return nullptr;
}
char *
MimeHeaders_close_crypto_stamp(void)
{
return nullptr;
}
char *
MimeHeaders_make_crypto_stamp(bool encrypted_p,
bool signed_p,
bool good_p,
bool unverified_p,
bool close_parent_stamp_p,
const char *stamp_url)
{
return nullptr;
}

View file

@ -0,0 +1,88 @@
/* -*- 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/. */
#ifndef _MIMEHDRS_H_
#define _MIMEHDRS_H_
#include "modlmime.h"
/* This file defines the interface to message-header parsing and formatting
code, including conversion to HTML. */
/* Other structs defined later in this file.
*/
/* Creation and destruction.
*/
extern MimeHeaders *MimeHeaders_new (void);
//extern void MimeHeaders_free (MimeHeaders *);
//extern MimeHeaders *MimeHeaders_copy (MimeHeaders *);
/* Feed this method the raw data from which you would like a header
block to be parsed, one line at a time. Feed it a blank line when
you're done. Returns negative on allocation-related failure.
*/
extern int MimeHeaders_parse_line (const char *buffer, int32_t size,
MimeHeaders *hdrs);
/* Converts a MimeHeaders object into HTML, by writing to the provided
output function.
*/
extern int MimeHeaders_write_headers_html (MimeHeaders *hdrs,
MimeDisplayOptions *opt,
bool attachment);
/*
* Writes all headers to the mime emitter.
*/
extern int
MimeHeaders_write_all_headers (MimeHeaders *, MimeDisplayOptions *, bool);
/* Writes the headers as text/plain.
This writes out a blank line after the headers, unless
dont_write_content_type is true, in which case the header-block
is not closed off, and none of the Content- headers are written.
*/
extern int MimeHeaders_write_raw_headers (MimeHeaders *hdrs,
MimeDisplayOptions *opt,
bool dont_write_content_type);
/* Some crypto-related HTML-generated utility routines.
* XXX This may not be needed. XXX
*/
extern char *MimeHeaders_open_crypto_stamp(void);
extern char *MimeHeaders_finish_open_crypto_stamp(void);
extern char *MimeHeaders_close_crypto_stamp(void);
extern char *MimeHeaders_make_crypto_stamp(bool encrypted_p,
bool signed_p,
bool good_p,
bool unverified_p,
bool close_parent_stamp_p,
const char *stamp_url);
/* Does all the heuristic silliness to find the filename in the given headers.
*/
extern char *MimeHeaders_get_name(MimeHeaders *hdrs, MimeDisplayOptions *opt);
extern char *mime_decode_filename(const char *name, const char* charset,
MimeDisplayOptions *opt);
extern "C" char * MIME_StripContinuations(char *original);
/**
* Convert this value to a unicode string, based on the charset.
*/
extern void MimeHeaders_convert_header_value(MimeDisplayOptions *opt,
nsCString &value,
bool convert_charset_only);
#endif /* _MIMEHDRS_H_ */

1920
mailnews/mime/src/mimei.cpp Normal file

File diff suppressed because it is too large Load diff

422
mailnews/mime/src/mimei.h Normal file
View file

@ -0,0 +1,422 @@
/* -*- 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/. */
#ifndef _MIMEI_H_
#define _MIMEI_H_
/*
This module, libmime, implements a general-purpose MIME parser.
One of the methods provided by this parser is the ability to emit
an HTML representation of it.
All Mozilla-specific code is (and should remain) isolated in the
file mimemoz.c. Generally, if the code involves images, netlib
streams it should be in mimemoz.c instead of in the main body of
the MIME parser.
The parser is object-oriented and fully buzzword-compliant.
There is a class for each MIME type, and each class is responsible
for parsing itself, and/or handing the input data off to one of its
child objects.
The class hierarchy is:
MimeObject (abstract)
|
+--- MimeContainer (abstract)
| |
| +--- MimeMultipart (abstract)
| | |
| | +--- MimeMultipartMixed
| | |
| | +--- MimeMultipartDigest
| | |
| | +--- MimeMultipartParallel
| | |
| | +--- MimeMultipartAlternative
| | |
| | +--- MimeMultipartRelated
| | |
| | +--- MimeMultipartAppleDouble
| | |
| | +--- MimeSunAttachment
| | |
| | \--- MimeMultipartSigned (abstract)
| | |
| | \--- MimeMultipartSignedCMS
| |
| +--- MimeEncrypted (abstract)
| | |
| | \--- MimeEncryptedPKCS7
| |
| +--- MimeXlateed (abstract)
| | |
| | \--- MimeXlateed
| |
| +--- MimeMessage
| |
| \--- MimeUntypedText
|
+--- MimeLeaf (abstract)
| |
| +--- MimeInlineText (abstract)
| | |
| | +--- MimeInlineTextPlain
| | | |
| | | \--- MimeInlineTextHTMLAsPlaintext
| | |
| | +--- MimeInlineTextPlainFlowed
| | |
| | +--- MimeInlineTextHTML
| | | |
| | | +--- MimeInlineTextHTMLParsed
| | | |
| | | \--- MimeInlineTextHTMLSanitized
| | |
| | +--- MimeInlineTextRichtext
| | | |
| | | \--- MimeInlineTextEnriched
| | |
| | +--- MimeInlineTextVCard
| |
| +--- MimeInlineImage
| |
| \--- MimeExternalObject
|
\--- MimeExternalBody
=========================================================================
The definition of these classes is somewhat idiosyncratic, since I defined
my own small object system, instead of giving the C++ virus another foothold.
(I would have liked to have written this in Java, but our runtime isn't
quite ready for prime time yet.)
There is one header file and one source file for each class (for example,
the MimeInlineText class is defined in "mimetext.h" and "mimetext.c".)
Each header file follows the following boiler-plate form:
TYPEDEFS: these come first to avoid circular dependencies.
typedef struct FoobarClass FoobarClass;
typedef struct Foobar Foobar;
CLASS DECLARATION:
Theis structure defines the callback routines and other per-class data
of the class defined in this module.
struct FoobarClass {
ParentClass superclass;
...any callbacks or class-variables...
};
CLASS DEFINITION:
This variable holds an instance of the one-and-only class record; the
various instances of this class point to this object. (One interrogates
the type of an instance by comparing the value of its class pointer with
the address of this variable.)
extern FoobarClass foobarClass;
INSTANCE DECLARATION:
Theis structure defines the per-instance data of an object, and a pointer
to the corresponding class record.
struct Foobar {
Parent parent;
...any instance variables...
};
Then, in the corresponding .c file, the following structure is used:
CLASS DEFINITION:
First we pull in the appropriate include file (which includes all necessary
include files for the parent classes) and then we define the class object
using the MimeDefClass macro:
#include "foobar.h"
#define MIME_SUPERCLASS parentlClass
MimeDefClass(Foobar, FoobarClass, foobarClass, &MIME_SUPERCLASS);
The definition of MIME_SUPERCLASS is just to move most of the knowlege of the
exact class hierarchy up to the file's header, instead of it being scattered
through the various methods; see below.
METHOD DECLARATIONS:
We will be putting function pointers into the class object, so we declare
them here. They can generally all be static, since nobody outside of this
file needs to reference them by name; all references to these routines should
be through the class object.
extern int FoobarMethod(Foobar *);
...etc...
CLASS INITIALIZATION FUNCTION:
The MimeDefClass macro expects us to define a function which will finish up
any initialization of the class object that needs to happen before the first
time it is instantiated. Its name must be of the form "<class>Initialize",
and it should initialize the various method slots in the class as
appropriate. Any methods or class variables which this class does not wish
to override will be automatically inherited from the parent class (by virtue
of its class-initialization function having been run first.) Each class
object will only be initialized once.
static int
FoobarClassInitialize(FoobarClass *class)
{
clazz->method = FoobarMethod.
...etc...
}
METHOD DEFINITIONS:
Next come the definitions of the methods we referred to in the class-init
function. The way to access earlier methods (methods defined on the
superclass) is to simply extract them from the superclass's object.
But note that you CANNOT get at methods by indirecting through
object->clazz->superclass: that will only work to one level, and will
go into a loop if some subclass tries to continue on this method.
The easiest way to do this is to make use of the MIME_SUPERCLASS macro that
was defined at the top of the file, as shown below. The alternative to that
involves typing the literal name of the direct superclass of the class
defined in this file, which will be a maintenance headache if the class
hierarchy changes. If you use the MIME_SUPERCLASS idiom, then a textual
change is required in only one place if this class's superclass changes.
static void
Foobar_finalize (MimeObject *object)
{
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object); // RIGHT
parentClass.whatnot.object.finalize(object); // (works...)
object->clazz->superclass->finalize(object); // WRONG!!
}
If you write a libmime content type handler, libmime might create several
instances of your class at once and call e.g. the same finalize code for
3 different objects in a row.
*/
#include "mimehdrs.h"
#include "nsTArray.h"
typedef struct MimeObject MimeObject;
typedef struct MimeObjectClass MimeObjectClass;
#ifdef ENABLE_SMIME
class nsICMSMessage;
#endif // ENABLE_SMIME
/* (I don't pretend to understand this.) */
#define cpp_stringify_noop_helper(x)#x
#define cpp_stringify(x) cpp_stringify_noop_helper(x)
#define MimeObjectClassInitializer(ITYPE,CSUPER) \
cpp_stringify(ITYPE), \
sizeof(ITYPE), \
(MimeObjectClass *) CSUPER, \
(int (*) (MimeObjectClass *)) ITYPE##ClassInitialize, \
0
/* Macro used for setting up class definitions.
*/
#define MimeDefClass(ITYPE,CTYPE,CVAR,CSUPER) \
static int ITYPE##ClassInitialize(ITYPE##Class *); \
ITYPE##Class CVAR = { ITYPE##ClassInitializer(ITYPE,CSUPER) }
/* Creates a new (subclass of) MimeObject of the given class, with the
given headers (which are copied.)
*/
extern MimeObject *mime_new (MimeObjectClass *clazz, MimeHeaders *hdrs,
const char *override_content_type);
/* Destroys a MimeObject (or subclass) and all data associated with it.
*/
extern "C" void mime_free (MimeObject *object);
/* Given a content-type string, finds and returns an appropriate subclass
of MimeObject. A class object is returned. If `exact_match_p' is true,
then only fully-known types will be returned; that is, if it is true,
then "text/x-unknown" will return MimeInlineTextPlainType, but if it is
false, it will return NULL.
*/
extern MimeObjectClass *mime_find_class (const char *content_type,
MimeHeaders *hdrs,
MimeDisplayOptions *opts,
bool exact_match_p);
/** Given a content-type string, creates and returns an appropriate subclass
* of MimeObject. The headers (from which the content-type was presumably
* extracted) are copied. forceInline is set to true when the caller wants
* the function to ignore opts->show_attachment_inline_p and force inline
* display, e.g., mimemalt wants the body part to be shown inline.
*/
extern MimeObject *mime_create (const char *content_type, MimeHeaders *hdrs,
MimeDisplayOptions *opts, bool forceInline = false);
/* Querying the type hierarchy */
extern bool mime_subclass_p(MimeObjectClass *child,
MimeObjectClass *parent);
extern bool mime_typep(MimeObject *obj, MimeObjectClass *clazz);
/* Returns a string describing the location of the part (like "2.5.3").
This is not a full URL, just a part-number.
*/
extern char *mime_part_address(MimeObject *obj);
/* Returns a string describing the location of the *IMAP* part (like "2.5.3").
This is not a full URL, just a part-number.
This part is explicitly passed in the X-Mozilla-IMAP-Part header.
Return value must be freed by the caller.
*/
extern char *mime_imap_part_address(MimeObject *obj);
extern char *mime_external_attachment_url(MimeObject *obj);
/* Puts a part-number into a URL. If append_p is true, then the part number
is appended to any existing part-number already in that URL; otherwise,
it replaces it.
*/
extern char *mime_set_url_part(const char *url, const char *part, bool append_p);
/*
cut the part of url for display a attachment as a email.
*/
extern char *mime_get_base_url(const char *url);
/* Puts an *IMAP* part-number into a URL.
*/
extern char *mime_set_url_imap_part(const char *url, const char *part, const char *libmimepart);
/* Given a part ID, looks through the MimeObject tree for a sub-part whose ID
number matches, and returns the MimeObject (else NULL.)
(part is not a URL -- it's of the form "1.3.5".)
*/
extern MimeObject *mime_address_to_part(const char *part, MimeObject *obj);
/* Given a part ID, looks through the MimeObject tree for a sub-part whose ID
number matches; if one is found, returns the Content-Name of that part.
Else returns NULL. (part is not a URL -- it's of the form "1.3.5".)
*/
extern char *mime_find_suggested_name_of_part(const char *part,
MimeObject *obj);
/* Given a part ID, looks through the MimeObject tree for a sub-part whose ID
number matches; if one is found, returns the Content-Name of that part.
Else returns NULL. (part is not a URL -- it's of the form "1.3.5".)
*/
extern char *mime_find_content_type_of_part(const char *part, MimeObject *obj);
/* Parse the various "?" options off the URL and into the options struct.
*/
extern int mime_parse_url_options(const char *url, MimeDisplayOptions *);
#ifdef ENABLE_SMIME
/* Asks whether the given object is one of the cryptographically signed
or encrypted objects that we know about. (MimeMessageClass uses this
to decide if the headers need to be presented differently.)
*/
extern bool mime_crypto_object_p(MimeHeaders *, bool clearsigned_counts, MimeDisplayOptions *);
/* Tells whether the given MimeObject is a message which has been encrypted
or signed. (Helper for MIME_GetMessageCryptoState()).
*/
extern void mime_get_crypto_state (MimeObject *obj,
bool *signed_p, bool *encrypted_p,
bool *signed_ok, bool *encrypted_ok);
/* Whether the given object has written out the HTML version of its headers
in such a way that it will have a "crypto stamp" next to the headers. If
this is true, then the child must write out its HTML slightly differently
to take this into account...
*/
extern bool mime_crypto_stamped_p(MimeObject *obj);
/* How the crypto code tells the MimeMessage object what the crypto stamp
on it says. */
extern void mime_set_crypto_stamp(MimeObject *obj,
bool signed_p, bool encrypted_p);
#endif // ENABLE_SMIME
class MimeParseStateObject {
public:
MimeParseStateObject()
{root = 0; separator_queued_p = false; separator_suppressed_p = false;
first_part_written_p = false; post_header_html_run_p = false; first_data_written_p = false;
decrypted_p = false; strippingPart = false;
}
MimeObject *root; /* The outermost parser object. */
bool separator_queued_p; /* Whether a separator should be written out
before the next text is written (this lets
us write separators lazily, so that one
doesn't appear at the end, and so that more
than one don't appear in a row.) */
bool separator_suppressed_p; /* Whether the currently-queued separator
should not be printed; this is a kludge to
prevent seps from being printed just after
a header block... */
bool first_part_written_p; /* State used for the `Show Attachments As
Links' kludge. */
bool post_header_html_run_p; /* Whether we've run the
options->generate_post_header_html_fn */
bool first_data_written_p; /* State used for Mozilla lazy-stream-
creation evilness. */
bool decrypted_p; /* If options->dexlate_p is true, then this
will be set to indicate whether any
dexlateion did in fact occur.
*/
nsTArray<nsCString> partsToStrip; /* if we're stripping parts, what parts to strip */
nsTArray<nsCString> detachToFiles; /* if we're detaching parts, where each part was detached to */
bool strippingPart;
nsCString detachedFilePath; /* if we've detached this part, filepath of detached part */
};
/* Some output-generation utility functions...
*/
extern int MimeObject_output_init(MimeObject *obj, const char *content_type);
/* The `user_visible_p' argument says whether the output that has just been
written will cause characters or images to show up on the screen, that
is, it should be false if the stuff being written is merely structural
HTML or whitespace ("<P>", "</TABLE>", etc.) This information is used
when making the decision of whether a separating <HR> is needed.
*/
extern int MimeObject_write(MimeObject *, const char *data, int32_t length,
bool user_visible_p);
extern int MimeOptions_write(MimeHeaders *,
MimeDisplayOptions *,
const char *data, int32_t length,
bool user_visible_p);
/* Writes out the right kind of HR (or rather, queues it for writing.) */
extern int MimeObject_write_separator(MimeObject *);
extern bool MimeObjectIsMessageBody(MimeObject *obj);
struct MimeDisplayData { /* This struct is what we hang off of
(context)->mime_data, to remember info
about the last MIME object we've
parsed and displayed. See
MimeGuessURLContentName() below.
*/
MimeObject *last_parsed_object;
char *last_parsed_url;
};
#endif /* _MIMEI_H_ */

View file

@ -0,0 +1,249 @@
/* -*- 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/. */
#include "nsCOMPtr.h"
#include "mimeiimg.h"
#include "mimemoz2.h"
#include "prmem.h"
#include "plstr.h"
#include "prlog.h"
#include "nsMimeTypes.h"
#include "nsMimeStringResources.h"
#include "nsINetUtil.h"
#include "nsMsgUtils.h"
#define MIME_SUPERCLASS mimeLeafClass
MimeDefClass(MimeInlineImage, MimeInlineImageClass,
mimeInlineImageClass, &MIME_SUPERCLASS);
static int MimeInlineImage_initialize (MimeObject *);
static void MimeInlineImage_finalize (MimeObject *);
static int MimeInlineImage_parse_begin (MimeObject *);
static int MimeInlineImage_parse_line (const char *, int32_t, MimeObject *);
static int MimeInlineImage_parse_eof (MimeObject *, bool);
static int MimeInlineImage_parse_decoded_buffer (const char *, int32_t, MimeObject *);
static int
MimeInlineImageClassInitialize(MimeInlineImageClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
MimeLeafClass *lclass = (MimeLeafClass *) clazz;
NS_ASSERTION(!oclass->class_initialized, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
oclass->initialize = MimeInlineImage_initialize;
oclass->finalize = MimeInlineImage_finalize;
oclass->parse_begin = MimeInlineImage_parse_begin;
oclass->parse_line = MimeInlineImage_parse_line;
oclass->parse_eof = MimeInlineImage_parse_eof;
lclass->parse_decoded_buffer = MimeInlineImage_parse_decoded_buffer;
return 0;
}
static int
MimeInlineImage_initialize (MimeObject *object)
{
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
}
static void
MimeInlineImage_finalize (MimeObject *object)
{
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
}
static int
MimeInlineImage_parse_begin (MimeObject *obj)
{
MimeInlineImage *img = (MimeInlineImage *) obj;
int status;
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
if (status < 0) return status;
if (!obj->output_p) return 0;
if (!obj->options || !obj->options->output_fn ||
// don't bother processing if the consumer doesn't want us
// gunking the body up.
obj->options->write_pure_bodies)
return 0;
if (obj->options &&
obj->options->image_begin &&
obj->options->write_html_p &&
obj->options->image_write_buffer)
{
char *html, *part, *image_url;
const char *ct;
part = mime_part_address(obj);
if (!part) return MIME_OUT_OF_MEMORY;
char *no_part_url = nullptr;
if (obj->options->part_to_load && obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay)
no_part_url = mime_get_base_url(obj->options->url);
if (no_part_url)
{
image_url = mime_set_url_part(no_part_url, part, true);
PR_Free(no_part_url);
}
else
image_url = mime_set_url_part(obj->options->url, part, true);
if (!image_url)
{
PR_Free(part);
return MIME_OUT_OF_MEMORY;
}
PR_Free(part);
ct = obj->content_type;
if (!ct) ct = IMAGE_GIF; /* Can't happen? Close enough. */
// Fill in content type and attachment name here.
nsAutoCString url_with_filename(image_url);
url_with_filename += "&type=";
url_with_filename += ct;
char * filename = MimeHeaders_get_name ( obj->headers, obj->options );
if (filename)
{
nsCString escapedName;
MsgEscapeString(nsDependentCString(filename), nsINetUtil::ESCAPE_URL_PATH,
escapedName);
url_with_filename += "&filename=";
url_with_filename += escapedName;
PR_Free(filename);
}
// We need to separate images with HR's...
MimeObject_write_separator(obj);
img->image_data =
obj->options->image_begin(url_with_filename.get(), ct, obj->options->stream_closure);
PR_Free(image_url);
if (!img->image_data) return MIME_OUT_OF_MEMORY;
html = obj->options->make_image_html(img->image_data);
if (!html) return MIME_OUT_OF_MEMORY;
status = MimeObject_write(obj, html, strlen(html), true);
PR_Free(html);
if (status < 0) return status;
}
//
// Now we are going to see if we should set the content type in the
// URI for the url being run...
//
if (obj->options && obj->options->stream_closure && obj->content_type)
{
mime_stream_data *msd = (mime_stream_data *) (obj->options->stream_closure);
if ( (msd) && (msd->channel) )
{
msd->channel->SetContentType(nsDependentCString(obj->content_type));
}
}
return 0;
}
static int
MimeInlineImage_parse_eof (MimeObject *obj, bool abort_p)
{
MimeInlineImage *img = (MimeInlineImage *) obj;
int status;
if (obj->closed_p) return 0;
/* Force out any buffered data from the superclass (the base64 decoder.) */
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
if (status < 0) abort_p = true;
if (img->image_data)
{
obj->options->image_end(img->image_data,
(status < 0 ? status : (abort_p ? -1 : 0)));
img->image_data = 0;
}
return status;
}
static int
MimeInlineImage_parse_decoded_buffer (const char *buf, int32_t size, MimeObject *obj)
{
/* This is called (by MimeLeafClass->parse_buffer) with blocks of data
that have already been base64-decoded. Pass this raw image data
along to the backend-specific image display code.
*/
MimeInlineImage *img = (MimeInlineImage *) obj;
int status;
/* Don't do a roundtrip through XPConnect when we're only interested in
* metadata and size. 0 means ok, the caller just checks for negative return
* value
*/
if (obj->options && obj->options->metadata_only)
return 0;
if (obj->output_p &&
obj->options &&
!obj->options->write_html_p)
{
/* in this case, we just want the raw data...
Make the stream, if it's not made, and dump the data out.
*/
if (!obj->options->state->first_data_written_p)
{
status = MimeObject_output_init(obj, 0);
if (status < 0) return status;
NS_ASSERTION(obj->options->state->first_data_written_p, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
}
return MimeObject_write(obj, buf, size, true);
}
if (!obj->options ||
!obj->options->image_write_buffer)
return 0;
/* If we don't have any image data, the image_end method must have already
been called, so don't call image_write_buffer again. */
if (!img->image_data) return 0;
/* Hand this data off to the backend-specific image display stream.
*/
status = obj->options->image_write_buffer (buf, size, img->image_data);
/* If the image display stream fails, then close the stream - but do not
return the failure status, and do not give up on parsing this object.
Just because the image data was corrupt doesn't mean we need to give up
on the whole document; we can continue by just skipping over the rest of
this part, and letting our parent continue.
*/
if (status < 0)
{
obj->options->image_end (img->image_data, status);
img->image_data = 0;
status = 0;
}
return status;
}
static int
MimeInlineImage_parse_line (const char *line, int32_t length, MimeObject *obj)
{
NS_ERROR("This method should never be called (inline images do no line buffering).");
return -1;
}

View file

@ -0,0 +1,35 @@
/* -*- 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/. */
#ifndef _MIMEIIMG_H_
#define _MIMEIIMG_H_
#include "mimeleaf.h"
/* The MimeInlineImage class implements those MIME image types which can be
displayed inline.
*/
typedef struct MimeInlineImageClass MimeInlineImageClass;
typedef struct MimeInlineImage MimeInlineImage;
struct MimeInlineImageClass {
MimeLeafClass leaf;
};
extern MimeInlineImageClass mimeInlineImageClass;
struct MimeInlineImage {
MimeLeaf leaf;
/* Opaque data object for the backend-specific inline-image-display code
(internal-external-reconnect nastiness.) */
void *image_data;
};
#define MimeInlineImageClassInitializer(ITYPE,CSUPER) \
{ MimeLeafClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEIIMG_H_ */

View file

@ -0,0 +1,221 @@
/* -*- 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/. */
#include "modmimee.h"
#include "mimeleaf.h"
#include "nsMimeTypes.h"
#include "prmem.h"
#include "plstr.h"
#include "prlog.h"
#include "nsMimeStringResources.h"
#define MIME_SUPERCLASS mimeObjectClass
MimeDefClass(MimeLeaf, MimeLeafClass, mimeLeafClass, &MIME_SUPERCLASS);
static int MimeLeaf_initialize (MimeObject *);
static void MimeLeaf_finalize (MimeObject *);
static int MimeLeaf_parse_begin (MimeObject *);
static int MimeLeaf_parse_buffer (const char *, int32_t, MimeObject *);
static int MimeLeaf_parse_line (const char *, int32_t, MimeObject *);
static int MimeLeaf_close_decoder (MimeObject *);
static int MimeLeaf_parse_eof (MimeObject *, bool);
static bool MimeLeaf_displayable_inline_p (MimeObjectClass *clazz,
MimeHeaders *hdrs);
static int
MimeLeafClassInitialize(MimeLeafClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
NS_ASSERTION(!oclass->class_initialized, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
oclass->initialize = MimeLeaf_initialize;
oclass->finalize = MimeLeaf_finalize;
oclass->parse_begin = MimeLeaf_parse_begin;
oclass->parse_buffer = MimeLeaf_parse_buffer;
oclass->parse_line = MimeLeaf_parse_line;
oclass->parse_eof = MimeLeaf_parse_eof;
oclass->displayable_inline_p = MimeLeaf_displayable_inline_p;
clazz->close_decoder = MimeLeaf_close_decoder;
/* Default `parse_buffer' method is one which line-buffers the now-decoded
data and passes it on to `parse_line'. (We snarf the implementation of
this method from our superclass's implementation of `parse_buffer', which
inherited it from MimeObject.)
*/
clazz->parse_decoded_buffer =
((MimeObjectClass*)&MIME_SUPERCLASS)->parse_buffer;
return 0;
}
static int
MimeLeaf_initialize (MimeObject *obj)
{
/* This is an abstract class; it shouldn't be directly instantiated. */
NS_ASSERTION(obj->clazz != (MimeObjectClass *) &mimeLeafClass, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
// Initial size is -1 (meaning "unknown size") - we'll correct it in
// parse_buffer.
MimeLeaf *leaf = (MimeLeaf *) obj;
leaf->sizeSoFar = -1;
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj);
}
static void
MimeLeaf_finalize (MimeObject *object)
{
MimeLeaf *leaf = (MimeLeaf *)object;
object->clazz->parse_eof (object, false);
/* Free the decoder data, if it's still around. It was probably freed
in MimeLeaf_parse_eof(), but just in case... */
if (leaf->decoder_data)
{
MimeDecoderDestroy(leaf->decoder_data, true);
leaf->decoder_data = 0;
}
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize (object);
}
static int
MimeLeaf_parse_begin (MimeObject *obj)
{
MimeLeaf *leaf = (MimeLeaf *) obj;
MimeDecoderData *(*fn) (MimeConverterOutputCallback, void*) = 0;
/* Initialize a decoder if necessary.
*/
if (!obj->encoding ||
// If we need the object as "raw" for saving or forwarding,
// don't decode text parts of message types. Other output formats,
// like "display" (nsMimeMessageBodyDisplay), need decoding.
(obj->options->format_out == nsMimeOutput::nsMimeMessageRaw &&
obj->parent &&
(!PL_strcasecmp(obj->parent->content_type, MESSAGE_NEWS) ||
!PL_strcasecmp(obj->parent->content_type, MESSAGE_RFC822)) &&
!PL_strncasecmp(obj->content_type, "text/", 5)))
/* no-op */ ;
else if (!PL_strcasecmp(obj->encoding, ENCODING_BASE64))
fn = &MimeB64DecoderInit;
else if (!PL_strcasecmp(obj->encoding, ENCODING_QUOTED_PRINTABLE))
leaf->decoder_data =
MimeQPDecoderInit(((MimeConverterOutputCallback)
((MimeLeafClass *)obj->clazz)->parse_decoded_buffer),
obj, obj);
else if (!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE) ||
!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE2) ||
!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE4))
fn = &MimeUUDecoderInit;
else if (!PL_strcasecmp(obj->encoding, ENCODING_YENCODE))
fn = &MimeYDecoderInit;
if (fn)
{
leaf->decoder_data =
fn (/* The MimeConverterOutputCallback cast is to turn the `void' argument
into `MimeObject'. */
((MimeConverterOutputCallback)
((MimeLeafClass *)obj->clazz)->parse_decoded_buffer),
obj);
if (!leaf->decoder_data)
return MIME_OUT_OF_MEMORY;
}
return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
}
static int
MimeLeaf_parse_buffer (const char *buffer, int32_t size, MimeObject *obj)
{
MimeLeaf *leaf = (MimeLeaf *) obj;
NS_ASSERTION(!obj->closed_p, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
if (obj->closed_p) return -1;
/* If we're not supposed to write this object, bug out now.
*/
if (!obj->output_p ||
!obj->options ||
!obj->options->output_fn)
return 0;
int rv;
if (leaf->sizeSoFar == -1)
leaf->sizeSoFar = 0;
if (leaf->decoder_data &&
obj->options &&
obj->options->format_out != nsMimeOutput::nsMimeMessageDecrypt
&& obj->options->format_out != nsMimeOutput::nsMimeMessageAttach) {
int outSize = 0;
rv = MimeDecoderWrite (leaf->decoder_data, buffer, size, &outSize);
leaf->sizeSoFar += outSize;
}
else {
rv = ((MimeLeafClass *)obj->clazz)->parse_decoded_buffer (buffer, size,
obj);
leaf->sizeSoFar += size;
}
return rv;
}
static int
MimeLeaf_parse_line (const char *line, int32_t length, MimeObject *obj)
{
NS_ERROR("MimeLeaf_parse_line shouldn't ever be called.");
return -1;
}
static int
MimeLeaf_close_decoder (MimeObject *obj)
{
MimeLeaf *leaf = (MimeLeaf *) obj;
if (leaf->decoder_data)
{
int status = MimeDecoderDestroy(leaf->decoder_data, false);
leaf->decoder_data = 0;
return status;
}
return 0;
}
static int
MimeLeaf_parse_eof (MimeObject *obj, bool abort_p)
{
MimeLeaf *leaf = (MimeLeaf *) obj;
if (obj->closed_p) return 0;
/* Close off the decoder, to cause it to give up any buffered data that
it is still holding.
*/
if (leaf->decoder_data)
{
int status = MimeLeaf_close_decoder(obj);
if (status < 0) return status;
}
/* Now run the superclass's parse_eof, which will force out the line
buffer (which we may have just repopulated, above.)
*/
return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof (obj, abort_p);
}
static bool
MimeLeaf_displayable_inline_p (MimeObjectClass *clazz, MimeHeaders *hdrs)
{
return true;
}

View file

@ -0,0 +1,59 @@
/* -*- 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/. */
#ifndef _MIMELEAF_H_
#define _MIMELEAF_H_
#include "mimeobj.h"
#include "modmimee.h"
/* MimeLeaf is the class for the objects representing all MIME types which
are not containers for other MIME objects. The implication of this is
that they are MIME types which can have Content-Transfer-Encodings
applied to their data. This class provides that service in its
parse_buffer() method:
int (*parse_decoded_buffer) (const char *buf, int32_t size, MimeObject *obj)
The `parse_buffer' method of MimeLeaf passes each block of data through
the appropriate decoder (if any) and then calls `parse_decoded_buffer'
on each block (not line) of output.
The default `parse_decoded_buffer' method of MimeLeaf line-buffers the
now-decoded data, handing each line to the `parse_line' method in turn.
If different behavior is desired (for example, if a class wants access
to the decoded data before it is line-buffered) the `parse_decoded_buffer'
method should be overridden. (MimeExternalObject does this.)
*/
typedef struct MimeLeafClass MimeLeafClass;
typedef struct MimeLeaf MimeLeaf;
struct MimeLeafClass {
MimeObjectClass object;
/* This is the callback that is handed to the decoder. */
int (*parse_decoded_buffer) (const char *buf, int32_t size, MimeObject *obj);
int (*close_decoder) (MimeObject *obj);
};
extern MimeLeafClass mimeLeafClass;
struct MimeLeaf {
MimeObject object; /* superclass variables */
/* If we're doing Base64, Quoted-Printable, or UU decoding, this is the
state object for the decoder. */
MimeDecoderData *decoder_data;
/* We want to count the size of the MimeObject to offer consumers the
* opportunity to display the sizes of attachments.
*/
int sizeSoFar;
};
#define MimeLeafClassInitializer(ITYPE,CSUPER) \
{ MimeObjectClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMELEAF_H_ */

View file

@ -0,0 +1,580 @@
/* -*- 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/. */
/*
BACKGROUND
----------
At the simplest level, multipart/alternative means "pick one of these and
display it." However, it's actually a lot more complicated than that.
The alternatives are in preference order, and counterintuitively, they go
from *least* to *most* preferred rather than the reverse. Therefore, when
we're parsing, we can't just take the first one we like and throw the rest
away -- we have to parse through the whole thing, discarding the n'th part if
we are capable of displaying the n+1'th.
Adding a wrinkle to that is the fact that we give the user the option of
demanding the plain-text alternative even though we are perfectly capable of
displaying the HTML, and it is almost always the preferred format, i.e., it
almost always comes after the plain-text alternative.
Speaking of which, you can't assume that each of the alternatives is just a
basic text/[whatever]. There may be, for example, a text/plain followed by a
multipart/related which contains text/html and associated embedded
images. Yikes!
You also can't assume that there will be just two parts. There can be an
arbitrary number, and the ones we are capable of displaying and the ones we
aren't could be interspersed in any order by the producer of the MIME.
We can't just throw away the parts we're not displaying when we're processing
the MIME for display. If we were to do that, then the MIME parts that
remained wouldn't get numbered properly, and that would mean, for example,
that deleting attachments wouldn't work in some messages. Indeed, that very
problem is what prompted a rewrite of this file into its current
architecture.
ARCHITECTURE
------------
Parts are read and queued until we know whether we're going to display
them. If the first pending part is one we don't know how to display, then we
can add it to the MIME structure immediatelly, with output_p disabled. If the
first pending part is one we know how to display, then we can't add it to the
in-memory MIME structure until either (a) we encounter a later, more
preferred part we know how to display, or (b) we reach the end of the
parts. A display-capable part of the queue may be followed by one or more
display-incapable parts. We can't add them to the in-memory structure until
we figure out what to do with the first, display-capable pending part,
because otherwise the order and numbering will be wrong. All of the logic in
this paragraph is implemented in the flush_children function.
The display_cached_part function is what actually adds a MIME part to the
in-memory MIME structure. There is one complication there which forces us to
violate abstrations... Even if we set output_p on a child before adding it to
the parent, the parse_begin function resets it. The kluge I came up with to
prevent that was to give the child a separate options object and set
output_fn to nullptr in it, because that causes parse_begin to set output_p to
false. This seemed like the least onerous way to accomplish this, although I
can't say it's a solution I'm particularly fond of.
Another complication in display_cached_part is that if we were just a normal
multipart type, we could rely on MimeMultipart_parse_line to notify emitters
about content types, character sets, part numbers, etc. as our new children
get created. However, since we defer creation of some children, the
notification doesn't happen there, so we have to handle it
ourselves. Unfortunately, this requires a small abstraction violation in
MimeMultipart_parse_line -- we have to check there if the entity is
multipart/alternative and if so not notify emitters there because
MimeMultipartAlternative_create_child handles it.
- Jonathan Kamens, 2010-07-23
When the option prefer_plaintext is on, the last text/plain part
should be preferred over any other part that can be displayed. But
if no text/plain part is found, then the algorithm should go as
normal and convert any html part found to text. To achive this I
found that the simplest way was to change the function display_part_p
into returning priority as an integer instead of boolean can/can't
display. Then I also changed the function flush_children so it selects
the last part with the highest priority. (Priority 0 means it cannot
be displayed and the part is never choosen.)
- Terje Bråten, 2013-02-16
*/
#include "mimemalt.h"
#include "prmem.h"
#include "plstr.h"
#include "prlog.h"
#include "nsMimeTypes.h"
#include "nsMimeStringResources.h"
#include "nsIPrefBranch.h"
#include "mimemoz2.h" // for prefs
extern "C" MimeObjectClass mimeMultipartRelatedClass;
#define MIME_SUPERCLASS mimeMultipartClass
MimeDefClass(MimeMultipartAlternative, MimeMultipartAlternativeClass,
mimeMultipartAlternativeClass, &MIME_SUPERCLASS);
static int MimeMultipartAlternative_initialize (MimeObject *);
static void MimeMultipartAlternative_finalize (MimeObject *);
static int MimeMultipartAlternative_parse_eof (MimeObject *, bool);
static int MimeMultipartAlternative_create_child(MimeObject *);
static int MimeMultipartAlternative_parse_child_line (MimeObject *, const char *,
int32_t, bool);
static int MimeMultipartAlternative_close_child(MimeObject *);
static int MimeMultipartAlternative_flush_children(MimeObject *, bool, priority_t);
static priority_t MimeMultipartAlternative_display_part_p(MimeObject *self,
MimeHeaders *sub_hdrs);
static priority_t MimeMultipartAlternative_prioritize_part(char *content_type,
bool prefer_plaintext);
static int MimeMultipartAlternative_display_cached_part(MimeObject *,
MimeHeaders *,
MimePartBufferData *,
bool);
static int
MimeMultipartAlternativeClassInitialize(MimeMultipartAlternativeClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
MimeMultipartClass *mclass = (MimeMultipartClass *) clazz;
PR_ASSERT(!oclass->class_initialized);
oclass->initialize = MimeMultipartAlternative_initialize;
oclass->finalize = MimeMultipartAlternative_finalize;
oclass->parse_eof = MimeMultipartAlternative_parse_eof;
mclass->create_child = MimeMultipartAlternative_create_child;
mclass->parse_child_line = MimeMultipartAlternative_parse_child_line;
mclass->close_child = MimeMultipartAlternative_close_child;
return 0;
}
static int
MimeMultipartAlternative_initialize (MimeObject *obj)
{
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
NS_ASSERTION(!malt->part_buffers, "object initialized multiple times");
NS_ASSERTION(!malt->buffered_hdrs, "object initialized multiple times");
malt->pending_parts = 0;
malt->max_parts = 0;
malt->buffered_priority = PRIORITY_UNDISPLAYABLE;
malt->buffered_hdrs = nullptr;
malt->part_buffers = nullptr;
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj);
}
static void
MimeMultipartAlternative_cleanup(MimeObject *obj)
{
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
int32_t i;
for (i = 0; i < malt->pending_parts; i++) {
MimeHeaders_free(malt->buffered_hdrs[i]);
MimePartBufferDestroy(malt->part_buffers[i]);
}
PR_FREEIF(malt->buffered_hdrs);
PR_FREEIF(malt->part_buffers);
malt->pending_parts = 0;
malt->max_parts = 0;
}
static void
MimeMultipartAlternative_finalize (MimeObject *obj)
{
MimeMultipartAlternative_cleanup(obj);
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(obj);
}
static int
MimeMultipartAlternative_flush_children(MimeObject *obj,
bool finished,
priority_t next_priority)
{
/*
The cache should always have at the head the part with highest priority.
Possible states:
1. Cache contains nothing: do nothing.
2. Finished, and the cache contains one displayable body followed
by zero or more bodies with lower priority:
3. Finished, and the cache contains one non-displayable body:
create it with output off.
4. Not finished, and the cache contains one displayable body
followed by zero or more bodies with lower priority, and the new
body we're about to create is higher or equal priority:
create all cached bodies with output off.
5. Not finished, and the cache contains one displayable body
followed by zero or more bodies with lower priority, and the new
body we're about to create has lower priority: do nothing.
6. Not finished, and the cache contains one non-displayable body:
create it with output off.
*/
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
bool have_displayable, do_flush, do_display;
/* Case 1 */
if (! malt->pending_parts)
return 0;
have_displayable = (malt->buffered_priority > next_priority);
if (finished && have_displayable) {
/* Case 2 */
do_flush = true;
do_display = true;
}
else if (finished && ! have_displayable) {
/* Case 3 */
do_flush = true;
do_display = false;
}
else if (! finished && have_displayable) {
/* Case 5 */
do_flush = false;
do_display = false;
}
else if (! finished && ! have_displayable) {
/* Case 4 */
/* Case 6 */
do_flush = true;
do_display = false;
}
else {
NS_ERROR("mimemalt.cpp: logic error in flush_children");
return -1;
}
if (do_flush) {
int32_t i;
for (i = 0; i < malt->pending_parts; i++) {
MimeMultipartAlternative_display_cached_part(obj,
malt->buffered_hdrs[i],
malt->part_buffers[i],
do_display && (i == 0));
MimeHeaders_free(malt->buffered_hdrs[i]);
MimePartBufferDestroy(malt->part_buffers[i]);
}
malt->pending_parts = 0;
}
return 0;
}
static int
MimeMultipartAlternative_parse_eof (MimeObject *obj, bool abort_p)
{
int status = 0;
if (obj->closed_p) return 0;
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
if (status < 0) return status;
status = MimeMultipartAlternative_flush_children(obj, true,
PRIORITY_UNDISPLAYABLE);
if (status < 0)
return status;
MimeMultipartAlternative_cleanup(obj);
return status;
}
static int
MimeMultipartAlternative_create_child(MimeObject *obj)
{
MimeMultipart *mult = (MimeMultipart *) obj;
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
priority_t priority =
MimeMultipartAlternative_display_part_p (obj, mult->hdrs);
MimeMultipartAlternative_flush_children(obj, false, priority);
mult->state = MimeMultipartPartFirstLine;
int32_t i = malt->pending_parts++;
if (i==0) {
malt->buffered_priority = priority;
}
if (malt->pending_parts > malt->max_parts) {
malt->max_parts = malt->pending_parts;
MimeHeaders **newBuf = (MimeHeaders **)
PR_REALLOC(malt->buffered_hdrs,
malt->max_parts * sizeof(*malt->buffered_hdrs));
NS_ENSURE_TRUE(newBuf, MIME_OUT_OF_MEMORY);
malt->buffered_hdrs = newBuf;
MimePartBufferData **newBuf2 = (MimePartBufferData **)
PR_REALLOC(malt->part_buffers,
malt->max_parts * sizeof(*malt->part_buffers));
NS_ENSURE_TRUE(newBuf2, MIME_OUT_OF_MEMORY);
malt->part_buffers = newBuf2;
}
malt->buffered_hdrs[i] = MimeHeaders_copy(mult->hdrs);
NS_ENSURE_TRUE(malt->buffered_hdrs[i], MIME_OUT_OF_MEMORY);
malt->part_buffers[i] = MimePartBufferCreate();
NS_ENSURE_TRUE(malt->part_buffers[i], MIME_OUT_OF_MEMORY);
return 0;
}
static int
MimeMultipartAlternative_parse_child_line (MimeObject *obj,
const char *line, int32_t length,
bool first_line_p)
{
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
NS_ASSERTION(malt->pending_parts, "should be pending parts, but there aren't");
if (!malt->pending_parts)
return -1;
int32_t i = malt->pending_parts - 1;
/* Push this line into the buffer for later retrieval. */
return MimePartBufferWrite (malt->part_buffers[i], line, length);
}
static int
MimeMultipartAlternative_close_child(MimeObject *obj)
{
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
MimeMultipart *mult = (MimeMultipart *) obj;
/* PR_ASSERT(malt->part_buffer); Some Mac brokenness trips this...
if (!malt->part_buffer) return -1; */
if (malt->pending_parts)
MimePartBufferClose(malt->part_buffers[malt->pending_parts-1]);
/* PR_ASSERT(mult->hdrs); I expect the Mac trips this too */
if (mult->hdrs) {
MimeHeaders_free(mult->hdrs);
mult->hdrs = 0;
}
return 0;
}
static priority_t
MimeMultipartAlternative_display_part_p(MimeObject *self,
MimeHeaders *sub_hdrs)
{
priority_t priority = PRIORITY_UNDISPLAYABLE;
char *ct = MimeHeaders_get (sub_hdrs, HEADER_CONTENT_TYPE, true, false);
if (!ct)
return priority;
/* RFC 1521 says:
Receiving user agents should pick and display the last format
they are capable of displaying. In the case where one of the
alternatives is itself of type "multipart" and contains unrecognized
sub-parts, the user agent may choose either to show that alternative,
an earlier alternative, or both.
*/
// We must pass 'true' as last parameter so that text/calendar is
// only displayable when Lightning is installed.
MimeObjectClass *clazz = mime_find_class(ct, sub_hdrs, self->options, true);
if (clazz && clazz->displayable_inline_p(clazz, sub_hdrs)) {
// prefer_plaintext pref
bool prefer_plaintext = false;
nsIPrefBranch *prefBranch = GetPrefBranch(self->options);
if (prefBranch) {
prefBranch->GetBoolPref("mailnews.display.prefer_plaintext",
&prefer_plaintext);
}
prefer_plaintext = prefer_plaintext &&
(self->options->format_out != nsMimeOutput::nsMimeMessageSaveAs) &&
(self->options->format_out != nsMimeOutput::nsMimeMessageRaw);
priority = MimeMultipartAlternative_prioritize_part(ct, prefer_plaintext);
}
PR_FREEIF(ct);
return priority;
}
/**
* RFC 1521 says we should display the last format we are capable of displaying.
* But for various reasons (mainly to improve the user experience) we choose
* to ignore that in some cases, and rather pick one that we prioritize.
*/
static priority_t
MimeMultipartAlternative_prioritize_part(char *content_type,
bool prefer_plaintext)
{
/*
* PRIORITY_NORMAL is the priority of text/html, multipart/..., etc. that
* we normally display. We should try to have as few exceptions from
* PRIORITY_NORMAL as possible
*/
/* (with no / in the type) */
if (!PL_strcasecmp(content_type, "text")) {
if (prefer_plaintext) {
/* When in plain text view, a plain text part is what we want. */
return PRIORITY_HIGH;
}
/* We normally prefer other parts over the unspecified text type. */
return PRIORITY_TEXT_UNKNOWN;
}
if (!PL_strncasecmp(content_type, "text/", 5)) {
char *text_type = content_type + 5;
if (!PL_strncasecmp(text_type, "plain", 5)) {
if (prefer_plaintext) {
/* When in plain text view,
the text/plain part is exactly what we want */
return PRIORITY_HIGHEST;
}
/*
* Because the html and the text part may be switched,
* or we have an extra text/plain added by f.ex. a buggy virus checker,
* we prioritize text/plain lower than normal.
*/
return PRIORITY_TEXT_PLAIN;
}
if (!PL_strncasecmp(text_type, "calendar", 8) && prefer_plaintext) {
/*
* text/calendar receives an equally high priority so an invitation
* shows even in plaintext mode.
*/
return PRIORITY_HIGHEST;
}
/* Need to white-list all text/... types that are or could be implemented. */
if (!PL_strncasecmp(text_type, "html", 4) ||
!PL_strncasecmp(text_type, "enriched", 8) ||
!PL_strncasecmp(text_type, "richtext", 8) ||
!PL_strncasecmp(text_type, "calendar", 8) ||
!PL_strncasecmp(text_type, "rtf", 3)) {
return PRIORITY_NORMAL;
}
/* We prefer other parts over unknown text types. */
return PRIORITY_TEXT_UNKNOWN;
}
// Guard against rogue messages with incorrect MIME structure and
// don't show images when plain text is requested.
if (!PL_strncasecmp(content_type, "image", 5)) {
if (prefer_plaintext)
return PRIORITY_UNDISPLAYABLE;
else
return PRIORITY_LOW;
}
return PRIORITY_NORMAL;
}
static int
MimeMultipartAlternative_display_cached_part(MimeObject *obj,
MimeHeaders *hdrs,
MimePartBufferData *buffer,
bool do_display)
{
int status;
bool old_options_no_output_p;
char *ct = (hdrs
? MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, true, false)
: 0);
const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type);
MimeObject *body;
/** Don't pass in NULL as the content-type (this means that the
* auto-uudecode-hack won't ever be done for subparts of a
* multipart, but only for untyped children of message/rfc822.
*/
const char *uct = (ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN);
// We always want to display the cached part inline.
body = mime_create(uct, hdrs, obj->options, true);
PR_FREEIF(ct);
if (!body) return MIME_OUT_OF_MEMORY;
body->output_p = do_display;
status = ((MimeContainerClass *) obj->clazz)->add_child(obj, body);
if (status < 0)
{
mime_free(body);
return status;
}
/* add_child assigns body->options from obj->options, but that's
just a pointer so if we muck with it in the child it'll modify
the parent as well, which we definitely don't want. Therefore we
need to make a copy of the old value and restore it later. */
old_options_no_output_p = obj->options->no_output_p;
if (! do_display)
body->options->no_output_p = true;
#ifdef MIME_DRAFTS
/* if this object is a child of a multipart/related object, the parent is
taking care of decomposing the whole part, don't need to do it at this level.
However, we still have to call decompose_file_init_fn and decompose_file_close_fn
in order to set the correct content-type. But don't call MimePartBufferRead
*/
bool multipartRelatedChild = mime_typep(obj->parent,(MimeObjectClass*)&mimeMultipartRelatedClass);
bool decomposeFile = do_display && obj->options &&
obj->options->decompose_file_p &&
obj->options->decompose_file_init_fn &&
!mime_typep(body, (MimeObjectClass *) &mimeMultipartClass);
if (decomposeFile)
{
status = obj->options->decompose_file_init_fn (
obj->options->stream_closure, hdrs);
if (status < 0) return status;
}
#endif /* MIME_DRAFTS */
/* Now that we've added this new object to our list of children,
notify emitters and start its parser going. */
MimeMultipart_notify_emitter(body);
status = body->clazz->parse_begin(body);
if (status < 0) return status;
#ifdef MIME_DRAFTS
if (decomposeFile && !multipartRelatedChild)
status = MimePartBufferRead (buffer,
obj->options->decompose_file_output_fn,
obj->options->stream_closure);
else
#endif /* MIME_DRAFTS */
status = MimePartBufferRead (buffer,
/* The MimeConverterOutputCallback cast is to turn the
`void' argument into `MimeObject'. */
((MimeConverterOutputCallback) body->clazz->parse_buffer),
body);
if (status < 0) return status;
/* Done parsing. */
status = body->clazz->parse_eof(body, false);
if (status < 0) return status;
status = body->clazz->parse_end(body, false);
if (status < 0) return status;
#ifdef MIME_DRAFTS
if (decomposeFile)
{
status = obj->options->decompose_file_close_fn ( obj->options->stream_closure );
if (status < 0) return status;
}
#endif /* MIME_DRAFTS */
/* Restore options to what parent classes expects. */
obj->options->no_output_p = old_options_no_output_p;
return 0;
}

View file

@ -0,0 +1,48 @@
/* -*- 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/. */
#ifndef _MIMEMALT_H_
#define _MIMEMALT_H_
#include "mimemult.h"
#include "mimepbuf.h"
/* The MimeMultipartAlternative class implements the multipart/alternative
MIME container, which displays only one (the `best') of a set of enclosed
documents.
*/
typedef struct MimeMultipartAlternativeClass MimeMultipartAlternativeClass;
typedef struct MimeMultipartAlternative MimeMultipartAlternative;
struct MimeMultipartAlternativeClass {
MimeMultipartClass multipart;
};
extern "C" MimeMultipartAlternativeClass mimeMultipartAlternativeClass;
enum priority_t {PRIORITY_UNDISPLAYABLE,
PRIORITY_LOW,
PRIORITY_TEXT_UNKNOWN,
PRIORITY_TEXT_PLAIN,
PRIORITY_NORMAL,
PRIORITY_HIGH,
PRIORITY_HIGHEST};
struct MimeMultipartAlternative {
MimeMultipart multipart; /* superclass variables */
MimeHeaders **buffered_hdrs; /* The headers of pending parts */
MimePartBufferData **part_buffers; /* The data of pending parts
(see mimepbuf.h) */
int32_t pending_parts;
int32_t max_parts;
priority_t buffered_priority; /* Priority of head of pending parts */
};
#define MimeMultipartAlternativeClassInitializer(ITYPE,CSUPER) \
{ MimeMultipartClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEMALT_H_ */

View file

@ -0,0 +1,189 @@
/* -*- 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/. */
#include "nsCOMPtr.h"
#include "mimemapl.h"
#include "prmem.h"
#include "plstr.h"
#include "nsMimeStringResources.h"
#include "mimemoz2.h"
#include "nsMimeTypes.h"
#define MIME_SUPERCLASS mimeMultipartClass
MimeDefClass(MimeMultipartAppleDouble, MimeMultipartAppleDoubleClass,
mimeMultipartAppleDoubleClass, &MIME_SUPERCLASS);
static int MimeMultipartAppleDouble_parse_begin (MimeObject *);
static bool MimeMultipartAppleDouble_output_child_p(MimeObject *,
MimeObject *);
static int
MimeMultipartAppleDoubleClassInitialize(MimeMultipartAppleDoubleClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
MimeMultipartClass *mclass = (MimeMultipartClass *) clazz;
NS_ASSERTION(!oclass->class_initialized, "mime class not initialized");
oclass->parse_begin = MimeMultipartAppleDouble_parse_begin;
mclass->output_child_p = MimeMultipartAppleDouble_output_child_p;
return 0;
}
static int
MimeMultipartAppleDouble_parse_begin (MimeObject *obj)
{
/* #### This method is identical to MimeExternalObject_parse_begin
which kinda s#$%s...
*/
int status;
status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
if (status < 0) return status;
/* If we're writing this object, and we're doing it in raw form, then
now is the time to inform the backend what the type of this data is.
*/
if (obj->output_p &&
obj->options &&
!obj->options->write_html_p &&
!obj->options->state->first_data_written_p)
{
status = MimeObject_output_init(obj, 0);
if (status < 0) return status;
NS_ASSERTION(obj->options->state->first_data_written_p, "first data not written");
}
#ifdef XP_MACOSX
if (obj->options && obj->options->state)
{
// obj->options->state->separator_suppressed_p = true;
goto done;
}
/*
* It would be nice to not showing the resource fork links
* if we are displaying inline. But, there is no way we could
* know ahead of time that we could display the data fork and
* the data fork is always hidden on MAC platform.
*/
#endif
/* If we're writing this object as HTML, then emit a link for the
multipart/appledouble part (both links) that looks just like the
links that MimeExternalObject emits for external leaf parts.
*/
if (obj->options &&
obj->output_p &&
obj->options->write_html_p &&
obj->options->output_fn)
{
char *id = 0;
char *id_url = 0;
char *id_imap = 0;
id = mime_part_address (obj);
if (! id) return MIME_OUT_OF_MEMORY;
if (obj->options->missing_parts)
id_imap = mime_imap_part_address (obj);
if (obj->options && obj->options->url)
{
const char *url = obj->options->url;
if (id_imap && id)
{
/* if this is an IMAP part. */
id_url = mime_set_url_imap_part(url, id_imap, id);
}
else
{
/* This is just a normal MIME part as usual. */
id_url = mime_set_url_part(url, id, true);
}
if (!id_url)
{
PR_Free(id);
return MIME_OUT_OF_MEMORY;
}
}
/**********************
if (!strcmp (id, "0"))
{
PR_Free(id);
id = MimeGetStringByID(MIME_MSG_ATTACHMENT);
}
else
{
const char *p = "Part ";
char *s = (char *)PR_MALLOC(strlen(p) + strlen(id) + 1);
if (!s)
{
PR_Free(id);
PR_Free(id_url);
return MIME_OUT_OF_MEMORY;
}
PL_strcpy(s, p);
PL_strcat(s, id);
PR_Free(id);
id = s;
}
if (all_headers_p &&
// Don't bother showing all headers on this part if it's the only
// part in the message: in that case, we've already shown these
// headers.
obj->options->state &&
obj->options->state->root == obj->parent)
all_headers_p = false;
newopt.fancy_headers_p = true;
newopt.headers = (all_headers_p ? MimeHeadersAll : MimeHeadersSome);
//
RICHIE SHERRY
GOTTA STILL DO THIS FOR QUOTING!
status = MimeHeaders_write_attachment_box (obj->headers, &newopt,
obj->content_type,
obj->encoding,
id_name? id_name : id, id_url, 0
//
*********************************************************************************/
// FAIL:
PR_FREEIF(id);
PR_FREEIF(id_url);
PR_FREEIF(id_imap);
if (status < 0) return status;
}
#ifdef XP_MACOSX
done:
#endif
return 0;
}
static bool
MimeMultipartAppleDouble_output_child_p(MimeObject *obj, MimeObject *child)
{
MimeContainer *cont = (MimeContainer *) obj;
/* If this is the first child, and it's an application/applefile, then
don't emit a link for it. (There *should* be only two children, and
the first one should always be an application/applefile.)
*/
if (cont->nchildren >= 1 && cont->children[0] == child && child->content_type &&
!PL_strcasecmp(child->content_type, APPLICATION_APPLEFILE))
{
#ifdef XP_MACOSX
if (obj->output_p && obj->options && obj->options->write_html_p) //output HTML
return false;
#else
/* if we are not on a Macintosh, don't emitte the resources fork at all. */
return false;
#endif
}
return true;
}

View file

@ -0,0 +1,32 @@
/* -*- 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/. */
#ifndef _MIMEMAPL_H_
#define _MIMEMAPL_H_
#include "mimemult.h"
/* The MimeMultipartAppleDouble class implements the multipart/appledouble
MIME container, which provides a method of encapsulating and reconstructing
a two-forked Macintosh file.
*/
typedef struct MimeMultipartAppleDoubleClass MimeMultipartAppleDoubleClass;
typedef struct MimeMultipartAppleDouble MimeMultipartAppleDouble;
struct MimeMultipartAppleDoubleClass {
MimeMultipartClass multipart;
};
extern MimeMultipartAppleDoubleClass mimeMultipartAppleDoubleClass;
struct MimeMultipartAppleDouble {
MimeMultipart multipart;
};
#define MimeMultipartAppleDoubleClassInitializer(ITYPE,CSUPER) \
{ MimeMultipartClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEMAPL_H_ */

View file

@ -0,0 +1,470 @@
/* -*- 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 "nsICMSMessage.h"
#include "nsICMSMessageErrors.h"
#include "nsICMSDecoder.h"
#include "nsICryptoHash.h"
#include "mimemcms.h"
#include "mimecryp.h"
#include "nsMimeTypes.h"
#include "nspr.h"
#include "nsMimeStringResources.h"
#include "mimemsg.h"
#include "mimemoz2.h"
#include "nsIURI.h"
#include "nsIMsgWindow.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsIMimeMiscStatus.h"
#include "nsIMsgSMIMEHeaderSink.h"
#include "nsCOMPtr.h"
#include "nsIX509Cert.h"
#include "plstr.h"
#include "nsComponentManagerUtils.h"
#define MIME_SUPERCLASS mimeMultipartSignedClass
MimeDefClass(MimeMultipartSignedCMS, MimeMultipartSignedCMSClass,
mimeMultipartSignedCMSClass, &MIME_SUPERCLASS);
static int MimeMultipartSignedCMS_initialize (MimeObject *);
static void *MimeMultCMS_init (MimeObject *);
static int MimeMultCMS_data_hash (const char *, int32_t, void *);
static int MimeMultCMS_sig_hash (const char *, int32_t, void *);
static int MimeMultCMS_data_eof (void *, bool);
static int MimeMultCMS_sig_eof (void *, bool);
static int MimeMultCMS_sig_init (void *, MimeObject *, MimeHeaders *);
static char * MimeMultCMS_generate (void *);
static void MimeMultCMS_free (void *);
extern int SEC_ERROR_CERT_ADDR_MISMATCH;
static int
MimeMultipartSignedCMSClassInitialize(MimeMultipartSignedCMSClass *clazz)
{
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
MimeMultipartSignedClass *sclass = (MimeMultipartSignedClass *) clazz;
oclass->initialize = MimeMultipartSignedCMS_initialize;
sclass->crypto_init = MimeMultCMS_init;
sclass->crypto_data_hash = MimeMultCMS_data_hash;
sclass->crypto_data_eof = MimeMultCMS_data_eof;
sclass->crypto_signature_init = MimeMultCMS_sig_init;
sclass->crypto_signature_hash = MimeMultCMS_sig_hash;
sclass->crypto_signature_eof = MimeMultCMS_sig_eof;
sclass->crypto_generate_html = MimeMultCMS_generate;
sclass->crypto_free = MimeMultCMS_free;
PR_ASSERT(!oclass->class_initialized);
return 0;
}
static int
MimeMultipartSignedCMS_initialize (MimeObject *object)
{
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);
}
typedef struct MimeMultCMSdata
{
int16_t hash_type;
nsCOMPtr<nsICryptoHash> data_hash_context;
nsCOMPtr<nsICMSDecoder> sig_decoder_context;
nsCOMPtr<nsICMSMessage> content_info;
char *sender_addr;
bool decoding_failed;
unsigned char* item_data;
uint32_t item_len;
MimeObject *self;
bool parent_is_encrypted_p;
bool parent_holds_stamp_p;
nsCOMPtr<nsIMsgSMIMEHeaderSink> smimeHeaderSink;
MimeMultCMSdata()
:hash_type(0),
sender_addr(nullptr),
decoding_failed(false),
item_data(nullptr),
self(nullptr),
parent_is_encrypted_p(false),
parent_holds_stamp_p(false)
{
}
~MimeMultCMSdata()
{
PR_FREEIF(sender_addr);
// Do a graceful shutdown of the nsICMSDecoder and release the nsICMSMessage //
if (sig_decoder_context)
{
nsCOMPtr<nsICMSMessage> cinfo;
sig_decoder_context->Finish(getter_AddRefs(cinfo));
}
delete [] item_data;
}
} MimeMultCMSdata;
/* #### MimeEncryptedCMS and MimeMultipartSignedCMS have a sleazy,
incestuous, dysfunctional relationship. */
extern bool MimeEncryptedCMS_encrypted_p (MimeObject *obj);
extern void MimeCMSGetFromSender(MimeObject *obj,
nsCString &from_addr,
nsCString &from_name,
nsCString &sender_addr,
nsCString &sender_name);
extern bool MimeCMSHeadersAndCertsMatch(MimeObject *obj,
nsICMSMessage *,
bool *signing_cert_without_email_address);
extern void MimeCMSRequestAsyncSignatureVerification(nsICMSMessage *aCMSMsg,
const char *aFromAddr, const char *aFromName,
const char *aSenderAddr, const char *aSenderName,
nsIMsgSMIMEHeaderSink *aHeaderSink, int32_t aMimeNestingLevel,
unsigned char* item_data, uint32_t item_len);
extern char *MimeCMS_MakeSAURL(MimeObject *obj);
extern char *IMAP_CreateReloadAllPartsUrl(const char *url);
extern int MIMEGetRelativeCryptoNestLevel(MimeObject *obj);
static void *
MimeMultCMS_init (MimeObject *obj)
{
MimeHeaders *hdrs = obj->headers;
MimeMultCMSdata *data = 0;
char *ct, *micalg;
int16_t hash_type;
nsresult rv;
ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, false, false);
if (!ct) return 0; /* #### bogus message? out of memory? */
micalg = MimeHeaders_get_parameter (ct, PARAM_MICALG, NULL, NULL);
PR_Free(ct);
ct = 0;
if (!micalg) return 0; /* #### bogus message? out of memory? */
if (!PL_strcasecmp(micalg, PARAM_MICALG_MD5) ||
!PL_strcasecmp(micalg, PARAM_MICALG_MD5_2))
hash_type = nsICryptoHash::MD5;
else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA1) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA1_2) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA1_3) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA1_4) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA1_5))
hash_type = nsICryptoHash::SHA1;
else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA256) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA256_2) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA256_3))
hash_type = nsICryptoHash::SHA256;
else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA384) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA384_2) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA384_3))
hash_type = nsICryptoHash::SHA384;
else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA512) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA512_2) ||
!PL_strcasecmp(micalg, PARAM_MICALG_SHA512_3))
hash_type = nsICryptoHash::SHA512;
else if (!PL_strcasecmp(micalg, PARAM_MICALG_MD2))
hash_type = nsICryptoHash::MD2;
else
hash_type = -1;
PR_Free(micalg);
micalg = 0;
if (hash_type == -1) return 0; /* #### bogus message? */
data = new MimeMultCMSdata;
if (!data)
return 0;
data->self = obj;
data->hash_type = hash_type;
data->data_hash_context = do_CreateInstance("@mozilla.org/security/hash;1", &rv);
if (NS_FAILED(rv))
{
delete data;
return 0;
}
rv = data->data_hash_context->Init(data->hash_type);
if (NS_FAILED(rv))
{
delete data;
return 0;
}
PR_SetError(0,0);
data->parent_holds_stamp_p =
(obj->parent && mime_crypto_stamped_p(obj->parent));
data->parent_is_encrypted_p =
(obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));
/* If the parent of this object is a crypto-blob, then it's the grandparent
who would have written out the headers and prepared for a stamp...
(This s##t s$%#s.)
*/
if (data->parent_is_encrypted_p &&
!data->parent_holds_stamp_p &&
obj->parent && obj->parent->parent)
data->parent_holds_stamp_p =
mime_crypto_stamped_p (obj->parent->parent);
mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);
if (msd)
{
nsIChannel *channel = msd->channel; // note the lack of ref counting...
if (channel)
{
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIMsgWindow> msgWindow;
nsCOMPtr<nsIMsgHeaderSink> headerSink;
nsCOMPtr<nsIMsgMailNewsUrl> msgurl;
nsCOMPtr<nsISupports> securityInfo;
channel->GetURI(getter_AddRefs(uri));
if (uri)
{
nsAutoCString urlSpec;
rv = uri->GetSpec(urlSpec);
// We only want to update the UI if the current mime transaction
// is intended for display.
// If the current transaction is intended for background processing,
// we can learn that by looking at the additional header=filter
// string contained in the URI.
//
// If we find something, we do not set smimeHeaderSink,
// which will prevent us from giving UI feedback.
//
// If we do not find header=filter, we assume the result of the
// processing will be shown in the UI.
if (!strstr(urlSpec.get(), "?header=filter") &&
!strstr(urlSpec.get(), "&header=filter")&&
!strstr(urlSpec.get(), "?header=attach") &&
!strstr(urlSpec.get(), "&header=attach"))
{
msgurl = do_QueryInterface(uri);
if (msgurl)
msgurl->GetMsgWindow(getter_AddRefs(msgWindow));
if (msgWindow)
msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
if (securityInfo)
data->smimeHeaderSink = do_QueryInterface(securityInfo);
}
}
} // if channel
} // if msd
return data;
}
static int
MimeMultCMS_data_hash (const char *buf, int32_t size, void *crypto_closure)
{
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
if (!data || !data->data_hash_context) {
return -1;
}
PR_SetError(0, 0);
nsresult rv = data->data_hash_context->Update((unsigned char *) buf, size);
data->decoding_failed = NS_FAILED(rv);
return 0;
}
static int
MimeMultCMS_data_eof (void *crypto_closure, bool abort_p)
{
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
if (!data || !data->data_hash_context) {
return -1;
}
nsAutoCString hashString;
data->data_hash_context->Finish(false, hashString);
PR_SetError(0, 0);
data->item_len = hashString.Length();
data->item_data = new unsigned char[data->item_len];
if (!data->item_data) return MIME_OUT_OF_MEMORY;
memcpy(data->item_data, hashString.get(), data->item_len);
// Release our reference to nsICryptoHash //
data->data_hash_context = nullptr;
/* At this point, data->item.data contains a digest for the first part.
When we process the signature, the security library will compare this
digest to what's in the signature object. */
return 0;
}
static int
MimeMultCMS_sig_init (void *crypto_closure,
MimeObject *multipart_object,
MimeHeaders *signature_hdrs)
{
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
char *ct;
int status = 0;
nsresult rv;
if (!signature_hdrs) {
return -1;
}
ct = MimeHeaders_get (signature_hdrs, HEADER_CONTENT_TYPE, true, false);
/* Verify that the signature object is of the right type. */
if (!ct || /* is not a signature type */
(PL_strcasecmp(ct, APPLICATION_XPKCS7_SIGNATURE) != 0
&& PL_strcasecmp(ct, APPLICATION_PKCS7_SIGNATURE) != 0)) {
status = -1; /* #### error msg about bogus message */
}
PR_FREEIF(ct);
if (status < 0) return status;
data->sig_decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return 0;
rv = data->sig_decoder_context->Start(nullptr, nullptr);
if (NS_FAILED(rv)) {
status = PR_GetError();
if (status >= 0) status = -1;
}
return status;
}
static int
MimeMultCMS_sig_hash (const char *buf, int32_t size, void *crypto_closure)
{
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
nsresult rv;
if (!data || !data->sig_decoder_context) {
return -1;
}
rv = data->sig_decoder_context->Update(buf, size);
data->decoding_failed = NS_FAILED(rv);
return 0;
}
static int
MimeMultCMS_sig_eof (void *crypto_closure, bool abort_p)
{
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
if (!data) {
return -1;
}
/* Hand an EOF to the crypto library.
We save away the value returned and will use it later to emit a
blurb about whether the signature validation was cool.
*/
if (data->sig_decoder_context) {
data->sig_decoder_context->Finish(getter_AddRefs(data->content_info));
// Release our reference to nsICMSDecoder //
data->sig_decoder_context = nullptr;
}
return 0;
}
static void
MimeMultCMS_free (void *crypto_closure)
{
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
if (!data) return;
delete data;
}
static char *
MimeMultCMS_generate (void *crypto_closure)
{
MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure;
if (!data) return 0;
nsCOMPtr<nsIX509Cert> signerCert;
int aRelativeNestLevel = MIMEGetRelativeCryptoNestLevel(data->self);
if (aRelativeNestLevel < 0)
return nullptr;
int32_t maxNestLevel = 0;
if (data->smimeHeaderSink && aRelativeNestLevel >= 0)
{
data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel);
if (aRelativeNestLevel > maxNestLevel)
return nullptr;
}
if (data->self->options->missing_parts)
{
// We were not given all parts of the message.
// We are therefore unable to verify correctness of the signature.
if (data->smimeHeaderSink)
data->smimeHeaderSink->SignedStatus(aRelativeNestLevel,
nsICMSMessageErrors::VERIFY_NOT_YET_ATTEMPTED,
nullptr);
return nullptr;
}
if (!data->content_info)
{
/* No content_info at all -- since we're inside a multipart/signed,
that means that we've either gotten a message that was truncated
before the signature part, or we ran out of memory, or something
awful has happened.
*/
return nullptr;
}
nsCString from_addr;
nsCString from_name;
nsCString sender_addr;
nsCString sender_name;
MimeCMSGetFromSender(data->self,
from_addr, from_name,
sender_addr, sender_name);
MimeCMSRequestAsyncSignatureVerification(data->content_info,
from_addr.get(), from_name.get(),
sender_addr.get(), sender_name.get(),
data->smimeHeaderSink, aRelativeNestLevel,
data->item_data, data->item_len);
if (data->content_info)
{
#if 0 // XXX Fix this. What do we do here? //
if (SEC_CMSContainsCertsOrCrls(data->content_info))
{
/* #### call libsec telling it to import the certs */
}
#endif
}
return nullptr;
}

View file

@ -0,0 +1,35 @@
/* -*- 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/. */
#ifndef _MIMEMPKC_H_
#define _MIMEMPKC_H_
#include "mimemsig.h"
class nsICMSMessage;
/* The MimeMultipartSignedCMS class implements a multipart/signed MIME
container with protocol=application/x-CMS-signature, which passes the
signed object through CMS code to verify the signature. See mimemsig.h
for details of the general mechanism on which this is built.
*/
typedef struct MimeMultipartSignedCMSClass MimeMultipartSignedCMSClass;
typedef struct MimeMultipartSignedCMS MimeMultipartSignedCMS;
struct MimeMultipartSignedCMSClass {
MimeMultipartSignedClass msigned;
};
extern MimeMultipartSignedCMSClass mimeMultipartSignedCMSClass;
struct MimeMultipartSignedCMS {
MimeMultipartSigned msigned;
};
#define MimeMultipartSignedCMSClassInitializer(ITYPE,CSUPER) \
{ MimeMultipartSignedClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEMPKC_H_ */

View file

@ -0,0 +1,24 @@
/* -*- 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/. */
#include "mimemdig.h"
#include "prlog.h"
#include "nsMimeTypes.h"
#define MIME_SUPERCLASS mimeMultipartClass
MimeDefClass(MimeMultipartDigest, MimeMultipartDigestClass,
mimeMultipartDigestClass, &MIME_SUPERCLASS);
static int
MimeMultipartDigestClassInitialize(MimeMultipartDigestClass *clazz)
{
#ifdef DEBUG
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
PR_ASSERT(!oclass->class_initialized);
#endif
MimeMultipartClass *mclass = (MimeMultipartClass *) clazz;
mclass->default_part_type = MESSAGE_RFC822;
return 0;
}

View file

@ -0,0 +1,33 @@
/* -*- 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/. */
#ifndef _MIMEMDIG_H_
#define _MIMEMDIG_H_
#include "mimemult.h"
/* The MimeMultipartDigest class implements the multipart/digest MIME
container, which is just like multipart/mixed, except that the default
type (for parts with no type explicitly specified) is message/rfc822
instead of text/plain.
*/
typedef struct MimeMultipartDigestClass MimeMultipartDigestClass;
typedef struct MimeMultipartDigest MimeMultipartDigest;
struct MimeMultipartDigestClass {
MimeMultipartClass multipart;
};
extern MimeMultipartDigestClass mimeMultipartDigestClass;
struct MimeMultipartDigest {
MimeMultipart multipart;
};
#define MimeMultipartDigestClassInitializer(ITYPE,CSUPER) \
{ MimeMultipartClassInitializer(ITYPE,CSUPER) }
#endif /* _MIMEMDIG_H_ */

View file

@ -0,0 +1,21 @@
/* -*- 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/. */
#include "mimemmix.h"
#include "prlog.h"
#define MIME_SUPERCLASS mimeMultipartClass
MimeDefClass(MimeMultipartMixed, MimeMultipartMixedClass,
mimeMultipartMixedClass, &MIME_SUPERCLASS);
static int
MimeMultipartMixedClassInitialize(MimeMultipartMixedClass *clazz)
{
#ifdef DEBUG
MimeObjectClass *oclass = (MimeObjectClass *) clazz;
PR_ASSERT(!oclass->class_initialized);
#endif
return 0;
}

Some files were not shown because too many files have changed in this diff Show more