3 /// Class which detects a set of available or known devices
4 /// in an opensync-able system.
8 Copyright (C) 2009-2012, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "deviceset.h"
24 #include <barry/barry.h>
32 //////////////////////////////////////////////////////////////////////////////
35 DeviceExtras::DeviceExtras(const Barry::Pin
&pin
)
38 , m_sync_types(PST_NONE
)
42 DeviceExtras::DeviceExtras(const Barry::Pin
& pin
,
43 const Barry::GlobalConfigFile
&config
,
44 const std::string
&group_name
)
48 Load(config
, group_name
);
51 std::string
DeviceExtras::MakeBaseKey(const std::string
&group_name
)
54 oss
<< m_pin
.Str() << "-" << group_name
<< "-";
58 void DeviceExtras::Load(const Barry::GlobalConfigFile
&config
,
59 const std::string
&group_name
)
61 string key
= MakeBaseKey(group_name
);
62 m_favour_plugin_name
= config
.GetKey(key
+ "FavourPlugin");
64 string num
= config
.GetKey(key
+ "LastSyncTime");
65 m_last_sync_time
= atol(num
.c_str());
67 using OpenSync::Config::PSTString2Type
;
68 using OpenSync::Config::PSTType2String
;
69 string stypes
= config
.GetKey(key
+ "SyncTypes",
70 PSTType2String(PST_ALL
));
71 m_sync_types
= PSTString2Type(stypes
);
74 void DeviceExtras::Save(Barry::GlobalConfigFile
&config
,
75 const std::string
&group_name
)
77 string key
= MakeBaseKey(group_name
);
78 config
.SetKey(key
+ "FavourPlugin", m_favour_plugin_name
);
81 oss
<< m_last_sync_time
;
82 config
.SetKey(key
+ "LastSyncTime", oss
.str());
84 config
.SetKey(key
+ "SyncTypes",
85 OpenSync::Config::PSTType2String(m_sync_types
));
89 //////////////////////////////////////////////////////////////////////////////
92 DeviceEntry::DeviceEntry(const Barry::GlobalConfigFile
&config
,
93 const Barry::ProbeResult
*result
,
95 OpenSync::API
*engine
,
96 const std::string
&secondary_device_name
)
100 , m_device_name(secondary_device_name
)
102 // just make sure that our device name has something in it
103 if( !m_device_name
.size() && m_result
)
104 m_device_name
= m_result
->m_cfgDeviceName
;
106 // load the extras if available
107 Barry::Pin pin
= GetPin();
108 if( pin
.Valid() && IsConfigured() ) {
109 m_extras
.reset( new DeviceExtras(pin
, config
,
110 m_group
->GetGroupName()) );
114 // returns pointer to the Barry plugin object in m_group
115 // or 0 if not available
116 OpenSync::Config::Barry
* DeviceEntry::FindBarry()
118 if( m_group
.get() && m_group
->HasBarryPlugins() )
119 return &m_group
->GetBarryPlugin();
123 Barry::Pin
DeviceEntry::GetPin() const
127 // load convenience values
129 pin
= m_result
->m_pin
;
132 if( m_group
.get() && m_group
->HasBarryPlugins() ) {
133 const OpenSync::Config::Barry
&bp
= m_group
->GetBarryPlugin();
135 if( bp
.GetPin().Valid() ) {
136 // double check for possible conflicting pin numbers
138 if( pin
!= bp
.GetPin() ) {
139 throw std::logic_error("Probe pin != group pin in DeviceEntry");
143 // got a valid pin, save it
151 std::string
DeviceEntry::GetDeviceName() const
153 if( m_device_name
.size() )
154 return m_device_name
;
156 return m_result
->m_cfgDeviceName
;
158 return std::string();
161 std::string
DeviceEntry::GetIdentifyingString() const
165 oss
<< GetPin().Str();
166 string name
= GetDeviceName();
168 oss
<< " (" << name
<< ")";
171 oss
<< ", Group: " << GetConfigGroup()->GetGroupName();
173 oss
<< ", Not configured";
176 oss
<< ", Engine: " << GetEngine()->GetVersion();
181 void DeviceEntry::SetConfigGroup(group_ptr group
,
182 OpenSync::API
*engine
,
190 std::ostream
& operator<< (std::ostream
&os
, const DeviceEntry
&de
)
192 os
<< setfill(' ') << setw(8) << de
.GetPin().Str();
193 os
<< "|" << setfill(' ') << setw(35) << de
.GetDeviceName();
194 os
<< "|" << setfill(' ') << setw(4) << (de
.IsConnected() ? "yes" : "no");
195 os
<< "|" << setfill(' ') << setw(4) << (de
.IsConfigured() ? "yes" : "no");
196 os
<< "|" << setfill(' ') << setw(7)
197 << (de
.GetEngine() ? de
.GetEngine()->GetVersion() : "");
201 //////////////////////////////////////////////////////////////////////////////
204 /// Does a USB probe automatically
205 DeviceSet::DeviceSet(const Barry::GlobalConfigFile
&config
,
206 OpenSync::APISet
&apiset
)
211 m_results
= probe
.GetResults();
215 /// Skips the USB probe and uses the results set given
216 DeviceSet::DeviceSet(const Barry::GlobalConfigFile
&config
,
217 OpenSync::APISet
&apiset
,
218 const Barry::Probe::Results
&results
)
226 void DeviceSet::LoadSet()
228 if( m_apiset
.os40() )
229 LoadConfigured(*m_apiset
.os40());
230 if( m_apiset
.os22() )
231 LoadConfigured(*m_apiset
.os22());
236 /// Constructor helper function. Adds configured DeviceEntry's to the set.
238 void DeviceSet::LoadConfigured(OpenSync::API
&api
)
240 using namespace OpenSync
;
243 // we already have the connected devices in m_results, so
244 // load every Barry-related group that exists in the given API
248 string_list_type groups
;
249 api
.GetGroupNames(groups
);
252 for( string_list_type::iterator b
= groups
.begin(); b
!= groups
.end(); ++b
) {
254 // load the group via Config::Group
255 DeviceEntry::group_ptr
g( new Config::Group(*b
, api
,
256 OSCG_THROW_ON_UNSUPPORTED
|
257 OSCG_THROW_ON_NO_BARRY
|
258 OSCG_THROW_ON_MULTIPLE_BARRIES
) );
260 // now that we have a config group, check to see
261 // if the pin in the group's Barry plugin is
262 // available in the probe results... if so, it is
264 OpenSync::Config::Barry
&plugin
= g
->GetBarryPlugin();
265 Barry::Probe::Results::iterator result
=
266 std::find(m_results
.begin(), m_results
.end(),
268 const Barry::ProbeResult
*connected
= 0;
270 if( result
!= m_results
.end() ) {
271 connected
= &(*result
);
272 dev_name
= connected
->m_cfgDeviceName
;
275 // the device is not connected, so do a
276 // special load of a possible device config
277 // to load the device name
278 Barry::ConfigFile
cf(plugin
.GetPin());
279 dev_name
= cf
.GetDeviceName();
282 // if no LoadError exceptions, add to configured list
283 push_back( DeviceEntry(m_config
, connected
, g
, &api
,
287 catch( Config::LoadError
&le
) {
288 // if we catch LoadError, it just means that this
289 // isn't a config that Barry Desktop can handle
290 // so just log and skip it
291 barryverbose("DeviceSet::LoadConfigured: " << le
.what());
296 void DeviceSet::LoadUnconfigured()
298 // cycle through the probe results, and add any devices for
299 // which their pins do not yet exist in the list
300 for( Barry::Probe::Results::const_iterator i
= m_results
.begin();
301 i
!= m_results
.end();
304 iterator p
= FindPin(i
->m_pin
);
306 // this pin isn't in the list yet, so add it
307 // as an unconfigured item
309 // create the DeviceEntry with a null group_ptr
310 DeviceEntry
item( m_config
, &(*i
),
311 DeviceEntry::group_ptr(), 0 );
317 /// Constructor helper function. Loads the device list. Sort by
318 /// pin number, but in the following groups:
320 /// - configured first (both connected and unconnected)
321 /// - unconfigured but connected second
323 /// This should preserve the sort order across multiple loads, to keep
324 /// a relatively consistent listing for the user.
327 bool DeviceEntryCompare(const DeviceEntry
&a
, const DeviceEntry
&b
)
329 if( a
.IsConfigured() == b
.IsConfigured() )
330 return strcmp(a
.GetPin().Str().c_str(),
331 b
.GetPin().Str().c_str()) < 0;
333 return a
.IsConfigured();
336 void DeviceSet::Sort()
338 std::sort(begin(), end(), &DeviceEntryCompare
);
341 DeviceSet::iterator
DeviceSet::FindPin(const Barry::Pin
&pin
)
343 for( iterator i
= begin(); i
!= end(); ++i
) {
344 if( i
->GetPin() == pin
)
350 DeviceSet::const_iterator
DeviceSet::FindPin(const Barry::Pin
&pin
) const
352 for( const_iterator i
= begin(); i
!= end(); ++i
) {
353 if( i
->GetPin() == pin
)
359 DeviceSet::subset_type::const_iterator
DeviceSet::FindPin(
360 const DeviceSet::subset_type
&subset
, const Barry::Pin
&pin
)
362 for( subset_type::const_iterator i
= subset
.begin();
366 if( (*i
)->GetPin() == pin
)
372 std::string
DeviceSet::Subset2String(const DeviceSet::subset_type
&set
)
376 subset_type::const_iterator i
= set
.begin();
377 for( ; i
!= set
.end(); ++i
) {
380 list
+= (*i
)->GetPin().Str();
385 DeviceSet::subset_type
DeviceSet::String2Subset(const std::string
&list
)
389 istringstream
iss(list
);
392 while( iss
>> pin
) {
396 // search for pin in device set
397 iterator i
= FindPin(pin
);
404 DeviceSet::subset_type
DeviceSet::FindDuplicates()
408 for( iterator i
= begin(); i
!= end(); ++i
) {
410 // start with this PIN
413 // search for a duplicate, and add all dups found
414 for( iterator j
= begin(); j
!= end(); ++j
) {
419 if( i
->GetPin() == j
->GetPin() ) {
425 // if we have multiple iterators in dups, we're done
426 if( dups
.size() > 1 )
436 void DeviceSet::KillDuplicates(const subset_type
&dups
)
439 if( dups
.size() == 0 )
443 if( dups
.size() == 1 ) {
448 // ok, we have multiple dups to erase, so we need to make
449 // a copy of ourselves and skip all matching iterators,
450 // then copy the result back to this
452 for( iterator i
= begin(); i
!= end(); ++i
) {
453 if( find(dups
.begin(), dups
.end(), i
) == dups
.end() ) {
454 // not in the dups list, copy it
461 base_type::operator=(copy
);
464 std::ostream
& operator<< (std::ostream
&os
, const DeviceSet
&ds
)
466 os
<< " PIN | Device Name |Con |Cfg |Engine\n";
467 os
<< "--------+-----------------------------------+----+----+-------\n";
469 for( DeviceSet::const_iterator i
= ds
.begin(); i
!= ds
.end(); ++i
)
470 os
<< *i
<< "\n" << i
->GetIdentifyingString() << endl
;