2 * $Id: enigma_dyn_wap.cpp,v 1.11 2005/10/12 20:46:27 digi_casi Exp $
4 * (C) 2005 by digi_casi <digi_casi@tuxbox.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
34 #include <arpa/inet.h>
35 #include <linux/if_ether.h>
41 #include <enigma_main.h>
42 #include <enigma_standby.h>
44 #include <lib/driver/eavswitch.h>
45 #include <lib/dvb/dvb.h>
46 #include <lib/dvb/edvb.h>
47 #include <lib/dvb/epgcache.h>
48 #include <lib/dvb/servicestructure.h>
49 #include <lib/dvb/decoder.h>
50 #include <lib/dvb/dvbservice.h>
51 #include <lib/dvb/service.h>
52 #include <lib/dvb/record.h>
53 #include <lib/dvb/serviceplaylist.h>
55 #include <lib/system/info.h>
56 #include <lib/system/http_dyn.h>
57 #include <lib/system/econfig.h>
58 #include <enigma_dyn.h>
59 #include <enigma_dyn_utils.h>
60 #include <enigma_dyn_epg.h>
61 #include <enigma_dyn_wap.h>
65 extern eString zap
[5][5];
66 extern eString
getCurService();
67 extern bool onSameTP(const eServiceReferenceDVB
& ref1
, const eServiceReferenceDVB
&ref2
); // implemented in timer.cpp
73 countTimer(int &count
,bool repeating
)
74 :count(count
), repeating(repeating
)
78 void operator()(ePlaylistEntry
*se
)
80 if (se
->type
&ePlaylistEntry::isRepeating
)
93 static eString
admin2(eString command
)
95 if (command
== "shutdown")
97 if (eSystemInfo::getInstance()->canShutdown())
98 eZap::getInstance()->quit();
101 if (command
== "reboot")
102 eZap::getInstance()->quit(4);
104 if (command
== "restart")
105 eZap::getInstance()->quit(2);
107 if (command
== "wakeup")
109 if (eZapStandby::getInstance())
110 eZapStandby::getInstance()->wakeUp(0);
113 if (command
== "standby")
115 if (eZapStandby::getInstance())
116 eZapMain::getInstance()->gotoStandby();
119 return "<?xml version=\"1.0\"?><!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\" \"http://www.wapforum.org/DTD/wml_1.1.xml\"><wml><card title=\"Info\"><p>Command " + command
+ " initiated.</p></card></wml>";
122 class eWapNavigatorListDirectory
: public Object
127 eServiceInterface
&iface
;
129 eWapNavigatorListDirectory(eString
&result
, eString origpath
, eString path
, eServiceInterface
&iface
): result(result
), origpath(origpath
), path(path
), iface(iface
)
131 eDebug("path: %s", path
.c_str());
133 void addEntry(const eServiceReference
&e
)
136 if (eDVB::getInstance()->recorder
&& !e
.path
&& !e
.flags
)
138 if (!onSameTP(eDVB::getInstance()->recorder
->recRef
,(eServiceReferenceDVB
&)e
))
142 eString serviceRef
= ref2string(e
);
144 if (!(e
.flags
& eServiceReference::isDirectory
))
145 result
+= "<a href=\"/wap?mode=zapto,path=" + serviceRef
+ "\">";
147 result
+= "<a href=\"/wap?mode=zap,path=" + serviceRef
+ "\">";
149 eService
*service
= iface
.addRef(e
);
154 result
+= filter_string(service
->service_name
);
163 static eString
getWapZapContent(eString path
)
165 eString tpath
, result
;
167 unsigned int pos
= 0, lastpos
= 0, temp
= 0;
169 if ((path
.find(";", 0)) == eString::npos
)
172 while ((pos
= path
.find(";", lastpos
)) != eString::npos
)
175 if ((temp
= path
.find(";", lastpos
)) != eString::npos
)
176 tpath
= path
.mid(lastpos
, temp
- lastpos
);
178 tpath
= path
.mid(lastpos
, strlen(path
.c_str()) - lastpos
);
180 eServiceReference current_service
= string2ref(tpath
);
181 eServiceInterface
*iface
= eServiceInterface::getInstance();
183 // first pass thru is to get all user bouquets
184 eWapNavigatorListDirectory
navlist(result
, path
, tpath
, *iface
);
185 Signal1
<void, const eServiceReference
&> signal
;
186 signal
.connect(slot(navlist
, &eWapNavigatorListDirectory::addEntry
));
187 iface
->enterDirectory(current_service
, signal
);
189 iface
->leaveDirectory(current_service
);
196 struct getWapEntryString
198 std::stringstream
&result
;
201 getWapEntryString(std::stringstream
&result
, bool repeating
)
202 :result(result
), repeating(repeating
)
206 void operator()(ePlaylistEntry
* se
)
208 if (!repeating
&& se
->type
& ePlaylistEntry::isRepeating
)
210 if (repeating
&& !(se
->type
& ePlaylistEntry::isRepeating
))
212 tm startTime
= *localtime(&se
->time_begin
);
213 time_t time_end
= se
->time_begin
+ se
->duration
;
214 tm endTime
= *localtime(&time_end
);
216 eString description
= se
->service
.descr
;
217 eString channel
= getLeft(description
, '/');
220 eService
*service
= eDVB::getInstance()->settings
->getTransponders()->searchService(se
->service
);
222 channel
= filter_string(service
->service_name
);
225 channel
= "No channel available";
227 description
= getRight(description
, '/');
229 description
= "No description available";
231 result
<< std::setw(2) << startTime
.tm_mday
<< '.'
232 << std::setw(2) << startTime
.tm_mon
+1 << ". - "
233 << std::setw(2) << startTime
.tm_hour
<< ':'
234 << std::setw(2) << startTime
.tm_min
236 << std::setw(2) << endTime
.tm_mday
<< '.'
237 << std::setw(2) << endTime
.tm_mon
+1 << ". - "
238 << std::setw(2) << endTime
.tm_hour
<< ':'
239 << std::setw(2) << endTime
.tm_min
248 static eString
wapTimerList(void)
250 std::stringstream result
;
251 eString tmp
= readFile(TEMPLATE_DIR
+ "wapTimerList.tmp");
254 eTimerManager::getInstance()->forEachEntry(countTimer(count
, false));
257 result
<< std::setfill('0');
258 if (!eTimerManager::getInstance()->getTimerCount())
259 result
<< eString("No timer events available");
261 eTimerManager::getInstance()->forEachEntry(getWapEntryString(result
, 0));
264 result
<< eString("No timer events available");
266 tmp
.strReplace("#BODY#", result
.str());
270 static eString
wapEPG(int page
)
272 std::stringstream result
;
274 result
<< std::setfill('0');
278 eDVBServiceController
*sapi
=eDVB::getInstance()->getServiceAPI();
280 return "No EPG available";
282 eServiceReference ref
= sapi
->service
;
284 current
= eDVB::getInstance()->settings
->getTransponders()->searchService(ref
);
287 return "No EPG available";
289 eServiceReferenceDVB
&rref
= (eServiceReferenceDVB
&)ref
;
290 eEPGCache::getInstance()->Lock();
291 const timeMap
* evt
= eEPGCache::getInstance()->getTimeMap(rref
);
294 return "No EPG available";
297 timeMap::const_iterator It
;
298 int tsidonid
= (rref
.getTransportStreamID().get()<<16)|rref
.getOriginalNetworkID().get();
301 for(It
=evt
->begin(); It
!= evt
->end(); ++It
)
303 if ((i
>= page
* 25) && (i
< (page
+ 1) * 25))
305 EITEvent
event(*It
->second
, tsidonid
);
307 led
.getLocalData(&event
, &description
);
308 tm
* t
= localtime(&event
.start_time
);
310 result
<< std::setw(2) << t
->tm_mday
<< '.'
311 << std::setw(2) << t
->tm_mon
+1 << ". - "
312 << std::setw(2) << t
->tm_hour
<< ':'
313 << std::setw(2) << t
->tm_min
<< ' '
316 result
<< "<a href=\"/wap?mode=epgDetails"
317 << ",path=" << ref2string(ref
)
318 << ",ID=" << std::hex
<< event
.event_id
<< std::dec
320 << filter_string(description
)
325 if (i
>= (page
+ 1) * 25)
328 result
<< "<a href=\"wap?mode=epg,page=" << eString().sprintf("%d", page
) << "\">Next Page</a><br/>";
331 eEPGCache::getInstance()->Unlock();
333 eString tmp
= readFile(TEMPLATE_DIR
+ "wapepg.tmp");
334 tmp
.strReplace("#CHANNEL#", filter_string(current
->service_name
));
335 tmp
.strReplace("#BODY#", result
.str());
339 static eString
wapAddTimerEvent(eString opts
)
343 std::map
<eString
, eString
> opt
= getRequestOptions(opts
, ',');
344 eString serviceRef
= opt
["path"];
345 eString eventID
= opt
["ID"];
346 eString eventStartTime
= opt
["start"];
347 eString eventDuration
= opt
["duration"];
348 eString channel
= httpUnescape(opt
["channel"]);
349 eString description
= httpUnescape(opt
["descr"]);
350 if (description
== "")
351 description
= "No description available";
354 sscanf(eventID
.c_str(), "%x", &eventid
);
357 if ((eConfig::getInstance()->getKey("/enigma/timeroffset", timeroffset
)) != 0)
360 int start
= atoi(eventStartTime
.c_str()) - (timeroffset
* 60);
361 int duration
= atoi(eventDuration
.c_str()) + (2 * timeroffset
* 60);
363 ePlaylistEntry
entry(string2ref(serviceRef
), start
, duration
, eventid
, ePlaylistEntry::stateWaiting
| ePlaylistEntry::RecTimerEntry
| ePlaylistEntry::recDVR
);
364 entry
.service
.descr
= channel
+ "/" + description
;
366 if (eTimerManager::getInstance()->addEventToTimerList(entry
) == -1)
367 result
+= "Timer event could not be added because time of the event overlaps with an already existing event.";
369 result
+= "Timer event was created successfully.";
370 eTimerManager::getInstance()->saveTimerList(); //not needed, but in case enigma crashes ;-)
374 static eString
wapEPGDetails(eString serviceRef
, eString eventID
)
377 eService
*current
= NULL
;
378 eString ext_description
;
379 std::stringstream record
;
381 eString description
= "No description available";
383 sscanf(eventID
.c_str(), "%x", &eventid
);
384 eDebug("[ENIGMA_DYN] getEPGDetails: serviceRef = %s, ID = %04x", serviceRef
.c_str(), eventid
);
386 // search for the event... to get the description...
387 eDVBServiceController
*sapi
=eDVB::getInstance()->getServiceAPI();
390 eServiceReference
ref(string2ref(serviceRef
));
391 current
= eDVB::getInstance()->settings
->getTransponders()->searchService((eServiceReferenceDVB
&)ref
);
394 EITEvent
*event
= eEPGCache::getInstance()->lookupEvent((eServiceReferenceDVB
&)ref
, eventid
);
398 led
.getLocalData(event
, &description
, 0, &ext_description
);
399 if (!ext_description
)
400 ext_description
= "No detailed information available";
402 record
<< "<a href=\"/wap?mode=addTimerEvent"
403 << ",path=" << ref2string(ref
)
404 << ",ID=" << std::hex
<< event
->event_id
<< std::dec
405 << ",start=" << event
->start_time
406 << ",duration=" << event
->duration
407 << ",descr=" << filter_string(description
)
408 << ",channel=" << filter_string(current
->service_name
)
416 result
= readFile(TEMPLATE_DIR
+ "wapEPGDetails.tmp");
417 result
.strReplace("#EVENT#", filter_string(description
));
418 result
.strReplace("#RECORD#", record
.str());
419 result
.strReplace("#BODY#", filter_string(ext_description
));
424 static eString
wap_web_root(eString request
, eString dirpath
, eString opts
, eHTTPConnection
*content
)
428 std::map
<eString
,eString
> opt
= getRequestOptions(opts
, ',');
429 eString mode
= opt
["mode"];
430 eString spath
= opt
["path"];
432 content
->local_header
["Content-Type"]="text/vnd.wap.wml";
436 eString command
= opt
["command"];
437 result
= admin2(command
);
442 if (opts
.find("path") == eString::npos
)
443 spath
= zap
[ZAPMODETV
][ZAPSUBMODEBOUQUETS
];
444 result
= readFile(TEMPLATE_DIR
+ "wapzap.tmp");
445 result
.strReplace("#BODY#", getWapZapContent(spath
));
450 eServiceReference current_service
= string2ref(spath
);
452 if (!(current_service
.flags
&eServiceReference::isDirectory
)) // is playable
453 eZapMain::getInstance()->playService(current_service
, eZapMain::psSetMode
|eZapMain::psDontAdd
);
455 result
= "<?xml version=\"1.0\"?><!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\" \"http://www.wapforum.org/DTD/wml_1.1.xml\"><wml><card title=\"Info\"><p>Zap complete.</p></card></wml>";
460 eString page
= opt
["page"];
461 result
= wapEPG(atoi(page
.c_str()));
464 if (mode
== "epgDetails")
466 eString eventID
= opt
["ID"];
467 result
= wapEPGDetails(spath
, eventID
);
470 if (mode
== "addTimerEvent")
472 result
= wapAddTimerEvent(opts
);
473 result
= "<?xml version=\"1.0\"?><!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\" \"http://www.wapforum.org/DTD/wml_1.1.xml\"><wml><card title=\"Info\"><p>" + result
+ "</p></card></wml>";
479 result
= wapTimerList();
482 if (mode
== "cleanupTimerList")
484 eTimerManager::getInstance()->cleanupEvents();
485 eTimerManager::getInstance()->saveTimerList(); //not needed, but in case enigma crashes ;-)
486 result
= "<?xml version=\"1.0\"?><!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\" \"http://www.wapforum.org/DTD/wml_1.1.xml\"><wml><card title=\"Info\"><p>Timers cleaned up.</p></card></wml>";
489 if (mode
== "clearTimerList")
491 eTimerManager::getInstance()->clearEvents();
492 eTimerManager::getInstance()->saveTimerList(); //not needed, but in case enigma crashes ;-)
493 result
= "<?xml version=\"1.0\"?><!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\" \"http://www.wapforum.org/DTD/wml_1.1.xml\"><wml><card title=\"Info\"><p>Timer list cleared.</p></card></wml>";
497 result
= readFile(TEMPLATE_DIR
+ "wap.tmp");
498 result
= getEITC(result
, "HTML");
499 result
.strReplace("#SERVICE#", getCurService());
505 void ezapWapInitializeDyn(eHTTPDynPathResolver
*dyn_resolver
, bool lockWeb
)
507 dyn_resolver
->addDyn("GET", "/wap", wap_web_root
, lockWeb
);