trunk 20080912
[gitenigma.git] / src / enigma_web.cpp
blob8ebbf85fcbce7d85badd29e7c326c6505bd103d7
1 #include <lib/system/http_dyn.h>
2 #include <lib/dvb/service.h>
3 #include <lib/dvb/epgcache.h>
4 #include <lib/dvb/dvb.h>
5 #include <lib/dvb/servicemp3.h>
6 #include <epgwindow.h>
8 extern eString httpUnescape(const eString &string);
9 extern eString httpEscape(const eString &string);
10 extern std::map<eString,eString> getRequestOptions(eString opt, char delimiter = '&');
11 extern eString ref2string(const eServiceReference &r);
12 extern eServiceReference string2ref(const eString &service);
14 eString xmlEscape(const eString &string)
16 eString ret="";
17 for (unsigned int i=0; i<string.length(); ++i)
19 int c=string[i];
21 if (c == '&')
22 ret+="&amp;";
23 else
24 ret+=c;
26 return ret;
30 static const eString xmlversion="<?xml version=\"1.0\"?>\n";
31 static inline eString xmlstylesheet(const eString &ss)
33 return eString("<?xml-stylesheet type=\"text/xsl\" href=\"/stylesheets/") + ss + ".xsl\"?>\n";
36 static eString web_root(eString request, eString dirpath, eString opts, eHTTPConnection *content)
38 eString ret;
39 content->local_header["Content-Type"]="text/xml; charset=utf-8";
41 ret=xmlversion;
42 ret+=xmlstylesheet("services");
43 ret+="<services>\n";
45 for (int i=0; i<10; ++i)
46 ret+="<service><name>" + eString().sprintf("Service #%d", i) + "</name></service>\n";
48 ret+="</services>\n";
49 return ret;
52 class eServiceToXml: public Object
54 eString &result;
55 eServiceInterface &iface;
56 public:
57 eServiceToXml(eString &result, eServiceInterface &iface): result(result), iface(iface)
60 void addEntry(const eServiceReference &e)
62 result+="<service>\n";
63 result+="<reference>" + ref2string(e) + "</reference>\n";
64 eService *service=iface.addRef(e);
65 if (service)
67 result+="<name>" + xmlEscape(service->service_name) + "</name>\n";
68 if (service->dvb)
70 result+="<dvb><namespace>";
71 result+=eString().setNum(service->dvb->dvb_namespace.get(), 0x10);
72 result+="</namespace><tsid>";
73 result+=eString().setNum(service->dvb->transport_stream_id.get(), 0x10);
74 result+="</tsid><onid>";
75 result+=eString().setNum(service->dvb->original_network_id.get(), 0x10);
76 result+="</onid><sid>";
77 result+=eString().setNum(service->dvb->service_id.get(), 0x10);
78 result+="</sid><type>";
79 result+=eString().setNum(service->dvb->service_type, 0x10);
80 result+="</type><provider>";
81 result+=xmlEscape(service->dvb->service_provider);
82 result+="</provider><number>";
83 result+=eString().setNum(service->dvb->service_number, 10);
84 result+="</number></dvb>\n";
86 #ifndef DISABLE_FILE
87 if (service->id3)
89 std::map<eString, eString> & tags = service->id3->getID3Tags();
90 result+="<id3>";
91 for (std::map<eString, eString>::iterator i(tags.begin()); i != tags.end(); ++i)
92 result+="<tag id=\"" + i->first + "\"><" + i->second + "<tag/>\n";
93 result+="</id3>";
95 #endif
97 iface.removeRef(e);
98 result+="</service>\n";
102 static eString xml_services(eString request, eString dirpath, eString opt, eHTTPConnection *content)
104 std::map<eString,eString> opts=getRequestOptions(opt);
105 eString spath=opts["path"];
107 eServiceInterface *iface=eServiceInterface::getInstance();
109 if (!iface)
110 return "n/a\n";
112 eString current;
114 unsigned int pos;
115 if ((pos=spath.rfind(';')) != eString::npos)
117 current=spath.mid(pos+1);
118 spath=spath.left(pos);
119 } else
121 current=spath;
122 spath="";
125 eServiceReference current_service=string2ref(current);
127 if (!opts["path"])
128 current_service=eServiceReference(eServiceReference::idStructure,
129 eServiceReference::isDirectory, 0);
131 eDebug("current_service: %s", current_service.path.c_str());
133 eString res;
135 eServiceToXml conv(res, *iface);
137 Signal1<void,const eServiceReference&> signal;
138 signal.connect(slot(conv, &eServiceToXml::addEntry));
140 res=xmlversion;
141 res+=xmlstylesheet("services");
142 res+="<services>\n";
144 iface->enterDirectory(current_service, signal);
145 iface->leaveDirectory(current_service);
147 res+="</services>\n";
149 return res;
152 class eHTTPLog: public eHTTPDataSource, public Object
154 int mask, format;
155 int ok, last;
156 void recvMessage(int lvl, const eString &str);
157 eString toWrite;
158 public:
159 eHTTPLog(eHTTPConnection *c, int mask, int format);
160 ~eHTTPLog();
162 int doWrite(int);
165 eHTTPLog::eHTTPLog(eHTTPConnection *c, int mask, int format):
166 eHTTPDataSource(c), mask(mask), format(format), ok(0)
168 if (format == 0)
169 connection->local_header["Content-Type"]="text/plain";
170 else if (format == 1)
171 connection->local_header["Content-Type"]="text/html";
172 connection->code=200;
173 connection->code_descr="OK";
174 CONNECT(logOutput, eHTTPLog::recvMessage);
175 last = -1;
176 if (format == 1)
178 toWrite="<html><head>"
179 "<link type=\"text/css\" rel=\"stylesheet\" href=\"/stylesheets/log.css\">"
180 "<title>Enigma Event Log</title>"
181 "</head><body><pre>\n";
185 int eHTTPLog::doWrite(int hm)
187 // we don't have YET data to send (but there's much to come)
188 ok=1;
189 if (toWrite.size())
191 connection->writeBlock(toWrite.c_str(), toWrite.size());
192 toWrite="";
194 return 0;
197 void eHTTPLog::recvMessage(int lvl, const eString &msg)
199 eString res;
200 if (lvl & mask)
202 if (format == 0) // text/plain
204 res=msg;
205 res.strReplace("\n", "\r\n");
206 } else
208 if (last != lvl)
210 eString cl="unknown";
211 if (lvl == lvlWarning)
212 cl="warning";
213 else if (lvl == lvlFatal)
214 cl="fatal";
215 else if (lvl == lvlDebug)
216 cl="debug";
218 if (last != -1)
219 res+="</div>";
220 res+="<div class=\"" + cl + "\">";
221 last=lvl;
223 res+=msg;
224 // res.strReplace("\n", "<br>\n"); <-- we are <pre>, so no need
226 if (ok)
227 connection->writeBlock(res.c_str(), res.size());
228 else
229 toWrite+=res;
233 eHTTPLog::~eHTTPLog()
237 eHTTPLogResolver::eHTTPLogResolver()
241 eHTTPDataSource *eHTTPLogResolver::getDataSource(eString request, eString path, eHTTPConnection *conn)
243 if ((path=="/log/debug") && (request=="GET"))
244 return new eHTTPLog(conn, -1, 0);
245 if ((path=="/log/warn") && (request=="GET"))
246 return new eHTTPLog(conn, 3, 0);
247 if ((path=="/log/crit") && (request=="GET"))
248 return new eHTTPLog(conn, 1, 0);
250 if ((path=="/log/debug.html") && (request=="GET"))
251 return new eHTTPLog(conn, -1, 1);
252 if ((path=="/log/warn.html") && (request=="GET"))
253 return new eHTTPLog(conn, 3, 1);
254 if ((path=="/log/crit.html") && (request=="GET"))
255 return new eHTTPLog(conn, 1, 1);
256 return 0;
259 extern eString filter_string(eString string);
261 class ERCServiceHandle: public Object
263 eString &result, search;
264 eServiceInterface &iface;
265 public:
266 ERCServiceHandle(eString &result, eServiceInterface &iface, eString search): result(result), search(search.upper()), iface(iface)
269 void addEntry(const eServiceReference &e)
271 eService *service=iface.addRef(e);
272 if (service)
274 if (filter_string(service->service_name).upper().find(search) == eString::npos)
275 return;
276 result += ref2string(e) + "\n";
277 result += service->service_name + "\n";
278 iface.removeRef(e);
283 static eString erc_services(eString request, eString dirpath, eString opt, eHTTPConnection *content)
285 std::map<eString,eString> opts=getRequestOptions(opt);
287 eServiceInterface *iface=eServiceInterface::getInstance();
288 eServiceReference all_services=eServiceReference(eServiceReference::idDVB,
289 eServiceReference::flagDirectory|eServiceReference::shouldSort,
290 -2, -1, 0xFFFFFFFF);
292 if (!iface)
293 return "n/a\n";
295 if (opts.find("name") == opts.end())
296 return "-specify name=\n";
298 // search "all dvb services":
300 eString res = "+\n";
302 ERCServiceHandle conv(res, *iface, opts["name"]);
304 Signal1<void,const eServiceReference&> signal;
305 signal.connect(slot(conv, &ERCServiceHandle::addEntry));
307 iface->enterDirectory(all_services, signal);
308 iface->leaveDirectory(all_services);
310 return res;
313 static void processEvent(eString &res, EITEvent *ev, const eString &search, int wantext)
315 eString title;
317 LocalEventData led;
318 led.getLocalData(ev, &title);
320 if (title.find(search) != eString::npos)
322 res += "I: ";
323 res += eString().setNum(ev->event_id, 0x10);
324 res += "\nB: ";
325 res += eString().setNum(ev->start_time);
326 res += "\nD: ";
327 res += eString().setNum(ev->duration);
328 res += "\nN: " + title + "\n";
329 LocalEventData led;
330 eString tmpname,tmptext;
331 if (!wantext)
333 led.getLocalData(ev, &tmpname);
334 if (!tmpname.isNull())
336 res += "T: ";
337 res += tmpname;
338 res += "\n";
341 else
343 led.getLocalData(ev, &tmpname, 0, &tmptext);
344 if (!tmptext.isNull())
346 res += "T: ";
347 res += tmpname;
348 res += "\n";
349 res += "E: ";
350 tmptext.strReplace("\n", eString("\\n"));
351 res += tmptext;
352 res +=" \n";
355 for (ePtrList<Descriptor>::const_iterator d(ev->descriptor); d != ev->descriptor.end(); ++d)
357 if (d->Tag()==DESCR_SHORT_EVENT)
359 const ShortEventDescriptor *s=(const ShortEventDescriptor*)*d;
360 res += "T: ";
361 res += s->text;
362 res += "\n";
363 if (!wantext)
364 break;
365 } else if (wantext && (d->Tag() == DESCR_EXTENDED_EVENT))
367 const ExtendedEventDescriptor *e=(ExtendedEventDescriptor*)*d;
368 res += "E: ";
369 eString t = e->text;
370 t.strReplace("\n", eString("\\n"));
371 res += t;
372 res +=" \n";
378 static eString erc_epg(eString request, eString dirpath, eString opt, eHTTPConnection *content)
380 std::map<eString,eString> opts=getRequestOptions(opt);
381 time_t begin = 0;
382 int duration = 0;
383 eString search;
384 eString res;
385 int wantext;
386 int event_id = -1;
388 if (opts.find("service") == opts.end())
389 return "-specify service";
390 if ((opts.find("text") == opts.end()) && (opts.find("begin") == opts.end()) && (opts.find("event_id") == opts.end()))
391 return "-specify text and/or begin or event_id";
392 eString text = opts["text"];
393 if (opts.find("begin") != opts.end())
394 begin = atoi(opts["begin"].c_str());
395 if (opts.find("duration") != opts.end())
396 duration = atoi(opts["duration"].c_str());
397 search = opts["text"];
399 if (opts.find("extended") != opts.end())
400 wantext = 1;
401 else
402 wantext = 0;
404 if (opts.find("event_id") != opts.end())
405 sscanf(opts["event_id"].c_str(), "%x", &event_id);
407 eEPGCache *epgcache=eEPGCache::getInstance();
408 eServiceReference ref(opts["service"]);
410 if (event_id == -1)
412 epgcache->Lock();
413 const timeMap *evmap = epgcache->getTimeMap((eServiceReferenceDVB&)ref);
414 if (!evmap)
416 epgcache->Unlock();
417 return "-no events for this service";
419 eServiceReferenceDVB &rref=(eServiceReferenceDVB&)ref;
420 timeMap::const_iterator ibegin = evmap->begin(), iend = evmap->end();
421 if (begin != 0)
423 ibegin = evmap->lower_bound(begin);
424 if ((ibegin != evmap->end()) && (ibegin != evmap->begin()))
425 --ibegin;
426 else
427 ibegin=evmap->begin();
429 timeMap::const_iterator iend = evmap->upper_bound(begin + duration);
430 if (iend != evmap->end())
431 ++iend;
433 int tsidonid =
434 (rref.getTransportStreamID().get()<<16)|rref.getOriginalNetworkID().get();
435 for (timeMap::const_iterator event(ibegin); event != iend; ++event)
437 EITEvent *ev = new EITEvent(*event->second, tsidonid);
438 processEvent(res, ev, search, wantext);
439 delete ev;
441 epgcache->Unlock();
443 else
445 EITEvent *ev = epgcache->lookupEvent((eServiceReferenceDVB&)ref, event_id);
446 if (!ev)
447 return "-service or event_id invalid";
448 else
450 processEvent(res, ev, search, wantext);
451 delete ev;
455 return res;
458 void ezapInitializeWeb(eHTTPDynPathResolver *dyn_resolver)
460 dyn_resolver->addDyn("GET", "/dyn2/", web_root);
461 dyn_resolver->addDyn("GET", "/dyn2/services", xml_services);
463 dyn_resolver->addDyn("GET", "/erc/services", erc_services);
464 dyn_resolver->addDyn("GET", "/erc/epg", erc_epg);