Switch to unified view

a/libupnpp/cdirectory.cxx b/libupnpp/cdirectory.cxx
...
...
21
21
22
#include <string>
22
#include <string>
23
#include <iostream>
23
#include <iostream>
24
#include <set>
24
#include <set>
25
#include <vector>
25
#include <vector>
26
using std::string;
26
using namespace std;
27
using std::cerr;
27
#include <functional>
28
using std::endl;
28
using namespace std::placeholders;
29
using std::vector;
30
using std::set;
31
29
32
#include "upnpp_p.hxx"
30
#include "upnpp_p.hxx"
33
31
34
#include <upnp/upnp.h>
32
#include <upnp/upnp.h>
35
#include <upnp/upnptools.h>
33
#include <upnp/upnptools.h>
36
34
37
#include "upnpplib.hxx"
35
#include "upnpplib.hxx"
38
#include "ixmlwrap.hxx"
36
#include "ixmlwrap.hxx"
39
#include "cdirectory.hxx"
37
#include "cdirectory.hxx"
40
#include "cdircontent.hxx"
38
#include "cdircontent.hxx"
39
#include "discovery.hxx"
40
41
namespace UPnPClient {
42
43
// The service type string for Content Directories:
44
const string ContentDirectoryService::SType("urn:schemas-upnp-org:service:ContentDirectory:1");
45
46
// We don't include a version in comparisons, as we are satisfied with
47
// version 1
48
bool ContentDirectoryService::isCDService(const string& st)
49
{
50
    const string::size_type sz(SType.size()-2);
51
    return !SType.compare(0, sz, st, 0, sz);
52
}
53
54
55
static bool DSAccum(vector<ContentDirectoryService>* out,
56
                    const UPnPDeviceDesc& device, 
57
                    const UPnPServiceDesc& service)
58
{
59
    if (ContentDirectoryService::isCDService(service.serviceType)) {
60
        out->push_back(ContentDirectoryService(device, service));
61
    }
62
    return true;
63
}
64
65
bool ContentDirectoryService::getServices(vector<ContentDirectoryService>& vds)
66
{
67
    //LOGDEB("UPnPDeviceDirectory::getDirServices" << endl);
68
    UPnPDeviceDirectory::Visitor visitor = bind(DSAccum, &vds, _1, _2);
69
  UPnPDeviceDirectory::getTheDir()->traverse(visitor);
70
    return !vds.empty();
71
}
72
73
static bool DSFriendlySelect(const string& friendlyName,
74
                             bool  *found,
75
                             ContentDirectoryService *out,
76
                             const UPnPDeviceDesc& device, 
77
                             const UPnPServiceDesc& service)
78
{
79
    if (ContentDirectoryService::isCDService(service.serviceType)) {
80
        if (!friendlyName.compare(device.friendlyName)) {
81
            *out = ContentDirectoryService(device, service);
82
            *found = true;
83
            return false;
84
        }
85
    }
86
    return true;
87
}
88
89
// Get server by friendly name. 
90
bool ContentDirectoryService::getServerByName(const string& friendlyName,
91
                                            ContentDirectoryService& server)
92
{
93
    bool found = false;
94
    UPnPDeviceDirectory::Visitor visitor = 
95
        bind(DSFriendlySelect, friendlyName, &found, &server, _1, _2);
96
  UPnPDeviceDirectory::getTheDir()->traverse(visitor);
97
    return found;
98
}
99
41
100
42
class DirBResFree {
101
class DirBResFree {
43
public:
102
public:
44
  IXML_Document **rqpp, **rspp;
103
    IXML_Document **rqpp, **rspp;
45
  DirBResFree(IXML_Document** _rqpp, IXML_Document **_rspp)
104
    DirBResFree(IXML_Document** _rqpp, IXML_Document **_rspp)
46
      :rqpp(_rqpp), rspp(_rspp)
105
        :rqpp(_rqpp), rspp(_rspp)
47
      {}
106
        {}
48
  ~DirBResFree()
107
    ~DirBResFree()
49
      {
108
        {
50
          if (*rqpp)
109
            if (*rqpp)
51
              ixmlDocument_free(*rqpp);
110
                ixmlDocument_free(*rqpp);
52
          if (*rspp)
111
            if (*rspp)
53
              ixmlDocument_free(*rspp);
112
                ixmlDocument_free(*rspp);
54
      }
113
        }
55
};
114
};
56
115
57
int ContentDirectoryService::readDirSlice(const string& objectId, int offset,
116
int ContentDirectoryService::readDirSlice(const string& objectId, int offset,
58
                                        int count, UPnPDirContent& dirbuf,
117
                                          int count, UPnPDirContent& dirbuf,
59
                                        int *didreadp, int *totalp)
118
                                          int *didreadp, int *totalp)
60
{
119
{
61
  PLOGDEB("CDService::readDirSlice: objId [%s] offset %d count %d\n",
120
    PLOGDEB("CDService::readDirSlice: objId [%s] offset %d count %d\n",
62
          objectId.c_str(), offset, count);
121
            objectId.c_str(), offset, count);
63
  LibUPnP* lib = LibUPnP::getLibUPnP();
122
    LibUPnP* lib = LibUPnP::getLibUPnP();
64
  if (lib == 0) {
123
    if (lib == 0) {
65
      PLOGINF("CDService::readDir: no lib\n");
124
        PLOGINF("CDService::readDir: no lib\n");
66
      return UPNP_E_OUTOF_MEMORY;
125
        return UPNP_E_OUTOF_MEMORY;
67
  }
126
    }
68
  UpnpClient_Handle hdl = lib->getclh();
127
    UpnpClient_Handle hdl = lib->getclh();
69
128
70
  IXML_Document *request(0);
129
    IXML_Document *request(0);
71
  IXML_Document *response(0);
130
    IXML_Document *response(0);
72
  DirBResFree cleaner(&request, &response);
131
    DirBResFree cleaner(&request, &response);
73
132
74
  // Create request
133
    // Create request
75
  char ofbuf[100], cntbuf[100];
134
    char ofbuf[100], cntbuf[100];
76
  sprintf(ofbuf, "%d", offset);
135
    sprintf(ofbuf, "%d", offset);
77
  sprintf(cntbuf, "%d", count);
136
    sprintf(cntbuf, "%d", count);
78
  int argcnt = 6;
137
    int argcnt = 6;
79
  // Some devices require an empty SortCriteria, else bad params
138
    // Some devices require an empty SortCriteria, else bad params
80
  request = UpnpMakeAction("Browse", m_serviceType.c_str(), argcnt,
139
    request = UpnpMakeAction("Browse", m_serviceType.c_str(), argcnt,
81
                           "ObjectID", objectId.c_str(),
140
                             "ObjectID", objectId.c_str(),
82
                           "BrowseFlag", "BrowseDirectChildren",
141
                             "BrowseFlag", "BrowseDirectChildren",
83
                           "Filter", "*",
142
                             "Filter", "*",
84
                           "SortCriteria", "",
143
                             "SortCriteria", "",
85
                           "StartingIndex", ofbuf,
144
                             "StartingIndex", ofbuf,
86
                           "RequestedCount", cntbuf,
145
                             "RequestedCount", cntbuf,
87
                           NULL, NULL);
146
                             NULL, NULL);
88
  if (request == 0) {
147
    if (request == 0) {
89
      PLOGINF("CDService::readDir: UpnpMakeAction failed\n");
148
        PLOGINF("CDService::readDir: UpnpMakeAction failed\n");
90
      return   UPNP_E_OUTOF_MEMORY;
149
        return  UPNP_E_OUTOF_MEMORY;
91
  }
150
    }
92
151
93
  //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
152
    //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
94
153
95
  int ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
154
    int ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
96
                           0 /*devUDN*/, request, &response);
155
                             0 /*devUDN*/, request, &response);
97
156
98
  if (ret != UPNP_E_SUCCESS) {
157
    if (ret != UPNP_E_SUCCESS) {
99
      PLOGINF("CDService::readDir: UpnpSendAction failed: %s\n",
158
        PLOGINF("CDService::readDir: UpnpSendAction failed: %s\n",
100
              UpnpGetErrorMessage(ret));
159
                UpnpGetErrorMessage(ret));
101
      return ret;
160
        return ret;
102
  }
161
    }
103
162
104
  int didread = -1;
163
    int didread = -1;
105
  string tbuf = ixmlwrap::getFirstElementValue(response, "NumberReturned");
164
    string tbuf = ixmlwrap::getFirstElementValue(response, "NumberReturned");
106
  if (!tbuf.empty())
165
    if (!tbuf.empty())
107
      didread = atoi(tbuf.c_str());
166
        didread = atoi(tbuf.c_str());
108
167
109
  if (count == -1 || count == 0) {
168
    if (count == -1 || count == 0) {
110
      PLOGINF("CDService::readDir: got -1 or 0 entries\n");
169
        PLOGINF("CDService::readDir: got -1 or 0 entries\n");
111
      return UPNP_E_BAD_RESPONSE;
170
        return UPNP_E_BAD_RESPONSE;
112
  }
171
    }
113
172
114
  tbuf = ixmlwrap::getFirstElementValue(response, "TotalMatches");
173
    tbuf = ixmlwrap::getFirstElementValue(response, "TotalMatches");
115
  if (!tbuf.empty())
174
    if (!tbuf.empty())
116
      *totalp = atoi(tbuf.c_str());
175
        *totalp = atoi(tbuf.c_str());
117
176
118
  tbuf = ixmlwrap::getFirstElementValue(response, "Result");
177
    tbuf = ixmlwrap::getFirstElementValue(response, "Result");
119
178
120
#if 0
179
#if 0
121
  cerr << "CDService::readDirSlice: count " << count <<
180
    cerr << "CDService::readDirSlice: count " << count <<
122
      " offset " << offset <<
181
        " offset " << offset <<
123
      " total " << *totalp << endl;
182
        " total " << *totalp << endl;
124
  cerr << " result " << tbuf << endl;
183
    cerr << " result " << tbuf << endl;
125
#endif
184
#endif
126
185
127
  dirbuf.parse(tbuf);
186
    dirbuf.parse(tbuf);
128
  *didreadp = didread;
187
    *didreadp = didread;
129
  return UPNP_E_SUCCESS;
188
    return UPNP_E_SUCCESS;
130
}
189
}
131
190
132
191
133
int ContentDirectoryService::readDir(const string& objectId,
192
int ContentDirectoryService::readDir(const string& objectId,
134
                                   UPnPDirContent& dirbuf)
193
                                     UPnPDirContent& dirbuf)
