summaryrefslogtreecommitdiff
path: root/upnp
diff options
context:
space:
mode:
authorDenis Loh <denis.loh@gmail.com>2010-01-25 12:10:01 +0100
committerDenis Loh <denis.loh@gmail.com>2010-01-25 12:10:01 +0100
commit724cb5e3783311f6b8c808852dbe2de59f2399b0 (patch)
treebe1f2d617b4a3e2e156b7a2d6ba9ee335cde63cf /upnp
parent0152f33daffe3fe943d6a134409d02df7ecaa982 (diff)
downloadvdr-plugin-upnp-724cb5e3783311f6b8c808852dbe2de59f2399b0.tar.gz
vdr-plugin-upnp-724cb5e3783311f6b8c808852dbe2de59f2399b0.tar.bz2
Fixed small bug which leads to an empty TV folder
Diffstat (limited to 'upnp')
-rw-r--r--upnp/connectionmanager.cpp393
-rw-r--r--upnp/contentdirectory.cpp306
-rw-r--r--upnp/service.cpp118
3 files changed, 817 insertions, 0 deletions
diff --git a/upnp/connectionmanager.cpp b/upnp/connectionmanager.cpp
new file mode 100644
index 0000000..4d1f97b
--- /dev/null
+++ b/upnp/connectionmanager.cpp
@@ -0,0 +1,393 @@
+/*
+ * File: connectionmanager.cpp
+ * Author: savop
+ *
+ * Created on 21. August 2009, 18:35
+ */
+
+#include <string.h>
+#include <upnp/ixml.h>
+#include <upnp/upnptools.h>
+#include <vdr/tools.h>
+#include "upnp/connectionmanager.h"
+#include "../common.h"
+#include "upnp/dlna.h"
+
+cVirtualConnection::cVirtualConnection() : mRcsID(-1) {}
+
+cConnectionManager::cConnectionManager(UpnpDevice_Handle DeviceHandle) : cUpnpService(DeviceHandle) {
+ this->mVirtualConnections = new cList<cVirtualConnection>;
+ this->mDefaultConnection = this->createVirtualConnection();
+ this->mSupportedProtocols = cDlna::getInstance()->getSupportedProtocols();
+}
+
+cConnectionManager::~cConnectionManager() {
+ delete this->mDefaultConnection;
+ delete this->mVirtualConnections;
+}
+
+int cConnectionManager::subscribe(Upnp_Subscription_Request* Request){
+ IXML_Document* PropertySet = NULL;
+ /* The protocol infos which this server supports */
+ UpnpAddToPropertySet(&PropertySet, "SourceProtocolInfo", this->mSupportedProtocols);
+ /* Not set, this field is only used by Media Renderers */
+ UpnpAddToPropertySet(&PropertySet, "SinkProtocolInfo", "");
+ /* The current connection IDs of all virtual connections */
+ const char* IDs = this->getConnectionIDsCVS();
+ if(!IDs){
+ return UPNP_E_INTERNAL_ERROR;
+ }
+ UpnpAddToPropertySet(&PropertySet, "CurrentConnectionIDs", IDs);
+ // Accept subscription
+ int ret = UpnpAcceptSubscriptionExt(this->mDeviceHandle, Request->UDN, Request->ServiceId, PropertySet, Request->Sid);
+
+ if(ret != UPNP_E_SUCCESS){
+ ERROR("Subscription failed (Error code: %d)", ret);
+ }
+
+ ixmlDocument_free(PropertySet);
+ return ret;
+}
+
+int cConnectionManager::execute(Upnp_Action_Request* Request){
+ if (Request == NULL) {
+ ERROR("CMS Action Handler - request is null");
+ return UPNP_E_BAD_REQUEST;
+ }
+
+ if(!strcmp(Request->ActionName, UPNP_CMS_ACTION_GETPROTOCOLINFO))
+ return this->getProtocolInfo(Request);
+ if(!strcmp(Request->ActionName, UPNP_CMS_ACTION_GETCURRENTCONNECTIONIDS))
+ return this->getCurrentConnectionIDs(Request);
+ if(!strcmp(Request->ActionName, UPNP_CMS_ACTION_GETCURRENTCONNECTIONINFO))
+ return this->getCurrentConnectionInfo(Request);
+ if(!strcmp(Request->ActionName, UPNP_CMS_ACTION_PREPAREFORCONNECTION))
+ return this->prepareForConnection(Request);
+ if(!strcmp(Request->ActionName, UPNP_CMS_ACTION_CONNECTIONCOMPLETE))
+ return this->connectionComplete(Request);
+
+ return UPNP_E_BAD_REQUEST;
+}
+
+int cConnectionManager::getProtocolInfo(Upnp_Action_Request* Request){
+ MESSAGE(VERBOSE_CMS, "Protocol info requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ cString Result = cString::sprintf(
+ "<u:%sResponse xmlns:u=\"%s\"> \
+ <Source>%s</Source> \
+ <Sink></Sink> \
+ </u:%sResponse>",
+ Request->ActionName,
+ UPNP_CMS_SERVICE_TYPE,
+ *this->mSupportedProtocols,
+ Request->ActionName
+ );
+ Request->ActionResult = ixmlParseBuffer(Result);
+ Request->ErrCode = UPNP_E_SUCCESS;
+ return Request->ErrCode;
+}
+
+int cConnectionManager::getCurrentConnectionIDs(Upnp_Action_Request* Request){
+ MESSAGE(VERBOSE_CMS, "Current connection IDs requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ cString Result;
+ const char* IDs = this->getConnectionIDsCVS();
+ if(!IDs){
+ Request->ErrCode = UPNP_E_INTERNAL_ERROR;
+ return Request->ErrCode;
+ }
+ Result = cString::sprintf(
+ "<u:%sResponse xmlns:u=\"%s\"> \
+ <ConnectionIDs>%s</ConnectionIDs> \
+ </u:%sResponse>",
+ Request->ActionName,
+ UPNP_CMS_SERVICE_TYPE,
+ IDs,
+ Request->ActionName
+ );
+ Request->ActionResult = ixmlParseBuffer(Result);
+ Request->ErrCode = UPNP_E_SUCCESS;
+ return Request->ErrCode;
+}
+
+int cConnectionManager::getCurrentConnectionInfo(Upnp_Action_Request* Request){
+ MESSAGE(VERBOSE_CMS, "Current connection info requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ int ConnectionID;
+
+ if(this->parseIntegerValue(Request->ActionRequest, "ConnectionID", &ConnectionID) != 0){
+ ERROR("Invalid arguments. ConnectionID missing or wrong");
+ this->setError(Request, 402);
+ return Request->ErrCode;
+ }
+
+ cVirtualConnection* Connection;
+ for(Connection = this->mVirtualConnections->First(); Connection && Connection->mConnectionID != ConnectionID; Connection = this->mVirtualConnections->Next(Connection)){}
+
+ if(Connection){
+ cString Result = cString::sprintf(
+ "<u:%sResponse xmlns:u=\"%s\">\
+ <ProtocolInfo>%s</ProtocolInfo>\
+ <PeerConnectionManager>%s</PeerConnectionManager>\
+ <PeerConnectionID>%d</PeerConnectionID>\
+ <Direction>%s</Direction>\
+ <RcsID>%d</RcsID>\
+ <AVTransportID>%d</AVTransportID>\
+ <Status>%s</Status>\
+ </u:%sResponse>",
+ Request->ActionName,
+ UPNP_CMS_SERVICE_TYPE,
+ *Connection->mRemoteProtocolInfo,
+ *Connection->mRemoteConnectionManager,
+ -1,
+ cVirtualConnection::getDirectionString(OUTPUT),
+ Connection->mRcsID,
+ Connection->mAVTransportID,
+ cVirtualConnection::getStatusString(Connection->mStatus),
+ Request->ActionName
+ );
+ Request->ActionResult = ixmlParseBuffer(Result);
+ Request->ErrCode = UPNP_E_SUCCESS;
+ }
+ else {
+ ERROR("No valid connection found with given ID=%d!", ConnectionID);
+ this->setError(Request, 706);
+ }
+
+ return Request->ErrCode;
+
+}
+
+int cConnectionManager::prepareForConnection(Upnp_Action_Request* Request){
+ MESSAGE(VERBOSE_CMS, "Request for a new connection by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ //char* Result = NULL;
+ char* RemoteProtocolInfo = NULL;
+ char* PeerConnectionManager = NULL;
+ int PeerConnectionID = 0;
+ char* DirectionStr = NULL;
+ int Direction;
+
+ if(this->parseStringValue(Request->ActionRequest, "RemoteProtocolInfo", &RemoteProtocolInfo) != 0){
+ ERROR("Invalid argument RemoteProtocolInfo: Missing or wrong");
+ this->setError(Request, 402);
+ return Request->ErrCode;
+ }
+
+ if(this->parseStringValue(Request->ActionRequest, "PeerConnectionManager", &PeerConnectionManager) != 0){
+ ERROR("Invalid argument PeerConnectionManager: Missing or wrong");
+ this->setError(Request, 402);
+ return Request->ErrCode;
+ }
+
+ if(this->parseStringValue(Request->ActionRequest, "Direction", &DirectionStr) != 0 && (Direction = cVirtualConnection::getDirection(DirectionStr)) == -1){
+ ERROR("Invalid argument Direction: Missing or wrong");
+ this->setError(Request, 402);
+ return Request->ErrCode;
+ }
+
+ if(this->parseIntegerValue(Request->ActionRequest, "PeerConnectionID", &PeerConnectionID) != 0){
+ ERROR("Invalid argument PeerConnectionID: Missing or wrong");
+ this->setError(Request, 402);
+ return Request->ErrCode;
+ }
+
+
+ /* TODO:
+ Create Connection
+ Notify AVTransport that a new connection was established
+ Send back the response */
+ this->setError(Request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED);
+ return Request->ErrCode;
+}
+
+int cConnectionManager::connectionComplete(Upnp_Action_Request* Request){
+ MESSAGE(VERBOSE_CMS, "Request for closing an open connection by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ //char* Result = NULL;
+ int ConnectionID;
+
+ if(this->parseIntegerValue(Request->ActionRequest, "ConnectionID", &ConnectionID) != 0){
+ ERROR("Invalid argument ConnectionID: Missing or wrong");
+ this->setError(Request, 402);
+ return Request->ErrCode;
+ }
+
+ // TODO:
+ // Close and clear any open resources
+ // Close and delete the connection
+ // Free other resources left
+ this->setError(Request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED);
+ return Request->ErrCode;
+}
+
+//bool cConnectionManager::setProtocolInfo(const char* ProtocolInfo){
+// if(strcmp(this->mSupportedProtocols, ProtocolInfo)){
+// // ProtocolInfo changed, save and invoke a event notification
+// this->mSupportedProtocols = ProtocolInfo;
+//
+// IXML_Document* PropertySet = NULL;
+// UpnpAddToPropertySet(&PropertySet, "SourceProtocolInfo", this->mSupportedProtocols);
+// int ret = UpnpNotifyExt(this->mDeviceHandle, UPNP_DEVICE_UDN, UPNP_CMS_SERVICE_ID, PropertySet);
+// ixmlDocument_free(PropertySet);
+//
+// if(ret != UPNP_E_SUCCESS){
+// ERROR("State change notification failed (Error code: %d)",ret);
+// return false;
+// }
+// }
+// return true;
+//}
+
+cVirtualConnection* cConnectionManager::createVirtualConnection(const char* RemoteProtocolInfo, const char* RemoteConnectionManager, int RemoteConnectionID, eDirection Direction){
+ static int lastConnectionID = 0;
+ MESSAGE(VERBOSE_CMS, "Create virtual connection");
+ if(lastConnectionID == 2147483647) lastConnectionID = 1;
+ cVirtualConnection* Connection = new cVirtualConnection;
+ // AVT is available
+ Connection->mAVTransportID = 0;
+ // The ProtocolInfo of the remote device (i.e. Media Renderer)
+ Connection->mRemoteProtocolInfo = RemoteProtocolInfo;
+ // The responsible connection manager
+ Connection->mRemoteConnectionManager = RemoteConnectionManager;
+ // The virtual connection direction is output
+ Connection->mDirection = Direction;
+ // The remote connection ID, -1 says ID is unknown
+ Connection->mRemoteConnectionID = RemoteConnectionID;
+ // Connection status, assume that its ok.
+ Connection->mStatus = OK;
+ // new assigned ConnectionID
+ Connection->mConnectionID = lastConnectionID++;
+
+ // Notify the subscribers
+ IXML_Document* PropertySet = NULL;
+ const char* IDs = this->getConnectionIDsCVS();
+ if(!IDs){
+ return NULL;
+ }
+ UpnpAddToPropertySet(&PropertySet, "CurrentConnectionIDs", IDs);
+ int ret = UpnpNotifyExt(this->mDeviceHandle, UPNP_DEVICE_UDN, UPNP_CMS_SERVICE_ID, PropertySet);
+ ixmlDocument_free(PropertySet);
+
+ if(ret != UPNP_E_SUCCESS){
+ ERROR("State change notification failed (Error code: %d)",ret);
+ return NULL;
+ }
+ MESSAGE(VERBOSE_CMS, "Notification of connection creation sent");
+ this->mVirtualConnections->Add(Connection);
+ return Connection;
+}
+
+bool cConnectionManager::destroyVirtualConnection(int ConnectionID){
+ if(ConnectionID == 0){
+ ERROR("Cannot delete default connection with ID 0!");
+ return false;
+ }
+
+ cVirtualConnection* Connection;
+ for(Connection = this->mVirtualConnections->First(); Connection && Connection->mConnectionID != ConnectionID; Connection = this->mVirtualConnections->Next(Connection)){}
+
+ if(Connection){
+ this->mVirtualConnections->Del(Connection);
+ // Notify the subscribers
+ IXML_Document* PropertySet = NULL;
+ const char* IDs = this->getConnectionIDsCVS();
+ if(!IDs){
+ return false;
+ }
+ UpnpAddToPropertySet(&PropertySet, "CurrentConnectionIDs", IDs);
+ int ret = UpnpNotifyExt(this->mDeviceHandle, UPNP_DEVICE_UDN, UPNP_CMS_SERVICE_ID, PropertySet);
+ ixmlDocument_free(PropertySet);
+
+ if(ret != UPNP_E_SUCCESS){
+ ERROR("State change notification failed (Error code: %d)",ret);
+ return false;
+ }
+ return true;
+ }
+ ERROR("No connection with ID=%d found!", ConnectionID);
+ return false;
+}
+
+const char* cConnectionManager::getConnectionIDsCVS(){
+ cString IDs;
+ for(cVirtualConnection* Connection = this->mVirtualConnections->First(); Connection; Connection = this->mVirtualConnections->Next(Connection)){
+ IDs = cString::sprintf("%s,%d", (*IDs)?*IDs:"", Connection->mConnectionID);
+ }
+ return IDs;
+}
+
+void cConnectionManager::setError(Upnp_Action_Request* Request, int Error){
+ Request->ErrCode = Error;
+ switch(Error){
+ case 701:
+ strn0cpy(Request->ErrStr,_("Incompatible protocol info"),LINE_SIZE);
+ break;
+ case 702:
+ strn0cpy(Request->ErrStr,_("Incompatible directions"),LINE_SIZE);
+ break;
+ case 703:
+ strn0cpy(Request->ErrStr,_("Insufficient network resources"),LINE_SIZE);
+ break;
+ case 704:
+ strn0cpy(Request->ErrStr,_("Local restrictions"),LINE_SIZE);
+ break;
+ case 705:
+ strn0cpy(Request->ErrStr,_("Access denied"),LINE_SIZE);
+ break;
+ case 706:
+ strn0cpy(Request->ErrStr,_("Invalid connection reference"),LINE_SIZE);
+ break;
+ case 707:
+ strn0cpy(Request->ErrStr,_("Not in network"),LINE_SIZE);
+ break;
+ default:
+ cUpnpService::setError(Request, Error);
+ break;
+ }
+}
+
+const char* cVirtualConnection::getDirectionString(eDirection Direction){
+ switch(Direction){
+ case INPUT:
+ return "Input";
+ case OUTPUT:
+ return "Output";
+ default:
+ return NULL;
+ }
+}
+
+const char* cVirtualConnection::getStatusString(eConnectionStatus Status){
+ switch(Status){
+ case OK:
+ return "OK";
+ case CONTENT_FORMAT_MISMATCH:
+ return "ContentFormatMismatch";
+ case INSUFFICIENT_BANDWIDTH:
+ return "InsufficientBandwidth";
+ case UNRELIABLE_CHANNEL:
+ return "UnreliableChannel";
+ case UNKNOWN:
+ return "Unknown";
+ default:
+ return NULL;
+ }
+}
+
+int cVirtualConnection::getConnectionStatus(const char* eConnectionStatus){
+ if(!strcasecmp(eConnectionStatus,"OK"))
+ return OK;
+ if(!strcasecmp(eConnectionStatus,"ContentFormatMismatch"))
+ return CONTENT_FORMAT_MISMATCH;
+ if(!strcasecmp(eConnectionStatus,"InsufficientBandwidth"))
+ return INSUFFICIENT_BANDWIDTH;
+ if(!strcasecmp(eConnectionStatus,"UnreliableChannel"))
+ return UNRELIABLE_CHANNEL;
+ if(!strcasecmp(eConnectionStatus,"Unknown"))
+ return UNKNOWN;
+ return -1;
+}
+
+int cVirtualConnection::getDirection(const char* Direction){
+ if(!strcasecmp(Direction, "Output"))
+ return OUTPUT;
+ if(!strcasecmp(Direction, "Input"))
+ return INPUT;
+ return -1;
+} \ No newline at end of file
diff --git a/upnp/contentdirectory.cpp b/upnp/contentdirectory.cpp
new file mode 100644
index 0000000..954f001
--- /dev/null
+++ b/upnp/contentdirectory.cpp
@@ -0,0 +1,306 @@
+/*
+ * File: contentdirectory.cpp
+ * Author: savop
+ *
+ * Created on 21. August 2009, 16:12
+ */
+
+#include <upnp/ixml.h>
+#include <upnp/upnptools.h>
+#include "upnp/contentdirectory.h"
+#include "../common.h"
+#include "util.h"
+
+cContentDirectory::cContentDirectory(UpnpDevice_Handle DeviceHandle, cMediaDatabase* MediaDatabase)
+: cUpnpService(DeviceHandle) {
+ this->mMediaDatabase = MediaDatabase;
+}
+
+cContentDirectory::~cContentDirectory() {}
+
+int cContentDirectory::subscribe(Upnp_Subscription_Request* Request){
+ IXML_Document* PropertySet = NULL;
+
+ /* The system update ID */
+ UpnpAddToPropertySet(&PropertySet, "SystemUpdateID", itoa(this->mMediaDatabase->getSystemUpdateID()));
+ /* The container update IDs as CSV list */
+ UpnpAddToPropertySet(&PropertySet, "ContainerUpdateIDs", this->mMediaDatabase->getContainerUpdateIDs());
+ /* The transfer IDs, which are not supported, i.e. empty */
+ UpnpAddToPropertySet(&PropertySet, "TransferIDs", "");
+ // Accept subscription
+ int ret = UpnpAcceptSubscriptionExt(this->mDeviceHandle, Request->UDN, Request->ServiceId, PropertySet, Request->Sid);
+
+ if(ret != UPNP_E_SUCCESS){
+ ERROR("Subscription failed (Error code: %d)", ret);
+ }
+
+ ixmlDocument_free(PropertySet);
+ return ret;
+}
+
+void cContentDirectory::Action(){
+ static int Retry = 5;
+ MESSAGE(VERBOSE_CDS, "Start Content directory thread");
+ while(this->Running()){
+ IXML_Document* PropertySet = NULL;
+ UpnpAddToPropertySet(&PropertySet, "SystemUpdateID", itoa(this->mMediaDatabase->getSystemUpdateID()));
+ int ret = UpnpNotifyExt(this->mDeviceHandle, UPNP_DEVICE_UDN, UPNP_CMS_SERVICE_ID, PropertySet);
+ ixmlDocument_free(PropertySet);
+
+ if(ret != UPNP_E_SUCCESS){
+ Retry--;
+ ERROR("State change notification failed (Error code: %d)",ret);
+ ERROR("%d of %d notifications failed", (5-Retry), 5);
+ }
+ else {
+ Retry = 5;
+ }
+ if (!Retry){
+ ERROR("Maximum retries of notifications reached. Stopping...");
+ this->Cancel();
+ }
+ // Sleep 2 seconds
+ cCondWait::SleepMs(2000);
+ }
+}
+
+int cContentDirectory::execute(Upnp_Action_Request* Request){
+ if (Request == NULL) {
+ ERROR("CMS Action Handler - request is null");
+ return UPNP_E_BAD_REQUEST;
+ }
+
+ if(!strcmp(Request->ActionName, UPNP_CDS_ACTION_BROWSE))
+ return this->browse(Request);
+ if(!strcmp(Request->ActionName, UPNP_CDS_ACTION_SEARCHCAPABILITIES))
+ return this->getSearchCapabilities(Request);
+ if(!strcmp(Request->ActionName, UPNP_CDS_ACTION_SORTCAPABILITIES))
+ return this->getSortCapabilities(Request);
+ if(!strcmp(Request->ActionName, UPNP_CDS_ACTION_SYSTEMUPDATEID))
+ return this->getSystemUpdateID(Request);
+
+ return UPNP_E_BAD_REQUEST;
+}
+
+
+int cContentDirectory::browse(Upnp_Action_Request* Request){
+ MESSAGE(VERBOSE_CDS, "Browse requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+
+ char* ObjectID = NULL;
+ if(this->parseStringValue(Request->ActionRequest, "ObjectID", &ObjectID)){
+ ERROR("Invalid arguments. ObjectID missing or wrong");
+ this->setError(Request, UPNP_SOAP_E_INVALID_ARGS);
+ return Request->ErrCode;
+ }
+
+ char* BrowseFlag = NULL;
+ bool BrowseMetadata = false;
+ if(this->parseStringValue(Request->ActionRequest, "BrowseFlag", &BrowseFlag)){
+ ERROR("Invalid arguments. Browse flag missing or wrong");
+ this->setError(Request, UPNP_SOAP_E_INVALID_ARGS);
+ return Request->ErrCode;
+ }
+ if(!strcasecmp(BrowseFlag, "BrowseMetadata")){
+ BrowseMetadata = true;
+ }
+ else if(!strcasecmp(BrowseFlag, "BrowseDirectChildren")){
+ BrowseMetadata = false;
+ }
+ else {
+ ERROR("Invalid argument. Browse flag invalid");
+ this->setError(Request, UPNP_SOAP_E_INVALID_ARGS);
+ return Request->ErrCode;
+ }
+
+ char* Filter = NULL;
+ if(this->parseStringValue(Request->ActionRequest, "Filter", &Filter)){
+ ERROR("Invalid arguments. Filter missing or wrong");
+ this->setError(Request, UPNP_SOAP_E_INVALID_ARGS);
+ return Request->ErrCode;
+ }
+
+ int StartingIndex = 0;
+ if(this->parseIntegerValue(Request->ActionRequest, "StartingIndex", &StartingIndex)){
+ ERROR("Invalid arguments. Starting index missing or wrong");
+ this->setError(Request, UPNP_SOAP_E_INVALID_ARGS);
+ return Request->ErrCode;
+ }
+
+ int RequestedCount = 0;
+ if(this->parseIntegerValue(Request->ActionRequest, "RequestedCount", &RequestedCount)){
+ ERROR("Invalid arguments. Requested count missing or wrong");
+ this->setError(Request, UPNP_SOAP_E_INVALID_ARGS);
+ return Request->ErrCode;
+ }
+
+ char* SortCriteria = NULL;
+ if(this->parseStringValue(Request->ActionRequest, "SortCriteria", &SortCriteria)){
+ ERROR("Invalid arguments. Sort criteria missing or wrong");
+ this->setError(Request, UPNP_SOAP_E_INVALID_ARGS);
+ return Request->ErrCode;
+ }
+
+ cUPnPResultSet* ResultSet;
+
+ int ret = this->mMediaDatabase->browse(&ResultSet, ObjectID, BrowseMetadata, Filter, StartingIndex, RequestedCount, SortCriteria);
+ if(ret!=UPNP_E_SUCCESS){
+ ERROR("Error while browsing. Code: %d", ret);
+ this->setError(Request, ret);
+ return Request->ErrCode;
+ }
+
+ char* escapedResult = NULL;
+ escapeXMLCharacters(ResultSet->mResult, &escapedResult);
+
+ if(!escapedResult){
+ ERROR("Escaping XML data failed");
+ this->setError(Request, UPNP_SOAP_E_ACTION_FAILED);
+ return Request->ErrCode;
+ }
+
+ cString Result = cString::sprintf(
+ "<u:%sResponse xmlns:u=\"%s\"> \
+ <Result>%s</Result> \
+ <NumberReturned>%d</NumberReturned> \
+ <TotalMatches>%d</TotalMatches> \
+ <UpdateID>%d</UpdateID> \
+ </u:%sResponse>",
+ Request->ActionName,
+ UPNP_CDS_SERVICE_TYPE,
+ escapedResult,
+ ResultSet->mNumberReturned,
+ ResultSet->mTotalMatches,
+ this->mMediaDatabase->getSystemUpdateID(),
+ Request->ActionName
+ );
+
+ Request->ActionResult = ixmlParseBuffer(Result);
+ Request->ErrCode = UPNP_E_SUCCESS;
+
+ free(escapedResult);
+
+ return Request->ErrCode;
+
+}
+
+int cContentDirectory::getSystemUpdateID(Upnp_Action_Request* Request){
+ cString Result = cString::sprintf(
+ "<u:%sResponse xmlns:u=\"%s\"> \
+ <Id>%d</Id> \
+ </u:%sResponse>",
+ Request->ActionName,
+ UPNP_CDS_SERVICE_TYPE,
+ this->mMediaDatabase->getSystemUpdateID(),
+ Request->ActionName
+ );
+
+ Request->ActionResult = ixmlParseBuffer(Result);
+ Request->ErrCode = UPNP_E_SUCCESS;
+
+ return Request->ErrCode;
+}
+
+int cContentDirectory::getSearchCapabilities(Upnp_Action_Request* Request){
+ MESSAGE(VERBOSE_CDS, "Sorry, no search capabilities yet");
+
+ cString Result = cString::sprintf(
+ "<u:%sResponse xmlns:u=\"%s\"> \
+ <SearchCaps>%s</SearchCaps> \
+ </u:%sResponse>",
+ Request->ActionName,
+ UPNP_CDS_SERVICE_TYPE,
+ UPNP_CDS_SEARCH_CAPABILITIES,
+ Request->ActionName
+ );
+
+ Request->ActionResult = ixmlParseBuffer(Result);
+ Request->ErrCode = UPNP_E_SUCCESS;
+
+ return Request->ErrCode;
+}
+
+int cContentDirectory::getSortCapabilities(Upnp_Action_Request* Request){
+ MESSAGE(VERBOSE_CDS, "Sorry, no sort capabilities yet");
+
+ cString Result = cString::sprintf(
+ "<u:%sResponse xmlns:u=\"%s\"> \
+ <SortCaps>%s</SortCaps> \
+ </u:%sResponse>",
+ Request->ActionName,
+ UPNP_CDS_SERVICE_TYPE,
+ UPNP_CDS_SORT_CAPABILITIES,
+ Request->ActionName
+ );
+
+ Request->ActionResult = ixmlParseBuffer(Result);
+ Request->ErrCode = UPNP_E_SUCCESS;
+
+ return Request->ErrCode;
+}
+
+void cContentDirectory::setError(Upnp_Action_Request* Request, int Error){
+ Request->ErrCode = Error;
+ switch(Error){
+ case UPNP_CDS_E_BAD_METADATA:
+ strn0cpy(Request->ErrStr,_("Bad metadata"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_CANT_PROCESS_REQUEST:
+ strn0cpy(Request->ErrStr,_("Cannot process the request"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_DEST_RESOURCE_ACCESS_DENIED:
+ strn0cpy(Request->ErrStr,_("Destination resource access denied"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_INVALID_CURRENT_TAG:
+ strn0cpy(Request->ErrStr,_("Invalid current tag"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_INVALID_NEW_TAG:
+ strn0cpy(Request->ErrStr,_("Invalid new tag"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_INVALID_SEARCH_CRITERIA:
+ strn0cpy(Request->ErrStr,_("Invalid or unsupported search criteria"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_INVALID_SORT_CRITERIA:
+ strn0cpy(Request->ErrStr,_("Invalid or unsupported sort criteria"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_NO_SUCH_CONTAINER:
+ strn0cpy(Request->ErrStr,_("No such container"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_NO_SUCH_DESTINATION_RESOURCE:
+ strn0cpy(Request->ErrStr,_("No such destination resource"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_NO_SUCH_FILE_TRANSFER:
+ strn0cpy(Request->ErrStr,_("No such file transfer"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_NO_SUCH_OBJECT:
+ strn0cpy(Request->ErrStr,_("No such objectID"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_NO_SUCH_SOURCE_RESOURCE:
+ strn0cpy(Request->ErrStr,_("No such source resource"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_PARAMETER_MISMATCH:
+ strn0cpy(Request->ErrStr,_("Parameter mismatch"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_READ_ONLY_TAG:
+ strn0cpy(Request->ErrStr,_("Read only tag"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_REQUIRED_TAG:
+ strn0cpy(Request->ErrStr,_("Required tag"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_RESOURCE_ACCESS_DENIED:
+ strn0cpy(Request->ErrStr,_("Resource access denied"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_RESTRICTED_OBJECT:
+ strn0cpy(Request->ErrStr,_("Restricted object"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_RESTRICTED_PARENT:
+ strn0cpy(Request->ErrStr,_("Restricted parent"),LINE_SIZE);
+ break;
+ case UPNP_CDS_E_TRANSFER_BUSY:
+ strn0cpy(Request->ErrStr,_("Transfer busy"),LINE_SIZE);
+ break;
+ default:
+ cUpnpService::setError(Request, Error);
+ break;
+ }
+ return;
+} \ No newline at end of file
diff --git a/upnp/service.cpp b/upnp/service.cpp
new file mode 100644
index 0000000..4d17af1
--- /dev/null
+++ b/upnp/service.cpp
@@ -0,0 +1,118 @@
+/*
+ * File: upnpservice.cpp
+ * Author: savop
+ *
+ * Created on 21. August 2009, 18:38
+ */
+
+#include "upnp/service.h"
+#include "../common.h"
+#include "util.h"
+
+cUpnpService::cUpnpService(UpnpDevice_Handle DeviceHandle) {
+ this->mDeviceHandle = DeviceHandle;
+}
+
+int cUpnpService::parseIntegerValue(IN IXML_Document* Document, IN const char* Item, OUT int* Value){
+ char* Val = NULL;
+ int Error = 0;
+
+ Val = ixmlGetFirstDocumentItem(Document, Item, &Error);
+
+ if(Error != 0){
+ ERROR("Error while parsing integer value for item=%s", Item);
+ Error = -1;
+ }
+ else if(!Value){
+ WARNING("Value %s empty!", Item);
+ *Value = 0;
+ }
+ else {
+ *Value = atoi(Val);
+ free(Val);
+ }
+ return Error;
+}
+
+int cUpnpService::parseStringValue(IN IXML_Document* Document, IN const char* Item, OUT char** Value){
+ char* Val = NULL;
+ int Error = 0;
+
+ Val = ixmlGetFirstDocumentItem(Document, Item, &Error);
+
+ if(Error != 0){
+ ERROR("Error while parsing string value for item=%s", Item);
+ Error = -1;
+ }
+ else if(!Val){
+ WARNING("Value %s empty!", Item);
+ *Value = NULL;
+ }
+ else {
+ *Value = strdup(Val);
+ free(Val);
+ }
+
+ return Error;
+}
+
+void cUpnpService::setError(Upnp_Action_Request* Request, int Error){
+ Request->ErrCode = Error;
+ switch(Error){
+ case UPNP_SOAP_E_INVALID_ACTION:
+ strn0cpy(Request->ErrStr,_("Invalid action"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_INVALID_ARGS:
+ strn0cpy(Request->ErrStr,_("Invalid args"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_INVALID_VAR:
+ strn0cpy(Request->ErrStr,_("Invalid var"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_ACTION_FAILED:
+ strn0cpy(Request->ErrStr,_("Action failed"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_ARGUMENT_INVALID:
+ strn0cpy(Request->ErrStr,_("Argument value invalid"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_ARGUMENT_OUT_OF_RANGE:
+ strn0cpy(Request->ErrStr,_("Argument value out of range"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED:
+ strn0cpy(Request->ErrStr,_("Optional action not implemented"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_OUT_OF_MEMORY:
+ strn0cpy(Request->ErrStr,_("Out of memory"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_HUMAN_INTERVENTION:
+ strn0cpy(Request->ErrStr,_("Human intervention required"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_STRING_TO_LONG:
+ strn0cpy(Request->ErrStr,_("String argument to long"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_NOT_AUTHORIZED:
+ strn0cpy(Request->ErrStr,_("Action not authorized"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_SIGNATURE_FAILURE:
+ strn0cpy(Request->ErrStr,_("Signature failure"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_SIGNATURE_MISSING:
+ strn0cpy(Request->ErrStr,_("Signature missing"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_NOT_ENCRYPTED:
+ strn0cpy(Request->ErrStr,_("Not encrypted"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_INVALID_SEQUENCE:
+ strn0cpy(Request->ErrStr,_("Invalid sequence"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_INVALID_CONTROL_URL:
+ strn0cpy(Request->ErrStr,_("Invalid control URL"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_NO_SUCH_SESSION:
+ strn0cpy(Request->ErrStr,_("No such session"),LINE_SIZE);
+ break;
+ case UPNP_SOAP_E_OUT_OF_SYNC:
+ default:
+ strn0cpy(Request->ErrStr,_("Unknown error code. Contact the device manufacturer"),LINE_SIZE);
+ break;
+ }
+} \ No newline at end of file