From 6d81a82a76208cc31a74c248921d23348fb8be40 Mon Sep 17 00:00:00 2001 From: randomdan Date: Tue, 3 Jan 2012 23:10:47 +0000 Subject: Allowing specification of output encoding --- project2/cgi/cgiAppEngine.cpp | 22 ++++++----- project2/cgi/cgiAppEngine.h | 3 +- project2/cgi/cgiEnvironment.cpp | 2 + project2/cgi/cgiEnvironment.h | 1 + project2/cgi/cgiStageCustomError.cpp | 2 +- project2/cgi/cgiStageCustomNotFound.cpp | 2 +- project2/cgi/cgiStageDefaultError.cpp | 2 +- project2/cgi/cgiStageDefaultNotFound.cpp | 2 +- project2/cgi/cgiStageFail.cpp | 2 +- project2/cgi/cgiStagePresent.cpp | 7 ++-- project2/cgi/cgiStageRedirect.cpp | 2 +- project2/cgi/cgiStageRequest.cpp | 2 +- project2/common/scripts.cpp | 13 +++++++ project2/common/scripts.h | 1 + project2/common/transform.h | 2 +- project2/json/couchSession.cpp | 4 +- project2/json/json.h | 16 ++++---- project2/json/presenter.cpp | 6 +-- project2/json/serialize.cpp | 46 ++++++++++++---------- project2/json/transformStream.cpp | 15 +++++-- project2/mail/sendmailTask.cpp | 67 +++++++++++++------------------- project2/mail/sendmailTask.h | 2 + project2/xml/transformHtml.cpp | 6 +-- project2/xml/transformHtml.h | 2 +- project2/xml/transformText.cpp | 18 +++++---- project2/xml/transformText.h | 4 +- project2/xml/xmlPresenter.cpp | 4 +- project2/xml/xmlPresenter.h | 2 +- 28 files changed, 141 insertions(+), 116 deletions(-) diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 8093ef3..b92095c 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -45,20 +45,22 @@ CgiApplicationEngine::env() const class CgiResult : public TransformChainLink { public: - CgiResult(CgiApplicationEngine::HttpHeaderPtr & h, std::ostream & s) : + CgiResult(CgiApplicationEngine::HttpHeaderPtr & h, std::ostream & s, const std::string & e) : header(h), - stream(s) { + stream(s), + encoding(e) { } CgiApplicationEngine::HttpHeaderPtr header; std::ostream & stream; + const std::string encoding; }; class WriteToCgiResult : public TransformImpl { public: void transform(const WritableContent * wc, CgiResult * cr) const { - cr->header->addHeader("Content-Type", wc->getContentType()); + cr->header->addHeader("Content-Type", Glib::ustring::compose("%1; charset=%2", wc->getContentType(), cr->encoding)); cr->header->render(cr->stream); - wc->writeTo(cr->stream); + wc->writeTo(cr->stream, cr->encoding); } }; DECLARE_TRANSFORM(WriteToCgiResult); @@ -115,9 +117,9 @@ CgiApplicationEngine::process() const } while (currentStage.get<0>()); endTime = boost::date_time::microsec_clock::universal_time(); ResponseStagePtr rs = currentStage.get<1>(); - if (currentStage.get<3>()) { - addAppData(currentStage.get<3>().get(), rs->outputOptions); - addEnvData(currentStage.get<3>().get(), rs->outputOptions); + if (const MultiRowSetPresenter * p = currentStage.get<3>().get()) { + addAppData(p, rs->outputOptions); + addEnvData(p, rs->outputOptions); } HttpHeaderPtr header = rs->getHeader(); if (!sessionEmpty || !cursession->Empty()) { @@ -125,9 +127,9 @@ CgiApplicationEngine::process() const header->setCookie(cgicc::HTTPCookie(SESSIONID, cursession->ID.str(), "Session ID", _env->getServerName().substr(_env->getServerName().find(".")), env()->sessionTimeOut, "/", false)); } - if (currentStage.get<2>()) { - TransformSourcePtr ts = currentStage.get<2>(); - addFinalTransformTarget(ts, new CgiResult(header, IO)); + if (TransformSourcePtr ts = currentStage.get<2>()) { + addFinalTransformTarget(ts, new CgiResult(header, IO, + rs && rs->root ? rs->root->value("encoding", _env->outputEncoding) : VariableType(_env->outputEncoding))); std::fstream * ddd = NULL; if (!_env->dumpdatadoc.empty()) { ddd = new std::fstream(_env->dumpdatadoc.c_str(), std::fstream::trunc | std::fstream::out); diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h index 80dad6e..a7648d1 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -67,10 +67,11 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink /// Base class for a stage that can be a response to the client class ResponseStage : public Stage { public: - ResponseStage(const CgiEnvironment * e); + ResponseStage(const CgiEnvironment * e, ScriptNodePtr root); virtual HttpHeaderPtr getHeader() const = 0; OutputOptionsPtr outputOptions; + ScriptNodePtr root; }; /// Stage implementation used to bootstrap the iteration process based on the CGI environment diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index 7b2b254..b1565ad 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -55,6 +55,8 @@ CgiEnvironment::CgiEnvironment(cgicc::Cgicc * c) : "The module with which to implement session management") ("cgi.hostRegex", hpi, "Regular expression used to define a hostname -> platform association") + ("cgi.outputEncoding", Options::value(&outputEncoding, "utf-8"), + "The encoding to use when outputing to the web server") ; } diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index 28e47d3..25ea90f 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -53,6 +53,7 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { std::string onErrorPresent; std::string defaultPresenter; std::string sessionModule; + std::string outputEncoding; }; #endif diff --git a/project2/cgi/cgiStageCustomError.cpp b/project2/cgi/cgiStageCustomError.cpp index eb66ff0..957b572 100644 --- a/project2/cgi/cgiStageCustomError.cpp +++ b/project2/cgi/cgiStageCustomError.cpp @@ -5,7 +5,7 @@ #include "logger.h" CgiApplicationEngine::CustomErrorStage::CustomErrorStage(const CgiEnvironment * env, const std::exception & ex, ScriptReaderPtr s) : - CgiApplicationEngine::ResponseStage(env), + CgiApplicationEngine::ResponseStage(env, s->root()), ::CommonObjects(s->root()), ::CheckHost(s->root()), CgiApplicationEngine::DefaultErrorStage(env, ex), diff --git a/project2/cgi/cgiStageCustomNotFound.cpp b/project2/cgi/cgiStageCustomNotFound.cpp index e6520dd..3ce8012 100644 --- a/project2/cgi/cgiStageCustomNotFound.cpp +++ b/project2/cgi/cgiStageCustomNotFound.cpp @@ -5,7 +5,7 @@ #include "logger.h" CgiApplicationEngine::CustomNotFoundStage::CustomNotFoundStage(const CgiEnvironment * env, const ScriptNotFound & notfound, ScriptReaderPtr s) : - CgiApplicationEngine::ResponseStage(env), + CgiApplicationEngine::ResponseStage(env, s->root()), ::CommonObjects(s->root()), ::CheckHost(s->root()), CgiApplicationEngine::DefaultNotFoundStage(env, notfound), diff --git a/project2/cgi/cgiStageDefaultError.cpp b/project2/cgi/cgiStageDefaultError.cpp index e464981..d2abeef 100644 --- a/project2/cgi/cgiStageDefaultError.cpp +++ b/project2/cgi/cgiStageDefaultError.cpp @@ -8,7 +8,7 @@ static const Glib::ustring DefaultErrorStageResp("error"); CgiApplicationEngine::DefaultErrorStage::DefaultErrorStage(const CgiEnvironment * env, const std::exception & ex) : - CgiApplicationEngine::ResponseStage(env), + CgiApplicationEngine::ResponseStage(env, NULL), buf(__cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL)), what(ex.what()), pres(new XmlPresenter(DefaultErrorStageResp, e->errorTransformStyle, e->errorContentType)) diff --git a/project2/cgi/cgiStageDefaultNotFound.cpp b/project2/cgi/cgiStageDefaultNotFound.cpp index 2cf0475..b971dc3 100644 --- a/project2/cgi/cgiStageDefaultNotFound.cpp +++ b/project2/cgi/cgiStageDefaultNotFound.cpp @@ -7,7 +7,7 @@ static const Glib::ustring DefaultNotFoundStageResp("notfound"); CgiApplicationEngine::DefaultNotFoundStage::DefaultNotFoundStage(const CgiEnvironment * env, const ScriptNotFound & notfound) : - CgiApplicationEngine::ResponseStage(env), + CgiApplicationEngine::ResponseStage(env, NULL), nf(notfound), pres(new XmlPresenter(DefaultNotFoundStageResp, e->errorTransformStyle, e->errorContentType)) { diff --git a/project2/cgi/cgiStageFail.cpp b/project2/cgi/cgiStageFail.cpp index 62de295..64bc15a 100644 --- a/project2/cgi/cgiStageFail.cpp +++ b/project2/cgi/cgiStageFail.cpp @@ -9,7 +9,7 @@ namespace CgiApplicationExtras { class FailStage : public CgiApplicationEngine::ResponseStage { public: FailStage(const CgiEnvironment * env, int c, const std::string & m) : - ResponseStage(env), + ResponseStage(env, NULL), code(c), message(m) { } diff --git a/project2/cgi/cgiStagePresent.cpp b/project2/cgi/cgiStagePresent.cpp index 1330cdc..2ca6147 100644 --- a/project2/cgi/cgiStagePresent.cpp +++ b/project2/cgi/cgiStagePresent.cpp @@ -6,7 +6,7 @@ #include CgiApplicationEngine::PresentStage::PresentStage(const CgiEnvironment * e, ScriptReaderPtr s) : - CgiApplicationEngine::ResponseStage(e), + CgiApplicationEngine::ResponseStage(e, s->root()), CommonObjects(s->root()), CheckHost(s->root()), ViewHost(s->root()), @@ -41,8 +41,9 @@ CgiApplicationEngine::PresentStage::getPresenter() const return presenter; } -CgiApplicationEngine::ResponseStage::ResponseStage(const CgiEnvironment * e) : - CgiApplicationEngine::Stage(e) +CgiApplicationEngine::ResponseStage::ResponseStage(const CgiEnvironment * e, ScriptNodePtr r) : + CgiApplicationEngine::Stage(e), + root(r) { } diff --git a/project2/cgi/cgiStageRedirect.cpp b/project2/cgi/cgiStageRedirect.cpp index 8c918f1..5459e08 100644 --- a/project2/cgi/cgiStageRedirect.cpp +++ b/project2/cgi/cgiStageRedirect.cpp @@ -8,7 +8,7 @@ namespace CgiApplicationExtras { class RedirectStage : public CgiApplicationEngine::ResponseStage { public: RedirectStage(const CgiEnvironment * env, const std::string & u) : - ResponseStage(env), + ResponseStage(env, NULL), url(u) { } diff --git a/project2/cgi/cgiStageRequest.cpp b/project2/cgi/cgiStageRequest.cpp index d505f3c..136627f 100644 --- a/project2/cgi/cgiStageRequest.cpp +++ b/project2/cgi/cgiStageRequest.cpp @@ -9,7 +9,7 @@ CgiApplicationEngine::RequestStage::RequestStage(const CgiEnvironment * e, Scrip SourceObject(s->root()), CommonObjects(s->root()), ::CheckHost(s->root()), - CgiApplicationEngine::ResponseStage(e), + CgiApplicationEngine::ResponseStage(e, s->root()), ::TaskHost(s->root()), present(s->root()->value("present","").as()) { diff --git a/project2/common/scripts.cpp b/project2/common/scripts.cpp index 4d15cfe..65a1ed0 100644 --- a/project2/common/scripts.cpp +++ b/project2/common/scripts.cpp @@ -27,3 +27,16 @@ ScriptNode::value(const Glib::ustring & n, const VariableType & def) const return def; } } + +bool +ScriptNode::applyValue(const Glib::ustring & n, VariableType & target) const +{ + try { + target = value(n); + return true; + } + catch (const ValueNotFound &) { + return false; + } +} + diff --git a/project2/common/scripts.h b/project2/common/scripts.h index becfda2..3469d4a 100644 --- a/project2/common/scripts.h +++ b/project2/common/scripts.h @@ -38,6 +38,7 @@ class ScriptNode : public IntrusivePtrBase { virtual ScriptNodes childrenIn(const Glib::ustring & sub) const = 0; virtual bool valueExists(const Glib::ustring & name) const = 0; + bool applyValue(const Glib::ustring & name, VariableType & target) const; virtual VariableImpl * variable(const boost::optional & defaultSource = boost::optional()) const = 0; virtual VariableImpl * variable(const Glib::ustring & name) const = 0; VariableImpl * variable(const Glib::ustring & name, const VariableType & def) const; diff --git a/project2/common/transform.h b/project2/common/transform.h index 175bf42..4e80476 100644 --- a/project2/common/transform.h +++ b/project2/common/transform.h @@ -89,7 +89,7 @@ class TransformImpl : public Transform { class WritableContent { public: virtual Glib::ustring getContentType() const = 0; - virtual void writeTo(std::ostream &) const = 0; + virtual void writeTo(std::ostream &, const std::string & encoding) const = 0; }; #endif diff --git a/project2/json/couchSession.cpp b/project2/json/couchSession.cpp index a328ad5..f810486 100644 --- a/project2/json/couchSession.cpp +++ b/project2/json/couchSession.cpp @@ -42,7 +42,7 @@ class CouchSessionContainer : public SessionContainer { json::Object obj; s->ForeachValue(boost::bind(&CouchSessionContainer::addToObject, &obj, _1, _2)); obj[ExpiryKey] = json::ValuePtr(new json::Value((json::Number)s->ExpiryTime())); - Glib::ustring out = json::serializeObject(obj); + Glib::ustring out = json::serializeObject(obj, "utf-8"); c->setopt(CURLOPT_INFILESIZE_LARGE, (curl_off_t)out.size()); unsigned int off = 0; BOOST_FOREACH(const std::string & b, baseUrls) { @@ -147,7 +147,7 @@ class CustomCouchSessionLoader : public SessionContainerLoaderImplsetopt(CURLOPT_FAILONERROR, 1); diff --git a/project2/json/json.h b/project2/json/json.h index 7339ce4..23eeac2 100644 --- a/project2/json/json.h +++ b/project2/json/json.h @@ -29,14 +29,14 @@ namespace json { Value parseValue(Glib::ustring::const_iterator & s); Array parseArray(Glib::ustring::const_iterator &); - void serializeObject(const Object &, std::ostream & s); - void serializeValue(const Value &, std::ostream & s); - void serializeArray(const Array &, std::ostream & s); - void serializeString(const String &, std::ostream & s); - void serializeNumber(const Number &, std::ostream & s); - void serializeBoolean(const Boolean &, std::ostream & s); - void serializeNull(const Null &, std::ostream & s); - Glib::ustring serializeObject(const Object &); + void serializeObject(const Object &, std::ostream & s, const std::string & encoding); + void serializeValue(const Value &, std::ostream & s, const std::string & encoding); + void serializeArray(const Array &, std::ostream & s, const std::string & encoding); + void serializeString(const String &, std::ostream & s, const std::string & encoding); + void serializeNumber(const Number &, std::ostream & s, const std::string & encoding); + void serializeBoolean(const Boolean &, std::ostream & s, const std::string & encoding); + void serializeNull(const Null &, std::ostream & s, const std::string & encoding); + Glib::ustring serializeObject(const Object &, const std::string & encoding); } #endif diff --git a/project2/json/presenter.cpp b/project2/json/presenter.cpp index aaa72bf..6500ea1 100644 --- a/project2/json/presenter.cpp +++ b/project2/json/presenter.cpp @@ -9,7 +9,7 @@ class JsonPresenter : public MultiRowSetPresenter, public ContentPresenter, publ public: JsonPresenter(ScriptNodePtr s) : TransformSource(s), - ContentPresenter("application/json; charset=UTF-8"), + ContentPresenter("application/json"), SourceOf(s), SourceOf(s) { curRowSet.push(&object); @@ -53,8 +53,8 @@ class JsonPresenter : public MultiRowSetPresenter, public ContentPresenter, publ Glib::ustring getContentType() const { return contentType; } - void writeTo(std::ostream & o) const { - serializeObject(object, o); + void writeTo(std::ostream & o, const std::string & encoding) const { + serializeObject(object, o, encoding); } private: diff --git a/project2/json/serialize.cpp b/project2/json/serialize.cpp index ff2d778..a1ba1f6 100644 --- a/project2/json/serialize.cpp +++ b/project2/json/serialize.cpp @@ -2,35 +2,39 @@ #include "json.h" #include #include +#include namespace json { class JsonSerialize : public boost::static_visitor<> { public: - JsonSerialize(std::ostream & out) : o(out) { + JsonSerialize(std::ostream & out, const std::string & encoding) : + o(out), + e(encoding) { } void operator()(const String & s) const { - serializeString(s, o); + serializeString(s, o, e); } void operator()(const Number & s) const { - serializeNumber(s, o); + serializeNumber(s, o, e); } void operator()(const Array & s) const { - serializeArray(s, o); + serializeArray(s, o, e); } void operator()(const Object & s) const { - serializeObject(s, o); + serializeObject(s, o, e); } void operator()(const Null & s) const { - serializeNull(s, o); + serializeNull(s, o, e); } void operator()(const Boolean & s) const { - serializeBoolean(s, o); + serializeBoolean(s, o, e); } private: std::ostream & o; + std::string e; }; - void serializeObject(const Object & o, std::ostream & s) { + void serializeObject(const Object & o, std::ostream & s, const std::string & enc) { s << std::boolalpha; s << std::fixed; s << '{'; @@ -38,29 +42,30 @@ namespace json { if (&v != &*o.begin()) { s << ','; } - serializeString(v.first, s); + serializeString(v.first, s, enc); s << ':'; - serializeValue(*v.second, s); + serializeValue(*v.second, s, enc); } s << '}'; } - void serializeValue(const Value & v, std::ostream & s) { - boost::apply_visitor(JsonSerialize(s), v); + void serializeValue(const Value & v, std::ostream & s, const std::string & enc) { + boost::apply_visitor(JsonSerialize(s, enc), v); } - void serializeArray(const Array & a, std::ostream & s) { + void serializeArray(const Array & a, std::ostream & s, const std::string & enc) { s << '['; BOOST_FOREACH(const Array::value_type & v, a) { if (&v != &*a.begin()) { s << ','; } - serializeValue(*v, s); + serializeValue(*v, s, enc); } s << ']'; } - void serializeString(const String & str, std::ostream & s) { + void serializeString(const String & str, std::ostream & o, const std::string & encoding) { + std::stringstream s; s << '"'; BOOST_FOREACH(gunichar c, str) { if (c < 32) { @@ -105,23 +110,24 @@ namespace json { } } s << '"'; + o << Glib::convert(s.str(), encoding, "utf-8"); } - void serializeNumber(const Number & n, std::ostream & s) { + void serializeNumber(const Number & n, std::ostream & s, const std::string & ) { s << n; } - void serializeBoolean(const Boolean & b, std::ostream & s) { + void serializeBoolean(const Boolean & b, std::ostream & s, const std::string & ) { s << b; } - void serializeNull(const Null &, std::ostream & s) { + void serializeNull(const Null &, std::ostream & s, const std::string & ) { s << "null"; } - Glib::ustring serializeObject(const Object & o) { + Glib::ustring serializeObject(const Object & o, const std::string & enc) { std::stringstream out; - serializeObject(o, out); + serializeObject(o, out, enc); return out.str(); } } diff --git a/project2/json/transformStream.cpp b/project2/json/transformStream.cpp index 25f5d17..fae71b0 100644 --- a/project2/json/transformStream.cpp +++ b/project2/json/transformStream.cpp @@ -4,13 +4,22 @@ #include "json.h" #include "ostreamWrapper.h" -class TransformJsonToHttpStream : public TransformImpl { +class TransformJsonToStream : public TransformImpl { public: + TransformJsonToStream() : + encoding("utf-8") { + } void transform(const json::Object * obj, ostreamWrapper * o) const { - json::serializeObject(*obj, o->strm); + json::serializeObject(*obj, o->strm, encoding); + } + void configure(ScriptNodePtr s) + { + s->applyValue("encoding", encoding); } + private: + VariableType encoding; }; -DECLARE_TRANSFORM(TransformJsonToHttpStream); +DECLARE_TRANSFORM(TransformJsonToStream); diff --git a/project2/mail/sendmailTask.cpp b/project2/mail/sendmailTask.cpp index 2fc77fa..d3ee53a 100644 --- a/project2/mail/sendmailTask.cpp +++ b/project2/mail/sendmailTask.cpp @@ -12,6 +12,7 @@ #include "transformText.h" std::string SendMailTask::defaultMailServer; +std::string SendMailTask::defaultMailEncoding; class CustomSendMailTaskLoader : public ElementLoaderImpl { public: @@ -21,6 +22,8 @@ class CustomSendMailTaskLoader : public ElementLoaderImpl { opts ("sendmail.defaultServer", Options::value(&SendMailTask::defaultMailServer), "The address of the default mail relay server") + ("sendmail.defaultEncoding", Options::value(&SendMailTask::defaultMailEncoding, "utf-8"), + "The default encoding to use in email content") ; } const Options * @@ -84,16 +87,18 @@ SendMailTask::SortMailParts::operator()(const MailPartPtr & a, const MailPartPtr class BoundaryBegin : public SendMailTask::MailPart { public: - BoundaryBegin(const std::string & ct, uint8_t m) : + BoundaryBegin(const std::string & ct, const std::string & enc, uint8_t m) : MailPart(m, MailPart::mimeIdx, 0), - contentType(ct) { + contentType(ct), + encoding(enc) { } const char * write(char ** buf, int * len) { - *len = asprintf(buf, "\r\n--<>\r\nContent-Type: %s\r\n\r\n", contentType.c_str()); + *len = asprintf(buf, "\r\n--<>\r\nContent-Type: %s; %s\r\n\r\n", contentType.c_str(), encoding.c_str()); return *buf; } private: const std::string contentType; + const std::string encoding; }; class BoundaryEnd : public SendMailTask::MailPart { @@ -133,60 +138,40 @@ class Header : public SendMailTask::MailPart { class MimeContent : public SendMailTask::MailPart { public: - MimeContent(const char * s, int l, uint8_t m) : + MimeContent(const std::string & s, uint8_t m) : MailPart(m, MailPart::mimeIdx, 1), - str(s), - length(l) { + str(s) { } const char * write(char ** buf, int * len) { *buf = NULL; - *len = length; - return str; + *len = str.length(); + return str.c_str(); } private: - const char * str; - const int length; + const std::string str; }; -class TransformHtmlToEmail : public TransformImpl { +class TransformWritableContentToEmail : public TransformImpl { public: - TransformHtmlToEmail() : buf(NULL) - { - } - ~TransformHtmlToEmail() - { - if (buf) { - xmlFree(buf); - } + TransformWritableContentToEmail() : + encoding(SendMailTask::defaultMailEncoding) { } - void transform(const HtmlDocument * cdoc, SendMailTask::Parts * parts) const + void transform(const WritableContent * wc, SendMailTask::Parts * parts) const { - if (buf) { - xmlFree(buf); - buf = NULL; - } - xmlDoc * doc = const_cast(cdoc->doc); - int len = 0; - xmlDocDumpFormatMemoryEnc(doc, &buf, &len, "utf-8", 1); - parts->parts.insert(new BoundaryBegin("text/html; utf-8", 2)); - parts->parts.insert(new MimeContent(reinterpret_cast(buf), len, 2)); + parts->parts.insert(new BoundaryBegin(wc->getContentType(), encoding, 1)); + std::stringstream str; + wc->writeTo(str, encoding); + parts->parts.insert(new MimeContent(str.str(), 1)); SendMailTask::MailPart::mimeIdx += 1; } - private: - mutable xmlChar * buf; -}; -DECLARE_TRANSFORM(TransformHtmlToEmail); - -class TransformTextToEmail : public TransformImpl { - public: - void transform(const TextDocument * str, SendMailTask::Parts * parts) const + void configure(ScriptNodePtr s) { - parts->parts.insert(new BoundaryBegin("text/plain; utf-8", 1)); - parts->parts.insert(new MimeContent(str->doc.c_str(), str->doc.length(), 1)); - SendMailTask::MailPart::mimeIdx += 1; + s->applyValue("encoding", encoding); } + private: + VariableType encoding; }; -DECLARE_TRANSFORM(TransformTextToEmail); +DECLARE_TRANSFORM(TransformWritableContentToEmail); class EmailViewHost : public ViewHost { public: diff --git a/project2/mail/sendmailTask.h b/project2/mail/sendmailTask.h index 9cf4922..3703203 100644 --- a/project2/mail/sendmailTask.h +++ b/project2/mail/sendmailTask.h @@ -51,7 +51,9 @@ class SendMailTask : public Task { // Configurables friend class CustomSendMailTaskLoader; + friend class TransformWritableContentToEmail; static std::string defaultMailServer; + static std::string defaultMailEncoding; }; #endif diff --git a/project2/xml/transformHtml.cpp b/project2/xml/transformHtml.cpp index 54919ef..8cc9202 100644 --- a/project2/xml/transformHtml.cpp +++ b/project2/xml/transformHtml.cpp @@ -8,7 +8,7 @@ HtmlDocument::HtmlDocument(ScriptNodePtr s) : TransformSource(s), SourceOf(s), SourceOf(s), - contentType(s, "contenttype", "text/html; charset=utf-8") + contentType(s, "contenttype", "text/html") { } @@ -27,10 +27,10 @@ int xmlstrmwritecallback(void * context, const char * buffer, int len) } void -HtmlDocument::writeTo(std::ostream & o) const +HtmlDocument::writeTo(std::ostream & o, const std::string & encoding) const { xmlOutputBufferPtr buf = xmlOutputBufferCreateIO(xmlstrmwritecallback, xmlstrmclosecallback, &o, NULL); - htmlDocContentDumpFormatOutput(buf, doc, "utf-8", 0); + htmlDocContentDumpFormatOutput(buf, doc, encoding.c_str(), 0); xmlOutputBufferClose(buf); } diff --git a/project2/xml/transformHtml.h b/project2/xml/transformHtml.h index 8a34f2f..3ea10fd 100644 --- a/project2/xml/transformHtml.h +++ b/project2/xml/transformHtml.h @@ -11,7 +11,7 @@ class HtmlDocument : public SourceOf, public WritableContent, publ operator const HtmlDocument * () const; operator const WritableContent * () const; Glib::ustring getContentType() const; - void writeTo(std::ostream &) const; + void writeTo(std::ostream &, const std::string & encoding) const; Variable contentType; }; diff --git a/project2/xml/transformText.cpp b/project2/xml/transformText.cpp index 6bc43a7..b9b5e56 100644 --- a/project2/xml/transformText.cpp +++ b/project2/xml/transformText.cpp @@ -4,12 +4,13 @@ #include "transformHtml.h" #include #include +#include TextDocument::TextDocument(ScriptNodePtr s) : TransformSource(s), SourceOf(s), SourceOf(s), - contentType(s, "contenttype", "text/plain; charset=utf-8") + contentType(s, "contenttype", "text/plain") { } @@ -17,9 +18,9 @@ TextDocument::operator const TextDocument * () const { return this; } TextDocument::operator const WritableContent * () const { return this; } void -TextDocument::writeTo(std::ostream & o) const +TextDocument::writeTo(std::ostream & o, const std::string & encoding) const { - o << doc; + o << Glib::convert(doc.raw(), encoding, "utf-8"); } Glib::ustring @@ -43,14 +44,15 @@ class TransformHtmlToText : public TransformImpl { "/usr/bin/lynx", "-dump", "-stdin", "-width=105", "-nonumbers", "-nolist", NULL }; popenrw(callLynx, fds); FILE * lynxIn = fdopen(fds[0], "w"); - FILE * lynxOut = fdopen(fds[1], "r"); - htmlNodeDumpFile(lynxIn, doc, xmlDocGetRootElement(doc)); + // Fixed encoding as we want the result to go back into a ustring + htmlNodeDumpFileFormat(lynxIn, doc, xmlDocGetRootElement(doc), "utf-8", 0); fclose(lynxIn); close(fds[0]); - for (int ch ; ((ch = fgetc(lynxOut)) >= 0); ) { - str->doc.push_back(ch); + char buf[1024]; + int r; + while ((r = read(fds[1], buf, sizeof(buf))) > 0) { + str->doc.append(std::string(buf, r)); } - fclose(lynxOut); close(fds[1]); int status; wait(&status); diff --git a/project2/xml/transformText.h b/project2/xml/transformText.h index 07eb583..7fd1e8f 100644 --- a/project2/xml/transformText.h +++ b/project2/xml/transformText.h @@ -7,11 +7,11 @@ class TextDocument : public SourceOf, public WritableContent, public SourceOf { public: TextDocument(ScriptNodePtr); - std::string doc; + Glib::ustring doc; operator const TextDocument * () const; operator const WritableContent * () const; Glib::ustring getContentType() const; - void writeTo(std::ostream &) const; + void writeTo(std::ostream &, const std::string & encoding) const; Variable contentType; }; diff --git a/project2/xml/xmlPresenter.cpp b/project2/xml/xmlPresenter.cpp index e9d9a18..91d43aa 100644 --- a/project2/xml/xmlPresenter.cpp +++ b/project2/xml/xmlPresenter.cpp @@ -152,6 +152,6 @@ XmlPresenter::getContentType() const { } void -XmlPresenter::writeTo(std::ostream & o) const { - responseDoc->write_to_stream_formatted(o, "UTF-8"); +XmlPresenter::writeTo(std::ostream & o, const std::string & enc) const { + responseDoc->write_to_stream_formatted(o, enc); } diff --git a/project2/xml/xmlPresenter.h b/project2/xml/xmlPresenter.h index 0671548..eacc793 100644 --- a/project2/xml/xmlPresenter.h +++ b/project2/xml/xmlPresenter.h @@ -29,7 +29,7 @@ class XmlPresenter : public Presenter, public ContentPresenter, public SourceOf< operator const boost::shared_ptr * () const; operator const WritableContent * () const; Glib::ustring getContentType() const; - void writeTo(std::ostream &) const; + void writeTo(std::ostream &, const std::string & enc) const; private: void createDoc(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle) const; -- cgit v1.2.3