mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-28 11:27:32 +09:00
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
This commit is contained in:
parent
23e0d82436
commit
e400f4130a
1564 changed files with 510348 additions and 0 deletions
132
mailnews/mime/cthandlers/glue/mimexpcom.cpp
Normal file
132
mailnews/mime/cthandlers/glue/mimexpcom.cpp
Normal 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;
|
||||
}
|
||||
93
mailnews/mime/cthandlers/glue/mimexpcom.h
Normal file
93
mailnews/mime/cthandlers/glue/mimexpcom.h
Normal 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_ */
|
||||
18
mailnews/mime/cthandlers/glue/moz.build
Normal file
18
mailnews/mime/cthandlers/glue/moz.build
Normal 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')
|
||||
|
||||
60
mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.cpp
Normal file
60
mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
47
mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.h
Normal file
47
mailnews/mime/cthandlers/glue/nsMimeContentTypeHandler.h
Normal 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_ */
|
||||
12
mailnews/mime/cthandlers/moz.build
Normal file
12
mailnews/mime/cthandlers/moz.build
Normal 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',
|
||||
]
|
||||
|
||||
20
mailnews/mime/cthandlers/pgpmime/moz.build
Normal file
20
mailnews/mime/cthandlers/pgpmime/moz.build
Normal 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',
|
||||
]
|
||||
634
mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp
Normal file
634
mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.cpp
Normal 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;
|
||||
}
|
||||
69
mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.h
Normal file
69
mailnews/mime/cthandlers/pgpmime/nsPgpMimeProxy.h
Normal 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
|
||||
378
mailnews/mime/cthandlers/vcard/mimevcrd.cpp
Normal file
378
mailnews/mime/cthandlers/vcard/mimevcrd.cpp
Normal 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, " <<a href=""mailto:%s"" private>%s</a>>", 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;
|
||||
}
|
||||
33
mailnews/mime/cthandlers/vcard/mimevcrd.h
Normal file
33
mailnews/mime/cthandlers/vcard/mimevcrd.h
Normal 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_ */
|
||||
14
mailnews/mime/cthandlers/vcard/moz.build
Normal file
14
mailnews/mime/cthandlers/vcard/moz.build
Normal 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',
|
||||
]
|
||||
21
mailnews/mime/emitters/moz.build
Normal file
21
mailnews/mime/emitters/moz.build
Normal 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'
|
||||
|
||||
67
mailnews/mime/emitters/nsEmitterUtils.cpp
Normal file
67
mailnews/mime/emitters/nsEmitterUtils.cpp
Normal 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;
|
||||
}
|
||||
|
||||
14
mailnews/mime/emitters/nsEmitterUtils.h
Normal file
14
mailnews/mime/emitters/nsEmitterUtils.h
Normal 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_
|
||||
|
||||
1092
mailnews/mime/emitters/nsMimeBaseEmitter.cpp
Normal file
1092
mailnews/mime/emitters/nsMimeBaseEmitter.cpp
Normal file
File diff suppressed because it is too large
Load diff
147
mailnews/mime/emitters/nsMimeBaseEmitter.h
Normal file
147
mailnews/mime/emitters/nsMimeBaseEmitter.h
Normal 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_ */
|
||||
51
mailnews/mime/emitters/nsMimeEmitterCID.h
Normal file
51
mailnews/mime/emitters/nsMimeEmitterCID.h
Normal 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__
|
||||
543
mailnews/mime/emitters/nsMimeHtmlEmitter.cpp
Normal file
543
mailnews/mime/emitters/nsMimeHtmlEmitter.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
64
mailnews/mime/emitters/nsMimeHtmlEmitter.h
Normal file
64
mailnews/mime/emitters/nsMimeHtmlEmitter.h
Normal 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_ */
|
||||
64
mailnews/mime/emitters/nsMimePlainEmitter.cpp
Normal file
64
mailnews/mime/emitters/nsMimePlainEmitter.cpp
Normal 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;
|
||||
}
|
||||
|
||||
31
mailnews/mime/emitters/nsMimePlainEmitter.h
Normal file
31
mailnews/mime/emitters/nsMimePlainEmitter.h
Normal 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_ */
|
||||
34
mailnews/mime/emitters/nsMimeRawEmitter.cpp
Normal file
34
mailnews/mime/emitters/nsMimeRawEmitter.cpp
Normal 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;
|
||||
}
|
||||
|
||||
29
mailnews/mime/emitters/nsMimeRawEmitter.h
Normal file
29
mailnews/mime/emitters/nsMimeRawEmitter.h
Normal 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_ */
|
||||
50
mailnews/mime/emitters/nsMimeRebuffer.cpp
Normal file
50
mailnews/mime/emitters/nsMimeRebuffer.cpp
Normal 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;
|
||||
}
|
||||
29
mailnews/mime/emitters/nsMimeRebuffer.h
Normal file
29
mailnews/mime/emitters/nsMimeRebuffer.h
Normal 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_ */
|
||||
184
mailnews/mime/emitters/nsMimeXmlEmitter.cpp
Normal file
184
mailnews/mime/emitters/nsMimeXmlEmitter.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
47
mailnews/mime/emitters/nsMimeXmlEmitter.h
Normal file
47
mailnews/mime/emitters/nsMimeXmlEmitter.h
Normal 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_ */
|
||||
19
mailnews/mime/jsmime/LICENSE
Normal file
19
mailnews/mime/jsmime/LICENSE
Normal 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.
|
||||
59
mailnews/mime/jsmime/README.md
Normal file
59
mailnews/mime/jsmime/README.md
Normal 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.
|
||||
3300
mailnews/mime/jsmime/jsmime.js
Normal file
3300
mailnews/mime/jsmime/jsmime.js
Normal file
File diff suppressed because it is too large
Load diff
15
mailnews/mime/moz.build
Normal file
15
mailnews/mime/moz.build
Normal 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',
|
||||
]
|
||||
44
mailnews/mime/public/MimeEncoder.h
Normal file
44
mailnews/mime/public/MimeEncoder.h
Normal 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
|
||||
174
mailnews/mime/public/MimeHeaderParser.h
Normal file
174
mailnews/mime/public/MimeHeaderParser.h
Normal 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
|
||||
36
mailnews/mime/public/moz.build
Normal file
36
mailnews/mime/public/moz.build
Normal 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',
|
||||
]
|
||||
209
mailnews/mime/public/msgIStructuredHeaders.idl
Normal file
209
mailnews/mime/public/msgIStructuredHeaders.idl
Normal 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());
|
||||
}
|
||||
%}
|
||||
};
|
||||
29
mailnews/mime/public/nsICMSDecoder.idl
Normal file
29
mailnews/mime/public/nsICMSDecoder.idl
Normal 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);
|
||||
};
|
||||
|
||||
30
mailnews/mime/public/nsICMSEncoder.idl
Normal file
30
mailnews/mime/public/nsICMSEncoder.idl
Normal 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);
|
||||
};
|
||||
|
||||
39
mailnews/mime/public/nsICMSMessage.idl
Normal file
39
mailnews/mime/public/nsICMSMessage.idl
Normal 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);
|
||||
};
|
||||
|
||||
64
mailnews/mime/public/nsICMSMessage2.idl
Normal file
64
mailnews/mime/public/nsICMSMessage2.idl
Normal 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);
|
||||
};
|
||||
|
||||
35
mailnews/mime/public/nsICMSMessageErrors.idl
Normal file
35
mailnews/mime/public/nsICMSMessageErrors.idl
Normal 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;
|
||||
};
|
||||
42
mailnews/mime/public/nsICMSSecureMessage.idl
Normal file
42
mailnews/mime/public/nsICMSSecureMessage.idl
Normal 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"
|
||||
%}
|
||||
65
mailnews/mime/public/nsIMimeContentTypeHandler.h
Normal file
65
mailnews/mime/public/nsIMimeContentTypeHandler.h
Normal 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_ */
|
||||
75
mailnews/mime/public/nsIMimeConverter.idl
Normal file
75
mailnews/mime/public/nsIMimeConverter.idl
Normal 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);
|
||||
};
|
||||
|
||||
81
mailnews/mime/public/nsIMimeEmitter.idl
Normal file
81
mailnews/mime/public/nsIMimeEmitter.idl
Normal 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);
|
||||
};
|
||||
41
mailnews/mime/public/nsIMimeHeaders.idl
Normal file
41
mailnews/mime/public/nsIMimeHeaders.idl
Normal 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;
|
||||
};
|
||||
76
mailnews/mime/public/nsIMimeMiscStatus.idl
Normal file
76
mailnews/mime/public/nsIMimeMiscStatus.idl
Normal 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();
|
||||
};
|
||||
49
mailnews/mime/public/nsIMimeObjectClassAccess.h
Normal file
49
mailnews/mime/public/nsIMimeObjectClassAccess.h
Normal 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_ */
|
||||
93
mailnews/mime/public/nsIMimeStreamConverter.idl
Normal file
93
mailnews/mime/public/nsIMimeStreamConverter.idl
Normal 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;
|
||||
};
|
||||
235
mailnews/mime/public/nsIMsgHeaderParser.idl
Normal file
235
mailnews/mime/public/nsIMsgHeaderParser.idl
Normal 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);
|
||||
};
|
||||
|
||||
69
mailnews/mime/public/nsIPgpMimeProxy.idl
Normal file
69
mailnews/mime/public/nsIPgpMimeProxy.idl
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
22
mailnews/mime/public/nsISimpleMimeConverter.idl
Normal file
22
mailnews/mime/public/nsISimpleMimeConverter.idl
Normal 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"
|
||||
|
||||
%}
|
||||
90
mailnews/mime/public/nsMailHeaders.h
Normal file
90
mailnews/mime/public/nsMailHeaders.h
Normal 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_ */
|
||||
33
mailnews/mime/public/nsMsgMimeCID.h
Normal file
33
mailnews/mime/public/nsMsgMimeCID.h
Normal 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__
|
||||
229
mailnews/mime/src/MimeHeaderParser.cpp
Normal file
229
mailnews/mime/src/MimeHeaderParser.cpp
Normal 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
|
||||
108
mailnews/mime/src/comi18n.cpp
Normal file
108
mailnews/mime/src/comi18n.cpp
Normal 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
|
||||
|
||||
42
mailnews/mime/src/comi18n.h
Normal file
42
mailnews/mime/src/comi18n.h
Normal 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_
|
||||
|
||||
29
mailnews/mime/src/extraMimeParsers.jsm
Normal file
29
mailnews/mime/src/extraMimeParsers.jsm
Normal 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);
|
||||
90
mailnews/mime/src/jsmime.jsm
Normal file
90
mailnews/mime/src/jsmime.jsm
Normal 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");
|
||||
}
|
||||
7
mailnews/mime/src/mime.def
Normal file
7
mailnews/mime/src/mime.def
Normal 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
|
||||
512
mailnews/mime/src/mimeJSComponents.js
Normal file
512
mailnews/mime/src/mimeJSComponents.js
Normal 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);
|
||||
258
mailnews/mime/src/mimeParser.jsm
Normal file
258
mailnews/mime/src/mimeParser.jsm
Normal 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";
|
||||
}
|
||||
},
|
||||
};
|
||||
150
mailnews/mime/src/mimeTextHTMLParsed.cpp
Normal file
150
mailnews/mime/src/mimeTextHTMLParsed.cpp
Normal 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;
|
||||
}
|
||||
28
mailnews/mime/src/mimeTextHTMLParsed.h
Normal file
28
mailnews/mime/src/mimeTextHTMLParsed.h
Normal 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_ */
|
||||
249
mailnews/mime/src/mimebuf.cpp
Normal file
249
mailnews/mime/src/mimebuf.cpp
Normal 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;
|
||||
}
|
||||
39
mailnews/mime/src/mimebuf.h
Normal file
39
mailnews/mime/src/mimebuf.h
Normal 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_ */
|
||||
716
mailnews/mime/src/mimecms.cpp
Normal file
716
mailnews/mime/src/mimecms.cpp
Normal 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;
|
||||
}
|
||||
|
||||
36
mailnews/mime/src/mimecms.h
Normal file
36
mailnews/mime/src/mimecms.h
Normal 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_ */
|
||||
74
mailnews/mime/src/mimecom.cpp
Normal file
74
mailnews/mime/src/mimecom.cpp
Normal 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);
|
||||
}
|
||||
38
mailnews/mime/src/mimecom.h
Normal file
38
mailnews/mime/src/mimecom.h
Normal 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_ */
|
||||
218
mailnews/mime/src/mimecont.cpp
Normal file
218
mailnews/mime/src/mimecont.cpp
Normal 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
|
||||
43
mailnews/mime/src/mimecont.h
Normal file
43
mailnews/mime/src/mimecont.h
Normal 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_ */
|
||||
571
mailnews/mime/src/mimecryp.cpp
Normal file
571
mailnews/mime/src/mimecryp.cpp
Normal 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;
|
||||
}
|
||||
140
mailnews/mime/src/mimecryp.h
Normal file
140
mailnews/mime/src/mimecryp.h
Normal 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_ */
|
||||
51
mailnews/mime/src/mimecth.cpp
Normal file
51
mailnews/mime/src/mimecth.cpp
Normal 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
135
mailnews/mime/src/mimecth.h
Normal 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_ */
|
||||
2084
mailnews/mime/src/mimedrft.cpp
Normal file
2084
mailnews/mime/src/mimedrft.cpp
Normal file
File diff suppressed because it is too large
Load diff
509
mailnews/mime/src/mimeebod.cpp
Normal file
509
mailnews/mime/src/mimeebod.cpp
Normal 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;
|
||||
}
|
||||
37
mailnews/mime/src/mimeebod.h
Normal file
37
mailnews/mime/src/mimeebod.h
Normal 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_ */
|
||||
1107
mailnews/mime/src/mimeenc.cpp
Normal file
1107
mailnews/mime/src/mimeenc.cpp
Normal file
File diff suppressed because it is too large
Load diff
236
mailnews/mime/src/mimeeobj.cpp
Normal file
236
mailnews/mime/src/mimeeobj.cpp
Normal 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;
|
||||
}
|
||||
34
mailnews/mime/src/mimeeobj.h
Normal file
34
mailnews/mime/src/mimeeobj.h
Normal 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_ */
|
||||
399
mailnews/mime/src/mimefilt.cpp
Normal file
399
mailnews/mime/src/mimefilt.cpp
Normal 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);
|
||||
}
|
||||
888
mailnews/mime/src/mimehdrs.cpp
Normal file
888
mailnews/mime/src/mimehdrs.cpp
Normal 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;
|
||||
}
|
||||
88
mailnews/mime/src/mimehdrs.h
Normal file
88
mailnews/mime/src/mimehdrs.h
Normal 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
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
422
mailnews/mime/src/mimei.h
Normal 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_ */
|
||||
249
mailnews/mime/src/mimeiimg.cpp
Normal file
249
mailnews/mime/src/mimeiimg.cpp
Normal 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;
|
||||
}
|
||||
35
mailnews/mime/src/mimeiimg.h
Normal file
35
mailnews/mime/src/mimeiimg.h
Normal 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_ */
|
||||
221
mailnews/mime/src/mimeleaf.cpp
Normal file
221
mailnews/mime/src/mimeleaf.cpp
Normal 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;
|
||||
}
|
||||
59
mailnews/mime/src/mimeleaf.h
Normal file
59
mailnews/mime/src/mimeleaf.h
Normal 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_ */
|
||||
580
mailnews/mime/src/mimemalt.cpp
Normal file
580
mailnews/mime/src/mimemalt.cpp
Normal 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;
|
||||
}
|
||||
48
mailnews/mime/src/mimemalt.h
Normal file
48
mailnews/mime/src/mimemalt.h
Normal 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_ */
|
||||
189
mailnews/mime/src/mimemapl.cpp
Normal file
189
mailnews/mime/src/mimemapl.cpp
Normal 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;
|
||||
}
|
||||
32
mailnews/mime/src/mimemapl.h
Normal file
32
mailnews/mime/src/mimemapl.h
Normal 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_ */
|
||||
470
mailnews/mime/src/mimemcms.cpp
Normal file
470
mailnews/mime/src/mimemcms.cpp
Normal 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;
|
||||
}
|
||||
35
mailnews/mime/src/mimemcms.h
Normal file
35
mailnews/mime/src/mimemcms.h
Normal 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_ */
|
||||
24
mailnews/mime/src/mimemdig.cpp
Normal file
24
mailnews/mime/src/mimemdig.cpp
Normal 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;
|
||||
}
|
||||
33
mailnews/mime/src/mimemdig.h
Normal file
33
mailnews/mime/src/mimemdig.h
Normal 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_ */
|
||||
21
mailnews/mime/src/mimemmix.cpp
Normal file
21
mailnews/mime/src/mimemmix.cpp
Normal 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
Loading…
Add table
Add a link
Reference in a new issue