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
96
97
98
99
100
101
102
103
104
105
|
#include "xsltStreamSerializer.h"
#include "xml/serializer.h"
#include <array>
#include <cstdio>
#include <libxml/HTMLtree.h> // IWYU pragma: keep
#include <libxslt/transform.h>
#include <libxslt/xsltInternals.h>
#include <memory>
#include <mimeImpl.h>
#include <notifications/css/style.h>
#include <ostream>
#include <processPipes.h>
#include <stdexcept>
#include <string>
#include <sys/wait.h>
#include <unistd.h>
#include <utility>
#include <vector>
namespace Gentoo {
using namespace IceTray::Mime;
static const std::string css(style_css, style_css + style_css_len);
static int
xmlstrmclosecallback(void * context)
{
(static_cast<std::ostream *>(context))->flush();
return 0;
}
static int
xmlstrmwritecallback(void * context, const char * buffer, int len)
{
(static_cast<std::ostream *>(context))->write(buffer, len);
return len;
}
XsltStreamSerializer::XsltStreamSerializer(IceTray::Mail::EmailPtr e, xsltStylesheet * ss) :
Slicer::XmlDocumentSerializer(doc), mail(std::move(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, nullptr);
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 {
"/usr/bin/lynx",
"-dump",
"-stdin",
"-width=78",
};
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);
std::array<char, BUFSIZ> buf {};
ssize_t r;
while ((r = read(fds.fdOut(), buf.data(), buf.size())) > 0) {
strm.write(buf.data(), 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());
}
}
|