135
{
194
{
136
  PLOGDEB("CDService::readDir: url [%s] type [%s] udn [%s] objId [%s]\n",
195
    PLOGDEB("CDService::readDir: url [%s] type [%s] udn [%s] objId [%s]\n",
137
          m_actionURL.c_str(), m_serviceType.c_str(), m_deviceId.c_str(),
196
            m_actionURL.c_str(), m_serviceType.c_str(), m_deviceId.c_str(),
138
          objectId.c_str());
197
            objectId.c_str());
139
198
140
  int offset = 0;
199
    int offset = 0;
141
  int total = 1000;// Updated on first read.
200
    int total = 1000;// Updated on first read.
142
201
143
  while (offset < total) {
202
    while (offset < total) {
144
      int count;
203
        int count;
145
      int error = readDirSlice(objectId, offset, m_rdreqcnt, dirbuf,
204
        int error = readDirSlice(objectId, offset, m_rdreqcnt, dirbuf,
146
                               &count, &total);
205
                                 &count, &total);
147
      if (error != UPNP_E_SUCCESS)
206
        if (error != UPNP_E_SUCCESS)
148
          return error;
207
            return error;
149
208
150
      offset += count;
209
        offset += count;
151
  }
210
    }
152
211
153
  return UPNP_E_SUCCESS;
212
    return UPNP_E_SUCCESS;
154
}
213
}
155
214
156
int ContentDirectoryService::search(const string& objectId,
215
int ContentDirectoryService::search(const string& objectId,
157
                                  const string& ss,
216
                                    const string& ss,
158
                                  UPnPDirContent& dirbuf)
217
                                    UPnPDirContent& dirbuf)
