1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
#include "xsltStreamSerializer.h"
#include <factory.impl.h>
#include <libxml/HTMLtree.h>
#include <libxslt/xsltInternals.h>
#include <mimeImpl.h>
#include <notifications/css/style.h>
#include <processPipes.h>
#include <sys/wait.h>
namespace Gentoo {
using namespace IceTray::Mime;
static const std::string css(style_css, style_css + style_css_len);
static int
xmlstrmclosecallback(void * context)
{
((std::ostream *)context)->flush();
return 0;
}
static int
xmlstrmwritecallback(void * context, const char * buffer, int len)
{
((std::ostream *)context)->write(buffer, len);
return len;
}
XsltStreamSerializer::XsltStreamSerializer(const IceTray::Mail::EmailPtr & e, xsltStylesheet * ss) :
Slicer::XmlDocumentSerializer(doc), mail(e), doc(nullptr), stylesheet(ss)
{
}
XsltStreamSerializer::~XsltStreamSerializer()
{
delete doc;
}
void
XsltStreamSerializer::Serialize(Slicer::ModelPartForRootPtr mp)
{
Slicer::XmlDocumentSerializer::Serialize(mp);
auto result = std::shared_ptr<xmlDoc>(xsltApplyStylesheet(stylesheet, doc->cobj(), nullptr), xmlFreeDoc);
if (!result) {
throw xmlpp::exception("Failed to apply XSL transform");
}
mail->content = std::make_shared<MultiPart>(
Headers {}, "alternative", Parts {getText(result.get()), getHtml(result.get())});
}
IceTray::Mime::BasicPartPtr
XsltStreamSerializer::getHtml(xmlDoc * result)
{
std::stringstream strm;
xmlOutputBufferPtr buf = xmlOutputBufferCreateIO(xmlstrmwritecallback, xmlstrmclosecallback, &strm, NULL);
htmlDocContentDumpFormatOutput(buf, result, "utf-8", 0);
xmlOutputBufferClose(buf);
return std::make_shared<MultiPart>(Headers {}, "related",
Parts {
std::make_shared<TextPart>(Headers {}, "text/html", strm.str()),
std::make_shared<TextPart>(
Headers {
{"Content-Id", "<style.css@gentoobrowse.randomdan.homeip.net>"},
},
"text/css", css),
});
}
IceTray::Mime::BasicPartPtr
XsltStreamSerializer::getText(xmlDoc * result)
{
std::stringstream strm;
std::vector<std::string> callLynx;
callLynx.push_back("/usr/bin/lynx");
callLynx.push_back("-dump");
callLynx.push_back("-stdin");
std::string widthArg = "-width=78";
callLynx.push_back(widthArg);
AdHoc::System::ProcessPipes fds(callLynx, true, true, false);
FILE * lynxIn = fdopen(fds.fdIn(), "w");
// Fixed encoding as we want the result to go back into a ustring
htmlNodeDumpFileFormat(lynxIn, result, xmlDocGetRootElement(result), "utf-8", 0);
fclose(lynxIn);
char buf[1024];
int r;
while ((r = read(fds.fdOut(), buf, sizeof(buf))) > 0) {
strm.write(buf, r);
}
int status;
waitpid(fds.pid(), &status, 0);
if (status != 0) {
throw std::runtime_error("Lynx failed");
}
return std::make_shared<TextPart>(Headers {}, "text/plain", strm.str());
}
}
|