00001
00002
00003
00004
00005
00006
00007
00008
00010
00011 #include "upnp.h"
00012 #include "upnpcds.h"
00013 #include "upnputil.h"
00014
00015 #include "util.h"
00016
00017 #include <qtextstream.h>
00018 #include <math.h>
00019 #include <qregexp.h>
00020
00021 #define DIDL_LITE_BEGIN "<DIDL-Lite xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\">"
00022 #define DIDL_LITE_END "</DIDL-Lite>";
00023
00025
00027
00028 void UPnpCDSExtensionResults::Add( CDSObject *pObject )
00029 {
00030 if (pObject)
00031 m_List.append( pObject );
00032 }
00033
00035
00037
00038 QString UPnpCDSExtensionResults::GetResultXML()
00039 {
00040 QString sXML;
00041
00042 for ( CDSObject *pObject = m_List.first();
00043 pObject != NULL;
00044 pObject = m_List.next() )
00045 {
00046 sXML += pObject->toXml();
00047 }
00048
00049 return( sXML );
00050 }
00051
00053
00055
00056 UPnpCDS::UPnpCDS( UPnpDevice *pDevice, const QString &sSharePath ) : Eventing( "UPnpCDS", "CDS_Event" )
00057 {
00058 m_extensions.setAutoDelete( true );
00059
00060 m_root.m_eType = OT_Container;
00061 m_root.m_sId = "0";
00062 m_root.m_sParentId = "-1";
00063 m_root.m_sTitle = "MythTv";
00064 m_root.m_sClass = "object.container";
00065 m_root.m_bRestricted= true;
00066 m_root.m_bSearchable= true;
00067
00068 AddVariable( new StateVariable< QString >( "TransferIDs" , true ) );
00069 AddVariable( new StateVariable< QString >( "ContainerUpdateIDs", true ) );
00070 AddVariable( new StateVariable< unsigned short >( "SystemUpdateID" , true ) );
00071
00072 SetValue< unsigned short >( "SystemUpdateID", 1 );
00073
00074 QString sUPnpDescPath = UPnp::g_pConfig->GetValue( "UPnP/DescXmlPath", sSharePath );
00075
00076 m_sSharePath = sSharePath;
00077 m_sServiceDescFileName = sUPnpDescPath + "CDS_scpd.xml";
00078 m_sControlUrl = "/CDS_Control";
00079
00080
00081
00082
00083 RegisterService( pDevice );
00084 }
00085
00087
00089
00090 UPnpCDS::~UPnpCDS()
00091 {
00092 }
00093
00095
00097
00098 UPnpCDSMethod UPnpCDS::GetMethod( const QString &sURI )
00099 {
00100 if (sURI == "GetServDesc" ) return CDSM_GetServiceDescription;
00101 if (sURI == "Browse" ) return CDSM_Browse ;
00102 if (sURI == "Search" ) return CDSM_Search ;
00103 if (sURI == "GetSearchCapabilities" ) return CDSM_GetSearchCapabilities;
00104 if (sURI == "GetSortCapabilities" ) return CDSM_GetSortCapabilities ;
00105 if (sURI == "GetSystemUpdateID" ) return CDSM_GetSystemUpdateID ;
00106
00107 return( CDSM_Unknown );
00108 }
00109
00111
00113
00114 UPnpCDSBrowseFlag UPnpCDS::GetBrowseFlag( const QString &sFlag )
00115 {
00116 if (sFlag == "BrowseMetadata" ) return( CDS_BrowseMetadata );
00117 if (sFlag == "BrowseDirectChildren" ) return( CDS_BrowseDirectChildren );
00118
00119 return( CDS_BrowseUnknown );
00120 }
00121
00123
00125
00126 void UPnpCDS::RegisterExtension ( UPnpCDSExtension *pExtension )
00127 {
00128 if (pExtension != NULL )
00129 m_extensions.append( pExtension );
00130 }
00131
00133
00135
00136 void UPnpCDS::UnregisterExtension( UPnpCDSExtension *pExtension )
00137 {
00138 if (pExtension != NULL )
00139 m_extensions.remove( pExtension );
00140 }
00141
00143
00145
00146 bool UPnpCDS::ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest )
00147 {
00148 if (pRequest)
00149 {
00150 if (Eventing::ProcessRequest( pThread, pRequest ))
00151 return true;
00152
00153 if ( pRequest->m_sBaseUrl != m_sControlUrl )
00154 {
00155
00156 return false;
00157 }
00158
00159 switch( GetMethod( pRequest->m_sMethod ) )
00160 {
00161 case CDSM_GetServiceDescription : pRequest->FormatFileResponse( m_sServiceDescFileName ); break;
00162 case CDSM_Browse : HandleBrowse ( pRequest ); break;
00163 case CDSM_Search : HandleSearch ( pRequest ); break;
00164 case CDSM_GetSearchCapabilities : HandleGetSearchCapabilities ( pRequest ); break;
00165 case CDSM_GetSortCapabilities : HandleGetSortCapabilities ( pRequest ); break;
00166 case CDSM_GetSystemUpdateID : HandleGetSystemUpdateID ( pRequest ); break;
00167 default:
00168 UPnp::FormatErrorResponse( pRequest, UPnPResult_InvalidAction );
00169 break;
00170 }
00171
00172 return true;
00173 }
00174
00175 return false;
00176
00177 }
00178
00180
00182
00183 void UPnpCDS::HandleBrowse( HTTPRequest *pRequest )
00184 {
00185 UPnpCDSExtensionResults *pResult = NULL;
00186 UPnpCDSRequest request;
00187
00188 request.m_sObjectId = pRequest->m_mapParams[ "ObjectID" ];
00189 request.m_sContainerID = pRequest->m_mapParams[ "ContainerID" ];
00190 request.m_sParentId = "0";
00191 request.m_eBrowseFlag = GetBrowseFlag( pRequest->m_mapParams[ "BrowseFlag" ] );
00192 request.m_sFilter = pRequest->m_mapParams[ "Filter" ];
00193 request.m_nStartingIndex = pRequest->m_mapParams[ "StartingIndex" ].toLong();
00194 request.m_nRequestedCount = pRequest->m_mapParams[ "RequestedCount"].toLong();
00195 request.m_sSortCriteria = pRequest->m_mapParams[ "SortCriteria" ];
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 UPnPResultCode eErrorCode = UPnPResult_CDS_NoSuchObject;
00218 QString sErrorDesc = "";
00219 short nNumberReturned = 0;
00220 short nTotalMatches = 0;
00221 short nUpdateID = 0;
00222 QString sResultXML;
00223
00224 VERBOSE(VB_UPNP, QString("UPnpCDS::HandleBrowse ObjectID=%1, ContainerId=%2")
00225 .arg(request.m_sObjectId)
00226 .arg(request.m_sContainerID));
00227
00228 if (request.m_sObjectId == "0")
00229 {
00230
00231
00232
00233
00234 switch( request.m_eBrowseFlag )
00235 {
00236 case CDS_BrowseMetadata:
00237 {
00238
00239
00240
00241
00242 eErrorCode = UPnPResult_Success;
00243 nNumberReturned = 1;
00244 nTotalMatches = 1;
00245 nUpdateID = m_root.m_nUpdateId;
00246
00247 m_root.SetChildCount( m_extensions.count() );
00248
00249 sResultXML = m_root.toXml();
00250
00251 break;
00252 }
00253
00254 case CDS_BrowseDirectChildren:
00255 {
00256
00257
00258
00259
00260 eErrorCode = UPnPResult_Success;
00261 nTotalMatches = m_extensions.count();
00262 nUpdateID = m_root.m_nUpdateId;
00263
00264 if (request.m_nRequestedCount == 0)
00265 request.m_nRequestedCount = nTotalMatches;
00266
00267 short nStart = Max( request.m_nStartingIndex, short( 0 ));
00268 short nCount = Min( nTotalMatches, request.m_nRequestedCount );
00269
00270 UPnpCDSExtension *pExtension = m_extensions.at( nStart );
00271 UPnpCDSRequest childRequest;
00272
00273 childRequest.m_sParentId = "0";
00274 childRequest.m_eBrowseFlag = CDS_BrowseMetadata;
00275 childRequest.m_sFilter = "";
00276 childRequest.m_nStartingIndex = 0;
00277 childRequest.m_nRequestedCount = 1;
00278 childRequest.m_sSortCriteria = "";
00279
00280 while (( pExtension != NULL ) && (nNumberReturned < nCount ))
00281 {
00282 childRequest.m_sObjectId = pExtension->m_sExtensionId;
00283
00284 pResult = pExtension->Browse( &childRequest );
00285
00286 if (pResult != NULL)
00287 {
00288 if (pResult->m_eErrorCode == UPnPResult_Success)
00289 {
00290 sResultXML += pResult->GetResultXML();
00291 nNumberReturned ++;
00292 }
00293
00294 delete pResult;
00295 }
00296
00297 pExtension = m_extensions.next();
00298 }
00299
00300 break;
00301 }
00302 default: break;
00303 }
00304 }
00305 else
00306 {
00307
00308
00309
00310
00311 UPnpCDSExtension *pExtension = m_extensions.first();
00312
00313 while (( pExtension != NULL ) && (pResult == NULL))
00314 {
00315 VERBOSE(VB_UPNP, QString("UPNP Browse : Searching for : %1 / ObjectID : %2").arg(pExtension->m_sExtensionId).arg(request.m_sObjectId));
00316 pResult = pExtension->Browse( &request );
00317
00318 pExtension = m_extensions.next();
00319 }
00320
00321 if (pResult != NULL)
00322 {
00323 eErrorCode = pResult->m_eErrorCode;
00324 sErrorDesc = pResult->m_sErrorDesc;
00325
00326 if (eErrorCode == UPnPResult_Success)
00327 {
00328 nNumberReturned = pResult->m_List.count();
00329 nTotalMatches = pResult->m_nTotalMatches;
00330 nUpdateID = pResult->m_nUpdateID;
00331 sResultXML = pResult->GetResultXML();
00332 }
00333
00334 delete pResult;
00335 }
00336 }
00337
00338
00339
00340
00341
00342 if (eErrorCode == UPnPResult_Success)
00343 {
00344 NameValueList list;
00345
00346 QString sResults = DIDL_LITE_BEGIN;
00347 sResults += sResultXML;
00348 sResults += DIDL_LITE_END;
00349
00350 list.append( new NameValue( "Result" , sResults ));
00351 list.append( new NameValue( "NumberReturned", QString::number( nNumberReturned )));
00352 list.append( new NameValue( "TotalMatches" , QString::number( nTotalMatches )));
00353 list.append( new NameValue( "UpdateID" , QString::number( nUpdateID )));
00354
00355 pRequest->FormatActionResponse( &list );
00356 }
00357 else
00358 UPnp::FormatErrorResponse ( pRequest, eErrorCode, sErrorDesc );
00359
00360 }
00361
00363
00365
00366 void UPnpCDS::HandleSearch( HTTPRequest *pRequest )
00367 {
00368 UPnpCDSExtensionResults *pResult = NULL;
00369 UPnpCDSRequest request;
00370
00371 UPnPResultCode eErrorCode = UPnPResult_InvalidAction;
00372 QString sErrorDesc = "";
00373 short nNumberReturned = 0;
00374 short nTotalMatches = 0;
00375 short nUpdateID = 0;
00376 QString sResultXML;
00377
00378 request.m_sObjectId = pRequest->m_mapParams[ "ObjectID" ];
00379 request.m_sContainerID = pRequest->m_mapParams[ "ContainerID" ];
00380 request.m_sFilter = pRequest->m_mapParams[ "Filter" ];
00381 request.m_nStartingIndex = pRequest->m_mapParams[ "StartingIndex" ].toLong();
00382 request.m_nRequestedCount = pRequest->m_mapParams[ "RequestedCount"].toLong();
00383 request.m_sSortCriteria = pRequest->m_mapParams[ "SortCriteria" ];
00384 request.m_sSearchCriteria = pRequest->m_mapParams[ "SearchCriteria"];
00385
00386 VERBOSE(VB_UPNP, QString("UPnpCDS::HandleSearch ObjectID=%1, ContainerId=%2")
00387 .arg(request.m_sObjectId)
00388 .arg(request.m_sContainerID));
00389
00390
00391
00392
00393
00394
00395 QRegExp rMatch( "\\b(or|and)\\b" );
00396 rMatch.setCaseSensitive( FALSE );
00397
00398 request.m_sSearchList = QStringList::split( rMatch, request.m_sSearchCriteria );
00399 request.m_sSearchClass = "object";
00400
00401
00402
00403
00404
00405
00406 for ( QStringList::Iterator it = request.m_sSearchList.begin();
00407 it != request.m_sSearchList.end();
00408 ++it )
00409 {
00410 if ( (*it).contains( "upnp:class derivedfrom", FALSE ) > 0)
00411 {
00412 QStringList sParts = QStringList::split( ' ', *it );
00413
00414 if (sParts.count() > 2)
00415 {
00416 request.m_sSearchClass = sParts[2].stripWhiteSpace();
00417 request.m_sSearchClass.remove( '"' );
00418
00419 break;
00420 }
00421 }
00422 }
00423
00424
00425
00426
00427 VERBOSE(VB_UPNP,QString("UPnpCDS::ProcessRequest \n"
00428 ": url = %1 \n"
00429 ": Method = %2 \n"
00430 ": ObjectId = %3 \n"
00431 ": SearchCriteria = %4 \n"
00432 ": Filter = %5 \n"
00433 ": StartingIndex = %6 \n"
00434 ": RequestedCount = %7 \n"
00435 ": SortCriteria = %8 \n"
00436 ": SearchClass = %9" )
00437 .arg( pRequest->m_sBaseUrl )
00438 .arg( pRequest->m_sMethod )
00439 .arg( request.m_sObjectId )
00440 .arg( request.m_sSearchCriteria)
00441 .arg( request.m_sFilter )
00442 .arg( request.m_nStartingIndex )
00443 .arg( request.m_nRequestedCount)
00444 .arg( request.m_sSortCriteria )
00445 .arg( request.m_sSearchClass ));
00446
00447
00448 UPnpCDSExtension *pExtension = m_extensions.first();
00449
00450
00451
00452 while (( pExtension != NULL ) && (pResult == NULL))
00453 {
00454
00455 pResult = pExtension->Search( &request );
00456
00457 pExtension = m_extensions.next();
00458 }
00459
00460 if (pResult != NULL)
00461 {
00462 eErrorCode = pResult->m_eErrorCode;
00463 sErrorDesc = pResult->m_sErrorDesc;
00464
00465 if (eErrorCode == UPnPResult_Success)
00466 {
00467 nNumberReturned = pResult->m_List.count();
00468 nTotalMatches = pResult->m_nTotalMatches;
00469 nUpdateID = pResult->m_nUpdateID;
00470 sResultXML = pResult->GetResultXML();
00471
00472 }
00473
00474 delete pResult;
00475 }
00476
00477
00478
00479
00480 if (eErrorCode == UPnPResult_Success)
00481 {
00482 NameValueList list;
00483 QString sResults = DIDL_LITE_BEGIN;
00484 sResults += sResultXML;
00485 sResults += DIDL_LITE_END;
00486
00487 list.append( new NameValue( "Result" , sResults ));
00488 list.append( new NameValue( "NumberReturned", QString::number( nNumberReturned )));
00489 list.append( new NameValue( "TotalMatches" , QString::number( nTotalMatches )));
00490 list.append( new NameValue( "UpdateID" , QString::number( nUpdateID )));
00491
00492 pRequest->FormatActionResponse( &list );
00493 }
00494 else
00495 UPnp::FormatErrorResponse( pRequest, eErrorCode, sErrorDesc );
00496
00497 }
00498
00500
00502
00503 void UPnpCDS::HandleGetSearchCapabilities( HTTPRequest *pRequest )
00504 {
00505 NameValueList list;
00506
00507 VERBOSE(VB_UPNP,QString("UPnpCDS::ProcessRequest : %1 : %2")
00508 .arg(pRequest->m_sBaseUrl)
00509 .arg(pRequest->m_sMethod));
00510
00511
00512
00513 list.append( new NameValue( "SearchCaps", "dc:title,dc:creator,dc:date,upnp:class,res@size" ));
00514
00515 pRequest->FormatActionResponse( &list );
00516 }
00517
00519
00521
00522 void UPnpCDS::HandleGetSortCapabilities( HTTPRequest *pRequest )
00523 {
00524 NameValueList list;
00525
00526 VERBOSE(VB_UPNP,QString("UPnpCDS::ProcessRequest : %1 : %2")
00527 .arg(pRequest->m_sBaseUrl)
00528 .arg(pRequest->m_sMethod));
00529
00530
00531
00532 list.append( new NameValue( "SortCaps", "dc:title,dc:creator,dc:date,upnp:class,res@size" ));
00533
00534 pRequest->FormatActionResponse( &list );
00535 }
00536
00538
00540
00541 void UPnpCDS::HandleGetSystemUpdateID( HTTPRequest *pRequest )
00542 {
00543 NameValueList list;
00544
00545 VERBOSE(VB_UPNP,QString("UPnpCDS::ProcessRequest : %1 : %2")
00546 .arg(pRequest->m_sBaseUrl)
00547 .arg(pRequest->m_sMethod));
00548
00549 unsigned short nId = GetValue< unsigned short >( "SystemUpdateID" );
00550
00551 list.append( new NameValue( "Id", QString::number( nId ) ));
00552
00553 pRequest->FormatActionResponse( &list );
00554 }
00555
00556
00557
00560
00561
00562
00565
00567
00569
00570 bool UPnpCDSExtension::IsBrowseRequestForUs( UPnpCDSRequest *pRequest )
00571 {
00572 if (!pRequest->m_sObjectId.startsWith( m_sExtensionId, true ))
00573 return false;
00574
00575 return true;
00576 }
00577
00579
00581
00582 UPnpCDSExtensionResults *UPnpCDSExtension::Browse( UPnpCDSRequest *pRequest )
00583 {
00584
00585
00586
00587 if (!IsBrowseRequestForUs( pRequest ))
00588 return( NULL );
00589
00590
00591
00592
00593
00594 QStringList idPath = QStringList::split( "/", pRequest->m_sObjectId.section('=',0,0) );
00595
00596 QString key = pRequest->m_sObjectId.section('=',1);
00597
00598 if (idPath.count() == 0)
00599 return( NULL );
00600
00601
00602
00603
00604
00605 UPnpCDSExtensionResults *pResults = new UPnpCDSExtensionResults();
00606
00607 if (pResults != NULL)
00608 {
00609
00610 if (key)
00611 idPath.last().append(QString("=%1").arg(key));
00612 else
00613 {
00614 if (pRequest->m_sObjectId.contains("item"))
00615 {
00616 idPath = QStringList::split( " ", idPath[idPath.count() - 2] );
00617 idPath = QStringList::split( "?", idPath[0] );
00618
00619 idPath = idPath[0];
00620
00621 if (idPath[0].startsWith("Id"))
00622 idPath[0] = QString("item=%1").arg(idPath[0].right(idPath[0].length() - 2));
00623 }
00624 }
00625
00626 QString sLast = idPath.last();
00627
00628 pRequest->m_sParentId = pRequest->m_sObjectId;
00629
00630 if (sLast == m_sExtensionId ) { return( ProcessRoot ( pRequest, pResults, idPath )); }
00631 if (sLast == "0" ) { return( ProcessAll ( pRequest, pResults, idPath )); }
00632 if (sLast.startsWith( "key" , true )) { return( ProcessKey ( pRequest, pResults, idPath )); }
00633 if (sLast.startsWith( "item", true )) { return( ProcessItem ( pRequest, pResults, idPath )); }
00634
00635 int nNodeIdx = sLast.toInt();
00636
00637 if ((nNodeIdx > 0) && (nNodeIdx < GetRootCount()))
00638 return( ProcessContainer( pRequest, pResults, nNodeIdx, idPath ));
00639
00640 pResults->m_eErrorCode = UPnPResult_CDS_NoSuchObject;
00641 pResults->m_sErrorDesc = "";
00642 }
00643
00644 return( pResults );
00645 }
00646
00648
00650
00651 bool UPnpCDSExtension::IsSearchRequestForUs( UPnpCDSRequest *pRequest )
00652 {
00653 if ( !m_sClass.startsWith( pRequest->m_sSearchClass ))
00654 return false;
00655
00656 return true;
00657 }
00658
00660
00662
00663 UPnpCDSExtensionResults *UPnpCDSExtension::Search( UPnpCDSRequest *pRequest )
00664 {
00665
00666
00667
00668 QStringList sEmptyList;
00669 VERBOSE(VB_UPNP, QString("UPnpCDSExtension::Search : m_sClass = %1 : m_sSearchClass = %2").arg(m_sClass).arg(pRequest->m_sSearchClass));
00670
00671 if ( !IsSearchRequestForUs( pRequest ))
00672 {
00673 VERBOSE( VB_UPNP, QString("UPnpCDSExtension::Search - Not For Us : m_sClass = %1 : m_sSearchClass = %2").arg(m_sClass).arg(pRequest->m_sSearchClass));
00674 return NULL;
00675 }
00676
00677 UPnpCDSExtensionResults *pResults = new UPnpCDSExtensionResults();
00678
00679 CreateItems( pRequest, pResults, 0, "", false );
00680
00681 return pResults;
00682 }
00683
00685
00687
00688 QString UPnpCDSExtension::RemoveToken( const QString &sToken, const QString &sStr, int num )
00689 {
00690 QString sResult( "" );
00691 int nPos = -1;
00692
00693 for (int nIdx=0; nIdx < num; nIdx++)
00694 {
00695 if ((nPos = sStr.findRev( sToken, nPos )) == -1)
00696 break;
00697 }
00698
00699 if (nPos > 0)
00700 sResult = sStr.left( nPos );
00701
00702 return sResult;
00703 }
00704
00706
00708
00709 UPnpCDSExtensionResults *UPnpCDSExtension::ProcessRoot( UPnpCDSRequest *pRequest,
00710 UPnpCDSExtensionResults *pResults,
00711 QStringList & )
00712 {
00713 pResults->m_nTotalMatches = 0;
00714 pResults->m_nUpdateID = 1;
00715
00716 short nRootCount = GetRootCount();
00717
00718 switch( pRequest->m_eBrowseFlag )
00719 {
00720 case CDS_BrowseMetadata:
00721 {
00722
00723
00724
00725
00726 pResults->m_nTotalMatches = 1;
00727 pResults->m_nUpdateID = 1;
00728
00729 CDSObject *pRoot = CreateContainer( m_sExtensionId, m_sName, "0");
00730
00731 pRoot->SetChildCount( nRootCount );
00732
00733 pResults->Add( pRoot );
00734
00735 break;
00736 }
00737
00738 case CDS_BrowseDirectChildren:
00739 {
00740 VERBOSE(VB_UPNP, "CDS_BrowseDirectChildren");
00741 pResults->m_nUpdateID = 1;
00742 pResults->m_nTotalMatches = nRootCount ;
00743
00744 if ( pRequest->m_nRequestedCount == 0)
00745 pRequest->m_nRequestedCount = nRootCount ;
00746
00747 short nStart = Max( pRequest->m_nStartingIndex, short( 0 ));
00748 short nEnd = Min( nRootCount, short( nStart + pRequest->m_nRequestedCount));
00749
00750 if (nStart < nRootCount)
00751 {
00752 for (short nIdx = nStart; nIdx < nEnd; nIdx++)
00753 {
00754 UPnpCDSRootInfo *pInfo = GetRootInfo( nIdx );
00755 if (pInfo != NULL)
00756 {
00757
00758 QString sId = QString( "%1/%2" ).arg( pRequest->m_sObjectId )
00759 .arg( nIdx );
00760
00761 CDSObject *pItem = CreateContainer( sId,
00762 QObject::tr( pInfo->title ),
00763 m_sExtensionId );
00764
00765 pItem->SetChildCount( GetDistinctCount( pInfo ) );
00766
00767 pResults->Add( pItem );
00768 }
00769 }
00770 }
00771 }
00772
00773 case CDS_BrowseUnknown:
00774 default:
00775 break;
00776 }
00777
00778 return pResults;
00779 }
00780
00781
00783
00785
00786 UPnpCDSExtensionResults *UPnpCDSExtension::ProcessAll ( UPnpCDSRequest *pRequest,
00787 UPnpCDSExtensionResults *pResults,
00788 QStringList & )
00789 {
00790 pResults->m_nTotalMatches = 0;
00791 pResults->m_nUpdateID = 1;
00792
00793
00794
00795
00796
00797 switch( pRequest->m_eBrowseFlag )
00798 {
00799 case CDS_BrowseMetadata:
00800 {
00801
00802
00803
00804
00805 UPnpCDSRootInfo *pInfo = GetRootInfo( 0 );
00806
00807 if (pInfo != NULL)
00808 {
00809 pResults->m_nTotalMatches = 1;
00810 pResults->m_nUpdateID = 1;
00811
00812 CDSObject *pItem = CreateContainer( pRequest->m_sObjectId,
00813 QObject::tr( pInfo->title ),
00814 m_sExtensionId );
00815
00816 pItem->SetChildCount( GetDistinctCount( pInfo ) );
00817
00818 pResults->Add( pItem );
00819 }
00820
00821 break;
00822 }
00823
00824 case CDS_BrowseDirectChildren:
00825 {
00826
00827 CreateItems( pRequest, pResults, 0, "", false );
00828
00829 break;
00830 }
00831
00832 case CDS_BrowseUnknown:
00833 default:
00834 break;
00835
00836 }
00837
00838
00839 return pResults;
00840 }
00841
00843
00845
00846 UPnpCDSExtensionResults *UPnpCDSExtension::ProcessItem( UPnpCDSRequest *pRequest,
00847 UPnpCDSExtensionResults *pResults,
00848 QStringList &idPath )
00849 {
00850 pResults->m_nTotalMatches = 0;
00851 pResults->m_nUpdateID = 1;
00852
00853
00854
00855
00856
00857 switch( pRequest->m_eBrowseFlag )
00858 {
00859 case CDS_BrowseMetadata:
00860 {
00861
00862
00863
00864
00865 QStringMap mapParams;
00866 QString sParams = idPath.last().section( '?', 1, 1 );
00867 sParams.replace(QRegExp( "&"), "&" );
00868
00869 HTTPRequest::GetParameters( sParams, mapParams );
00870
00871 MSqlQuery query(MSqlQuery::InitCon());
00872
00873 if (query.isConnected())
00874 {
00875 BuildItemQuery( query, mapParams );
00876
00877 query.exec();
00878
00879 if (query.isActive() && query.size() > 0)
00880 {
00881 if ( query.next() )
00882 {
00883 pRequest->m_sObjectId = RemoveToken( "/", pRequest->m_sObjectId, 1 );
00884
00885 AddItem( pRequest->m_sObjectId, pResults, false, query );
00886 pResults->m_nTotalMatches = 1;
00887 }
00888 }
00889 }
00890 break;
00891 }
00892 case CDS_BrowseDirectChildren:
00893 {
00894
00895 break;
00896 }
00897
00898 }
00899
00900 return pResults;
00901 }
00902
00904
00906
00907 UPnpCDSExtensionResults *UPnpCDSExtension::ProcessKey( UPnpCDSRequest *pRequest,
00908 UPnpCDSExtensionResults *pResults,
00909 QStringList &idPath )
00910 {
00911 pResults->m_nTotalMatches = 0;
00912 pResults->m_nUpdateID = 1;
00913
00914
00915
00916
00917
00918 QString sKey = idPath.last().section( '=', 1, 1 );
00919 QUrl::decode( sKey );
00920
00921 if (sKey.length() > 0)
00922 {
00923 int nNodeIdx = idPath[ idPath.count() - 2 ].toInt();
00924
00925 switch( pRequest->m_eBrowseFlag )
00926 {
00927
00928 case CDS_BrowseMetadata:
00929 {
00930 UPnpCDSRootInfo *pInfo = GetRootInfo( nNodeIdx );
00931
00932 if (pInfo == NULL)
00933 return pResults;
00934
00935 pRequest->m_sParentId = RemoveToken( "/", pRequest->m_sObjectId, 1 );
00936
00937
00938
00939
00940
00941 MSqlQuery query(MSqlQuery::InitCon());
00942
00943 if (query.isConnected())
00944 {
00945 QString sSQL = QString( pInfo->sql )
00946 .arg( pInfo->where );
00947
00948
00949
00950
00951
00952 query.prepare ( sSQL );
00953 query.bindValue( ":KEY", sKey );
00954 query.exec();
00955
00956 if (query.isActive() && query.size() > 0)
00957 {
00958 if ( query.next() )
00959 {
00960
00961
00962
00963
00964 pResults->m_nTotalMatches = 1;
00965 pResults->m_nUpdateID = 1;
00966
00967 CDSObject *pItem = CreateContainer( pRequest->m_sObjectId,
00968 query.value(1).toString(),
00969 pRequest->m_sParentId );
00970
00971 pItem->SetChildCount( GetDistinctCount( pInfo ));
00972
00973 pResults->Add( pItem );
00974 }
00975 }
00976 }
00977 break;
00978 }
00979
00980 case CDS_BrowseDirectChildren:
00981 {
00982
00983 CreateItems( pRequest, pResults, nNodeIdx, sKey, true );
00984
00985 break;
00986 }
00987
00988 case CDS_BrowseUnknown:
00989 default:
00990 break;
00991 }
00992 }
00993
00994 return pResults;
00995 }
00996
00998
01000
01001 UPnpCDSExtensionResults *UPnpCDSExtension::ProcessContainer( UPnpCDSRequest *pRequest,
01002 UPnpCDSExtensionResults *pResults,
01003 int nNodeIdx,
01004 QStringList & )
01005
01006 {
01007 pResults->m_nUpdateID = 1;
01008 pResults->m_nTotalMatches = 0;
01009
01010 UPnpCDSRootInfo *pInfo = GetRootInfo( nNodeIdx );
01011
01012 if (pInfo == NULL)
01013 return pResults;
01014
01015 switch( pRequest->m_eBrowseFlag )
01016 {
01017 case CDS_BrowseMetadata:
01018 {
01019
01020
01021
01022
01023 pResults->m_nTotalMatches = 1;
01024 pResults->m_nUpdateID = 1;
01025
01026 CDSObject *pItem = CreateContainer( pRequest->m_sObjectId,
01027 QObject::tr( pInfo->title ),
01028 m_sExtensionId );
01029
01030 pItem->SetChildCount( GetDistinctCount( pInfo ));
01031
01032 pResults->Add( pItem );
01033
01034 break;
01035 }
01036
01037 case CDS_BrowseDirectChildren:
01038 {
01039 pResults->m_nTotalMatches = GetDistinctCount( pInfo );
01040 pResults->m_nUpdateID = 1;
01041
01042 if (pRequest->m_nRequestedCount == 0)
01043 pRequest->m_nRequestedCount = SHRT_MAX;
01044
01045 MSqlQuery query(MSqlQuery::InitCon());
01046
01047 if (query.isConnected())
01048 {
01049
01050
01051 QString sSQL = pInfo->sql;
01052
01053 sSQL.replace( "%1", "" );
01054
01055 sSQL += QString( " LIMIT %2, %3" )
01056 .arg( pRequest->m_nStartingIndex )
01057 .arg( pRequest->m_nRequestedCount );
01058
01059 query.prepare( sSQL );
01060 query.exec();
01061
01062 if (query.isActive() && query.size() > 0)
01063 {
01064
01065 while(query.next())
01066 {
01067 QString sKey = query.value(0).toString();
01068 QString sTitle =
01069 QString::fromUtf8(query.value(1).toString());
01070 long nCount = query.value(2).toInt();
01071
01072 if (sTitle.length() == 0)
01073 sTitle = "(undefined)";
01074
01075 QString sId = QString( "%1/key=%2" )
01076 .arg( pRequest->m_sParentId )
01077 .arg( sKey );
01078
01079 CDSObject *pRoot = CreateContainer( sId, sTitle, pRequest->m_sParentId );
01080
01081 pRoot->SetChildCount( nCount );
01082
01083 pResults->Add( pRoot );
01084 }
01085 }
01086 }
01087
01088 break;
01089 }
01090
01091 case CDS_BrowseUnknown:
01092 break;
01093
01094 }
01095
01096 return pResults;
01097 }
01098
01100
01102
01103 int UPnpCDSExtension::GetDistinctCount( UPnpCDSRootInfo *pInfo )
01104 {
01105 int nCount = 0;
01106
01107 if ((pInfo == NULL) || (pInfo->column == NULL))
01108 return 0;
01109
01110 MSqlQuery query(MSqlQuery::InitCon());
01111
01112 if (query.isConnected())
01113 {
01114
01115
01116
01117 QString sSQL;
01118
01119 if (strncmp( pInfo->column, "*", 1) == 0)
01120 {
01121 sSQL = QString( "SELECT count( %1 ) FROM %2" )
01122 .arg( pInfo->column )
01123 .arg( GetTableName( pInfo->column ));
01124 }
01125 else
01126 {
01127 sSQL = QString( "SELECT count( DISTINCT %1 ) FROM %2" )
01128 .arg( pInfo->column )
01129 .arg( GetTableName( pInfo->column ) );
01130 }
01131
01132 query.prepare( sSQL );
01133 query.exec();
01134
01135 if (query.size() > 0)
01136 {
01137 query.next();
01138
01139 nCount = query.value(0).toInt();
01140 }
01141 }
01142
01143 return( nCount );
01144 }
01145
01147
01149
01150 int UPnpCDSExtension::GetCount( const QString &sColumn, const QString &sKey )
01151 {
01152 int nCount = 0;
01153
01154 MSqlQuery query(MSqlQuery::InitCon());
01155
01156 if (query.isConnected())
01157 {
01158
01159
01160
01161 QString sSQL;
01162
01163 if (sColumn == "*")
01164 sSQL = QString( "SELECT count( * ) FROM %1" ).arg( GetTableName( sColumn ) );
01165 else
01166 sSQL = QString( "SELECT count( %1 ) FROM %2 WHERE %3=:KEY" )
01167 .arg( sColumn )
01168 .arg( GetTableName( sColumn ) )
01169 .arg( sColumn );
01170
01171 query.prepare( sSQL );
01172 query.bindValue( ":KEY", sKey );
01173 query.exec();
01174
01175 if (query.size() > 0)
01176 {
01177 query.next();
01178
01179 nCount = query.value(0).toInt();
01180 }
01181
01182 }
01183
01184 return( nCount );
01185 }
01186
01188
01190
01191 void UPnpCDSExtension::CreateItems( UPnpCDSRequest *pRequest,
01192 UPnpCDSExtensionResults *pResults,
01193 int nNodeIdx,
01194 const QString &sKey,
01195 bool bAddRef )
01196 {
01197 pResults->m_nTotalMatches = 0;
01198 pResults->m_nUpdateID = 1;
01199
01200 UPnpCDSRootInfo *pInfo = GetRootInfo( nNodeIdx );
01201
01202 if (pInfo == NULL)
01203 return;
01204
01205 pResults->m_nTotalMatches = GetCount( pInfo->column, sKey );
01206 pResults->m_nUpdateID = 1;
01207
01208 if (pRequest->m_nRequestedCount == 0)
01209 pRequest->m_nRequestedCount = SHRT_MAX;
01210
01211 MSqlQuery query(MSqlQuery::InitCon());
01212
01213 if (query.isConnected())
01214 {
01215 QString sWhere( "" );
01216
01217 if ( sKey.length() > 0)
01218 {
01219 sWhere = QString( "WHERE %1=:KEY " )
01220 .arg( pInfo->column );
01221 }
01222
01223 QString sSQL = QString( "%1 %2 LIMIT %3, %4" )
01224 .arg( GetItemListSQL( pInfo->column ) )
01225 .arg( sWhere )
01226 .arg( pRequest->m_nStartingIndex )
01227 .arg( pRequest->m_nRequestedCount );
01228
01229 query.prepare ( sSQL );
01230 query.bindValue(":KEY", sKey );
01231 query.exec();
01232
01233 if (query.isActive() && query.size() > 0)
01234 {
01235 while(query.next())
01236 AddItem( pRequest->m_sObjectId, pResults, bAddRef, query );
01237
01238 }
01239 }
01240 }