diff options
Diffstat (limited to 'misc')
-rw-r--r-- | misc/config.cpp | 109 | ||||
-rw-r--r-- | misc/config.h | 33 | ||||
-rw-r--r-- | misc/menusetup.cpp | 205 | ||||
-rw-r--r-- | misc/menusetup.h | 78 | ||||
-rw-r--r-- | misc/search.cpp | 795 | ||||
-rw-r--r-- | misc/search.h | 90 | ||||
-rw-r--r-- | misc/util.cpp | 488 | ||||
-rw-r--r-- | misc/util.h | 45 |
8 files changed, 1843 insertions, 0 deletions
diff --git a/misc/config.cpp b/misc/config.cpp new file mode 100644 index 0000000..59bf4a6 --- /dev/null +++ b/misc/config.cpp @@ -0,0 +1,109 @@ +/* + * File: config.cpp + * Author: savop + * + * Created on 15. August 2009, 13:03 + */ + +#include <stdio.h> +#include <vdr/tools.h> +#include <getopt.h> +#include "config.h" +#include "../common.h" + +cUPnPConfig::cUPnPConfig(){ + this->mParsedArgs = NULL; + this->mInterface = NULL; + this->mAddress = NULL; + this->mAutoSetup = 0; + this->mEnable = 0; + this->mPort = 0; +} + +cUPnPConfig::~cUPnPConfig(){} + +cUPnPConfig* cUPnPConfig::get(){ + if(cUPnPConfig::mInstance == NULL) + cUPnPConfig::mInstance = new cUPnPConfig(); + + if(cUPnPConfig::mInstance) + return cUPnPConfig::mInstance; + else return NULL; +} + +cUPnPConfig* cUPnPConfig::mInstance = NULL; + +bool cUPnPConfig::processArgs(int argc, char* argv[]){ + // Implement command line argument processing here if applicable. + static struct option long_options[] = { + {"int", required_argument, NULL, 'i'}, + {"address", required_argument, NULL, 'a'}, + {"port", required_argument, NULL, 'p'}, + {"autodetect", no_argument, NULL, 'd'} + }; + + int c = 0; + + // Check if anything went wrong by setting 'success' to false + // As there are multiple tests you may get a faulty behavior + // if the current value is not considered in latter tests. + // Asume that: Success = true; + // success && false = false; --> new value of success is false + // success && true = true; --> still true. + // So, in the case of true and only true, success contains the + // desired value. + bool success = true; + bool ifaceExcistent = false; + bool addExcistent = false; + + while((c = getopt_long(argc, argv, "i:a:p:v",long_options, NULL)) != -1){ + switch(c){ + case 'i': + if(addExcistent) { ERROR("Address given but must be absent!"); return false; } + success = this->parseSetup(SETUP_SERVER_INT, optarg) && success; + success = this->parseSetup(SETUP_SERVER_ADDRESS, NULL) && success; + success = this->parseSetup(SETUP_SERVER_AUTO, "0") && success; + ifaceExcistent = true; + break; + case 'a': + if(ifaceExcistent) { ERROR("Interface given but must be absent!"); return false; } + success = this->parseSetup(SETUP_SERVER_ADDRESS, optarg) && success; + success = this->parseSetup(SETUP_SERVER_INT, NULL) && success; + success = this->parseSetup(SETUP_SERVER_AUTO, "0") && success; + addExcistent = true; + break; + case 'p': + success = this->parseSetup(SETUP_SERVER_PORT, optarg) && success; + success = this->parseSetup(SETUP_SERVER_AUTO, "0") && success; + break; + case 'd': + success = this->parseSetup(SETUP_SERVER_AUTO, optarg) && success; + default: + return false; + } + } + + return success; +} + +bool cUPnPConfig::parseSetup(const char *Name, const char *Value) +{ + const char* ptr; + if(*this->mParsedArgs && (ptr = strstr(this->mParsedArgs,Name))!=NULL){ + MESSAGE("Skipping %s=%s, was overridden in command line.",Name, Value); + return true; + } + + MESSAGE("VARIABLE %s has value %s", Name, Value); + // Parse your own setup parameters and store their values. + if (!strcasecmp(Name, SETUP_SERVER_ENABLED)) this->mEnable = atoi(Value); + else if (!strcasecmp(Name, SETUP_SERVER_AUTO)) this->mAutoSetup = atoi(Value); + else if (!strcasecmp(Name, SETUP_SERVER_INT)) this->mInterface = strdup0(Value); // (Value) ? strn0cpy(this->mInterface, Value, strlen(this->mInterface)) : NULL; + else if (!strcasecmp(Name, SETUP_SERVER_ADDRESS)) this->mAddress = strdup0(Value); //(Value) ? strn0cpy(this->mAddress, Value, strlen(this->mAddress)) : NULL; + else if (!strcasecmp(Name, SETUP_SERVER_PORT)) this->mPort = atoi(Value); + else return false; + + this->mParsedArgs = cString::sprintf("%s%s",*this->mParsedArgs,Name); + + return true; +}
\ No newline at end of file diff --git a/misc/config.h b/misc/config.h new file mode 100644 index 0000000..018213e --- /dev/null +++ b/misc/config.h @@ -0,0 +1,33 @@ +/* + * File: config.h + * Author: savop + * + * Created on 15. August 2009, 13:03 + */ + +#ifndef _CONFIG_H +#define _CONFIG_H + +#include <vdr/tools.h> +#include "../common.h" + +class cUPnPConfig { +private: + static cUPnPConfig* mInstance; + cString mParsedArgs; + cUPnPConfig(); +public: + char* mInterface; + char* mAddress; + int mPort; + int mEnable; + int mAutoSetup; +public: + virtual ~cUPnPConfig(); + static cUPnPConfig* get(); + bool parseSetup(const char* Name, const char* Value); + bool processArgs(int argc, char* argv[]); +}; + +#endif /* _CONFIG_H */ + diff --git a/misc/menusetup.cpp b/misc/menusetup.cpp new file mode 100644 index 0000000..9e8386f --- /dev/null +++ b/misc/menusetup.cpp @@ -0,0 +1,205 @@ +/* + * File: menusetup.cpp + * Author: savop + * + * Created on 19. April 2009, 16:50 + */ + +#include "config.h" +#include <vdr/osdbase.h> +#include "menusetup.h" +#include "../common.h" +#include "util.h" +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <vdr/menuitems.h> + + +cMenuSetupUPnP::cMenuSetupUPnP(){ + // Get server acitve state + MESSAGE("Creating menu"); + this->mCtrlBind = NULL; + this->mCtrlAutoMode = NULL; + this->mCtrlEnabled = NULL; + this->mCtrlPort = NULL; + this->mEnable = 0; + this->mDetectPort = 0; + this->mAutoSetup = 0; + this->mPort = 0; + this->mAddress = NULL; + this->mInterfaceIndex = 0; + this->Load(); + this->Update(); +} + +//cMenuSetupUPnP::~cMenuSetupUPnP() { +// delete this->mCtrlAutoMode; +// delete this->mCtrlEnabled; +// delete this->mCtrlPort; +// free(this->mAddress); +//} + +void cMenuSetupUPnP::Load(void){ + cUPnPConfig* Config = cUPnPConfig::get(); + this->mEnable = Config->mEnable; + this->mAutoSetup = Config->mAutoSetup; + this->mInterfaceIndex = this->getInterfaceIndex(Config->mInterface); + this->mAddress = strdup(Config->mAddress?Config->mAddress:"0.0.0.0"); + this->mPort = Config->mPort; + + if(Config->mPort==0) this->mDetectPort = 1; +} + +const char* const* cMenuSetupUPnP::getInterfaceList(int* count){ + char** Ifaces = getNetworkInterfaces(count); + char** IfaceList = new char*[++(*count)]; + IfaceList[0] = strdup(_("User defined")); + for(int i=0; i < *count-1; i++){ + IfaceList[i+1] = strdup(Ifaces[i]); + } + delete [] Ifaces; + return IfaceList; +} + +int cMenuSetupUPnP::getInterfaceIndex(const char* Interface){ + MESSAGE("Getting Index of %s", Interface); + if(!Interface) return 0; + int count; + int Index = 0; + const char* const* Ifaces = this->getInterfaceList(&count); + + for(int i=1; i < count; i++){ + if(!strcmp(Interface, Ifaces[i])){ + Index = i; + break; + } + } + delete [] Ifaces; + return Index; +} + +const char* cMenuSetupUPnP::getInterface(int Index){ + int count; + const char* const* Ifaces = this->getInterfaceList(&count); + + if(count < Index || Index < 1) return NULL; + const char* Interface = strdup0(Ifaces[Index]); + delete [] Ifaces; + return Interface; +} + +void cMenuSetupUPnP::Update(void){ + int Current = this->Current(); + this->Clear(); + // Add OSD menu item for enabling UPnP Server + this->Add(mCtrlEnabled = new cMenuEditBoolItem(_("Enable UPnP Server"),&this->mEnable,_("disabled"),_("enabled"))); + if(this->mEnable){ + cMenuEditIntItem* editPortItem = NULL; + this->Add(mCtrlAutoMode = new cMenuEditBoolItem(_("Auto detect settings"),&this->mAutoSetup,_("no"),_("yes"))); + // Add OSD menu item for IP address + int Count; + const char* const* Interfaces = this->getInterfaceList(&Count); + this->Add(mCtrlBind = new cMenuEditStraItem(_("Bind to network interface"), &this->mInterfaceIndex, Count, Interfaces)); + + cMenuEditIpItem* editIpItem; + if(this->mInterfaceIndex){ + const sockaddr_in* addr = getIPFromInterface(this->getInterface(this->mInterfaceIndex)); + char* IP = strdup(inet_ntoa(addr->sin_addr)); + editIpItem = new cMenuEditIpItem(_("Current IP address"),IP); + editIpItem->SetSelectable(false); + free(IP); + } + else { + editIpItem = new cMenuEditIpItem(_("Set IP address"),this->mAddress); + } + this->Add(editIpItem); + this->Add(mCtrlPort = new cMenuEditBoolItem(_("Select port"), &this->mDetectPort, _("auto"), _("user definied"))); + if(this->mDetectPort){ + this->Add(editPortItem = new cMenuEditIntItem(_("User specified port"), + &this->mPort, + SERVER_MIN_PORT, + SERVER_MAX_PORT + )); + } + + if(this->mAutoSetup){ + if(mCtrlPort) mCtrlPort->SetSelectable(false); + if(mCtrlBind) mCtrlBind->SetSelectable(false); + if(editPortItem) editPortItem->SetSelectable(false); + if(editIpItem) editIpItem->SetSelectable(false); + } + else { + if(mCtrlPort) mCtrlPort->SetSelectable(true); + if(mCtrlBind) mCtrlBind->SetSelectable(true); + if(editPortItem) editPortItem->SetSelectable(true); + if(editIpItem && !this->mInterfaceIndex) editIpItem->SetSelectable(true); + } + } + this->SetCurrent(this->Get(Current)); + this->Display(); +} + +eOSState cMenuSetupUPnP::ProcessKey(eKeys Key){ + + cOsdItem *Item = this->Get(this->Current()); + + eOSState State = cMenuSetupPage::ProcessKey(Key); + + Key = NORMALKEY(Key); + + if(Key != kRight && Key != kLeft){ + return State; + } + + if(Item == this->mCtrlEnabled){ + if(this->mEnable){ + this->Update(); + } + else if (!this->mEnable) { + this->Update(); + } + } + else if (Item == this->mCtrlPort){ + if(this->mDetectPort){ + this->Update(); + } + else if(!this->mDetectPort) { + this->Update(); + } + } + else if (Item == this->mCtrlAutoMode){ + if(this->mAutoSetup){ + this->Update(); + } + else if(!this->mAutoSetup) { + this->Update(); + } + } + else if(Item == this->mCtrlBind){ +// if(!this->mInterfaceIndex){ +// this->Update(); +// } +// else if(!this->mInterfaceIndex){ +// this->Update(); +// } + this->Update(); + } + return State; +} + +void cMenuSetupUPnP::Store(void){ + cUPnPConfig* Config = cUPnPConfig::get(); + Config->mAddress = strdup0(this->mAddress); + Config->mAutoSetup = this->mAutoSetup; + Config->mEnable = this->mEnable; + Config->mInterface = strdup0(this->getInterface(this->mInterfaceIndex)); + Config->mPort = (this->mDetectPort) ? 0 : this->mPort; + + this->SetupStore(SETUP_SERVER_AUTO, this->mAutoSetup); + this->SetupStore(SETUP_SERVER_ENABLED, this->mEnable); + this->SetupStore(SETUP_SERVER_INT, this->getInterface(this->mInterfaceIndex)); + this->SetupStore(SETUP_SERVER_ADDRESS, this->mAddress); + this->SetupStore(SETUP_SERVER_PORT, this->mPort); + +} diff --git a/misc/menusetup.h b/misc/menusetup.h new file mode 100644 index 0000000..ae40e97 --- /dev/null +++ b/misc/menusetup.h @@ -0,0 +1,78 @@ +/* + * File: menusetup.h + * Author: savop + * + * Created on 19. April 2009, 16:50 + */ + +#ifndef _CMENUSETUPUPNP_H +#define _CMENUSETUPUPNP_H + +#include <vdr/plugin.h> +#include "../server/server.h" +#include "config.h" + +/** + * The VDR setup page + * + * This class shows and manages the settings within the VDR setup OSD + * + * @author Denis Loh + * @version 0.0.1 + */ +class cMenuSetupUPnP : public cMenuSetupPage { +public: + cMenuSetupUPnP(); +// virtual ~cMenuSetupUPnP(); + virtual eOSState ProcessKey(eKeys Key); +protected: + virtual void Store(void); + void Update(void); + void Load(void); +private: + const char* const* getInterfaceList(int *count); + int getInterfaceIndex(const char* Interface); + const char* getInterface(int Index); + cOsdItem *mCtrlBind; + cOsdItem *mCtrlEnabled; + cOsdItem *mCtrlPort; + cOsdItem *mCtrlAutoMode; + cUPnPServer* mUpnpServer; + /** + * Is the server enabled or not + * + * The server can be switched on or off. If it is turned off, the server + * will close open transmissions and ports + * + */ + int mEnable; + int mAutoSetup; + /** + * The port to listen to (Default: 0 autodetect) + * + * The port the server is bound to. The default setting is 0. + * So, the server will determine automatically a free random port between + * 49152 and 65535. If a server should use a specific port it can be set + * to one out of that range. + * + */ + int mPort; + int mDetectPort; + /** + * The Interface the server is bound to + * + * If multiple interfaces exist the server can be bound to a specific + * one + * + */ + int mInterfaceIndex; + /** + * The socket address of the server + * + * The IP address and the port of the server + */ + char *mAddress; +}; + +#endif /* _CMENUSETUPUPNP_H */ + diff --git a/misc/search.cpp b/misc/search.cpp new file mode 100644 index 0000000..deee8b0 --- /dev/null +++ b/misc/search.cpp @@ -0,0 +1,795 @@ +/* + * File: search.cpp + * Author: savop + * + * Created on 27. August 2009, 21:21 + */ + +// uncomment this to enable debuging of the grammar +//#define BOOST_SPIRIT_DEBUG + +#include <string> +#include "search.h" +#include "../common.h" +#include <boost/spirit.hpp> +#include <boost/function.hpp> +#include <boost/bind.hpp> + +using namespace std; +using namespace boost; +using namespace boost::spirit; + +// This is the standard callback function which will be overloaded +// with all the specific callbacks +typedef function2<void, const char*, const char*> expCallback; +typedef function1<void, const char*> propCallback; +typedef function1<void, const char*> opCallback; +typedef function1<void, const char> charCallback; +typedef function1<void, int> intCallback; + +// The defined ColumnNames +struct cProperties : symbols<const char*> { +//struct cProperties : symbols<> { + cProperties(){ + add +// (UPNP_PROP_OBJECTID, UPNP_PROP_OBJECTID) +// (UPNP_PROP_PARENTID, UPNP_PROP_PARENTID) +// (UPNP_PROP_RESTRICTED, UPNP_PROP_RESTRICTED) +// (UPNP_PROP_CLASS, UPNP_PROP_CLASS) +// (UPNP_PROP_CLASSNAME, UPNP_PROP_CLASSNAME) +// (UPNP_PROP_WRITESTATUS, UPNP_PROP_WRITESTATUS) +// (UPNP_PROP_CHILDCOUNT, UPNP_PROP_CHILDCOUNT) +// (UPNP_PROP_REFERENCEID, UPNP_PROP_REFERENCEID) +// (UPNP_PROP_TITLE, UPNP_PROP_TITLE) +// (UPNP_PROP_CREATOR, UPNP_PROP_CREATOR) +// ("dc:description", "Description") +// ("dc:date", "Date") +// ("res", "Resource") +// ("res@bitrate", "Bitrate") +// ("res@duration", "Duration") +// ("res@size", "Size") +// ("res@sampleFrequency", "SampleFrequency") +// ("res@resolution", "Resolution") +// ("res@protocolInfo", "ProtocolInfo") +// ; + (UPNP_PROP_OBJECTID,UPNP_PROP_OBJECTID) + (UPNP_PROP_PARENTID,UPNP_PROP_PARENTID) + (UPNP_PROP_TITLE,UPNP_PROP_TITLE) + (UPNP_PROP_CREATOR,UPNP_PROP_CREATOR) + (UPNP_PROP_RESTRICTED,UPNP_PROP_RESTRICTED) + (UPNP_PROP_WRITESTATUS,UPNP_PROP_WRITESTATUS) + (UPNP_PROP_CLASS,UPNP_PROP_CLASS) + (UPNP_PROP_CLASSNAME,UPNP_PROP_CLASSNAME) + (UPNP_PROP_SEARCHCLASS,UPNP_PROP_SEARCHCLASS) + (UPNP_PROP_SCLASSDERIVED,UPNP_PROP_SCLASSDERIVED) + (UPNP_PROP_REFERENCEID,UPNP_PROP_REFERENCEID) + (UPNP_PROP_SCLASSNAME,UPNP_PROP_SCLASSNAME) + (UPNP_PROP_SEARCHABLE,UPNP_PROP_SEARCHABLE) + (UPNP_PROP_CHILDCOUNT,UPNP_PROP_CHILDCOUNT) + (UPNP_PROP_RESOURCE,UPNP_PROP_RESOURCE) + (UPNP_PROP_PROTOCOLINFO,UPNP_PROP_PROTOCOLINFO) + (UPNP_PROP_SIZE,UPNP_PROP_SIZE) + (UPNP_PROP_DURATION,UPNP_PROP_DURATION) + (UPNP_PROP_BITRATE,UPNP_PROP_BITRATE) + (UPNP_PROP_SAMPLEFREQUENCE,UPNP_PROP_SAMPLEFREQUENCE) + (UPNP_PROP_BITSPERSAMPLE,UPNP_PROP_BITSPERSAMPLE) + (UPNP_PROP_NOAUDIOCHANNELS,UPNP_PROP_NOAUDIOCHANNELS) + (UPNP_PROP_COLORDEPTH,UPNP_PROP_COLORDEPTH) + (UPNP_PROP_RESOLUTION,UPNP_PROP_RESOLUTION) + (UPNP_PROP_GENRE,UPNP_PROP_GENRE) + (UPNP_PROP_LONGDESCRIPTION,UPNP_PROP_LONGDESCRIPTION) + (UPNP_PROP_PRODUCER,UPNP_PROP_PRODUCER) + (UPNP_PROP_RATING,UPNP_PROP_RATING) + (UPNP_PROP_ACTOR,UPNP_PROP_ACTOR) + (UPNP_PROP_DIRECTOR,UPNP_PROP_DIRECTOR) + (UPNP_PROP_DESCRIPTION,UPNP_PROP_DESCRIPTION) + (UPNP_PROP_PUBLISHER,UPNP_PROP_PUBLISHER) + (UPNP_PROP_LANGUAGE,UPNP_PROP_LANGUAGE) + (UPNP_PROP_RELATION,UPNP_PROP_RELATION) + (UPNP_PROP_STORAGEMEDIUM,UPNP_PROP_STORAGEMEDIUM) + (UPNP_PROP_DVDREGIONCODE,UPNP_PROP_DVDREGIONCODE) + (UPNP_PROP_CHANNELNAME,UPNP_PROP_CHANNELNAME) + (UPNP_PROP_SCHEDULEDSTARTTIME,UPNP_PROP_SCHEDULEDSTARTTIME) + (UPNP_PROP_SCHEDULEDENDTIME,UPNP_PROP_SCHEDULEDENDTIME) + (UPNP_PROP_ICON,UPNP_PROP_ICON) + (UPNP_PROP_REGION,UPNP_PROP_REGION) + (UPNP_PROP_CHANNELNR,UPNP_PROP_CHANNELNR) + (UPNP_PROP_RIGHTS,UPNP_PROP_RIGHTS) + (UPNP_PROP_RADIOCALLSIGN,UPNP_PROP_RADIOCALLSIGN) + (UPNP_PROP_RADIOSTATIONID,UPNP_PROP_RADIOSTATIONID) + (UPNP_PROP_RADIOBAND,UPNP_PROP_RADIOBAND) + (UPNP_PROP_CONTRIBUTOR,UPNP_PROP_CONTRIBUTOR) + (UPNP_PROP_DATE,UPNP_PROP_DATE) + (UPNP_PROP_ALBUM,UPNP_PROP_ALBUM) + (UPNP_PROP_ARTIST,UPNP_PROP_ARTIST) + (UPNP_PROP_DLNA_CONTAINERTYPE,UPNP_PROP_DLNA_CONTAINERTYPE) + ; + } +} Properties; + +struct cOperators : symbols<const char*> { + cOperators(){ + add + ("=", "==") + ("!=", "!=") + ("<", "<") + (">", ">") + ("<=", "<=") + (">=", ">=") + ("contains", "LIKE") + ("doesNotContain", "NOT LIKE") + ("derivedfrom", "derivedFrom") + ; + } +} Operators; + +struct cConcatOperators : symbols<const char*> { + cConcatOperators(){ + add + ("and", "AND") + ("or", "OR") + ; + } +} ConcatOperators; + +struct cExistanceOperator : symbols<const char*> { + cExistanceOperator(){ + add + ("true", "NOT NULL") + ("false", "NULL") + ; + } +} Existance; + +// THE GRAMMAR! +// This is the grammar including the functors which calls the member functions +// of search. The callback definitions at the end of the constructor are +// essential. DO NOT MODIFY if you don't know how! +struct cSearchGrammar : public boost::spirit::grammar<cSearchGrammar> { + // The callbacks members + charCallback &endBrackedExp; + expCallback &pushSimpleExp; + opCallback &pushOperator; + expCallback &pushQuotedValue; + opCallback &pushExistance; + propCallback &pushProperty; + opCallback &pushConcatOp; + charCallback &startBrackedExp; + + // Constructor with the callback functions + cSearchGrammar( + charCallback &endBrackedExp, + expCallback &pushSimpleExp, + opCallback &pushOperator, + expCallback &pushQuotedValue, + opCallback &pushExistance, + propCallback &pushProperty, + opCallback &pushConcatOp, + charCallback &startBrackedExp): + endBrackedExp(endBrackedExp), + pushSimpleExp(pushSimpleExp), + pushOperator(pushOperator), + pushQuotedValue(pushQuotedValue), + pushExistance(pushExistance), + pushProperty(pushProperty), + pushConcatOp(pushConcatOp), + startBrackedExp(startBrackedExp){} + + template <typename scanner> + struct definition { + boost::spirit::rule<scanner> searchCrit, searchExp, logOp, \ + relExp, binOp, relOp, stringOp, \ + existsOp, boolVal, quotedVal, \ + wChar, property, brackedExp, exp; + const boost::spirit::rule<scanner> &start(){ + return searchCrit; + } + definition(const cSearchGrammar &self){ + /*************************************************************************\ + * * + * The grammar of a UPnP search expression * + * * + * searchCrit ::= searchExp | asterisk * + * * + * searchExp ::= relExp | * + * searchExp wChar+ logOp wChar+ searchExp | * + * '(' wChar* searchExp wChar* ')' * + * * + * logOp ::= 'and' | 'or' * + * * + * relExp ::= property wChar+ binOp wChar+ quotedVal | * + * property wChar* existsOp wChar+ boolVal * + * * + * binOp ::= relOp | stringOp * + * * + * relOp ::= '=' | '!=' | '<' | '<=' | '>' | '>=' * + * * + * stringOp ::= 'contains' | 'doesNotContain' | 'derivedfrom' * + * * + * existsOp ::= 'exists' * + * * + * boolVal ::= 'true' | 'false' * + * * + * quotedVal ::= dQuote escapedQuote dQuote * + * * + * wChar ::= space | hTab | lineFeed | * + * vTab | formFeed | return * + * * + * property ::= See ContentDirectory Section 2.4 * + * * + * escapedQuote ::= See ContentDirectory Section 2.3.1 * + * * + \*************************************************************************/ + searchCrit = searchExp | "*"; + + searchExp = exp >> *(+wChar >> logOp >> +wChar >> exp); + ; + + exp = relExp + | brackedExp + ; + + brackedExp = confix_p( + ch_p('(')[self.startBrackedExp], + *wChar >> searchExp >> *wChar, + ch_p(')')[self.endBrackedExp] + ) + ; + + logOp = ConcatOperators[self.pushConcatOp] + ; + + relExp = (property >> +wChar >> binOp >> +wChar >> quotedVal) [self.pushSimpleExp] + | (property >> +wChar >> existsOp >> +wChar >> boolVal) [self.pushSimpleExp] + ; + + binOp = Operators[self.pushOperator] + ; + + existsOp = str_p("exists") + ; + + boolVal = Existance[self.pushExistance] + ; + + quotedVal = confix_p('"', (*c_escape_ch_p)[self.pushQuotedValue], '"'); + + wChar = space_p; + + property = Properties[self.pushProperty] + ; + + // Debug mode + #ifdef BOOST_SPIRIT_DEBUG + BOOST_SPIRIT_DEBUG_NODE(searchCrit); + BOOST_SPIRIT_DEBUG_NODE(searchExp); + BOOST_SPIRIT_DEBUG_NODE(logOp); + BOOST_SPIRIT_DEBUG_NODE(relExp); + BOOST_SPIRIT_DEBUG_NODE(binOp); + BOOST_SPIRIT_DEBUG_NODE(relOp); + BOOST_SPIRIT_DEBUG_NODE(stringOp); + BOOST_SPIRIT_DEBUG_NODE(existsOp); + BOOST_SPIRIT_DEBUG_NODE(boolVal); + BOOST_SPIRIT_DEBUG_NODE(quotedVal); + BOOST_SPIRIT_DEBUG_NODE(wChar); + BOOST_SPIRIT_DEBUG_NODE(property); + #endif + } + }; +}; + +struct cSortGrammar : public boost::spirit::grammar<cSortGrammar> { + // The callback members + propCallback &pushProperty; + charCallback &pushDirection; + + cSortGrammar( + propCallback &pushProperty, + charCallback &pushDirection): + pushProperty(pushProperty), + pushDirection(pushDirection){} + + template <typename scanner> + struct definition { + boost::spirit::rule<scanner> sortCrit, sortExp, property, direction; + + const boost::spirit::rule<scanner> &start(){ + return sortCrit; + } + definition(const cSortGrammar &self){ + sortCrit = sortExp + ; + + sortExp = direction >> property >> *(ch_p(',') >> sortExp) + ; + + direction = sign_p[self.pushDirection] + ; + + property = Properties[self.pushProperty] + ; + } + }; +}; + +struct cFilterGrammar : public boost::spirit::grammar<cFilterGrammar> { + // The callback members + propCallback &pushProperty; + charCallback &pushAsterisk; + + cFilterGrammar( + propCallback &pushProperty, + charCallback &pushAsterisk): + pushProperty(pushProperty), + pushAsterisk(pushAsterisk){} + + template <typename scanner> + struct definition { + boost::spirit::rule<scanner> filterCrit, filterExp, property; + + const boost::spirit::rule<scanner> &start(){ + return filterCrit; + } + definition(const cFilterGrammar &self){ + filterCrit = filterExp + | ch_p('*')[self.pushAsterisk] + ; + + filterExp = property >> *(ch_p(',') >> filterExp) + ; + + property = Properties[self.pushProperty] + ; + } + }; +}; + + /**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cSearch::pushEndBrackedExp(const char){ + MESSAGE("Pushing closing bracket"); + if(asprintf(&this->SQLWhereStmt, "%s)", this->SQLWhereStmt)==-1){ + ERROR("Unable to allocate SQL Statement"); + return; + } +} + +void cSearch::pushExpression(const char*, const char*){ + + const char* Property = this->CurrentProperty; + const char* Operator = this->CurrentOperator; + const char* Value = this->CurrentValue; + + if(Property && Operator && Value){ + char* Statement; + long int IntegerValue; + + if(sscanf(Value, "%ld", &IntegerValue)!=EOF && sscanf(Value, "%*4d-%*2d-%*2d")==EOF){ + MESSAGE("Popping '%s %s %ld'",Property, Operator, IntegerValue); + if(asprintf(&Statement, "%s %s %ld", Property, Operator, IntegerValue)==-1){ + ERROR("Failed to allocated memory for statement."); + return; + } + } + else if(!strcasecmp(Operator, "IS")){ + MESSAGE("Popping '%s %s %s'", Property, Operator, Value); + if(asprintf(&Statement, "%s %s %s", Property, Operator, Value)==-1){ + ERROR("Failed to allocated memory for statement."); + return; + } + } + else { + MESSAGE("Popping '%s %s \"%s\"'",Property, Operator, Value); + if(asprintf(&Statement, "%s %s '%s'", Property, Operator, Value)==-1){ + ERROR("Failed to allocated memory for statement."); + return; + } + } + + if(asprintf(&this->SQLWhereStmt, "%s %s", this->SQLWhereStmt, Statement)==-1){ + ERROR("Unable to allocate SQL Statement"); + return; + } + + } + return; +} + +void cSearch::pushProperty(const char* Property){ + this->CurrentProperty = strdup(Property); + MESSAGE("Property %s added",Property); +} + +void cSearch::pushOperator(const char* Operator){ + this->CurrentOperator = strdup(Operator); + MESSAGE("Operator %s added",Operator); +} + +void cSearch::pushValue(const char* Start, const char* End){ + const char* Value = string(Start,End).c_str(); + if(!Value || !strcmp(Value,"")) return; + + this->CurrentValue = strdup(Value); + MESSAGE("Value %s added", Value); +} + +void cSearch::pushExistance(const char* Exists){ + this->CurrentValue = strdup(Exists); + this->CurrentOperator = strdup("IS"); + MESSAGE("Existance expression called. '%s'", Exists); +} + +void cSearch::pushConcatOp(const char* Operator){ + if(asprintf(&this->SQLWhereStmt, "%s %s ", this->SQLWhereStmt, Operator)==-1){ + ERROR("Unable to allocate SQL Statement"); + return; + } + + MESSAGE("Concatenation expression called. '%s'", Operator); +} + +void cSearch::pushStartBrackedExp(const char){ + MESSAGE("Pushing opening bracket"); + if(asprintf(&this->SQLWhereStmt, "%s(", this->SQLWhereStmt)==-1){ + ERROR("Unable to allocate SQL Statement"); + return; + } +} + + /**********************************************\ + * * + * The rest * + * * + \**********************************************/ + +cSearch* cSearch::mInstance = NULL; + +const char* cSearch::parse(const char* Search){ + if(!cSearch::mInstance) cSearch::mInstance = new cSearch(); + + if(cSearch::mInstance && cSearch::mInstance->parseCriteria(Search)){ + return cSearch::mInstance->SQLWhereStmt; + } + return NULL; +} + +bool cSearch::parseCriteria(const char* Search){ + + charCallback endBrackedExpCB(bind(&cSearch::pushEndBrackedExp, this, _1)); + expCallback pushSimpleExpCB(bind(&cSearch::pushExpression, this, _1, _2)); + opCallback pushOperatorCB(bind(&cSearch::pushOperator, this, _1)); + expCallback pushQuotedValueCB(bind(&cSearch::pushValue, this, _1, _2)); + opCallback pushExistanceCB(bind(&cSearch::pushExistance, this, _1)); + propCallback pushPropertyCB(bind(&cSearch::pushProperty, this, _1)); + opCallback pushConcatOpCB(bind(&cSearch::pushConcatOp, this, _1)); + charCallback startBrackedExpCB(bind(&cSearch::pushStartBrackedExp, this, _1)); + + // Craft the grammar + cSearchGrammar Grammar(endBrackedExpCB, + pushSimpleExpCB, + pushOperatorCB, + pushQuotedValueCB, + pushExistanceCB, + pushPropertyCB, + pushConcatOpCB, + startBrackedExpCB); + + MESSAGE("Starting search parsing"); + + if(boost::spirit::parse(Search, Grammar).full){ + MESSAGE("Parsing successful"); + } + else { + ERROR("Parsing failed"); + return false; + } + return true; +} + +cSearch::cSearch(){ + this->CurrentOperator = NULL; + this->CurrentProperty = NULL; + this->CurrentValue = NULL; + this->SQLWhereStmt = strdup(""); +} + +cSearch::~cSearch(){ + delete this->CurrentOperator; + delete this->CurrentProperty; + delete this->CurrentValue; +} + + /**********************************************\ + * * + * The filter * + * * + \**********************************************/ + +cFilterCriteria::cFilterCriteria(){ + this->mFilterList = NULL; +} + +cFilterCriteria::~cFilterCriteria(){} + +cStringList* cFilterCriteria::parse(const char* Filter){ + cFilterCriteria* FilterParser = new cFilterCriteria; + cStringList* List = NULL; + + if(FilterParser && FilterParser->parseFilter(Filter)){ + List = FilterParser->getFilterList(); + } + + delete FilterParser; + + return List; +} + +bool cFilterCriteria::parseFilter(const char* Filter){ + this->mFilterList = new cStringList; + + if(Filter && !strcasecmp(Filter, "")){ + MESSAGE("Empty filter"); + return true; + } + + charCallback pushAsteriskCB(bind(&cFilterCriteria::pushAsterisk,this,_1)); + propCallback pushPropertyCB(bind(&cFilterCriteria::pushProperty,this,_1)); + + cFilterGrammar Grammar(pushPropertyCB, pushAsteriskCB); + + if(boost::spirit::parse(Filter, Grammar).full){ + MESSAGE("Parse filter successful"); + } + else { + ERROR("Parsing filter failed"); + return false; + } + return true; +} + + /**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cFilterCriteria::pushProperty(const char* Property){ + MESSAGE("Pushing property"); + this->mFilterList->Append(strdup(Property)); +} + +void cFilterCriteria::pushAsterisk(const char){ + MESSAGE("Pushing asterisk (*)"); + if(this->mFilterList) delete this->mFilterList; + this->mFilterList = NULL; + return; +} + + /**********************************************\ + * * + * The sorter * + * * + \**********************************************/ + +cSortCriteria::cSortCriteria(){ + this->mCriteriaList = new cList<cSortCrit>; + this->mCurrentCrit = NULL; +} + +cSortCriteria::~cSortCriteria(){} + +cList<cSortCrit>* cSortCriteria::parse(const char* Sort){ + cSortCriteria* SortParser = new cSortCriteria; + cList<cSortCrit>* List = NULL; + if(SortParser && SortParser->parseSort(Sort)){ + List = SortParser->getSortList(); + } + + delete SortParser; + + return List; +} + +bool cSortCriteria::parseSort(const char* Sort){ + if(!Sort || !strcasecmp(Sort, "")){ + MESSAGE("Empty Sort"); + return true; + } + + charCallback pushDirectionCB(bind(&cSortCriteria::pushDirection,this,_1)); + propCallback pushPropertyCB(bind(&cSortCriteria::pushProperty,this,_1)); + + cSortGrammar Grammar(pushPropertyCB, pushDirectionCB); + + if(boost::spirit::parse(Sort, Grammar).full){ + MESSAGE("Parse Sort successful"); + } + else { + ERROR("Parsing Sort failed"); + return false; + } + return true; +} + + /**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cSortCriteria::pushProperty(const char* Property){ + MESSAGE("Pushing property '%s'", Property); + this->mCurrentCrit->Property = strdup(Property); + this->mCriteriaList->Add(this->mCurrentCrit); + return; +} + +void cSortCriteria::pushDirection(const char Direction){ + MESSAGE("Pushing direction '%c'", Direction); + this->mCurrentCrit = new cSortCrit; + this->mCurrentCrit->SortDescending = (Direction=='-')?true:false; + return; +} + + /**********************************************\ + * * + * The pathparser * + * * + \**********************************************/ + +struct cWebserverSections : symbols<> { + cWebserverSections(){ + add + (UPNP_DIR_SHARES) + ; + } +} WebserverSections; + +struct cWebserverMethods : symbols<int> { + cWebserverMethods(){ + add + ("browse", UPNP_WEB_METHOD_BROWSE) + ("download", UPNP_WEB_METHOD_DOWNLOAD) + ("search", UPNP_WEB_METHOD_SEARCH) + ("show", UPNP_WEB_METHOD_SHOW) + ("get", UPNP_WEB_METHOD_STREAM) + ; + } +} WebserverMethods; + +struct cPathParserGrammar : public boost::spirit::grammar<cPathParserGrammar> { + + intCallback &pushSection; + intCallback &pushMethod; + expCallback &pushPropertyKey; + expCallback &pushPropertyValue; + + cPathParserGrammar(intCallback &pushSection, + intCallback &pushMethod, + expCallback &pushPropertyKey, + expCallback &pushPropertyValue): + pushSection(pushSection), + pushMethod(pushMethod), + pushPropertyKey(pushPropertyKey), + pushPropertyValue(pushPropertyValue){} + + template <typename scanner> + struct definition { + boost::spirit::rule<scanner> pathExp, section, method, methodProperties, + property, key, value, uncriticalChar; + + const boost::spirit::rule<scanner> &start(){ + return pathExp; + } + definition(const cPathParserGrammar &self){ + pathExp = section >> ch_p('/') >> method >> ch_p('?') >> methodProperties + ; + + section = WebserverSections[self.pushSection] + ; + + method = WebserverMethods[self.pushMethod] + ; + + methodProperties = property >> *(ch_p('&') >> methodProperties) + ; + + property = key >> ch_p('=') >> value + ; + + key = (+alnum_p)[self.pushPropertyKey] + ; + + value = (*uncriticalChar)[self.pushPropertyValue] + ; + + uncriticalChar = chset_p("-_.%~0-9A-Za-z") + ; + } + }; +}; + +cPathParser::cPathParser(){ + this->mSection = 0; + this->mMethod = 0; +} + +cPathParser::~cPathParser(){} + +bool cPathParser::parse(const char* Path, int* Section, int* Method, propertyMap* Properties){ + cPathParser* Parser = new cPathParser(); + bool ret = (Parser && Parser->parsePath(Path, Section, Method, Properties)) ? true : false; + + delete Parser; + + return ret; +} + +bool cPathParser::parsePath(const char* Path, int* Section, int* Method, propertyMap* Properties){ + if(!Path){ + return false; + } + + intCallback pushSectionCB(bind(&cPathParser::pushSection,this,_1)); + intCallback pushMethodCB(bind(&cPathParser::pushMethod,this,_1)); + expCallback pushPropertyKeyCB(bind(&cPathParser::pushPropertyKey, this, _1, _2)); + expCallback pushPropertyValueCB(bind(&cPathParser::pushPropertyValue, this, _1, _2)); + + cPathParserGrammar Grammar(pushSectionCB, pushMethodCB, pushPropertyKeyCB, pushPropertyValueCB); + + if(boost::spirit::parse(Path, Grammar).full){ + MESSAGE("Parse path successful"); + *Section = this->mSection; + *Method = this->mMethod; + *Properties = this->mProperties; + return true; + } + else { + ERROR("Parsing path failed"); + return false; + } + + return true; +} + + /**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cPathParser::pushPropertyKey(const char* Start, const char* End){ + char* Key = strndup(Start, End-Start); + + MESSAGE("Pushing key '%s'", Key); + + this->mKey = Key; + + free(Key); +} + +void cPathParser::pushPropertyValue(const char* Start, const char* End){ + char* Value = strndup(Start, End-Start); + + MESSAGE("Pushing value '%s'", Value); + // TODO: urlDecode Value + + if(*this->mKey){ + char* Key = strdup(this->mKey); + this->mProperties[Key] = Value; + } +} + +void cPathParser::pushMethod(int Method){ + MESSAGE("Pushing method '%d'", Method); + this->mMethod = Method; +} + +void cPathParser::pushSection(int Section){ + MESSAGE("Pushing section '%d'", Section); + this->mSection = Section; +}
\ No newline at end of file diff --git a/misc/search.h b/misc/search.h new file mode 100644 index 0000000..df2442e --- /dev/null +++ b/misc/search.h @@ -0,0 +1,90 @@ +/* + * File: search.h + * Author: savop + * + * Created on 27. August 2009, 21:21 + */ + +#ifndef _SEARCH_H +#define _SEARCH_H + +#include <map> +#include <vdr/tools.h> +#include "util.h" + +struct cSortCrit : public cListObject { + const char* Property; + bool SortDescending; +}; + +typedef std::map<const char*, const char*, strCmp> propertyMap; + +class cPathParser { +private: + cString mKey; + propertyMap mProperties; + int mSection; + int mMethod; + bool parsePath(const char* Path, int* Section, int* Method, propertyMap* Properties); + void pushPropertyKey(const char* Start, const char* End); + void pushPropertyValue(const char* Start, const char* End); + void pushMethod(int Method); + void pushSection(int Section); + cPathParser(); +public: + virtual ~cPathParser(); + static bool parse(const char* Path, int* Section, int* Method, propertyMap* Properties); +}; + +class cSortCriteria { +private: + cSortCrit* mCurrentCrit; + cList<cSortCrit>* mCriteriaList; + bool parseSort(const char* Sort); + void pushProperty(const char* Property); + void pushDirection(const char Direction); + cList<cSortCrit>* getSortList() const { return this->mCriteriaList; } + cSortCriteria(); +public: + virtual ~cSortCriteria(); + static cList<cSortCrit>* parse(const char* Sort); +}; + +class cFilterCriteria { +private: + cStringList* mFilterList; + cFilterCriteria(); + bool parseFilter(const char* Filter); + void pushProperty(const char* Property); + void pushAsterisk(const char Asterisk); + cStringList* getFilterList() const { return this->mFilterList; } +public: + virtual ~cFilterCriteria(); + static cStringList* parse(const char* Filter); +}; + +class cSearch { +private: + char* SQLWhereStmt; + const char* CurrentProperty; + const char* CurrentOperator; + const char* CurrentValue; + static cSearch* mInstance; + cSearch(); + bool parseCriteria(const char* Search); + void pushExistance (const char* Exists); + void pushProperty (const char* Property); + void pushOperator (const char* Operator); + void pushConcatOp (const char* Operator); + void pushStartBrackedExp(const char); + void pushEndBrackedExp(const char); + void pushValue (const char* Start, const char* End); + void pushExpression(const char* Start, const char* End); +public: + virtual ~cSearch(); + static const char* parse(const char* Search); +}; + + +#endif /* _SEARCH_H */ + diff --git a/misc/util.cpp b/misc/util.cpp new file mode 100644 index 0000000..dc75706 --- /dev/null +++ b/misc/util.cpp @@ -0,0 +1,488 @@ +/* + * File: util.cpp + * Author: savop, andreas + * + * Created on 21. Mai 2009, 21:25 + * + * Extracted from streamdev-server plugin common.c + * $Id: common.c,v 1.6 2008/03/31 10:34:26 schmirl Exp $ + */ +#include "util.h" +#include "../common.h" +#include <string.h> +#include <string> +#include <sys/ioctl.h> +#include <net/if.h> +#include <upnp/ixml.h> +#include <arpa/inet.h> +#include <iosfwd> + +char* substr(const char* str, unsigned int offset, unsigned int length){ + if(offset > strlen(str)) return NULL; + if(length > strlen(str+offset)) length = strlen(str+offset); + char* substring = (char*)malloc(sizeof(substring)*length+1); + strncpy(substring, str+offset, length); + substring[length] = '\0'; + return substring; +} + +const char* getMACFromInterface(const char* Interface) { + int fd; + struct ifreq ifr; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, Interface, IFNAMSIZ-1); + + ioctl(fd, SIOCGIFHWADDR, &ifr); + + close(fd); + + char *ret = new char[18]; + + sprintf(ret, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + (unsigned char)ifr.ifr_hwaddr.sa_data[0], + (unsigned char)ifr.ifr_hwaddr.sa_data[1], + (unsigned char)ifr.ifr_hwaddr.sa_data[2], + (unsigned char)ifr.ifr_hwaddr.sa_data[3], + (unsigned char)ifr.ifr_hwaddr.sa_data[4], + (unsigned char)ifr.ifr_hwaddr.sa_data[5]); + + return ret; +} + +char** getNetworkInterfaces(int *count){ + int fd; + struct ifconf ifc; + struct ifreq ifr[10]; + int nifaces, i; + char** ifaces; + *count = 0; + + memset(&ifc,0,sizeof(ifc)); + ifc.ifc_buf = (char*) (ifr); + ifc.ifc_len = sizeof(ifr); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + int ret = ioctl(fd, SIOCGIFCONF, &ifc); + close(fd); + if(ret==0){ + nifaces = ifc.ifc_len/sizeof(struct ifreq); + ifaces = new char* [nifaces+1]; + for(i = 0; i < nifaces; i++){ + ifaces[i] = new char[IFNAMSIZ]; + ifaces[i] = strdup(ifr[i].ifr_name); + } + ifaces[i] = NULL; + *count = nifaces; + return ifaces; + } + else { + return NULL; + } +} + +const sockaddr_in* getIPFromInterface(const char* Interface){ + if(Interface==NULL) return NULL; + int fd; + struct ifreq ifr; + fd = socket(AF_INET, SOCK_DGRAM, 0); + /* I want to get an IPv4 IP address */ + ifr.ifr_addr.sa_family = AF_INET; + /* I want IP address attached to "eth0" */ + strncpy(ifr.ifr_name, Interface, IFNAMSIZ-1); + int ret = ioctl(fd, SIOCGIFADDR, &ifr); + close(fd); + const sockaddr_in* IpAddress = new sockaddr_in; + if(ret==0){ + IpAddress = (sockaddr_in *)&ifr.ifr_addr; + return IpAddress; + } + else { + delete IpAddress; + return NULL; + } +} + +cMenuEditIpItem::cMenuEditIpItem(const char *Name, char *Value):cMenuEditItem(Name) { + value = Value; + curNum = -1; + pos = -1; + step = false; + Set(); +} + +cMenuEditIpItem::~cMenuEditIpItem() { +} + +void cMenuEditIpItem::Set(void) { + char buf[1000]; + if (pos >= 0) { + in_addr_t addr = inet_addr(value); + if ((int)addr == -1) + addr = 0; + int p = 0; + for (int i = 0; i < 4; ++i) { + p += snprintf(buf + p, sizeof(buf) - p, pos == i ? "[%d]" : "%d", + pos == i ? curNum : (addr >> (i * 8)) & 0xff); + if (i < 3) + buf[p++] = '.'; + } + SetValue(buf); + } else + SetValue(value); +} + +eOSState cMenuEditIpItem::ProcessKey(eKeys Key) { + in_addr addr; + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + + switch (Key) { + case kUp: + if (pos >= 0) { + if (curNum < 255) ++curNum; + } else + return cMenuEditItem::ProcessKey(Key); + break; + + case kDown: + if (pos >= 0) { + if (curNum > 0) --curNum; + } else + return cMenuEditItem::ProcessKey(Key); + break; + + case kOk: + if (pos >= 0) { + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + addr.s_addr &= ~(0xff << (pos * 8)); + addr.s_addr |= curNum << (pos * 8); + strcpy(value, inet_ntoa(addr)); + } else + return cMenuEditItem::ProcessKey(Key); + curNum = -1; + pos = -1; + break; + + case kRight: + if (pos >= 0) { + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + addr.s_addr &= ~(0xff << (pos * 8)); + addr.s_addr |= curNum << (pos * 8); + strcpy(value, inet_ntoa(addr)); + } + + if (pos == -1 || pos == 3) + pos = 0; + else + ++pos; + + curNum = (addr.s_addr >> (pos * 8)) & 0xff; + step = true; + break; + + case kLeft: + if (pos >= 0) { + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + addr.s_addr &= ~(0xff << (pos * 8)); + addr.s_addr |= curNum << (pos * 8); + strcpy(value, inet_ntoa(addr)); + } + + if (pos <= 0) + pos = 3; + else + --pos; + + curNum = (addr.s_addr >> (pos * 8)) & 0xff; + step = true; + break; + + case k0 ... k9: /* Netbeans reports error with this line (.. is okay but wrong) */ + if (pos == -1) + pos = 0; + + if (curNum == -1 || step) { + curNum = Key - k0; + step = false; + } else + curNum = curNum * 10 + (Key - k0); + + if ((curNum * 10 > 255) || (curNum == 0)) { + in_addr addr; + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + addr.s_addr &= ~(0xff << (pos * 8)); + addr.s_addr |= curNum << (pos * 8); + strcpy(value, inet_ntoa(addr)); + if (++pos == 4) + pos = 0; + curNum = (addr.s_addr >> (pos * 8)) & 0xff; + step = true; + } + break; + + default: + return cMenuEditItem::ProcessKey(Key); + } + + Set(); + return osContinue; +} + +const char* escapeSQLite(const char* Data, char** Buf){ + if(!Data){ + *Buf = NULL; + } + else { + std::string NewData = ""; + int Char = 0; + for(unsigned int i = 0; i < strlen(Data); i++){ + Char = Data[i]; + switch(Char){ + case L'\'': NewData += "''"; break; + default: NewData += Data[i]; break; + } + } + *Buf = strdup(NewData.c_str()); + } + return (*Buf); +} + +const char* escapeXMLCharacters(const char* Data, char** Buf){ + if(Data==NULL){ + ERROR("Escape XML: No data to escape"); + return NULL; + } + std::string NewData = ""; + int Char = 0; + for(unsigned int i = 0; i < strlen(Data); i++){ + Char = Data[i]; + switch(Char){ + case L'€': NewData += "€"; break; + case L'"': NewData += """; break; + case L'&': NewData += "&"; break; + case L'<': NewData += "<"; break; + case L'>': NewData += ">"; break; + case L'¡': NewData += "¡"; break; + case L'¢': NewData += "¢"; break; + case L'£': NewData += "£"; break; + case L'¤': NewData += "¤"; break; + case L'¥': NewData += "¥"; break; + case L'¦': NewData += "¦"; break; + case L'§': NewData += "§"; break; + case L'¨': NewData += "¨"; break; + case L'©': NewData += "©"; break; + case L'ª': NewData += "ª"; break; + case L'¬': NewData += "¬"; break; + case L'': NewData += "­"; break; + case L'®': NewData += "®"; break; + case L'¯': NewData += "¯"; break; + case L'°': NewData += "°"; break; + case L'±': NewData += "±"; break; + case L'²': NewData += "²"; break; + case L'³': NewData += "³"; break; + case L'´': NewData += "´"; break; + case L'µ': NewData += "µ"; break; + case L'¶': NewData += "¶"; break; + case L'·': NewData += "·"; break; + case L'¸': NewData += "¸"; break; + case L'¹': NewData += "¹"; break; + case L'º': NewData += "º"; break; + case L'»': NewData += "»"; break; + case L'«': NewData += "«"; break; + case L'¼': NewData += "¼"; break; + case L'½': NewData += "½"; break; + case L'¾': NewData += "¾"; break; + case L'¿': NewData += "¿"; break; + case L'À': NewData += "À"; break; + case L'Á': NewData += "Á"; break; + case L'Â': NewData += "Â"; break; + case L'Ã': NewData += "Ã"; break; + case L'Ä': NewData += "Ä"; break; + case L'Å': NewData += "Å"; break; + case L'Æ': NewData += "Æ"; break; + case L'Ç': NewData += "Ç"; break; + case L'È': NewData += "È"; break; + case L'É': NewData += "É"; break; + case L'Ê': NewData += "Ê"; break; + case L'Ë': NewData += "Ë"; break; + case L'Ì': NewData += "Ì"; break; + case L'Í': NewData += "Í"; break; + case L'Î': NewData += "Î"; break; + case L'Ï': NewData += "Ï"; break; + case L'Ð': NewData += "Ð"; break; + case L'Ñ': NewData += "Ñ"; break; + case L'Ò': NewData += "Ò"; break; + case L'Ó': NewData += "Ó"; break; + case L'Ô': NewData += "Ô"; break; + case L'Õ': NewData += "Õ"; break; + case L'Ö': NewData += "Ö"; break; + case L'×': NewData += "×"; break; + case L'Ø': NewData += "Ø"; break; + case L'Ù': NewData += "Ù"; break; + case L'Ú': NewData += "Ú"; break; + case L'Û': NewData += "Û"; break; + case L'Ü': NewData += "Ü"; break; + case L'Ý': NewData += "Ý"; break; + case L'Þ': NewData += "Þ"; break; + case L'ß': NewData += "ß"; break; + case L'à': NewData += "à"; break; + case L'á': NewData += "á"; break; + case L'â': NewData += "â"; break; + case L'ã': NewData += "ã"; break; + case L'ä': NewData += "ä"; break; + case L'å': NewData += "å"; break; + case L'æ': NewData += "æ"; break; + case L'ç': NewData += "ç"; break; + case L'è': NewData += "è"; break; + case L'é': NewData += "é"; break; + case L'ê': NewData += "ê"; break; + case L'ë': NewData += "ë"; break; + case L'ì': NewData += "ì"; break; + case L'í': NewData += "í"; break; + case L'î': NewData += "î"; break; + case L'ï': NewData += "ï"; break; + case L'ð': NewData += "ð"; break; + case L'ñ': NewData += "ñ"; break; + case L'ò': NewData += "ò"; break; + case L'ó': NewData += "ó"; break; + case L'ô': NewData += "ô"; break; + case L'õ': NewData += "õ"; break; + case L'ö': NewData += "ö"; break; + case L'÷': NewData += "÷"; break; + case L'ø': NewData += "ø"; break; + case L'ù': NewData += "ù"; break; + case L'ú': NewData += "ú"; break; + case L'û': NewData += "û"; break; + case L'ü': NewData += "ü"; break; + case L'ý': NewData += "ý"; break; + case L'þ': NewData += "þ"; break; + default: NewData += Data[i]; break; + } + } + *Buf = strdup(NewData.c_str()); + return (*Buf); +} + +//Function copied from Intel SDK +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2000-2003 Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither name of Intel Corporation nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// +/******************************************************************************** + * SampleUtil_GetFirstDocumentItem + * + * Description: + * Given a document node, this routine searches for the first element + * named by the input string item, and returns its value as a string. + * String must be freed by caller using free. + * Parameters: + * doc -- The DOM document from which to extract the value + * item -- The item to search for + * + * + ********************************************************************************/ +char* ixmlGetFirstDocumentItem( IN IXML_Document * doc, IN const char *item, int* error ) { + IXML_NodeList *nodeList = NULL; + IXML_Node *textNode = NULL; + IXML_Node *tmpNode = NULL; + + char *ret = NULL; + *error = 0; + + nodeList = ixmlDocument_getElementsByTagName( doc, ( char * )item ); + + if( nodeList != NULL ) { + if( ( tmpNode = ixmlNodeList_item( nodeList, 0 ) ) ) { + + textNode = ixmlNode_getFirstChild( tmpNode ); + + if(textNode != NULL){ + ret = strdup( ixmlNode_getNodeValue( textNode ) ); + } + } + } else { + *error = -1; + } + + if( nodeList != NULL) { + ixmlNodeList_free( nodeList ); + } + + + return ret; +} + +int ixmlAddProperty(IXML_Document* document, IXML_Element* node, const char* upnpproperty, const char* value){ + if(!node) return -1; + IXML_Element* PropertyNode = NULL; + + const char* attribute = att(upnpproperty); + const char* property = prop(upnpproperty); + if(attribute){ + if(strcasecmp(property,"")){ + ixmlElement_setAttribute(node, attribute, value); + } + else { + IXML_NodeList* NodeList = ixmlElement_getElementsByTagName(node, property); + if(NodeList!=NULL){ + IXML_Node* Node = ixmlNodeList_item(NodeList, 0); + PropertyNode = (IXML_Element*) ixmlNode_getFirstChild(Node); + if(PropertyNode){ + ixmlElement_setAttribute(PropertyNode, attribute, value); + } + else { + ixmlNodeList_free(NodeList); + return -1; + } + } + else { + return -1; + } + } + } + else { + PropertyNode = ixmlDocument_createElement(document, property); + IXML_Node* PropertyText = ixmlDocument_createTextNode(document, value); + ixmlNode_appendChild((IXML_Node*) PropertyNode, PropertyText); + ixmlNode_appendChild((IXML_Node*) node, (IXML_Node*) PropertyNode); + } + return 0; +} diff --git a/misc/util.h b/misc/util.h new file mode 100644 index 0000000..ffedd67 --- /dev/null +++ b/misc/util.h @@ -0,0 +1,45 @@ +/* + * File: util.h + * Author: savop + * + * Created on 21. Mai 2009, 21:25 + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#include <vdr/tools.h> +#include <vdr/plugin.h> +#include <upnp/ixml.h> + +#ifdef __cplusplus +extern "C" { +struct strCmp { bool operator()(const char* s1, const char* s2) const { return (strcmp(s1,s2) < 0); }}; +const sockaddr_in* getIPFromInterface(const char* Interface); +const char* getMACFromInterface(const char* Interface); +char** getNetworkInterfaces(int *count); +char* ixmlGetFirstDocumentItem( IN IXML_Document * doc, IN const char *item, int* error ); +int ixmlAddProperty(IN IXML_Document* document, IN IXML_Element* node, const char* upnpproperty, const char* value ); +char* substr(const char* str, unsigned int offset, unsigned int length); +} +#endif + +const char* escapeSQLite(const char* Data, char** Buf); +const char* escapeXMLCharacters(const char* Data, char** Buf); + +class cMenuEditIpItem: public cMenuEditItem { +private: + char *value; + int curNum; + int pos; + bool step; +protected: + virtual void Set(void); +public: + cMenuEditIpItem(const char *Name, char *Value); // Value must be 16 bytes + ~cMenuEditIpItem(); + virtual eOSState ProcessKey(eKeys Key); +}; + +#endif /* _UTIL_H */ + |