159
{
218
{
160
  PLOGDEB("CDService::search: url [%s] type [%s] udn [%s] objid [%s] "
219
    PLOGDEB("CDService::search: url [%s] type [%s] udn [%s] objid [%s] "
161
          "search [%s]\n",
220
            "search [%s]\n",
162
          m_actionURL.c_str(), m_serviceType.c_str(), m_deviceId.c_str(),
221
            m_actionURL.c_str(), m_serviceType.c_str(), m_deviceId.c_str(),
163
          objectId.c_str(), ss.c_str());
222
            objectId.c_str(), ss.c_str());
164
223
165
  LibUPnP* lib = LibUPnP::getLibUPnP();
224
    LibUPnP* lib = LibUPnP::getLibUPnP();
166
  if (lib == 0) {
225
    if (lib == 0) {
167
      PLOGINF("CDService::search: no lib\n");
226
        PLOGINF("CDService::search: no lib\n");
168
      return UPNP_E_OUTOF_MEMORY;
227
        return UPNP_E_OUTOF_MEMORY;
169
  }
228
    }
170
  UpnpClient_Handle hdl = lib->getclh();
229
    UpnpClient_Handle hdl = lib->getclh();
171
230
172
  int ret = UPNP_E_SUCCESS;
231
    int ret = UPNP_E_SUCCESS;
173
  IXML_Document *request(0);
232
    IXML_Document *request(0);
174
  IXML_Document *response(0);
233
    IXML_Document *response(0);
175
234
176
  int offset = 0;
235
    int offset = 0;
177
  int total = 1000;// Updated on first read.
236
    int total = 1000;// Updated on first read.
178
237
179
  while (offset < total) {
238
    while (offset < total) {
180
      DirBResFree cleaner(&request, &response);
239
        DirBResFree cleaner(&request, &response);
181
      char ofbuf[100];
240
        char ofbuf[100];
182
      sprintf(ofbuf, "%d", offset);
241
        sprintf(ofbuf, "%d", offset);
183
      // Create request
242
        // Create request
184
      int argcnt = 6;
243
        int argcnt = 6;
185
      request = UpnpMakeAction(
244
        request = UpnpMakeAction(
186
          "Search", m_serviceType.c_str(), argcnt,
245
            "Search", m_serviceType.c_str(), argcnt,
187
          "ContainerID", objectId.c_str(),
246
            "ContainerID", objectId.c_str(),
188
          "SearchCriteria", ss.c_str(),
247
            "SearchCriteria", ss.c_str(),
189
          "Filter", "*",
248
            "Filter", "*",
190
          "SortCriteria", "",
249
            "SortCriteria", "",
191
          "StartingIndex", ofbuf,
250
            "StartingIndex", ofbuf,
192
          "RequestedCount", "0", // Setting a value here gets twonky into fits
251
            "RequestedCount", "0", // Setting a value here gets twonky into fits
193
          NULL, NULL);
252
            NULL, NULL);
194
      if (request == 0) {
253
        if (request == 0) {
195
          PLOGINF("CDService::search: UpnpMakeAction failed\n");
254
            PLOGINF("CDService::search: UpnpMakeAction failed\n");
196
          return   UPNP_E_OUTOF_MEMORY;
255
            return  UPNP_E_OUTOF_MEMORY;
197
      }
256
        }
198
257
199
      // cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
258
        // cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
200
259
201
      ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
260
        ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
202
                           0 /*devUDN*/, request, &response);
261
                             0 /*devUDN*/, request, &response);
203
262
204
      if (ret != UPNP_E_SUCCESS) {
263
        if (ret != UPNP_E_SUCCESS) {
205
          PLOGINF("CDService::search: UpnpSendAction failed: %s\n",
264
            PLOGINF("CDService::search: UpnpSendAction failed: %s\n",
206
                  UpnpGetErrorMessage(ret));
265
                    UpnpGetErrorMessage(ret));
207
          return ret;
266
            return ret;
208
      }
267
        }
209
268
210
      int count = -1;
269
        int count = -1;
211
      string tbuf =
270
        string tbuf =
212
          ixmlwrap::getFirstElementValue(response, "NumberReturned");
271
            ixmlwrap::getFirstElementValue(response, "NumberReturned");
213
      if (!tbuf.empty())
272
        if (!tbuf.empty())
214
          count = atoi(tbuf.c_str());
273
            count = atoi(tbuf.c_str());
215
274
216
      if (count == -1 || count == 0) {
275
        if (count == -1 || count == 0) {
217
          PLOGINF("CDService::search: got -1 or 0 entries\n");
276
            PLOGINF("CDService::search: got -1 or 0 entries\n");
218
          return count == -1 ? UPNP_E_BAD_RESPONSE : UPNP_E_SUCCESS;
277
            return count == -1 ? UPNP_E_BAD_RESPONSE : UPNP_E_SUCCESS;
219
      }
278
        }
220
      offset += count;
279
        offset += count;
221
280
222
      tbuf = ixmlwrap::getFirstElementValue(response, "TotalMatches");
281
        tbuf = ixmlwrap::getFirstElementValue(response, "TotalMatches");
223
      if (!tbuf.empty())
282
        if (!tbuf.empty())
224
          total = atoi(tbuf.c_str());
283
            total = atoi(tbuf.c_str());
225
284
226
      tbuf = ixmlwrap::getFirstElementValue(response, "Result");
285
        tbuf = ixmlwrap::getFirstElementValue(response, "Result");
227
286
228
#if 0
287
#if 0
229
      cerr << "CDService::search: count " << count <<
288
        cerr << "CDService::search: count " << count <<
230
          " offset " << offset <<
289
            " offset " << offset <<
231
          " total " << total << endl;
290
            " total " << total << endl;
232
      cerr << " result " << tbuf << endl;
291
        cerr << " result " << tbuf << endl;
233
#endif
292
#endif
234
293
235
      dirbuf.parse(tbuf);
294
        dirbuf.parse(tbuf);
236
  }
295
    }
