summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2012-01-03 23:10:47 +0000
committerrandomdan <randomdan@localhost>2012-01-03 23:10:47 +0000
commit2f7128a080b59aa2e51f2afa7b9631732856d6af (patch)
treecb83752e3d01f3432c47c65d4a42c0f1e5b34878
parentRegeneralise some code (diff)
downloadproject2-2f7128a080b59aa2e51f2afa7b9631732856d6af.tar.bz2
project2-2f7128a080b59aa2e51f2afa7b9631732856d6af.tar.xz
project2-2f7128a080b59aa2e51f2afa7b9631732856d6af.zip
Allowing specification of output encoding
-rw-r--r--project2/cgi/cgiAppEngine.cpp22
-rw-r--r--project2/cgi/cgiAppEngine.h3
-rw-r--r--project2/cgi/cgiEnvironment.cpp2
-rw-r--r--project2/cgi/cgiEnvironment.h1
-rw-r--r--project2/cgi/cgiStageCustomError.cpp2
-rw-r--r--project2/cgi/cgiStageCustomNotFound.cpp2
-rw-r--r--project2/cgi/cgiStageDefaultError.cpp2
-rw-r--r--project2/cgi/cgiStageDefaultNotFound.cpp2
-rw-r--r--project2/cgi/cgiStageFail.cpp2
-rw-r--r--project2/cgi/cgiStagePresent.cpp7
-rw-r--r--project2/cgi/cgiStageRedirect.cpp2
-rw-r--r--project2/cgi/cgiStageRequest.cpp2
-rw-r--r--project2/common/scripts.cpp13
-rw-r--r--project2/common/scripts.h1
-rw-r--r--project2/common/transform.h2
-rw-r--r--project2/json/couchSession.cpp4
-rw-r--r--project2/json/json.h16
-rw-r--r--project2/json/presenter.cpp6
-rw-r--r--project2/json/serialize.cpp46
-rw-r--r--project2/json/transformStream.cpp15
-rw-r--r--project2/mail/sendmailTask.cpp67
-rw-r--r--project2/mail/sendmailTask.h2
-rw-r--r--project2/xml/transformHtml.cpp6
-rw-r--r--project2/xml/transformHtml.h2
-rw-r--r--project2/xml/transformText.cpp18
-rw-r--r--project2/xml/transformText.h4
-rw-r--r--project2/xml/xmlPresenter.cpp4
-rw-r--r--project2/xml/xmlPresenter.h2
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<WritableContent, CgiResult> {
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<boost::posix_time::ptime>::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 <boost/bind.hpp>
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<std::string>())
{
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<Glib::ustring> & defaultSource = boost::optional<Glib::ustring>()) 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 SessionContainerLoaderImpl<CouchSessionC
mapBuf.appendf("function(doc) { var exp = doc['%s']; if (exp < %u) { emit(exp, doc._rev); } }",
CouchSessionContainer::ExpiryKey.c_str(), (unsigned int)time(NULL));
map["map"] = json::ValuePtr(new json::Value(mapBuf.str()));
- Glib::ustring mapStr(json::serializeObject(map));
+ Glib::ustring mapStr(json::serializeObject(map, "utf-8"));
// Create the CURL handle
CurlPtr c = new Curl();
c->setopt(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<json::Object>(s),
SourceOf<WritableContent>(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 <stdio.h>
#include <boost/foreach.hpp>
+#include <glibmm/convert.h>
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<json::Object, ostreamWrapper> {
+class TransformJsonToStream : public TransformImpl<json::Object, ostreamWrapper> {
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<SendMailTask> {
public:
@@ -21,6 +22,8 @@ class CustomSendMailTaskLoader : public ElementLoaderImpl<SendMailTask> {
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--<<divider>>\r\nContent-Type: %s\r\n\r\n", contentType.c_str());
+ *len = asprintf(buf, "\r\n--<<divider>>\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<HtmlDocument, SendMailTask::Parts> {
+class TransformWritableContentToEmail : public TransformImpl<WritableContent, SendMailTask::Parts> {
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<xmlDoc *>(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<const char *>(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<TextDocument, SendMailTask::Parts> {
- 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<HtmlDocument>(s),
SourceOf<WritableContent>(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<HtmlDocument>, 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 <sys/wait.h>
#include <misc.h>
+#include <glibmm/convert.h>
TextDocument::TextDocument(ScriptNodePtr s) :
TransformSource(s),
SourceOf<TextDocument>(s),
SourceOf<WritableContent>(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<HtmlDocument, TextDocument> {
"/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<TextDocument>, public WritableContent, public SourceOf<WritableContent> {
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<xmlpp::Document> * () 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;