1 // Implements dm_plugin_load and base DMPlugin methods
2
3 // For all support, instructions and copyright go to:
4 // http://e2guardian.org/
5 // Released under the GPL v2, with the OpenSSL exception described in the README file.
6
7 // INCLUDES
8
9 #ifdef HAVE_CONFIG_H
10 #include "dgconfig.h"
11 #endif
12 #include "DownloadManager.hpp"
13 #include "ConfigVar.hpp"
14 #include "OptionContainer.hpp"
15 #include "ConnectionHandler.hpp"
16 #include "RegExp.hpp"
17
18 #include <iostream>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <syslog.h>
24
25 // GLOBALS
26
27 extern bool is_daemonised;
28 extern OptionContainer o;
29 extern thread_local std::string thread_id;
30
31 extern dmcreate_t defaultdmcreate;
32
33 // find the class factory functions for any DM plugins we've been configured to build
34
35 #ifdef ENABLE_FANCYDM
36 extern dmcreate_t fancydmcreate;
37 #endif
38
39 #ifdef ENABLE_TRICKLEDM
40 extern dmcreate_t trickledmcreate;
41 #endif
42
43 // IMPLEMENTATION
44
45 //
46 // DMPlugin
47 //
48
49 // constructor
DMPlugin(ConfigVar & definition)50 DMPlugin::DMPlugin(ConfigVar &definition)
51 : alwaysmatchua(false), cv(definition), mimelistenabled(false), extensionlistenabled(false)
52 {
53 }
54
55 // default initialisation procedure
init(void * args)56 int DMPlugin::init(void *args)
57 {
58 bool lastplugin = *((bool *)args);
59 if (!lastplugin) {
60 // compile regex for matching supported user agents
61 String r(cv["useragentregexp"]);
62 if (r.length() > 0) {
63 #ifdef DGDEBUG
64 std::cerr << thread_id << "useragent regexp: " << r << std::endl;
65 #endif
66 ua_match.comp(r.toCharArray());
67 } else {
68 // no useragent regex? then default to .*
69 #ifdef DGDEBUG
70 std::cerr << thread_id << "no useragent regular expression; defaulting to .*" << std::endl;
71 #endif
72 alwaysmatchua = true;
73 }
74 if (!readStandardLists())
75 return -1;
76 }
77 #ifdef DGDEBUG
78 else
79 std::cerr << thread_id << "Fallback DM plugin; no matching options loaded" << std::endl;
80 #endif
81 return 0;
82 }
83
84 // default method for sending the client a download link
sendLink(Socket & peersock,String & linkurl,String & prettyurl)85 bool DMPlugin::sendLink(Socket &peersock, String &linkurl, String &prettyurl)
86 {
87 // 1220 "<p>Scan complete.</p><p>Click here to download: "
88 String message(o.language_list.getTranslation(1220));
89 message += "<a href=\"" + linkurl + "\">" + prettyurl + "</a></p></body></html>\n";
90 return peersock.writeString(message.toCharArray());
91 }
92
93 // default method for deciding whether we will handle a request
willHandle(HTTPHeader * requestheader,HTTPHeader * docheader)94 bool DMPlugin::willHandle(HTTPHeader *requestheader, HTTPHeader *docheader)
95 {
96 // match user agent first (quick)
97 RegResult Rre;
98 if (!(alwaysmatchua || ua_match.match(requestheader->userAgent().toCharArray(),Rre)))
99 return false;
100
101 // then check standard lists (mimetypes & extensions)
102
103 // mimetypes
104 String mimetype("");
105 bool matchedmime = false;
106 if (mimelistenabled) {
107 mimetype = docheader->getContentType();
108 #ifdef DGDEBUG
109 std::cerr << thread_id << "mimetype: " << mimetype << std::endl;
110 #endif
111 String lc;
112 if (mimetypelist.findInList(mimetype.toCharArray(), lc) == NULL) {
113 if (!extensionlistenabled)
114 return false;
115 } else
116 matchedmime = true;
117 }
118
119 if (extensionlistenabled && !matchedmime) {
120 // determine the extension
121 String path(requestheader->decode(requestheader->getUrl()));
122 path.removeWhiteSpace();
123 path.toLower();
124 path.removePTP();
125 path = path.after("/");
126 path.hexDecode();
127 path.realPath();
128 String disposition(docheader->disposition());
129 String extension;
130 if (disposition.length() > 2) {
131 extension = disposition;
132 while (extension.contains(".")) {
133 extension = extension.after(".");
134 }
135 extension = "." + extension;
136 } else {
137 if (!path.contains("?")) {
138 extension = path;
139 } else {
140 if (mimetype.length() == 0)
141 mimetype = docheader->getContentType();
142 if (mimetype.contains("application/")) {
143 extension = path;
144 if (extension.contains("?")) {
145 extension = extension.before("?");
146 }
147 }
148 }
149 }
150 #ifdef DGDEBUG
151 std::cerr << thread_id << "extension: " << extension << std::endl;
152 #endif
153 // check the extension list
154 String lc;
155 if (!extension.contains(".") || (extensionlist.findEndsWith(extension.toCharArray(), lc) == NULL))
156 return matchedmime;
157 }
158
159 return true;
160 }
161
162 // read in all the lists of various things we wish to handle
readStandardLists()163 bool DMPlugin::readStandardLists()
164 {
165 mimetypelist.reset(); // incase this is a reload
166 extensionlist.reset();
167
168 String filename(cv["managedmimetypelist"]);
169 if (filename.length() > 0) {
170 if (!mimetypelist.readItemList(filename.toCharArray(), false, 0)) {
171 if (!is_daemonised) {
172 std::cerr << thread_id << "Error opening managedmimetypelist" << std::endl;
173 }
174 syslog(LOG_ERR, "Error opening managedmimetypelist");
175 return false;
176 }
177 mimetypelist.doSort(false);
178 mimelistenabled = true;
179 } else {
180 mimelistenabled = false;
181 }
182
183 filename = cv["managedextensionlist"];
184 if (filename.length() > 0) {
185 if (!extensionlist.readItemList(filename.toCharArray(), false, 0)) {
186 if (!is_daemonised) {
187 std::cerr << thread_id << "Error opening managedextensionlist" << std::endl;
188 }
189 syslog(LOG_ERR, "Error opening managedextensionlist");
190 return false;
191 }
192 extensionlist.doSort(false);
193 extensionlistenabled = true;
194 } else {
195 extensionlistenabled = false;
196 }
197
198 return true;
199 }
200
201 // take in a DM plugin configuration file, find the DMPlugin descendent matching the value of plugname, and store its class factory funcs for later use
dm_plugin_load(const char * pluginConfigPath)202 DMPlugin *dm_plugin_load(const char *pluginConfigPath)
203 {
204 ConfigVar cv;
205
206 if (cv.readVar(pluginConfigPath, "=") > 0) {
207 if (!is_daemonised) {
208 std::cerr << thread_id << "Unable to load plugin config: " << pluginConfigPath << std::endl;
209 }
210 syslog(LOG_ERR, "Unable to load plugin config %s", pluginConfigPath);
211 return NULL;
212 }
213
214 String plugname(cv["plugname"]);
215
216 if (plugname.length() < 1) {
217 if (!is_daemonised) {
218 std::cerr << thread_id << "Unable read plugin config plugname variable: " << pluginConfigPath << std::endl;
219 }
220 syslog(LOG_ERR, "Unable read plugin config plugname variable %s", pluginConfigPath);
221 return NULL;
222 }
223
224 if (plugname == "default") {
225 #ifdef DGDEBUG
226 std::cerr << thread_id << "Enabling default DM plugin" << std::endl;
227 #endif
228 return defaultdmcreate(cv);
229 }
230
231 #ifdef ENABLE_FANCYDM
232 if (plugname == "fancy") {
233 #ifdef DGDEBUG
234 std::cerr << thread_id << "Enabling fancy DM plugin" << std::endl;
235 #endif
236 return fancydmcreate(cv);
237 }
238 #endif
239
240 #ifdef ENABLE_TRICKLEDM
241 if (plugname == "trickle") {
242 #ifdef DGDEBUG
243 std::cerr << thread_id << "Enabling trickle DM plugin" << std::endl;
244 #endif
245 return trickledmcreate(cv);
246 }
247 #endif
248
249 if (!is_daemonised) {
250 std::cerr << thread_id << "Unable to load plugin: " << plugname << std::endl;
251 }
252 syslog(LOG_ERR, "Unable to load plugin %s", plugname.toCharArray());
253 return NULL;
254 }
255