237
296
238
  return UPNP_E_SUCCESS;
297
    return UPNP_E_SUCCESS;
239
}
298
}
240
299
241
int ContentDirectoryService::getSearchCapabilities(set<string>& result)
300
int ContentDirectoryService::getSearchCapabilities(set<string>& result)
242
{
301
{
243
  PLOGDEB("CDService::getSearchCapabilities:\n");
302
    PLOGDEB("CDService::getSearchCapabilities:\n");
244
  LibUPnP* lib = LibUPnP::getLibUPnP();
303
    LibUPnP* lib = LibUPnP::getLibUPnP();
245
  if (lib == 0) {
304
    if (lib == 0) {
246
      PLOGINF("CDService::getSearchCapabilities: no lib\n");
305
        PLOGINF("CDService::getSearchCapabilities: no lib\n");
247
      return UPNP_E_OUTOF_MEMORY;
306
        return UPNP_E_OUTOF_MEMORY;
248
  }
307
    }
249
  UpnpClient_Handle hdl = lib->getclh();
308
    UpnpClient_Handle hdl = lib->getclh();
250
309
251
  int ret = UPNP_E_SUCCESS;
310
    int ret = UPNP_E_SUCCESS;
252
  IXML_Document *request(0);
311
    IXML_Document *request(0);
253
  IXML_Document *response(0);
312
    IXML_Document *response(0);
254
313
255
  request = UpnpMakeAction("GetSearchCapabilities", m_serviceType.c_str(),
314
    request = UpnpMakeAction("GetSearchCapabilities", m_serviceType.c_str(),
256
                           0,
315
                             0,
257
                           NULL, NULL);
316
                             NULL, NULL);
258
317
259
  if (request == 0) {
318
    if (request == 0) {
260
      PLOGINF("CDService::getSearchCapa: UpnpMakeAction failed\n");
319
        PLOGINF("CDService::getSearchCapa: UpnpMakeAction failed\n");
261
      return   UPNP_E_OUTOF_MEMORY;
320
        return  UPNP_E_OUTOF_MEMORY;
262
  }
321
    }
263
322
264
  //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
323
    //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
265
324
266
  ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
325
    ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
267
                       0 /*devUDN*/, request, &response);
326
                         0 /*devUDN*/, request, &response);
