Barry debian version 0.18.5-1
[barry.git] / desktop / src / deviceset.cc
blob396ab0e3efb592266ec0bced2ecbac183d44e154
1 ///
2 /// \file deviceset.cc
3 /// Class which detects a set of available or known devices
4 /// in an opensync-able system.
5 ///
7 /*
8 Copyright (C) 2009-2013, 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>
25 #include <string.h>
26 #include <algorithm>
27 #include <iostream>
28 #include <iomanip>
29 #include "i18n.h"
31 using namespace std;
33 //////////////////////////////////////////////////////////////////////////////
34 // DeviceExtras class
36 DeviceExtras::DeviceExtras(const Barry::Pin &pin)
37 : m_pin(pin)
38 , m_last_sync_time(0)
39 , m_sync_types(PST_NONE)
43 DeviceExtras::DeviceExtras(const Barry::Pin & pin,
44 const Barry::GlobalConfigFile &config,
45 const std::string &group_name)
46 : m_pin(pin)
47 , m_last_sync_time(0)
49 Load(config, group_name);
52 std::string DeviceExtras::MakeBaseKey(const std::string &group_name)
54 ostringstream oss;
55 oss << m_pin.Str() << "-" << group_name << "-";
56 return oss.str();
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);
81 ostringstream oss;
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 //////////////////////////////////////////////////////////////////////////////
91 // DeviceEntry class
93 DeviceEntry::DeviceEntry(const Barry::GlobalConfigFile &config,
94 const Barry::ProbeResult *result,
95 group_ptr group,
96 OpenSync::API *engine,
97 const std::string &secondary_device_name)
98 : m_result(result)
99 , m_group(group)
100 , m_engine(engine)
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();
121 return 0;
124 Barry::Pin DeviceEntry::GetPin() const
126 Barry::Pin pin;
128 // load convenience values
129 if( m_result ) {
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
138 if( pin.Valid() ) {
139 if( pin != bp.GetPin() ) {
140 throw std::logic_error("Probe pin != group pin in DeviceEntry");
144 // got a valid pin, save it
145 pin = bp.GetPin();
149 return pin;
152 std::string DeviceEntry::GetDeviceName() const
154 if( m_device_name.size() )
155 return m_device_name;
156 else if( m_result )
157 return m_result->m_cfgDeviceName;
158 else
159 return std::string();
162 std::string DeviceEntry::GetIdentifyingString() const
164 ostringstream oss;
166 oss << GetPin().Str();
167 string name = GetDeviceName();
168 if( name.size() )
169 oss << " (" << name << ")";
171 if( IsConfigured() )
172 oss << ", Group: " << GetConfigGroup()->GetGroupName();
173 else
174 oss << ", Not configured";
176 if( GetEngine() )
177 oss << ", Engine: " << GetEngine()->GetVersion();
179 return oss.str();
182 void DeviceEntry::SetConfigGroup(group_ptr group,
183 OpenSync::API *engine,
184 extras_ptr extras)
186 m_group = group;
187 m_engine = engine;
188 m_extras = extras;
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() : "");
199 return os;
202 //////////////////////////////////////////////////////////////////////////////
203 // DeviceSet class
205 /// Does a USB probe automatically
206 DeviceSet::DeviceSet(const Barry::GlobalConfigFile &config,
207 OpenSync::APISet &apiset)
208 : m_config(config)
209 , m_apiset(apiset)
211 Barry::Probe probe;
212 m_results = probe.GetResults();
213 LoadSet();
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)
220 : m_config(config)
221 , m_apiset(apiset)
222 , m_results(results)
224 LoadSet();
227 void DeviceSet::LoadSet()
229 if( m_apiset.os40() )
230 LoadConfigured(*m_apiset.os40());
231 if( m_apiset.os22() )
232 LoadConfigured(*m_apiset.os22());
233 LoadUnconfigured();
234 Sort();
237 /// Constructor helper function. Adds configured DeviceEntry's to the set.
238 /// Does no sorting.
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
248 // get group list
249 string_list_type groups;
250 api.GetGroupNames(groups);
252 // for each group
253 for( string_list_type::iterator b = groups.begin(); b != groups.end(); ++b ) {
254 try {
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
264 // also connected
265 OpenSync::Config::Barry &plugin = g->GetBarryPlugin();
266 Barry::Probe::Results::iterator result =
267 std::find(m_results.begin(), m_results.end(),
268 plugin.GetPin());
269 const Barry::ProbeResult *connected = 0;
270 string dev_name;
271 if( result != m_results.end() ) {
272 connected = &(*result);
273 dev_name = connected->m_cfgDeviceName;
275 else {
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,
285 dev_name) );
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();
303 ++i )
305 iterator p = FindPin(i->m_pin);
306 if( p == end() ) {
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 );
313 push_back( item );
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.
327 namespace {
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;
333 else
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 )
346 return i;
348 return end();
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 )
355 return i;
357 return end();
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();
364 i != subset.end();
365 ++i )
367 if( (*i)->GetPin() == pin )
368 return i;
370 return subset.end();
373 std::string DeviceSet::Subset2String(const DeviceSet::subset_type &set)
375 std::string list;
377 subset_type::const_iterator i = set.begin();
378 for( ; i != set.end(); ++i ) {
379 if( list.size() )
380 list += " ";
381 list += (*i)->GetPin().Str();
383 return list;
386 DeviceSet::subset_type DeviceSet::String2Subset(const std::string &list)
388 subset_type set;
390 istringstream iss(list);
391 Barry::Pin pin;
393 while( iss >> pin ) {
394 if( !pin.Valid() )
395 continue;
397 // search for pin in device set
398 iterator i = FindPin(pin);
399 if( i != end() )
400 set.push_back(i);
402 return set;
405 DeviceSet::subset_type DeviceSet::FindDuplicates()
407 subset_type dups;
409 for( iterator i = begin(); i != end(); ++i ) {
411 // start with this PIN
412 dups.push_back(i);
414 // search for a duplicate, and add all dups found
415 for( iterator j = begin(); j != end(); ++j ) {
416 // skip ourselves
417 if( j == i )
418 continue;
420 if( i->GetPin() == j->GetPin() ) {
421 // found a duplicate
422 dups.push_back(j);
426 // if we have multiple iterators in dups, we're done
427 if( dups.size() > 1 )
428 return dups;
430 // else, start over
431 dups.clear();
434 return dups;
437 void DeviceSet::KillDuplicates(const subset_type &dups)
439 // anything to do?
440 if( dups.size() == 0 )
441 return; // nope
443 // only one?
444 if( dups.size() == 1 ) {
445 erase(dups[0]);
446 return;
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
452 base_type copy;
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
456 copy.push_back(*i);
460 // copy back
461 clear();
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;
472 return os;