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>
33 //////////////////////////////////////////////////////////////////////////////
36 DeviceExtras::DeviceExtras(const Barry::Pin
&pin
)
39 , m_sync_types(PST_NONE
)
43 DeviceExtras::DeviceExtras(const Barry::Pin
& pin
,
44 const Barry::GlobalConfigFile
&config
,
45 const std::string
&group_name
)
49 Load(config
, group_name
);
52 std::string
DeviceExtras::MakeBaseKey(const std::string
&group_name
)
55 oss
<< m_pin
.Str() << "-" << group_name
<< "-";
59 void DeviceExtras::Load(const Barry::GlobalConfigFile
&config
,
60 const std::string
&group_name
)
62 string key
= MakeBaseKey(group_name
);
63 m_favour_plugin_name
= config
.GetKey(key
+ "FavourPlugin");
65 string num
= config
.GetKey(key
+ "LastSyncTime");
66 m_last_sync_time
= atol(num
.c_str());
68 using OpenSync::Config::PSTString2Type
;
69 using OpenSync::Config::PSTType2String
;
70 string stypes
= config
.GetKey(key
+ "SyncTypes",
71 PSTType2String(PST_ALL
));
72 m_sync_types
= PSTString2Type(stypes
);
75 void DeviceExtras::Save(Barry::GlobalConfigFile
&config
,
76 const std::string
&group_name
)
78 string key
= MakeBaseKey(group_name
);
79 config
.SetKey(key
+ "FavourPlugin", m_favour_plugin_name
);
82 oss
<< m_last_sync_time
;
83 config
.SetKey(key
+ "LastSyncTime", oss
.str());
85 config
.SetKey(key
+ "SyncTypes",
86 OpenSync::Config::PSTType2String(m_sync_types
));
90 //////////////////////////////////////////////////////////////////////////////
93 DeviceEntry::DeviceEntry(const Barry::GlobalConfigFile
&config
,
94 const Barry::ProbeResult
*result
,
96 OpenSync::API
*engine
,
97 const std::string
&secondary_device_name
)
101 , m_device_name(secondary_device_name
)
103 // just make sure that our device name has something in it
104 if( !m_device_name
.size() && m_result
)
105 m_device_name
= m_result
->m_cfgDeviceName
;
107 // load the extras if available
108 Barry::Pin pin
= GetPin();
109 if( pin
.Valid() && IsConfigured() ) {
110 m_extras
.reset( new DeviceExtras(pin
, config
,
111 m_group
->GetGroupName()) );
115 // returns pointer to the Barry plugin object in m_group
116 // or 0 if not available
117 OpenSync::Config::Barry
* DeviceEntry::FindBarry()
119 if( m_group
.get() && m_group
->HasBarryPlugins() )
120 return &m_group
->GetBarryPlugin();
124 Barry::Pin
DeviceEntry::GetPin() const
128 // load convenience values
130 pin
= m_result
->m_pin
;
133 if( m_group
.get() && m_group
->HasBarryPlugins() ) {
134 const OpenSync::Config::Barry
&bp
= m_group
->GetBarryPlugin();
136 if( bp
.GetPin().Valid() ) {
137 // double check for possible conflicting pin numbers
139 if( pin
!= bp
.GetPin() ) {
140 throw std::logic_error("Probe pin != group pin in DeviceEntry");
144 // got a valid pin, save it
152 std::string
DeviceEntry::GetDeviceName() const
154 if( m_device_name
.size() )
155 return m_device_name
;
157 return m_result
->m_cfgDeviceName
;
159 return std::string();
162 std::string
DeviceEntry::GetIdentifyingString() const
166 oss
<< GetPin().Str();
167 string name
= GetDeviceName();
169 oss
<< " (" << name
<< ")";
172 oss
<< ", Group: " << GetConfigGroup()->GetGroupName();
174 oss
<< ", Not configured";
177 oss
<< ", Engine: " << GetEngine()->GetVersion();
182 void DeviceEntry::SetConfigGroup(group_ptr group
,
183 OpenSync::API
*engine
,
191 std::ostream
& operator<< (std::ostream
&os
, const DeviceEntry
&de
)
193 os
<< setfill(' ') << setw(8) << de
.GetPin().Str();
194 os
<< "|" << setfill(' ') << setw(35) << de
.GetDeviceName();
195 os
<< "|" << setfill(' ') << setw(4) << (de
.IsConnected() ? _C("yes") : _C("no"));
196 os
<< "|" << setfill(' ') << setw(4) << (de
.IsConfigured() ? _C("yes") : _C("no"));
197 os
<< "|" << setfill(' ') << setw(7)
198 << (de
.GetEngine() ? de
.GetEngine()->GetVersion() : "");
202 //////////////////////////////////////////////////////////////////////////////
205 /// Does a USB probe automatically
206 DeviceSet::DeviceSet(const Barry::GlobalConfigFile
&config
,
207 OpenSync::APISet
&apiset
)
212 m_results
= probe
.GetResults();
216 /// Skips the USB probe and uses the results set given
217 DeviceSet::DeviceSet(const Barry::GlobalConfigFile
&config
,
218 OpenSync::APISet
&apiset
,
219 const Barry::Probe::Results
&results
)
227 void DeviceSet::LoadSet()
229 if( m_apiset
.os40() )
230 LoadConfigured(*m_apiset
.os40());
231 if( m_apiset
.os22() )
232 LoadConfigured(*m_apiset
.os22());
237 /// Constructor helper function. Adds configured DeviceEntry's to the set.
239 void DeviceSet::LoadConfigured(OpenSync::API
&api
)
241 using namespace OpenSync
;
244 // we already have the connected devices in m_results, so
245 // load every Barry-related group that exists in the given API
249 string_list_type groups
;
250 api
.GetGroupNames(groups
);
253 for( string_list_type::iterator b
= groups
.begin(); b
!= groups
.end(); ++b
) {
255 // load the group via Config::Group
256 DeviceEntry::group_ptr
g( new Config::Group(*b
, api
,
257 OSCG_THROW_ON_UNSUPPORTED
|
258 OSCG_THROW_ON_NO_BARRY
|
259 OSCG_THROW_ON_MULTIPLE_BARRIES
) );
261 // now that we have a config group, check to see
262 // if the pin in the group's Barry plugin is
263 // available in the probe results... if so, it is
265 OpenSync::Config::Barry
&plugin
= g
->GetBarryPlugin();
266 Barry::Probe::Results::iterator result
=
267 std::find(m_results
.begin(), m_results
.end(),
269 const Barry::ProbeResult
*connected
= 0;
271 if( result
!= m_results
.end() ) {
272 connected
= &(*result
);
273 dev_name
= connected
->m_cfgDeviceName
;
276 // the device is not connected, so do a
277 // special load of a possible device config
278 // to load the device name
279 Barry::ConfigFile
cf(plugin
.GetPin());
280 dev_name
= cf
.GetDeviceName();
283 // if no LoadError exceptions, add to configured list
284 push_back( DeviceEntry(m_config
, connected
, g
, &api
,
288 catch( Config::LoadError
&le
) {
289 // if we catch LoadError, it just means that this
290 // isn't a config that Barry Desktop can handle
291 // so just log and skip it
292 barryverbose("DeviceSet::LoadConfigured: " << le
.what());
297 void DeviceSet::LoadUnconfigured()
299 // cycle through the probe results, and add any devices for
300 // which their pins do not yet exist in the list
301 for( Barry::Probe::Results::const_iterator i
= m_results
.begin();
302 i
!= m_results
.end();
305 iterator p
= FindPin(i
->m_pin
);
307 // this pin isn't in the list yet, so add it
308 // as an unconfigured item
310 // create the DeviceEntry with a null group_ptr
311 DeviceEntry
item( m_config
, &(*i
),
312 DeviceEntry::group_ptr(), 0 );
318 /// Constructor helper function. Loads the device list. Sort by
319 /// pin number, but in the following groups:
321 /// - configured first (both connected and unconnected)
322 /// - unconfigured but connected second
324 /// This should preserve the sort order across multiple loads, to keep
325 /// a relatively consistent listing for the user.
328 bool DeviceEntryCompare(const DeviceEntry
&a
, const DeviceEntry
&b
)
330 if( a
.IsConfigured() == b
.IsConfigured() )
331 return strcmp(a
.GetPin().Str().c_str(),
332 b
.GetPin().Str().c_str()) < 0;
334 return a
.IsConfigured();
337 void DeviceSet::Sort()
339 std::sort(begin(), end(), &DeviceEntryCompare
);
342 DeviceSet::iterator
DeviceSet::FindPin(const Barry::Pin
&pin
)
344 for( iterator i
= begin(); i
!= end(); ++i
) {
345 if( i
->GetPin() == pin
)
351 DeviceSet::const_iterator
DeviceSet::FindPin(const Barry::Pin
&pin
) const
353 for( const_iterator i
= begin(); i
!= end(); ++i
) {
354 if( i
->GetPin() == pin
)
360 DeviceSet::subset_type::const_iterator
DeviceSet::FindPin(
361 const DeviceSet::subset_type
&subset
, const Barry::Pin
&pin
)
363 for( subset_type::const_iterator i
= subset
.begin();
367 if( (*i
)->GetPin() == pin
)
373 std::string
DeviceSet::Subset2String(const DeviceSet::subset_type
&set
)
377 subset_type::const_iterator i
= set
.begin();
378 for( ; i
!= set
.end(); ++i
) {
381 list
+= (*i
)->GetPin().Str();
386 DeviceSet::subset_type
DeviceSet::String2Subset(const std::string
&list
)
390 istringstream
iss(list
);
393 while( iss
>> pin
) {
397 // search for pin in device set
398 iterator i
= FindPin(pin
);
405 DeviceSet::subset_type
DeviceSet::FindDuplicates()
409 for( iterator i
= begin(); i
!= end(); ++i
) {
411 // start with this PIN
414 // search for a duplicate, and add all dups found
415 for( iterator j
= begin(); j
!= end(); ++j
) {
420 if( i
->GetPin() == j
->GetPin() ) {
426 // if we have multiple iterators in dups, we're done
427 if( dups
.size() > 1 )
437 void DeviceSet::KillDuplicates(const subset_type
&dups
)
440 if( dups
.size() == 0 )
444 if( dups
.size() == 1 ) {
449 // ok, we have multiple dups to erase, so we need to make
450 // a copy of ourselves and skip all matching iterators,
451 // then copy the result back to this
453 for( iterator i
= begin(); i
!= end(); ++i
) {
454 if( find(dups
.begin(), dups
.end(), i
) == dups
.end() ) {
455 // not in the dups list, copy it
462 base_type::operator=(copy
);
465 std::ostream
& operator<< (std::ostream
&os
, const DeviceSet
&ds
)
467 os
<< " PIN | Device Name |Con |Cfg |Engine\n";
468 os
<< "--------+-----------------------------------+----+----+-------\n";
470 for( DeviceSet::const_iterator i
= ds
.begin(); i
!= ds
.end(); ++i
)
471 os
<< *i
<< "\n" << i
->GetIdentifyingString() << endl
;