aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/renderer')
-rw-r--r--src/core/renderer/MCAddressDisplay.cpp94
-rw-r--r--src/core/renderer/MCAddressDisplay.h34
-rw-r--r--src/core/renderer/MCDateFormatter.cpp160
-rw-r--r--src/core/renderer/MCDateFormatter.h69
-rw-r--r--src/core/renderer/MCHTMLRenderer.cpp446
-rw-r--r--src/core/renderer/MCHTMLRenderer.h38
-rw-r--r--src/core/renderer/MCHTMLRendererCallback.cpp259
-rw-r--r--src/core/renderer/MCHTMLRendererCallback.h51
-rw-r--r--src/core/renderer/MCRenderer.h18
-rw-r--r--src/core/renderer/MCSizeFormatter.cpp43
-rw-r--r--src/core/renderer/MCSizeFormatter.h28
11 files changed, 1240 insertions, 0 deletions
diff --git a/src/core/renderer/MCAddressDisplay.cpp b/src/core/renderer/MCAddressDisplay.cpp
new file mode 100644
index 00000000..842dd0df
--- /dev/null
+++ b/src/core/renderer/MCAddressDisplay.cpp
@@ -0,0 +1,94 @@
+//
+// MCAddressUI.cpp
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/27/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCAddressDisplay.h"
+
+using namespace mailcore;
+
+String * AddressDisplay::displayStringForAddress(Address * address)
+{
+ return address->nonEncodedRFC822String();
+}
+
+String * AddressDisplay::shortDisplayStringForAddress(Address * address)
+{
+ if ((address->displayName() != NULL) && (address->displayName()->length() > 0)) {
+ return address->displayName();
+ }
+ else if (address->mailbox()) {
+ return address->mailbox();
+ }
+ else {
+ return MCSTR("invalid");
+ }
+}
+
+String * AddressDisplay::veryShortDisplayStringForAddress(Address * address)
+{
+ if ((address->displayName() != NULL) && (address->displayName()->length() > 0)) {
+ Array * components;
+ String * senderName;
+
+ senderName = address->displayName();
+ senderName = (String *) senderName->copy()->autorelease();
+
+ senderName->replaceOccurrencesOfString(MCSTR(","), MCSTR(" "));
+ senderName->replaceOccurrencesOfString(MCSTR("'"), MCSTR(" "));
+ senderName->replaceOccurrencesOfString(MCSTR("\""), MCSTR(" "));
+ components = senderName->componentsSeparatedByString(MCSTR(" "));
+ if (components->count() == 0) {
+ return MCLOCALIZEDSTRING(MCSTR("invalid"));
+ }
+ return (String *) components->objectAtIndex(0);
+ }
+ else if (address->mailbox()) {
+ return address->mailbox();
+ }
+ else {
+ return MCLOCALIZEDSTRING(MCSTR("invalid"));
+ }
+}
+
+String * AddressDisplay::displayStringForAddresses(Array * addresses)
+{
+ String * result = String::string();
+ for(unsigned int i = 0 ; i < addresses->count() ; i ++) {
+ Address * address = (Address *) addresses->objectAtIndex(i);
+ if (i != 0) {
+ result->appendString(MCSTR(", "));
+ }
+ result->appendString(displayStringForAddress(address));
+ }
+ return result;
+}
+
+String * AddressDisplay::shortDisplayStringForAddresses(Array * addresses)
+{
+ String * result = String::string();
+ for(unsigned int i = 0 ; i < addresses->count() ; i ++) {
+ Address * address = (Address *) addresses->objectAtIndex(i);
+ if (i != 0) {
+ result->appendString(MCSTR(", "));
+ }
+ result->appendString(shortDisplayStringForAddress(address));
+ }
+ return result;
+}
+
+String * AddressDisplay::veryShortDisplayStringForAddresses(Array * addresses)
+{
+ String * result = String::string();
+ for(unsigned int i = 0 ; i < addresses->count() ; i ++) {
+ Address * address = (Address *) addresses->objectAtIndex(i);
+ if (i != 0) {
+ result->appendString(MCSTR(", "));
+ }
+ result->appendString(veryShortDisplayStringForAddress(address));
+ }
+ return result;
+}
diff --git a/src/core/renderer/MCAddressDisplay.h b/src/core/renderer/MCAddressDisplay.h
new file mode 100644
index 00000000..153ad245
--- /dev/null
+++ b/src/core/renderer/MCAddressDisplay.h
@@ -0,0 +1,34 @@
+//
+// MCAddressUI.h
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/27/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __MCAddressDisplay__
+#define __MCAddressDisplay__
+
+#include <mailcore/MCAbstract.h>
+
+#ifdef __cplusplus
+
+namespace mailcore {
+
+ class AddressDisplay {
+
+ public:
+ static String * displayStringForAddress(Address * address);
+ static String * shortDisplayStringForAddress(Address * address);
+ static String * veryShortDisplayStringForAddress(Address * address);
+
+ static String * displayStringForAddresses(Array * addresses);
+ static String * shortDisplayStringForAddresses(Array * addresses);
+ static String * veryShortDisplayStringForAddresses(Array * addresses);
+ };
+
+};
+
+#endif
+
+#endif /* defined(__MCAddressDisplay__) */
diff --git a/src/core/renderer/MCDateFormatter.cpp b/src/core/renderer/MCDateFormatter.cpp
new file mode 100644
index 00000000..0fa86699
--- /dev/null
+++ b/src/core/renderer/MCDateFormatter.cpp
@@ -0,0 +1,160 @@
+//
+// MCDateFormatter.cpp
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/28/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCDateFormatter.h"
+
+using namespace mailcore;
+
+DateFormatter::DateFormatter()
+{
+ mDateFormatter = NULL;
+ mDateStyle = DateFormatStyleMedium;
+ mTimeStyle = DateFormatStyleMedium;
+ mDateFormat = NULL;
+ mTimezone = NULL;
+ mLocale = NULL;
+}
+
+DateFormatter::~DateFormatter()
+{
+ if (mDateFormatter != NULL) {
+ udat_close(mDateFormatter);
+ }
+ MC_SAFE_RELEASE(mDateFormat);
+ MC_SAFE_RELEASE(mTimezone);
+ MC_SAFE_RELEASE(mLocale);
+}
+
+DateFormatter * DateFormatter::dateFormatter()
+{
+ DateFormatter * result = new DateFormatter();
+ result->autorelease();
+ return result;
+}
+
+
+void DateFormatter::setDateStyle(DateFormatStyle style)
+{
+ mDateStyle = style;
+}
+
+DateFormatStyle DateFormatter::dateStyle()
+{
+ return mDateStyle;
+}
+
+void DateFormatter::setTimeStyle(DateFormatStyle style)
+{
+ mTimeStyle = style;
+}
+
+DateFormatStyle DateFormatter::timeStyle()
+{
+ return mTimeStyle;
+}
+
+void DateFormatter::setLocale(String * locale)
+{
+ MC_SAFE_REPLACE_COPY(String, mLocale, locale);
+}
+
+String * DateFormatter::locale()
+{
+ return mLocale;
+}
+
+void DateFormatter::setTimezone(String * timezone)
+{
+ MC_SAFE_REPLACE_COPY(String, mTimezone, timezone);
+}
+
+String * DateFormatter::timezone()
+{
+ return mTimezone;
+}
+
+void DateFormatter::setDateFormat(String * dateFormat)
+{
+ MC_SAFE_REPLACE_COPY(String, mDateFormat, dateFormat);
+}
+
+String * DateFormatter::dateFormat()
+{
+ return mDateFormat;
+}
+
+String * DateFormatter::stringFromDate(time_t date)
+{
+ prepare();
+ if (mDateFormatter == NULL)
+ return NULL;
+
+ UErrorCode err = U_ZERO_ERROR;
+ int32_t len = udat_format(mDateFormatter, ((double) date) * 1000., NULL, 0, NULL, &err);
+ if(err != U_BUFFER_OVERFLOW_ERROR) {
+ return NULL;
+ }
+
+ String * result;
+
+ err = U_ZERO_ERROR;
+ UChar * unichars = (UChar *) malloc((len + 1) * sizeof(unichars));
+ udat_format(mDateFormatter, ((double) date) * 1000., unichars, len + 1, NULL, &err);
+ result = new String(unichars, len);
+ free(unichars);
+
+ result->autorelease();
+ return result;
+}
+
+time_t DateFormatter::dateFromString(String * dateString)
+{
+ prepare();
+ if (mDateFormatter == NULL)
+ return (time_t) -1;
+
+ UErrorCode err = U_ZERO_ERROR;
+ UDate date = udat_parse(mDateFormatter, dateString->unicodeCharacters(), dateString->length(),
+ NULL, &err);
+ if (err != U_ZERO_ERROR) {
+ return (time_t) -1;
+ }
+
+ return date / 1000.;
+}
+
+void DateFormatter::prepare()
+{
+ if (mDateFormatter != NULL)
+ return;
+
+ const UChar * tzID = NULL;
+ int32_t tzIDLength = -1;
+ const UChar * pattern = NULL;
+ int32_t patternLength = -1;
+ UErrorCode err = U_ZERO_ERROR;
+ const char * locale = NULL;
+
+ if (mTimezone != NULL) {
+ tzID = mTimezone->unicodeCharacters();
+ tzIDLength = mTimezone->length();
+ }
+ if (mDateFormat != NULL) {
+ pattern = mDateFormat->unicodeCharacters();
+ patternLength = mDateFormat->length();
+ }
+ if (mLocale != NULL) {
+ locale = mLocale->UTF8Characters();
+ }
+
+ mDateFormatter = udat_open((UDateFormatStyle) mTimeStyle, (UDateFormatStyle) mDateStyle,
+ locale,
+ tzID, tzIDLength,
+ pattern, patternLength,
+ &err);
+}
diff --git a/src/core/renderer/MCDateFormatter.h b/src/core/renderer/MCDateFormatter.h
new file mode 100644
index 00000000..6467aae6
--- /dev/null
+++ b/src/core/renderer/MCDateFormatter.h
@@ -0,0 +1,69 @@
+//
+// MCDateFormatter.h
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/28/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __testUI__MCDateFormatter__
+#define __testUI__MCDateFormatter__
+
+#include <mailcore/MCBaseTypes.h>
+#include <unicode/udat.h>
+
+#ifdef __cplusplus
+
+namespace mailcore {
+
+ class String;
+
+ enum DateFormatStyle {
+ DateFormatStyleFull = UDAT_FULL,
+ DateFormatStyleLong = UDAT_LONG,
+ DateFormatStyleMedium = UDAT_MEDIUM,
+ DateFormatStyleShort = UDAT_SHORT,
+ DateFormatStyleNone = UDAT_NONE,
+ };
+
+ class DateFormatter : public Object {
+ public:
+ DateFormatter();
+ virtual ~DateFormatter();
+
+ static DateFormatter * dateFormatter();
+
+ virtual void setDateStyle(DateFormatStyle style);
+ virtual DateFormatStyle dateStyle();
+
+ virtual void setTimeStyle(DateFormatStyle style);
+ virtual DateFormatStyle timeStyle();
+
+ virtual void setLocale(String * locale);
+ virtual String * locale();
+
+ virtual void setTimezone(String * timezone);
+ virtual String * timezone();
+
+ virtual void setDateFormat(String * dateFormat);
+ virtual String * dateFormat();
+
+ virtual String * stringFromDate(time_t date);
+ virtual time_t dateFromString(String * dateString);
+
+ private:
+ UDateFormat * mDateFormatter;
+ DateFormatStyle mDateStyle;
+ DateFormatStyle mTimeStyle;
+ String * mDateFormat;
+ String * mTimezone;
+ String * mLocale;
+
+ void prepare();
+ };
+
+}
+
+#endif
+
+#endif /* defined(__testUI__MCDateFormatter__) */
diff --git a/src/core/renderer/MCHTMLRenderer.cpp b/src/core/renderer/MCHTMLRenderer.cpp
new file mode 100644
index 00000000..10066fc4
--- /dev/null
+++ b/src/core/renderer/MCHTMLRenderer.cpp
@@ -0,0 +1,446 @@
+//
+// MCHTMLRenderer.cpp
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/23/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCHTMLRenderer.h"
+
+#include <ctemplate/template.h>
+#include "MCAddressDisplay.h"
+#include "MCDateFormatter.h"
+#include "MCSizeFormatter.h"
+#include "MCHTMLRendererCallback.h"
+
+using namespace mailcore;
+
+enum {
+ RENDER_STATE_NONE,
+ RENDER_STATE_HAD_ATTACHMENT,
+ RENDER_STATE_HAD_ATTACHMENT_THEN_TEXT,
+};
+
+struct htmlRendererContext {
+ HTMLRendererIMAPCallback * dataCallback;
+ HTMLRendererTemplateCallback * htmlCallback;
+ int firstRendered;
+ String * folder;
+ int state;
+ int pass;
+ bool hasMixedTextAndAttachments;
+ bool firstAttachment;
+ bool hasTextPart;
+};
+
+class DefaultTemplateCallback : public Object, public HTMLRendererTemplateCallback {
+};
+
+static bool partContainsMimeType(AbstractPart * part, String * mimeType);
+static bool singlePartContainsMimeType(AbstractPart * part, String * mimeType);
+static bool multipartContainsMimeType(AbstractMultipart * part, String * mimeType);
+static bool messagePartContainsMimeType(AbstractMessagePart * part, String * mimeType);
+
+static String * htmlForAbstractPart(AbstractPart * part, htmlRendererContext * context);
+
+static String * renderTemplate(String * templateContent, HashMap * values);
+
+static String * htmlForAbstractMessage(String * folder, AbstractMessage * message,
+ HTMLRendererIMAPCallback * dataCallback,
+ HTMLRendererTemplateCallback * htmlCallback);
+
+static bool isTextPart(AbstractPart * part, htmlRendererContext * context)
+{
+ String * mimeType = part->mimeType()->lowercaseString();
+ MCAssert(mimeType != NULL);
+
+ if (!part->isInlineAttachment()) {
+ if ((part->filename() != NULL) && context->firstRendered) {
+ return false;
+ }
+ }
+
+ if (mimeType->isEqual(MCSTR("text/plain"))) {
+ return true;
+ }
+ else if (mimeType->isEqual(MCSTR("text/html"))) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+static AbstractPart * preferredPartInMultipartAlternative(AbstractMultipart * part)
+{
+ int htmlPart = -1;
+ int textPart = -1;
+
+ for(unsigned int i = 0 ; i < part->parts()->count() ; i ++) {
+ AbstractPart * subpart = (AbstractPart *) part->parts()->objectAtIndex(i);
+ if (partContainsMimeType(subpart, MCSTR("text/html"))) {
+ htmlPart = i;
+ }
+ else if (partContainsMimeType(subpart, MCSTR("text/plain"))) {
+ textPart = i;
+ }
+ }
+ if (htmlPart != -1) {
+ return (AbstractPart *) part->parts()->objectAtIndex(htmlPart);
+ }
+ else if (textPart != -1) {
+ return (AbstractPart *) part->parts()->objectAtIndex(textPart);
+ }
+ else if (part->parts()->count() > 0) {
+ return (AbstractPart *) part->parts()->objectAtIndex(0);
+ }
+ else {
+ return NULL;
+ }
+}
+
+static bool partContainsMimeType(AbstractPart * part, String * mimeType)
+{
+ switch (part->partType()) {
+ case PartTypeSingle:
+ return singlePartContainsMimeType(part, mimeType);
+ case PartTypeMessage:
+ return messagePartContainsMimeType((AbstractMessagePart *) part, mimeType);
+ case PartTypeMultipartMixed:
+ case PartTypeMultipartRelated:
+ case PartTypeMultipartAlternative:
+ return multipartContainsMimeType((AbstractMultipart *) part, mimeType);
+ default:
+ return false;
+ }
+}
+
+static bool singlePartContainsMimeType(AbstractPart * part, String * mimeType)
+{
+ return part->mimeType()->lowercaseString()->isEqual(mimeType);
+}
+
+static bool multipartContainsMimeType(AbstractMultipart * part, String * mimeType)
+{
+ for(unsigned int i = 0 ; i < part->parts()->count() ; i ++) {
+ AbstractPart * subpart = (AbstractPart *) part->parts()->objectAtIndex(i);
+ if (partContainsMimeType(subpart, mimeType)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool messagePartContainsMimeType(AbstractMessagePart * part, String * mimeType)
+{
+ return partContainsMimeType(part->mainPart(), mimeType);
+}
+
+static String * htmlForAbstractMessage(String * folder, AbstractMessage * message,
+ HTMLRendererIMAPCallback * dataCallback,
+ HTMLRendererTemplateCallback * htmlCallback)
+{
+ AbstractPart * mainPart = NULL;
+
+ if (htmlCallback == NULL) {
+ htmlCallback = new DefaultTemplateCallback();
+ ((DefaultTemplateCallback *) htmlCallback)->autorelease();
+ }
+
+ if (message->className()->isEqual(MCSTR("mailcore::IMAPMessage"))) {
+ mainPart = ((IMAPMessage *) message)->mainPart();
+ }
+ else if (message->className()->isEqual(MCSTR("mailcore::MessageParser"))) {
+ mainPart = ((MessageParser *) message)->mainPart();
+ }
+ MCAssert(mainPart != NULL);
+
+ htmlRendererContext context;
+ context.dataCallback = dataCallback;
+ context.htmlCallback = htmlCallback;
+ context.firstRendered = 0;
+ context.folder = folder;
+ context.state = RENDER_STATE_NONE;
+
+ context.hasMixedTextAndAttachments = false;
+ context.pass = 0;
+ context.firstAttachment = false;
+ context.hasTextPart = false;
+ htmlForAbstractPart(mainPart, &context);
+
+ context.hasMixedTextAndAttachments = (context.state == RENDER_STATE_HAD_ATTACHMENT_THEN_TEXT);
+ context.pass = 1;
+ context.firstAttachment = false;
+ context.hasTextPart = false;
+ String * content = htmlForAbstractPart(mainPart, &context);
+ if (content == NULL)
+ return NULL;
+
+ content = htmlCallback->filterHTMLForMessage(content);
+
+ HashMap * values = htmlCallback->templateValuesForHeader(message->header());
+ String * headerString = renderTemplate(htmlCallback->templateForMainHeader(), values);
+
+ HashMap * msgValues = new HashMap();
+ msgValues->setObjectForKey(MCSTR("HEADER"), headerString);
+ msgValues->setObjectForKey(MCSTR("BODY"), content);
+ String * result = renderTemplate(htmlCallback->templateForMessage(), msgValues);
+ msgValues->release();
+
+ return result;
+}
+
+String * htmlForAbstractSinglePart(AbstractPart * part, htmlRendererContext * context);
+String * htmlForAbstractMessagePart(AbstractMessagePart * part, htmlRendererContext * context);
+String * htmlForAbstractMultipartRelated(AbstractMultipart * part, htmlRendererContext * context);
+String * htmlForAbstractMultipartMixed(AbstractMultipart * part, htmlRendererContext * context);
+String * htmlForAbstractMultipartAlternative(AbstractMultipart * part, htmlRendererContext * context);
+
+String * htmlForAbstractPart(AbstractPart * part, htmlRendererContext * context)
+{
+ switch (part->partType()) {
+ case PartTypeSingle:
+ return htmlForAbstractSinglePart((AbstractPart *) part, context);
+ case PartTypeMessage:
+ return htmlForAbstractMessagePart((AbstractMessagePart *) part, context);
+ case PartTypeMultipartMixed:
+ return htmlForAbstractMultipartMixed((AbstractMultipart *) part, context);
+ case PartTypeMultipartRelated:
+ return htmlForAbstractMultipartRelated((AbstractMultipart *) part, context);
+ case PartTypeMultipartAlternative:
+ return htmlForAbstractMultipartAlternative((AbstractMultipart *) part, context);
+ default:
+ MCAssert(0);
+ }
+ return NULL;
+}
+
+String * htmlForAbstractSinglePart(AbstractPart * part, htmlRendererContext * context)
+{
+ String * mimeType = part->mimeType()->lowercaseString();
+ MCAssert(mimeType != NULL);
+
+ if (isTextPart(part, context)) {
+ if (context->pass == 0) {
+ if (context->state == RENDER_STATE_HAD_ATTACHMENT) {
+ context->state = RENDER_STATE_HAD_ATTACHMENT_THEN_TEXT;
+ }
+ return NULL;
+ }
+
+ context->hasTextPart = true;
+
+ if (mimeType->isEqual(MCSTR("text/plain"))) {
+ String * charset = part->charset();
+ Data * data = NULL;
+ if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) {
+ data = context->dataCallback->dataForIMAPPart(context->folder, (IMAPPart *) part);
+ }
+ else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) {
+ data = ((Attachment *) part)->data();
+ MCAssert(data != NULL);
+ }
+ if (data == NULL)
+ return NULL;
+
+ String * str = data->stringWithDetectedCharset(charset, false);
+ context->firstRendered = true;
+ return str->htmlEncodedString();
+ }
+ else if (mimeType->isEqual(MCSTR("text/html"))) {
+ String * charset = part->charset();
+ Data * data = NULL;
+ if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) {
+ data = context->dataCallback->dataForIMAPPart(context->folder, (IMAPPart *) part);
+ }
+ else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) {
+ data = ((Attachment *) part)->data();
+ MCAssert(data != NULL);
+ }
+ if (data == NULL)
+ return NULL;
+
+ String * str = data->stringWithDetectedCharset(charset, true);
+ str = str->cleanedHTMLString();
+ str = context->htmlCallback->filterHTMLForPart(str);
+ context->firstRendered = true;
+ return str;
+ }
+ else {
+ MCAssert(0);
+ return NULL;
+ }
+ }
+ else {
+ if (context->pass == 0) {
+ if (context->state == RENDER_STATE_NONE) {
+ context->state = RENDER_STATE_HAD_ATTACHMENT;
+ }
+ return NULL;
+ }
+
+ if (part->uniqueID() == NULL) {
+ part->setUniqueID(String::uuidString());
+ }
+
+ String * result = String::string();
+ String * separatorString;
+ String * content;
+
+ if (!context->firstAttachment && context->hasTextPart) {
+ separatorString = context->htmlCallback->templateForAttachmentSeparator();
+ }
+ else {
+ separatorString = MCSTR("");
+ }
+
+ context->firstAttachment = true;
+
+ if (context->htmlCallback->canPreviewPart(part)) {
+ if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) {
+ context->dataCallback->prefetchImageIMAPPart(context->folder, (IMAPPart *) part);
+ }
+ String * url = String::stringWithUTF8Format("x-mailcore-image:%s",
+ part->uniqueID()->UTF8Characters());
+ HashMap * values = context->htmlCallback->templateValuesForPart(part);
+ values->setObjectForKey(MCSTR("URL"), url);
+ content = renderTemplate(context->htmlCallback->templateForImage(), values);
+ }
+ else {
+ if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) {
+ context->dataCallback->prefetchAttachmentIMAPPart(context->folder, (IMAPPart *) part);
+ }
+ HashMap * values = context->htmlCallback->templateValuesForPart(part);
+ content = renderTemplate(context->htmlCallback->templateForAttachment(), values);
+ }
+
+ result->appendString(separatorString);
+ result->appendString(content);
+
+ return result;
+ }
+}
+
+String * htmlForAbstractMessagePart(AbstractMessagePart * part, htmlRendererContext * context)
+{
+ String * substring = htmlForAbstractPart(part->mainPart(), context);
+ if (context->pass == 0) {
+ return NULL;
+ }
+ MCAssert(substring != NULL);
+
+ String * result = String::string();
+ HashMap * values = context->htmlCallback->templateValuesForHeader(part->header());
+ String * headerString = renderTemplate(context->htmlCallback->templateForMainHeader(), values);
+ result->appendString(headerString);
+ result->appendString(substring);
+ return result;
+}
+
+String * htmlForAbstractMultipartAlternative(AbstractMultipart * part, htmlRendererContext * context)
+{
+ AbstractPart * preferredAlternative = preferredPartInMultipartAlternative(part);
+ if (preferredAlternative == NULL)
+ return MCSTR("");
+
+ return htmlForAbstractPart(preferredAlternative, context);
+}
+
+String * htmlForAbstractMultipartMixed(AbstractMultipart * part, htmlRendererContext * context)
+{
+ String * result = String::string();
+ for(unsigned int i = 0 ; i < part->parts()->count() ; i ++) {
+ AbstractPart * subpart = (AbstractPart *) part->parts()->objectAtIndex(i);
+ String * substring = htmlForAbstractPart(subpart, context);
+ if (context->pass != 0) {
+ if (substring == NULL)
+ return NULL;
+
+ result->appendString(substring);
+ }
+ }
+ return result;
+}
+
+String * htmlForAbstractMultipartRelated(AbstractMultipart * part, htmlRendererContext * context)
+{
+ if (part->parts()->count() == 0) {
+ if (context->pass == 0) {
+ return NULL;
+ }
+ else {
+ return MCSTR("");
+ }
+ }
+
+ AbstractPart * subpart = (AbstractPart *) part->parts()->objectAtIndex(0);
+ return htmlForAbstractPart(subpart, context);
+}
+
+void fillTemplateDictionaryFromMCHashMap(ctemplate::TemplateDictionary * dict, HashMap * mcHashMap)
+{
+ Array * keys = mcHashMap->allKeys();
+
+ for(unsigned int i = 0 ; i < keys->count() ; i ++) {
+ String * key = (String *) keys->objectAtIndex(i);
+ Object * value;
+
+ value = mcHashMap->objectForKey(key);
+ if (value->className()->isEqual(MCSTR("mailcore::String"))) {
+ String * str;
+
+ str = (String *) value;
+ dict->SetValue(key->UTF8Characters(), str->UTF8Characters());
+ }
+ else if (value->className()->isEqual(MCSTR("mailcore::Array"))) {
+ Array * array;
+
+ array = (Array *) value;
+ for(unsigned int k = 0 ; k < array->count() ; k ++) {
+ HashMap * item = (HashMap *) array->objectAtIndex(k);
+ ctemplate::TemplateDictionary * subDict = dict->AddSectionDictionary(key->UTF8Characters());
+ fillTemplateDictionaryFromMCHashMap(subDict, item);
+ }
+ }
+ else if (value->className()->isEqual(MCSTR("mailcore::HashMap"))) {
+ ctemplate::TemplateDictionary * subDict;
+ HashMap * item;
+
+ item = (HashMap *) value;
+ subDict = dict->AddSectionDictionary(key->UTF8Characters());
+ fillTemplateDictionaryFromMCHashMap(subDict, item);
+ }
+ }
+}
+
+String * renderTemplate(String * templateContent, HashMap * values)
+{
+ ctemplate::TemplateDictionary dict("template dict");
+ std::string output;
+ Data * data;
+
+ fillTemplateDictionaryFromMCHashMap(&dict, values);
+ data = templateContent->dataUsingEncoding("utf-8");
+ ctemplate::Template * tpl = ctemplate::Template::StringToTemplate(data->bytes(), data->length(), ctemplate::DO_NOT_STRIP);
+ if (!tpl->Expand(&output, &dict))
+ return NULL;
+ delete tpl;
+
+ return String::stringWithUTF8Characters(output.c_str());
+}
+
+String * HTMLRenderer::htmlForRFC822Message(MessageParser * message,
+ HTMLRendererTemplateCallback * htmlCallback)
+{
+ return htmlForAbstractMessage(NULL, message, NULL, htmlCallback);
+}
+
+String * HTMLRenderer::htmlForIMAPMessage(String * folder,
+ IMAPMessage * message,
+ HTMLRendererIMAPCallback * dataCallback,
+ HTMLRendererTemplateCallback * htmlCallback)
+{
+ return htmlForAbstractMessage(folder, message, dataCallback, htmlCallback);
+}
diff --git a/src/core/renderer/MCHTMLRenderer.h b/src/core/renderer/MCHTMLRenderer.h
new file mode 100644
index 00000000..042625cf
--- /dev/null
+++ b/src/core/renderer/MCHTMLRenderer.h
@@ -0,0 +1,38 @@
+//
+// MCHTMLRenderer.h
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/23/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __testUI__MCHTMLRenderer__
+#define __testUI__MCHTMLRenderer__
+
+#include <mailcore/MCAbstract.h>
+#include <mailcore/MCIMAP.h>
+#include <mailcore/MCRFC822.h>
+
+#ifdef __cplusplus
+
+namespace mailcore {
+
+ class MessageParser;
+ class HTMLRendererTemplateCallback;
+ class HTMLRendererIMAPCallback;
+
+ class HTMLRenderer {
+ public:
+ static String * htmlForRFC822Message(MessageParser * message,
+ HTMLRendererTemplateCallback * htmlCallback);
+
+ static String * htmlForIMAPMessage(String * folder,
+ IMAPMessage * message,
+ HTMLRendererIMAPCallback * dataCallback,
+ HTMLRendererTemplateCallback * htmlCallback);
+ };
+};
+
+#endif
+
+#endif /* defined(__testUI__MCHTMLRenderer__) */
diff --git a/src/core/renderer/MCHTMLRendererCallback.cpp b/src/core/renderer/MCHTMLRendererCallback.cpp
new file mode 100644
index 00000000..10b704d6
--- /dev/null
+++ b/src/core/renderer/MCHTMLRendererCallback.cpp
@@ -0,0 +1,259 @@
+//
+// MCHTMLRendererCallback.cpp
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 2/2/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCHTMLRendererCallback.h"
+
+#include "MCAddressDisplay.h"
+#include "MCDateFormatter.h"
+#include "MCSizeFormatter.h"
+#include "MCAttachment.h"
+
+using namespace mailcore;
+
+mailcore::HashMap * HTMLRendererTemplateCallback::templateValuesForHeader(mailcore::MessageHeader * header)
+{
+ mailcore::HashMap * result = mailcore::HashMap::hashMap();
+
+ if (header->from() != NULL) {
+ result->setObjectForKey(MCSTR("HASFROM"), mailcore::HashMap::hashMap());
+ result->setObjectForKey(MCSTR("FROM"), mailcore::AddressDisplay::displayStringForAddress(header->from())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("SHORTFROM"), mailcore::AddressDisplay::shortDisplayStringForAddress(header->from())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("VERYSHORTFROM"), mailcore::AddressDisplay::veryShortDisplayStringForAddress(header->from())->htmlEncodedString());
+ }
+ else {
+ result->setObjectForKey(MCSTR("NOFROM"), mailcore::HashMap::hashMap());
+ }
+
+ if ((header->to() != NULL) && (header->to()->count() > 0)) {
+ result->setObjectForKey(MCSTR("HASTO"), mailcore::HashMap::hashMap());
+ result->setObjectForKey(MCSTR("TO"), mailcore::AddressDisplay::displayStringForAddresses(header->to())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("SHORTTO"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->to())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("VERYSHORTTO"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->to())->htmlEncodedString());
+ }
+ else {
+ result->setObjectForKey(MCSTR("NOTO"), mailcore::HashMap::hashMap());
+ }
+
+ if ((header->cc() != NULL) && (header->cc()->count() > 0)) {
+ result->setObjectForKey(MCSTR("HASCC"), mailcore::HashMap::hashMap());
+ result->setObjectForKey(MCSTR("CC"), mailcore::AddressDisplay::displayStringForAddresses(header->cc())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("SHORTCC"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->cc())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("VERYSHORTCC"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->cc())->htmlEncodedString());
+ }
+ else {
+ result->setObjectForKey(MCSTR("NOCC"), mailcore::HashMap::hashMap());
+ }
+
+ if ((header->bcc() != NULL) && (header->bcc()->count() > 0)) {
+ result->setObjectForKey(MCSTR("HASBCC"), mailcore::HashMap::hashMap());
+ result->setObjectForKey(MCSTR("BCC"), mailcore::AddressDisplay::displayStringForAddresses(header->bcc())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("SHORTBCC"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->bcc())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("VERYSHORTBCC"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->bcc())->htmlEncodedString());
+ }
+ else {
+ result->setObjectForKey(MCSTR("NOBCC"), mailcore::HashMap::hashMap());
+ }
+
+ mailcore::Array * recipient = new mailcore::Array();
+ recipient->addObjectsFromArray(header->to());
+ recipient->addObjectsFromArray(header->cc());
+ recipient->addObjectsFromArray(header->bcc());
+
+ if (recipient->count() > 0) {
+ result->setObjectForKey(MCSTR("HASRECIPIENT"), mailcore::HashMap::hashMap());
+ result->setObjectForKey(MCSTR("RECIPIENT"), mailcore::AddressDisplay::displayStringForAddresses(recipient)->htmlEncodedString());
+ result->setObjectForKey(MCSTR("SHORTRECIPIENT"), mailcore::AddressDisplay::shortDisplayStringForAddresses(recipient)->htmlEncodedString());
+ result->setObjectForKey(MCSTR("VERYSHORTRECIPIENT"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(recipient)->htmlEncodedString());
+ }
+ else {
+ result->setObjectForKey(MCSTR("NORECIPIENT"), mailcore::HashMap::hashMap());
+ }
+ recipient->release();
+
+ if ((header->replyTo() != NULL) && (header->replyTo()->count() > 0)) {
+ result->setObjectForKey(MCSTR("HASREPLYTO"), mailcore::HashMap::hashMap());
+ result->setObjectForKey(MCSTR("REPLYTO"), mailcore::AddressDisplay::displayStringForAddresses(header->replyTo())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("SHORTREPLYTO"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->replyTo())->htmlEncodedString());
+ result->setObjectForKey(MCSTR("VERYSHORTREPLYTO"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->replyTo())->htmlEncodedString());
+ }
+ else {
+ result->setObjectForKey(MCSTR("NOREPLYTO"), mailcore::HashMap::hashMap());
+ }
+
+ if ((header->subject() != NULL) && (header->subject()->length() > 0)) {
+ result->setObjectForKey(MCSTR("EXTRACTEDSUBJECT"), header->partialExtractedSubject()->htmlEncodedString());
+ result->setObjectForKey(MCSTR("SUBJECT"), header->subject()->htmlEncodedString());
+ result->setObjectForKey(MCSTR("HASSUBJECT"), mailcore::HashMap::hashMap());
+ }
+ else {
+ result->setObjectForKey(MCSTR("NOSUBJECT"), mailcore::HashMap::hashMap());
+ }
+
+ mailcore::String * dateString;
+ static mailcore::DateFormatter * fullFormatter = NULL;
+ if (fullFormatter == NULL) {
+ fullFormatter = new mailcore::DateFormatter();
+ fullFormatter->setDateStyle(mailcore::DateFormatStyleFull);
+ fullFormatter->setTimeStyle(mailcore::DateFormatStyleFull);
+ }
+ dateString = fullFormatter->stringFromDate(header->date());
+ if (dateString != NULL) {
+ result->setObjectForKey(MCSTR("FULLDATE"), dateString->htmlEncodedString());
+ }
+ static mailcore::DateFormatter * longFormatter = NULL;
+ if (longFormatter == NULL) {
+ longFormatter = new mailcore::DateFormatter();
+ longFormatter->setDateStyle(mailcore::DateFormatStyleLong);
+ longFormatter->setTimeStyle(mailcore::DateFormatStyleLong);
+ }
+ dateString = longFormatter->stringFromDate(header->date());
+ if (dateString != NULL) {
+ result->setObjectForKey(MCSTR("LONGDATE"), dateString->htmlEncodedString());
+ }
+ static mailcore::DateFormatter * mediumFormatter = NULL;
+ if (mediumFormatter == NULL) {
+ mediumFormatter = new mailcore::DateFormatter();
+ mediumFormatter->setDateStyle(mailcore::DateFormatStyleMedium);
+ mediumFormatter->setTimeStyle(mailcore::DateFormatStyleMedium);
+ }
+ dateString = mediumFormatter->stringFromDate(header->date());
+ if (dateString != NULL) {
+ result->setObjectForKey(MCSTR("MEDIUMDATE"), dateString->htmlEncodedString());
+ }
+ static mailcore::DateFormatter * shortFormatter = NULL;
+ if (shortFormatter == NULL) {
+ shortFormatter = new mailcore::DateFormatter();
+ shortFormatter->setDateStyle(mailcore::DateFormatStyleShort);
+ shortFormatter->setTimeStyle(mailcore::DateFormatStyleShort);
+ }
+ dateString = shortFormatter->stringFromDate(header->date());
+ if (dateString != NULL) {
+ result->setObjectForKey(MCSTR("SHORTDATE"), dateString->htmlEncodedString());
+ }
+
+ return result;
+}
+
+mailcore::HashMap * HTMLRendererTemplateCallback::templateValuesForPart(mailcore::AbstractPart * part)
+{
+ mailcore::HashMap * result = mailcore::HashMap::hashMap();
+ mailcore::String * filename = NULL;
+
+ if (part->filename() != NULL) {
+ filename = part->filename()->lastPathComponent();
+ }
+
+ if (filename != NULL) {
+ result->setObjectForKey(MCSTR("FILENAME"), filename->htmlEncodedString());
+ }
+
+ if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) {
+ mailcore::IMAPPart * imapPart = (mailcore::IMAPPart *) part;
+ mailcore::String * value = mailcore::SizeFormatter::stringWithSize(imapPart->size());
+ result->setObjectForKey(MCSTR("SIZE"), value);
+ result->setObjectForKey(MCSTR("HASSIZE"), mailcore::HashMap::hashMap());
+ }
+ else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) {
+ mailcore::Attachment * attachment = (mailcore::Attachment *) part;
+ mailcore::String * value = mailcore::SizeFormatter::stringWithSize(attachment->data()->length());
+ result->setObjectForKey(MCSTR("SIZE"), value);
+ result->setObjectForKey(MCSTR("HASSIZE"), mailcore::HashMap::hashMap());
+ }
+ else {
+ result->setObjectForKey(MCSTR("NOSIZE"), mailcore::HashMap::hashMap());
+ }
+
+ if (part->contentID() != NULL) {
+ result->setObjectForKey(MCSTR("CONTENTID"), part->contentID());
+ }
+ if (part->uniqueID() != NULL) {
+ result->setObjectForKey(MCSTR("UNIQUEID"), part->uniqueID());
+ }
+
+ return result;
+}
+
+mailcore::String * HTMLRendererTemplateCallback::templateForMainHeader()
+{
+ return MCSTR("<div style=\"background-color:#eee\">\
+ {{#HASFROM}}\
+ <div><b>From:</b> {{FROM}}</div>\
+ {{/HASFROM}}\
+ {{#HASTO}}\
+ <div><b>To:</b> {{TO}}</div>\
+ {{/HASTO}}\
+ {{#HASCC}}\
+ <div><b>Cc:</b> {{CC}}</div>\
+ {{/HASCC}}\
+ {{#HASBCC}}\
+ <div><b>Bcc:</b> {{BCC}}</div>\
+ {{/HASBCC}}\
+ {{#NORECIPIENT}}\
+ <div><b>To:</b> <i>Undisclosed recipient</i></div>\
+ {{/NORECIPIENT}}\
+ {{#HASSUBJECT}}\
+ <div><b>Subject:</b> {{EXTRACTEDSUBJECT}}</div>\
+ {{/HASSUBJECT}}\
+ {{#NOSUBJECT}}\
+ <div><b>Subject:</b> <i>No Subject</i></div>\
+ {{/NOSUBJECT}}\
+ <div><b>Date:</b> {{LONGDATE}}</div>\
+ </div>");
+}
+
+mailcore::String * HTMLRendererTemplateCallback::templateForHeader()
+{
+ return templateForMainHeader();
+}
+
+mailcore::String * HTMLRendererTemplateCallback::templateForImage()
+{
+ return MCSTR("");
+}
+
+mailcore::String * HTMLRendererTemplateCallback::templateForAttachment()
+{
+ return MCSTR("{{#HASSIZE}}\
+ <div>- {{FILENAME}}, {{SIZE}}</div>\
+ {{/HASSIZE}}\
+ {{#HASSIZE}}\
+ <div>- {{FILENAME}}</div>\
+ {{/NOSIZE}}\
+ ");
+}
+
+mailcore::String * HTMLRendererTemplateCallback::templateForMessage()
+{
+ return MCSTR("<div style=\"padding-bottom: 20px;\">{{HEADER}}</div><div>{{BODY}}</div>");
+}
+
+
+mailcore::String * HTMLRendererTemplateCallback::templateForEmbeddedMessage()
+{
+ return templateForMessage();
+}
+
+mailcore::String * HTMLRendererTemplateCallback::templateForAttachmentSeparator()
+{
+ return MCSTR("<hr/>");
+}
+
+mailcore::String * HTMLRendererTemplateCallback::filterHTMLForMessage(mailcore::String * html)
+{
+ return html;
+}
+
+mailcore::String * HTMLRendererTemplateCallback::filterHTMLForPart(mailcore::String * html)
+{
+ return html;
+}
+
+bool HTMLRendererTemplateCallback::canPreviewPart(AbstractPart * part)
+{
+ return false;
+}
diff --git a/src/core/renderer/MCHTMLRendererCallback.h b/src/core/renderer/MCHTMLRendererCallback.h
new file mode 100644
index 00000000..2972249e
--- /dev/null
+++ b/src/core/renderer/MCHTMLRendererCallback.h
@@ -0,0 +1,51 @@
+//
+// MCHTMLRendererCallback.h
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 2/2/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __mailcore2__MCHTMLRendererCallback__
+#define __mailcore2__MCHTMLRendererCallback__
+
+#include <mailcore/MCAbstract.h>
+#include <mailcore/MCIMAP.h>
+
+#ifdef __cplusplus
+
+namespace mailcore {
+
+ class MessageParser;
+
+ class HTMLRendererIMAPCallback {
+ public:
+ virtual Data * dataForIMAPPart(String * folder, IMAPPart * part) { return NULL; }
+ virtual void prefetchAttachmentIMAPPart(String * folder, IMAPPart * part) {}
+ virtual void prefetchImageIMAPPart(String * folder, IMAPPart * part) {}
+ };
+
+ class HTMLRendererTemplateCallback {
+ public:
+ virtual bool canPreviewPart(AbstractPart * part);
+
+ virtual HashMap * templateValuesForHeader(MessageHeader * header);
+ virtual HashMap * templateValuesForPart(AbstractPart * part);
+
+ virtual String * templateForMainHeader();
+ virtual String * templateForHeader();
+ virtual String * templateForImage();
+ virtual String * templateForAttachment();
+ virtual String * templateForMessage();
+ virtual String * templateForEmbeddedMessage();
+ virtual String * templateForAttachmentSeparator();
+
+ virtual String * filterHTMLForPart(String * html);
+ virtual String * filterHTMLForMessage(String * html);
+ };
+
+}
+
+#endif
+
+#endif /* defined(__mailcore2__MCHTMLRendererCallback__) */
diff --git a/src/core/renderer/MCRenderer.h b/src/core/renderer/MCRenderer.h
new file mode 100644
index 00000000..a03b5be9
--- /dev/null
+++ b/src/core/renderer/MCRenderer.h
@@ -0,0 +1,18 @@
+//
+// MCRenderer.h
+// mailcore2
+//
+// Created by DINH Viêt Hoà on 2/2/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef mailcore2_MCRenderer_h
+#define mailcore2_MCRenderer_h
+
+#include <mailcore/MCAddressDisplay.h>
+#include <mailcore/MCDateFormatter.h>
+#include <mailcore/MCSizeFormatter.h>
+#include <mailcore/MCHTMLRenderer.h>
+#include <mailcore/MCHTMLRendererCallback.h>
+
+#endif
diff --git a/src/core/renderer/MCSizeFormatter.cpp b/src/core/renderer/MCSizeFormatter.cpp
new file mode 100644
index 00000000..c3795c63
--- /dev/null
+++ b/src/core/renderer/MCSizeFormatter.cpp
@@ -0,0 +1,43 @@
+//
+// MCSizeFormatter.cpp
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/29/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#include "MCSizeFormatter.h"
+
+#include <math.h>
+
+using namespace mailcore;
+
+String * SizeFormatter::stringWithSize(unsigned int size)
+{
+ double divider;
+ String * unit;
+
+ if (size >= 1024 * 1024 * 1024) {
+ divider = 1024 * 1024 * 1024;
+ unit = MCLOCALIZEDSTRING(MCSTR("GB"));
+ }
+ else if (size >= 1024 * 1024) {
+ divider = 1024 * 1024;
+ unit = MCLOCALIZEDSTRING(MCSTR("MB"));
+ }
+ else if (size >= 1024) {
+ divider = 1024;
+ unit = MCLOCALIZEDSTRING(MCSTR("KB"));
+ }
+ else {
+ divider = 1;
+ unit = MCLOCALIZEDSTRING(MCSTR("bytes"));
+ }
+
+ if ((size / divider) - round(size / divider) < 0.1) {
+ return String::stringWithUTF8Format("%.0f %s", size / divider, unit->UTF8Characters());
+ }
+ else {
+ return String::stringWithUTF8Format("%.1f %@", size / divider, unit->UTF8Characters());
+ }
+}
diff --git a/src/core/renderer/MCSizeFormatter.h b/src/core/renderer/MCSizeFormatter.h
new file mode 100644
index 00000000..a6c74010
--- /dev/null
+++ b/src/core/renderer/MCSizeFormatter.h
@@ -0,0 +1,28 @@
+//
+// MCSizeFormatter.h
+// testUI
+//
+// Created by DINH Viêt Hoà on 1/29/13.
+// Copyright (c) 2013 MailCore. All rights reserved.
+//
+
+#ifndef __testUI__MCSizeFormatter__
+#define __testUI__MCSizeFormatter__
+
+#include <mailcore/MCBaseTypes.h>
+
+#ifdef __cplusplus
+
+namespace mailcore {
+ class String;
+
+ class SizeFormatter : public Object {
+ public:
+ static String * stringWithSize(unsigned int size);
+ };
+
+}
+
+#endif
+
+#endif /* defined(__testUI__MCSizeFormatter__) */