summaryrefslogtreecommitdiff
path: root/gentoobrowse-api/service/xsltStreamSerializer.cpp
blob: bbffebaabd94d61ffab4e29412cf7b3917c66b6b (plain)
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());
	}
}