268
327
269
  if (ret != UPNP_E_SUCCESS) {
328
    if (ret != UPNP_E_SUCCESS) {
270
      PLOGINF("CDService::getSearchCapa: UpnpSendAction failed: %s\n",
329
        PLOGINF("CDService::getSearchCapa: UpnpSendAction failed: %s\n",
271
              UpnpGetErrorMessage(ret));
330
                UpnpGetErrorMessage(ret));
272
      return ret;
331
        return ret;
273
  }
332
    }
274
  //cerr << "getSearchCapa: response xml: [" << ixmlPrintDocument(response)
333
    //cerr << "getSearchCapa: response xml: [" << ixmlPrintDocument(response)
275
  // << "]" << endl;
334
    // << "]" << endl;
276
335
277
  string tbuf = ixmlwrap::getFirstElementValue(response, "SearchCaps");
336
    string tbuf = ixmlwrap::getFirstElementValue(response, "SearchCaps");
278
  // cerr << "getSearchCapa: capa: [" << tbuf << "]" << endl;
337
    // cerr << "getSearchCapa: capa: [" << tbuf << "]" << endl;
279
338
280
  result.clear();
339
    result.clear();
281
  if (!tbuf.compare("*")) {
340
    if (!tbuf.compare("*")) {
282
      result.insert(result.end(), "*");
341
        result.insert(result.end(), "*");
283
  } else if (!tbuf.empty()) {
342
    } else if (!tbuf.empty()) {
284
      if (!csvToStrings(tbuf, result)) {
343
        if (!csvToStrings(tbuf, result)) {
285
          return UPNP_E_BAD_RESPONSE;
344
            return UPNP_E_BAD_RESPONSE;
286
      }
345
        }
287
  }
346
    }
