|
a/libupnpp/control/cdirectory.cxx |
|
b/libupnpp/control/cdirectory.cxx |
|
... |
|
... |
72 |
}
|
72 |
}
|
73 |
bool operator() (const string& val) const {
|
73 |
bool operator() (const string& val) const {
|
74 |
return simpleMatch(val);
|
74 |
return simpleMatch(val);
|
75 |
}
|
75 |
}
|
76 |
|
76 |
|
77 |
bool ok() const {return m_ok;}
|
77 |
bool ok() const {
|
|
|
78 |
return m_ok;
|
|
|
79 |
}
|
78 |
private:
|
80 |
private:
|
79 |
bool m_ok;
|
81 |
bool m_ok;
|
80 |
regex_t m_expr;
|
82 |
regex_t m_expr;
|
81 |
};
|
83 |
};
|
82 |
#else
|
84 |
#else
|
83 |
class SimpleRegexp {
|
85 |
class SimpleRegexp {
|
84 |
public:
|
86 |
public:
|
85 |
SimpleRegexp(const string& exp, int flags)
|
87 |
SimpleRegexp(const string& exp, int flags)
|
86 |
: m_expr(exp, basic_regex<char>::flag_type(flags)), m_ok(true) {}
|
88 |
: m_expr(exp, basic_regex<char>::flag_type(flags)), m_ok(true) {}
|
87 |
|
89 |
|
88 |
bool simpleMatch(const string& val) const {
|
90 |
bool simpleMatch(const string& val) const {
|
89 |
if (!ok())
|
91 |
if (!ok())
|
90 |
return false;
|
92 |
return false;
|
91 |
return regex_match(val, m_expr);
|
93 |
return regex_match(val, m_expr);
|
92 |
}
|
94 |
}
|
93 |
bool operator() (const string& val) const {
|
95 |
bool operator() (const string& val) const {
|
94 |
return simpleMatch(val);
|
96 |
return simpleMatch(val);
|
95 |
}
|
97 |
}
|
96 |
|
98 |
|
97 |
bool ok() const { return m_ok; }
|
99 |
bool ok() const {
|
|
|
100 |
return m_ok;
|
|
|
101 |
}
|
98 |
private:
|
102 |
private:
|
99 |
basic_regex<char> m_expr;
|
103 |
basic_regex<char> m_expr;
|
100 |
bool m_ok;
|
104 |
bool m_ok;
|
101 |
};
|
105 |
};
|
102 |
#define REG_ICASE std::regex_constants::icase
|
106 |
#define REG_ICASE std::regex_constants::icase
|
103 |
#define REG_NOSUB std::regex_constants::nosubs
|
107 |
#define REG_NOSUB std::regex_constants::nosubs
|
104 |
|
108 |
|
105 |
#endif
|
109 |
#endif
|
|
... |
|
... |
119 |
|
123 |
|
120 |
ContentDirectory::ContentDirectory(const UPnPDeviceDesc& device,
|
124 |
ContentDirectory::ContentDirectory(const UPnPDeviceDesc& device,
|
121 |
const UPnPServiceDesc& service)
|
125 |
const UPnPServiceDesc& service)
|
122 |
: Service(device, service), m_rdreqcnt(200), m_serviceKind(CDSKIND_UNKNOWN)
|
126 |
: Service(device, service), m_rdreqcnt(200), m_serviceKind(CDSKIND_UNKNOWN)
|
123 |
{
|
127 |
{
|
124 |
LOGERR("ContentDirectory::ContentDirectory: manufacturer: " <<
|
128 |
LOGERR("ContentDirectory::ContentDirectory: manufacturer: " <<
|
125 |
getManufacturer() << " model " << getModelName() << endl);
|
129 |
getManufacturer() << " model " << getModelName() << endl);
|
126 |
|
130 |
|
127 |
if (bubble_rx(getModelName())) {
|
131 |
if (bubble_rx(getModelName())) {
|
128 |
m_serviceKind = CDSKIND_BUBBLE;
|
132 |
m_serviceKind = CDSKIND_BUBBLE;
|
129 |
LOGDEB1("ContentDirectory::ContentDirectory: BUBBLE" << endl);
|
133 |
LOGDEB1("ContentDirectory::ContentDirectory: BUBBLE" << endl);
|
|
... |
|
... |
140 |
m_serviceKind = CDSKIND_MINIM;
|
144 |
m_serviceKind = CDSKIND_MINIM;
|
141 |
LOGDEB1("ContentDirectory::ContentDirectory: MINIM" << endl);
|
145 |
LOGDEB1("ContentDirectory::ContentDirectory: MINIM" << endl);
|
142 |
} else if (twonky_rx(getModelName())) {
|
146 |
} else if (twonky_rx(getModelName())) {
|
143 |
m_serviceKind = CDSKIND_TWONKY;
|
147 |
m_serviceKind = CDSKIND_TWONKY;
|
144 |
LOGDEB1("ContentDirectory::ContentDirectory: TWONKY" << endl);
|
148 |
LOGDEB1("ContentDirectory::ContentDirectory: TWONKY" << endl);
|
145 |
}
|
149 |
}
|
146 |
registerCallback();
|
150 |
registerCallback();
|
147 |
}
|
151 |
}
|
148 |
ContentDirectory::~ContentDirectory()
|
152 |
ContentDirectory::~ContentDirectory()
|
149 |
{
|
153 |
{
|
150 |
unregisterCallback();
|
154 |
unregisterCallback();
|
|
... |
|
... |
157 |
const string::size_type sz(SType.size()-2);
|
161 |
const string::size_type sz(SType.size()-2);
|
158 |
return !SType.compare(0, sz, st, 0, sz);
|
162 |
return !SType.compare(0, sz, st, 0, sz);
|
159 |
}
|
163 |
}
|
160 |
|
164 |
|
161 |
static bool DSAccum(vector<CDSH>* out,
|
165 |
static bool DSAccum(vector<CDSH>* out,
|
162 |
const UPnPDeviceDesc& device,
|
166 |
const UPnPDeviceDesc& device,
|
163 |
const UPnPServiceDesc& service)
|
167 |
const UPnPServiceDesc& service)
|
164 |
{
|
168 |
{
|
165 |
if (ContentDirectory::isCDService(service.serviceType)) {
|
169 |
if (ContentDirectory::isCDService(service.serviceType)) {
|
166 |
out->push_back(CDSH(new ContentDirectory(device, service)));
|
170 |
out->push_back(CDSH(new ContentDirectory(device, service)));
|
167 |
}
|
171 |
}
|
|
... |
|
... |
174 |
UPnPDeviceDirectory::Visitor visitor = bind(DSAccum, &vds, _1, _2);
|
178 |
UPnPDeviceDirectory::Visitor visitor = bind(DSAccum, &vds, _1, _2);
|
175 |
UPnPDeviceDirectory::getTheDir()->traverse(visitor);
|
179 |
UPnPDeviceDirectory::getTheDir()->traverse(visitor);
|
176 |
return !vds.empty();
|
180 |
return !vds.empty();
|
177 |
}
|
181 |
}
|
178 |
|
182 |
|
179 |
// Get server by friendly name.
|
183 |
// Get server by friendly name.
|
180 |
bool ContentDirectory::getServerByName(const string& fname, CDSH& server)
|
184 |
bool ContentDirectory::getServerByName(const string& fname, CDSH& server)
|
181 |
{
|
185 |
{
|
182 |
UPnPDeviceDesc ddesc;
|
186 |
UPnPDeviceDesc ddesc;
|
183 |
bool found = UPnPDeviceDirectory::getTheDir()->getDevByFName(fname, ddesc);
|
187 |
bool found = UPnPDeviceDirectory::getTheDir()->getDevByFName(fname, ddesc);
|
184 |
if (!found)
|
188 |
if (!found)
|
185 |
return false;
|
189 |
return false;
|
186 |
|
190 |
|
187 |
found = false;
|
191 |
found = false;
|
188 |
for (std::vector<UPnPServiceDesc>::const_iterator it =
|
192 |
for (std::vector<UPnPServiceDesc>::const_iterator it =
|
189 |
ddesc.services.begin(); it != ddesc.services.end(); it++) {
|
193 |
ddesc.services.begin(); it != ddesc.services.end(); it++) {
|
190 |
if (isCDService(it->serviceType)) {
|
194 |
if (isCDService(it->serviceType)) {
|
191 |
server = CDSH(new ContentDirectory(ddesc, *it));
|
195 |
server = CDSH(new ContentDirectory(ddesc, *it));
|
192 |
found = true;
|
196 |
found = true;
|
193 |
break;
|
197 |
break;
|
194 |
}
|
198 |
}
|
|
... |
|
... |
200 |
static int asyncReaddirCB(Upnp_EventType et, void *vev, void *cookie)
|
204 |
static int asyncReaddirCB(Upnp_EventType et, void *vev, void *cookie)
|
201 |
{
|
205 |
{
|
202 |
LOGDEB("asyncReaddirCB: " << LibUPnP::evTypeAsString(et) << endl);
|
206 |
LOGDEB("asyncReaddirCB: " << LibUPnP::evTypeAsString(et) << endl);
|
203 |
struct Upnp_Action_Complete *act = (struct Upnp_Action_Complete*)vev;
|
207 |
struct Upnp_Action_Complete *act = (struct Upnp_Action_Complete*)vev;
|
204 |
|
208 |
|
205 |
LOGDEB("asyncReaddirCB: errcode " << act->ErrCode <<
|
209 |
LOGDEB("asyncReaddirCB: errcode " << act->ErrCode <<
|
206 |
" cturl " << UpnpString_get_String(act->CtrlUrl) <<
|
210 |
" cturl " << UpnpString_get_String(act->CtrlUrl) <<
|
207 |
" actionrequest " << endl <<
|
211 |
" actionrequest " << endl <<
|
208 |
ixmlwPrintDoc(act->ActionRequest) << endl <<
|
212 |
ixmlwPrintDoc(act->ActionRequest) << endl <<
|
209 |
" actionresult " << ixmlwPrintDoc(act->ActionResult) << endl);
|
213 |
" actionresult " << ixmlwPrintDoc(act->ActionResult) << endl);
|
210 |
return 0;
|
214 |
return 0;
|
211 |
}
|
215 |
}
|
212 |
int ret =
|
216 |
int ret =
|
213 |
UpnpSendActionAsync(hdl, getActionURL().c_str(), getServiceType().c_str(),
|
217 |
UpnpSendActionAsync(hdl, getActionURL().c_str(), getServiceType().c_str(),
|
214 |
0 /*devUDN*/, request, asyncReaddirCB, 0);
|
218 |
0 /*devUDN*/, request, asyncReaddirCB, 0);
|
215 |
sleep(10);
|
219 |
sleep(10);
|
216 |
return -1;
|
220 |
return -1;
|
217 |
#endif
|
221 |
#endif
|
218 |
|
222 |
|
219 |
void ContentDirectory::evtCallback(const STD_UNORDERED_MAP<string, string>&)
|
223 |
void ContentDirectory::evtCallback(const STD_UNORDERED_MAP<string, string>&)
|
220 |
{
|
224 |
{
|
221 |
}
|
225 |
}
|
222 |
|
226 |
|
223 |
void ContentDirectory::registerCallback()
|
227 |
void ContentDirectory::registerCallback()
|
224 |
{
|
228 |
{
|
225 |
LOGDEB("ContentDirectory::registerCallback"<< endl);
|
229 |
LOGDEB("ContentDirectory::registerCallback"<< endl);
|
226 |
Service::registerCallback(bind(&ContentDirectory::evtCallback,
|
230 |
Service::registerCallback(bind(&ContentDirectory::evtCallback,
|
227 |
this, _1));
|
231 |
this, _1));
|
228 |
}
|
232 |
}
|
229 |
|
233 |
|
230 |
int ContentDirectory::readDirSlice(const string& objectId, int offset,
|
234 |
int ContentDirectory::readDirSlice(const string& objectId, int offset,
|
231 |
int count, UPnPDirContent& dirbuf,
|
235 |
int count, UPnPDirContent& dirbuf,
|
232 |
int *didread, int *total)
|
236 |
int *didread, int *total)
|
233 |
{
|
237 |
{
|
234 |
LOGDEB("CDService::readDirSlice: objId [" << objectId << "] offset " <<
|
238 |
LOGDEB("CDService::readDirSlice: objId [" << objectId << "] offset " <<
|
235 |
offset << " count " << count << endl);
|
239 |
offset << " count " << count << endl);
|
236 |
|
240 |
|
237 |
// Create request
|
241 |
// Create request
|
238 |
// Some devices require an empty SortCriteria, else bad params
|
242 |
// Some devices require an empty SortCriteria, else bad params
|
239 |
SoapOutgoing args(getServiceType(), "Browse");
|
243 |
SoapOutgoing args(getServiceType(), "Browse");
|
240 |
args("ObjectID", objectId)
|
244 |
args("ObjectID", objectId)
|
241 |
("BrowseFlag", "BrowseDirectChildren")
|
245 |
("BrowseFlag", "BrowseDirectChildren")
|
242 |
("Filter", "*")
|
246 |
("Filter", "*")
|
243 |
("SortCriteria", "")
|
247 |
("SortCriteria", "")
|
244 |
("StartingIndex", SoapHelp::i2s(offset))
|
248 |
("StartingIndex", SoapHelp::i2s(offset))
|
245 |
("RequestedCount", SoapHelp::i2s(count));
|
249 |
("RequestedCount", SoapHelp::i2s(count));
|
246 |
|
250 |
|
247 |
SoapIncoming data;
|
251 |
SoapIncoming data;
|
248 |
int ret = runAction(args, data);
|
252 |
int ret = runAction(args, data);
|
249 |
if (ret != UPNP_E_SUCCESS) {
|
253 |
if (ret != UPNP_E_SUCCESS) {
|
250 |
return ret;
|
254 |
return ret;
|
251 |
}
|
255 |
}
|
252 |
|
256 |
|
253 |
string tbuf;
|
257 |
string tbuf;
|
254 |
if (!data.get("NumberReturned", didread) ||
|
258 |
if (!data.get("NumberReturned", didread) ||
|
255 |
!data.get("TotalMatches", total) ||
|
259 |
!data.get("TotalMatches", total) ||
|
256 |
!data.get("Result", &tbuf)) {
|
260 |
!data.get("Result", &tbuf)) {
|
257 |
LOGERR("CDService::readDir: missing elts in response" << endl);
|
261 |
LOGERR("CDService::readDir: missing elts in response" << endl);
|
258 |
return UPNP_E_BAD_RESPONSE;
|
262 |
return UPNP_E_BAD_RESPONSE;
|
259 |
}
|
263 |
}
|
260 |
|
264 |
|
261 |
if (*didread <= 0) {
|
265 |
if (*didread <= 0) {
|
|
... |
|
... |
263 |
return UPNP_E_BAD_RESPONSE;
|
267 |
return UPNP_E_BAD_RESPONSE;
|
264 |
}
|
268 |
}
|
265 |
|
269 |
|
266 |
#if 0
|
270 |
#if 0
|
267 |
cerr << "CDService::readDirSlice: count " << count <<
|
271 |
cerr << "CDService::readDirSlice: count " << count <<
|
268 |
" offset " << offset <<
|
272 |
" offset " << offset <<
|
269 |
" total " << *total << endl;
|
273 |
" total " << *total << endl;
|
270 |
cerr << " result " << tbuf << endl;
|
274 |
cerr << " result " << tbuf << endl;
|
271 |
#endif
|
275 |
#endif
|
272 |
|
276 |
|
273 |
dirbuf.parse(tbuf);
|
277 |
dirbuf.parse(tbuf);
|
274 |
|
278 |
|
275 |
return UPNP_E_SUCCESS;
|
279 |
return UPNP_E_SUCCESS;
|
276 |
}
|
280 |
}
|
277 |
|
281 |
|
278 |
int ContentDirectory::readDir(const string& objectId,
|
282 |
int ContentDirectory::readDir(const string& objectId,
|
279 |
UPnPDirContent& dirbuf)
|
283 |
UPnPDirContent& dirbuf)
|
280 |
{
|
284 |
{
|
281 |
LOGDEB("CDService::readDir: url [" << getActionURL() << "] type [" <<
|
285 |
LOGDEB("CDService::readDir: url [" << getActionURL() << "] type [" <<
|
282 |
getServiceType() << "] udn [" << getDeviceId() << "] objId [" <<
|
286 |
getServiceType() << "] udn [" << getDeviceId() << "] objId [" <<
|
283 |
objectId << endl);
|
287 |
objectId << endl);
|
284 |
|
288 |
|
|
... |
|
... |
301 |
int ContentDirectory::searchSlice(const string& objectId,
|
305 |
int ContentDirectory::searchSlice(const string& objectId,
|
302 |
const string& ss,
|
306 |
const string& ss,
|
303 |
int offset, int count, UPnPDirContent& dirbuf,
|
307 |
int offset, int count, UPnPDirContent& dirbuf,
|
304 |
int *didread, int *total)
|
308 |
int *didread, int *total)
|
305 |
{
|
309 |
{
|
306 |
LOGDEB("CDService::searchSlice: objId [" << objectId << "] offset " <<
|
310 |
LOGDEB("CDService::searchSlice: objId [" << objectId << "] offset " <<
|
307 |
offset << " count " << count << endl);
|
311 |
offset << " count " << count << endl);
|
308 |
|
312 |
|
309 |
// Create request
|
313 |
// Create request
|
310 |
SoapOutgoing args(getServiceType(), "Search");
|
314 |
SoapOutgoing args(getServiceType(), "Search");
|
311 |
args("ContainerID", objectId)
|
315 |
args("ContainerID", objectId)
|
312 |
("SearchCriteria", ss)
|
316 |
("SearchCriteria", ss)
|
313 |
("Filter", "*")
|
317 |
("Filter", "*")
|
314 |
("SortCriteria", "")
|
318 |
("SortCriteria", "")
|
315 |
("StartingIndex", SoapHelp::i2s(offset))
|
319 |
("StartingIndex", SoapHelp::i2s(offset))
|
316 |
("RequestedCount", SoapHelp::i2s(count));
|
320 |
("RequestedCount", SoapHelp::i2s(count));
|
317 |
|
321 |
|
318 |
SoapIncoming data;
|
322 |
SoapIncoming data;
|
319 |
int ret = runAction(args, data);
|
323 |
int ret = runAction(args, data);
|
320 |
|
324 |
|
321 |
if (ret != UPNP_E_SUCCESS) {
|
325 |
if (ret != UPNP_E_SUCCESS) {
|
|
... |
|
... |
324 |
return ret;
|
328 |
return ret;
|
325 |
}
|
329 |
}
|
326 |
|
330 |
|
327 |
string tbuf;
|
331 |
string tbuf;
|
328 |
if (!data.get("NumberReturned", didread) ||
|
332 |
if (!data.get("NumberReturned", didread) ||
|
329 |
!data.get("TotalMatches", total) ||
|
333 |
!data.get("TotalMatches", total) ||
|
330 |
!data.get("Result", &tbuf)) {
|
334 |
!data.get("Result", &tbuf)) {
|
331 |
LOGERR("CDService::search: missing elts in response" << endl);
|
335 |
LOGERR("CDService::search: missing elts in response" << endl);
|
332 |
return UPNP_E_BAD_RESPONSE;
|
336 |
return UPNP_E_BAD_RESPONSE;
|
333 |
}
|
337 |
}
|
334 |
if (*didread <= 0) {
|
338 |
if (*didread <= 0) {
|
335 |
LOGINF("CDService::search: got -1 or 0 entries" << endl);
|
339 |
LOGINF("CDService::search: got -1 or 0 entries" << endl);
|
|
... |
|
... |
343 |
|
347 |
|
344 |
int ContentDirectory::search(const string& objectId,
|
348 |
int ContentDirectory::search(const string& objectId,
|
345 |
const string& ss,
|
349 |
const string& ss,
|
346 |
UPnPDirContent& dirbuf)
|
350 |
UPnPDirContent& dirbuf)
|
347 |
{
|
351 |
{
|
348 |
LOGDEB("CDService::search: url [" << getActionURL() << "] type [" <<
|
352 |
LOGDEB("CDService::search: url [" << getActionURL() << "] type [" <<
|
349 |
getServiceType() << "] udn [" << getDeviceId() << "] objid [" <<
|
353 |
getServiceType() << "] udn [" << getDeviceId() << "] objid [" <<
|
350 |
objectId << "] search [" << ss << "]" << endl);
|
354 |
objectId << "] search [" << ss << "]" << endl);
|
351 |
|
355 |
|
352 |
int offset = 0;
|
356 |
int offset = 0;
|
353 |
int total = 1000;// Updated on first read.
|
357 |
int total = 1000;// Updated on first read.
|
354 |
|
358 |
|
|
... |
|
... |
371 |
|
375 |
|
372 |
SoapOutgoing args(getServiceType(), "GetSearchCapabilities");
|
376 |
SoapOutgoing args(getServiceType(), "GetSearchCapabilities");
|
373 |
SoapIncoming data;
|
377 |
SoapIncoming data;
|
374 |
int ret = runAction(args, data);
|
378 |
int ret = runAction(args, data);
|
375 |
if (ret != UPNP_E_SUCCESS) {
|
379 |
if (ret != UPNP_E_SUCCESS) {
|
376 |
LOGINF("CDService::getSearchCapa: UpnpSendAction failed: " <<
|
380 |
LOGINF("CDService::getSearchCapa: UpnpSendAction failed: " <<
|
377 |
UpnpGetErrorMessage(ret) << endl);
|
381 |
UpnpGetErrorMessage(ret) << endl);
|
378 |
return ret;
|
382 |
return ret;
|
379 |
}
|
383 |
}
|
380 |
string tbuf;
|
384 |
string tbuf;
|
381 |
if (!data.get("SearchCaps", &tbuf)) {
|
385 |
if (!data.get("SearchCaps", &tbuf)) {
|
|
... |
|
... |
395 |
|
399 |
|
396 |
return UPNP_E_SUCCESS;
|
400 |
return UPNP_E_SUCCESS;
|
397 |
}
|
401 |
}
|
398 |
|
402 |
|
399 |
int ContentDirectory::getMetadata(const string& objectId,
|
403 |
int ContentDirectory::getMetadata(const string& objectId,
|
400 |
UPnPDirContent& dirbuf)
|
404 |
UPnPDirContent& dirbuf)
|
401 |
{
|
405 |
{
|
402 |
LOGDEB("CDService::getMetadata: url [" << getActionURL() << "] type [" <<
|
406 |
LOGDEB("CDService::getMetadata: url [" << getActionURL() << "] type [" <<
|
403 |
getServiceType() << "] udn [" << getDeviceId() << "] objId [" <<
|
407 |
getServiceType() << "] udn [" << getDeviceId() << "] objId [" <<
|
404 |
objectId << "]" << endl);
|
408 |
objectId << "]" << endl);
|
405 |
|
409 |
|
406 |
SoapOutgoing args(getServiceType(), "Browse");
|
410 |
SoapOutgoing args(getServiceType(), "Browse");
|
407 |
SoapIncoming data;
|
411 |
SoapIncoming data;
|
408 |
args("ObjectID", objectId)
|
412 |
args("ObjectID", objectId)
|
409 |
("BrowseFlag", "BrowseMetadata")
|
413 |
("BrowseFlag", "BrowseMetadata")
|
410 |
("Filter", "*")
|
414 |
("Filter", "*")
|
411 |
("SortCriteria", "")
|
415 |
("SortCriteria", "")
|
412 |
("StartingIndex", "0")
|
416 |
("StartingIndex", "0")
|
413 |
("RequestedCount", "1");
|
417 |
("RequestedCount", "1");
|
414 |
int ret = runAction(args, data);
|
418 |
int ret = runAction(args, data);
|
415 |
if (ret != UPNP_E_SUCCESS) {
|
419 |
if (ret != UPNP_E_SUCCESS) {
|
416 |
LOGINF("CDService::getmetadata: UpnpSendAction failed: " <<
|
420 |
LOGINF("CDService::getmetadata: UpnpSendAction failed: " <<
|
417 |
UpnpGetErrorMessage(ret) << endl);
|
421 |
UpnpGetErrorMessage(ret) << endl);
|
418 |
return ret;
|
422 |
return ret;
|
419 |
}
|
423 |
}
|
420 |
string tbuf;
|
424 |
string tbuf;
|
421 |
if (!data.get("Result", &tbuf)) {
|
425 |
if (!data.get("Result", &tbuf)) {
|