1/*
2 This file is part of the Cagibi daemon.
3
4 Copyright 2010-2011 Friedrich W. H. Kossebau <kossebau@kde.org>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of
9 the License or (at your option) version 3 or any later version
10 accepted by the membership of KDE e.V. (or its successor approved
11 by the membership of KDE e.V.), which shall act as a proxy
12 defined in Section 14 of version 3 of the license.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "devicelist.h"
24
25// program
26#include "ssdpwatcher.h"
27#include "rootdevice.h"
28#include "device.h"
29// Qt
30#include <QtCore/QTimer>
31
32
33namespace Cagibi
34{
35
36static void fillMap( DeviceTypeMap& map, const Device& device )
37{
38 map.insert( device.udn(), device.type() );
39 foreach( const Cagibi::Device& subDevice, device.devices() )
40 fillMap( map, subDevice );
41}
42
43static void fillMapByType( DeviceTypeMap& map, const Device& device,
44 const QString& type )
45{
46 const QString deviceType = device.type();
47
48 if( deviceType == type )
49 map.insert( device.udn(), deviceType );
50
51 foreach( const Cagibi::Device& subDevice, device.devices() )
52 fillMapByType( map, subDevice, type );
53}
54
55static const Device* find( const Device& device, const QString& udn )
56{
57 const Device* result = 0;
58
59 if( device.udn() == udn )
60 result = &device;
61 else
62 {
63 foreach( const Cagibi::Device& subDevice, device.devices() )
64 {
65 result = find( subDevice, udn );
66 if( result )
67 break;
68 }
69 }
70
71 return result;
72}
73
74
75DeviceList::DeviceList( int searchTimeout, int inactivityTimeout )
76 : QObject(),
77 mSsdpWatcher( new SSDPWatcher(this) ),
78 mShutDownTimeout( inactivityTimeout )
79{
80 // setup timer to shutdown on no UPnP activity
81 mShutDownTimer = new QTimer( this );
82 mShutDownTimer->setInterval( mShutDownTimeout * 1000 ); // in msec
83 mShutDownTimer->setSingleShot( true );
84 connect( mShutDownTimer, SIGNAL(timeout()),
85 this, SIGNAL(gotInactiv()) );
86
87 // install listener to UPnP changes
88 connect( mSsdpWatcher, SIGNAL(deviceDiscovered(Cagibi::RootDevice*)),
89 SLOT(onDeviceDiscovered(Cagibi::RootDevice*)) );
90 connect( mSsdpWatcher, SIGNAL(deviceRemoved(Cagibi::RootDevice*)),
91 SLOT(onDeviceRemoved(Cagibi::RootDevice*)) );
92 connect( mSsdpWatcher, SIGNAL(initialSearchCompleted()),
93 SLOT(onInitialSearchCompleted()) );
94
95 mSsdpWatcher->startDiscover( searchTimeout );
96}
97
98DeviceTypeMap DeviceList::allDevices() const
99{
100 DeviceTypeMap result;
101
102 const QList<RootDevice*> rootDevices = mSsdpWatcher->devices();
103
104 foreach( RootDevice* rootDevice, rootDevices )
105 {
106 const Device device = rootDevice->device();
107 fillMap( result, device );
108 }
109
110 // being used, so reset the shutdown timer if active
111 if( mShutDownTimer->isActive() )
112 mShutDownTimer->start();
113
114 return result;
115}
116
117DeviceTypeMap DeviceList::devicesByParent( const QString& udn ) const
118{
119 DeviceTypeMap result;
120
121 const QList<RootDevice*> rootDevices = mSsdpWatcher->devices();
122
123 foreach( RootDevice* rootDevice, rootDevices )
124 {
125 const Device device = rootDevice->device();
126
127 if( udn.isEmpty() )
128 result.insert( device.udn(), device.type() );
129 else
130 {
131 const Device* match = find( device, udn );
132 if( match )
133 {
134 foreach( const Cagibi::Device& subDevice, device.devices() )
135 result.insert( subDevice.udn(), subDevice.type() );
136 break;
137 }
138 }
139 }
140
141 // being used, so reset the shutdown timer if active
142 if( mShutDownTimer->isActive() )
143 mShutDownTimer->start();
144
145 return result;
146}
147
148DeviceTypeMap DeviceList::devicesByType( const QString& type ) const
149{
150 DeviceTypeMap result;
151
152 const QList<RootDevice*> rootDevices = mSsdpWatcher->devices();
153
154 foreach( RootDevice* rootDevice, rootDevices )
155 {
156 const Device device = rootDevice->device();
157 fillMapByType( result, device, type );
158 }
159
160 return result;
161}
162
163Device DeviceList::deviceDetails( const QString& udn ) const
164{
165 Device result;
166
167 const QList<RootDevice*> rootDevices = mSsdpWatcher->devices();
168
169 foreach( RootDevice* rootDevice, rootDevices )
170 {
171 const Device device = rootDevice->device();
172
173 const Device* match = find( device, udn );
174 if( match )
175 {
176 result = *match;
177 break;
178 }
179 }
180
181 return result;
182}
183
184void DeviceList::onInitialSearchCompleted()
185{
186 if( shutsDownOnNoActivity() && mSsdpWatcher->devicesCount() == 0 )
187 mShutDownTimer->start();
188}
189
190void DeviceList::onDeviceDiscovered( RootDevice* rootDevice )
191{
192 DeviceTypeMap devices;
193
194 const Device device = rootDevice->device();
195 fillMap( devices, device );
196
197 mShutDownTimer->stop();
198
199 emit devicesAdded( devices );
200}
201
202void DeviceList::onDeviceRemoved( RootDevice* rootDevice )
203{
204 DeviceTypeMap devices;
205
206 const Device device = rootDevice->device();
207 fillMap( devices, device );
208
209 if( shutsDownOnNoActivity() && mSsdpWatcher->devicesCount() == 0 )
210 mShutDownTimer->start();
211
212 emit devicesRemoved( devices );
213}
214
215DeviceList::~DeviceList()
216{
217 // simulate that all devices are removed
218 const QList<RootDevice*> rootDevices = mSsdpWatcher->devices();
219 foreach( RootDevice* rootDevice, rootDevices )
220 onDeviceRemoved( rootDevice );
221}
222
223}
224