288
347
289
  return UPNP_E_SUCCESS;
348
    return UPNP_E_SUCCESS;
290
}
349
}
291
350
292
int ContentDirectoryService::getMetadata(const string& objectId,
351
int ContentDirectoryService::getMetadata(const string& objectId,
293
                                       UPnPDirContent& dirbuf)
352
                                         UPnPDirContent& dirbuf)
294
{
353
{
295
  PLOGDEB("CDService::getMetadata: url [%s] type [%s] udn [%s] objId [%s]\n",
354
    PLOGDEB("CDService::getMetadata: url [%s] type [%s] udn [%s] objId [%s]\n",
296
          m_actionURL.c_str(), m_serviceType.c_str(), m_deviceId.c_str(),
355
            m_actionURL.c_str(), m_serviceType.c_str(), m_deviceId.c_str(),
297
          objectId.c_str());
356
            objectId.c_str());
298
357
299
  LibUPnP* lib = LibUPnP::getLibUPnP();
358
    LibUPnP* lib = LibUPnP::getLibUPnP();
300
  if (lib == 0) {
359
    if (lib == 0) {
301
      PLOGINF("CDService::getMetadata: no lib\n");
360
        PLOGINF("CDService::getMetadata: no lib\n");
302
      return UPNP_E_OUTOF_MEMORY;
361
        return UPNP_E_OUTOF_MEMORY;
303
  }
362
    }
304
  UpnpClient_Handle hdl = lib->getclh();
363
    UpnpClient_Handle hdl = lib->getclh();
305
364
306
  int ret = UPNP_E_SUCCESS;
365
    int ret = UPNP_E_SUCCESS;
307
  IXML_Document *request(0);
366
    IXML_Document *request(0);
308
  IXML_Document *response(0);
367
    IXML_Document *response(0);
309
368
310
  DirBResFree cleaner(&request, &response);
369
    DirBResFree cleaner(&request, &response);
311
  // Create request
370
    // Create request
312
  int argcnt = 6;
371
    int argcnt = 6;
313
  request = UpnpMakeAction("Browse", m_serviceType.c_str(), argcnt,
372
    request = UpnpMakeAction("Browse", m_serviceType.c_str(), argcnt,
314
                           "ObjectID", objectId.c_str(),
373
                             "ObjectID", objectId.c_str(),
315
                           "BrowseFlag", "BrowseMetadata",
374
                             "BrowseFlag", "BrowseMetadata",
316
                           "Filter", "*",
375
                             "Filter", "*",
317
                           "SortCriteria", "",
376
                             "SortCriteria", "",
318
                           "StartingIndex", "0",
377
                             "StartingIndex", "0",
319
                           "RequestedCount", "1",
378
                             "RequestedCount", "1",
320
                           NULL, NULL);
379
                             NULL, NULL);
321
  if (request == 0) {
380
    if (request == 0) {
322
      PLOGINF("CDService::getmetadata: UpnpMakeAction failed\n");
381
        PLOGINF("CDService::getmetadata: UpnpMakeAction failed\n");
323
      return   UPNP_E_OUTOF_MEMORY;
382
        return  UPNP_E_OUTOF_MEMORY;
324
  }
383
    }
325
384
326
  //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
385
    //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
327
386
328
  ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
387
    ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
329
                       0 /*devUDN*/, request, &response);
388
                         0 /*devUDN*/, request, &response);
330
389
331
  if (ret != UPNP_E_SUCCESS) {
390
    if (ret != UPNP_E_SUCCESS) {
332
      PLOGINF("CDService::getmetadata: UpnpSendAction failed: %s\n",
391
        PLOGINF("CDService::getmetadata: UpnpSendAction failed: %s\n",
333
              UpnpGetErrorMessage(ret));
392
                UpnpGetErrorMessage(ret));
334
      return ret;
393
        return ret;
335
  }
394
    }
336
  string tbuf = ixmlwrap::getFirstElementValue(response, "Result");
395
    string tbuf = ixmlwrap::getFirstElementValue(response, "Result");
337
  if (dirbuf.parse(tbuf))
396
    if (dirbuf.parse(tbuf))
338
      return UPNP_E_SUCCESS;
397
        return UPNP_E_SUCCESS;
339
  else
398
    else
340
      return UPNP_E_BAD_RESPONSE;
399
        return UPNP_E_BAD_RESPONSE;
341
}
400
}
342
/* Local Variables: */
401
343
/* mode: c++ */
402
} // namespace UPnPClient
344
/* c-basic-offset: 4 */
345
/* tab-width: 4 */
346
/* indent-tabs-mode: t */
347
/* End: */