desktop: string conversion to support i18n
[barry.git] / desktop / src / osconfig.cc
blob41a2ae64dcd87ef190abe8847e87389be9faa934
1 ///
2 /// \file osconfig.cc
3 /// Class which detects a set of available or known devices
4 /// in an opensync-able system.
5 ///
7 /*
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 "osconfig.h"
24 #include "os40.h"
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <pwd.h>
29 #include <algorithm>
30 #include "i18n.h"
32 using namespace std;
34 namespace OpenSync { namespace Config {
36 //////////////////////////////////////////////////////////////////////////////
37 // Unsupported config class
39 std::string Unsupported::AppName()
41 return _C("Unsupported");
45 //////////////////////////////////////////////////////////////////////////////
46 // Barry config class
48 Barry::Barry(const ::Barry::Pin &pin)
49 : m_debug_mode(false)
50 , m_pin(pin)
52 if( !m_pin.Valid() )
53 throw std::logic_error(_C("Barry config must have valid pin number."));
56 Barry::Barry(Converter *load_converter, const Member &member)
57 : m_debug_mode(false)
59 load_converter->Load(*this, member);
61 // check that the loaded pin is valid... if not, it is
62 // likely safe to assume that something is horribly wrong.
63 // in the case where the Application wishes to add a new
64 // barry plugin, it should use the Pin constructor.
65 // if you *really* need to try to salvage an old
66 // corrupt config, you can always do the
67 // converter->Load(barry_obj) manually, and pick out
68 // the left overs.
70 if( !m_pin.Valid() ) {
71 std::ostringstream oss;
72 oss << _C("Unable to load pin number from Barry plugin config. Consider this group corrupt, or not fully configured: ") << member;
73 throw LoadError(oss.str());
78 //////////////////////////////////////////////////////////////////////////////
79 // Group class
81 Group::Group(const std::string &group_name,
82 OpenSync::API &api,
83 unsigned throw_mask)
84 : m_group_name(group_name)
86 Load(api, throw_mask);
89 Group::Group(const std::string &group_name)
90 : m_group_name(group_name)
94 // Checks for OSCG_THROW_ON_NO_BARRY and OSCG_THROW_ON_MULTIPLE_BARRIES
95 void Group::BarryCheck(OpenSync::API &api,
96 const std::string &group_name,
97 const member_list_type &members,
98 unsigned throw_mask)
100 if( ! (throw_mask & (OSCG_THROW_ON_NO_BARRY | OSCG_THROW_ON_MULTIPLE_BARRIES) ) )
101 return; // nothing to do
103 int found = 0;
104 std::string barry_name = Config::Barry::PluginName(api);
105 member_list_type::const_iterator b = members.begin(), e = members.end();
106 for( ; b != e; ++b ) {
107 if( b->plugin_name == barry_name )
108 found++;
111 if( found == 0 && (throw_mask & OSCG_THROW_ON_NO_BARRY) ) {
112 ostringstream oss;
113 oss << _C("No Barry plugins found in group '") << group_name << _C("' and OSCG_THROW_ON_NO_BARRY is set.");
114 throw LoadError(oss.str());
117 if( found > 1 && (throw_mask & OSCG_THROW_ON_MULTIPLE_BARRIES) ) {
118 ostringstream oss;
119 oss << _C("Found ") << found << _C(" Barry plugins in group '") << group_name << _C("' and OSCG_THROW_ON_MULTIPLE_BARRIES is set.");
120 throw LoadError(oss.str());
124 bool Group::GroupMatchesExistingConfig(OpenSync::API &api)
126 member_list_type members;
127 api.GetMembers(m_group_name, members);
129 // what needs to match:
131 // - number of connected Config::Plugin objects in our
132 // list must match number of members in config
133 // - each member ID must match along with the plugin_name
134 // of each member
137 // check totals match
138 if( (unsigned) GetConnectedCount() != members.size() ) {
139 barryverbose(_C("Connected count of ") << GetConnectedCount() << _C(" does not match member count of ") << members.size());
140 return false;
143 // cycle through our own vector, matching against each member_id
144 // in the members list
145 const_iterator ci = begin(), ce = end();
146 for( ; ci != ce; ++ci ) {
147 if( (*ci)->GetMemberId() == -1 )
148 continue;
150 Member *m = members.Find( (*ci)->GetMemberId() );
151 if( !m ) {
152 barryverbose(_C("Can't match member ID: ") << (*ci)->GetMemberId() );
153 return false;
156 if( m->plugin_name != (*ci)->GetPluginName(api) ) {
157 barryverbose(_C("Plugin names don't match: ")
158 << m->plugin_name << ", "
159 << (*ci)->GetPluginName(api));
160 return false;
164 return true;
167 bool Group::HasUnsupportedPlugins() const
169 const_iterator b = begin(), e = end();
170 for( ; b != e; ++b ) {
171 if( (*b)->IsUnsupported() )
172 return true;
174 return false;
177 bool Group::HasBarryPlugins() const
179 const_iterator b = begin(), e = end();
180 for( ; b != e; ++b ) {
181 if( (*b)->GetAppName() == Config::Barry::AppName() )
182 return true;
184 return false;
187 bool Group::GroupExists(OpenSync::API &api) const
189 // does m_group_name exist in the API list?
190 string_list_type groups;
191 api.GetGroupNames(groups);
192 return std::find(groups.begin(), groups.end(), m_group_name) != groups.end();
195 bool Group::AllConfigured(OpenSync::API &api) const
197 const_iterator b = begin(), e = end();
198 for( ; b != e; ++b ) {
199 if( !(*b)->IsConfigured(api) )
200 return false;
202 return true;
205 int Group::GetConnectedCount() const
207 int count = 0;
208 const_iterator b = begin(), e = end();
209 for( ; b != e; ++b ) {
210 if( (*b)->GetMemberId() != -1 )
211 count++;
213 return count;
216 pst_type Group::GetSupportedSyncTypes(OpenSync::API &api) const
218 pst_type types = PST_ALL;
220 const_iterator b = begin(), e = end();
221 for( ; b != e; ++b ) {
222 types &= (*b)->GetSupportedSyncTypes(api);
225 return types;
228 std::string Group::GetAppNames() const
230 std::string names;
232 const_iterator b = begin(), e = end();
233 for( ; b != e; ++b ) {
234 std::string name = (*b)->GetAppName();
235 if( name != Config::Barry::AppName() ) {
236 if( names.size() )
237 names += ", ";
238 names += name;
242 return names;
245 OpenSync::Config::Barry& Group::GetBarryPlugin()
247 return const_cast<OpenSync::Config::Barry&> ( const_cast<const Group*> (this)->GetBarryPlugin() );
250 const OpenSync::Config::Barry& Group::GetBarryPlugin() const
252 const_iterator b = begin(), e = end();
253 for( ; b != e; ++b ) {
254 if( (*b)->GetAppName() == Config::Barry::AppName() )
255 return dynamic_cast<const OpenSync::Config::Barry&> (*(*b));
258 // not found
259 throw std::logic_error("No Barry Plugins in Group");
262 OpenSync::Config::Plugin* Group::GetNonBarryPlugin()
264 return const_cast<OpenSync::Config::Plugin*> ( const_cast<const Group*> (this)->GetNonBarryPlugin() );
267 const OpenSync::Config::Plugin* Group::GetNonBarryPlugin() const
269 const_iterator b = begin(), e = end();
270 for( ; b != e; ++b ) {
271 if( (*b)->GetAppName() != Config::Barry::AppName() )
272 return (*b).get();
275 return 0;
278 void Group::DisconnectMembers()
280 iterator b = begin(), e = end();
281 for( ; b != e; ++b ) {
282 (*b)->SetMemberId(-1);
286 void Group::Load(OpenSync::API &api, unsigned throw_mask)
288 Load(m_group_name, api, throw_mask);
291 void Group::Load(const std::string &src_group_name,
292 OpenSync::API &api,
293 unsigned throw_mask)
295 member_list_type members;
296 api.GetMembers(src_group_name, members);
298 BarryCheck(api, src_group_name, members, throw_mask);
300 member_list_type::const_iterator b = members.begin(), e = members.end();
301 for( ; b != e; ++b ) {
302 Converter &converter = api.GetConverter();
303 Converter::plugin_ptr p = converter.CreateAndLoadPlugin(*b);
304 p->SetMemberId(b->id);
306 if( p->IsUnsupported() && (throw_mask & OSCG_THROW_ON_UNSUPPORTED) ) {
307 ostringstream oss;
308 oss << _C("Unsupported plugin '") << b->plugin_name << _C("' in group '") << src_group_name << _C("' and OSCG_THROW_ON_UNSUPPORTED is set.");
309 throw LoadError(oss.str());
312 // everything looks ok, add the plugin to our list
313 push_back(p);
317 void Group::ResetGroupName(const std::string &new_group_name)
319 m_group_name = new_group_name;
322 void Group::AddPlugin(OpenSync::Config::Plugin *plugin)
324 plugin_ptr pp(plugin);
325 push_back(pp);
328 void Group::DeletePlugin(iterator i, OpenSync::API &api)
330 // is this plugin connected to a previously saved group config?
331 if( (*i)->GetMemberId() != -1 ) {
332 // this plugin has a member ID... only OpenSync 0.40 can
333 // delete members like that... do we have 40 support?
334 OpenSync::OpenSync40 *api40 = dynamic_cast<OpenSync::OpenSync40*> (&api);
335 if( !api40 ) {
336 // not version 0.40... can't do it capt'n!
337 throw DeleteError(_C("Cannot delete individual members from an OpenSync group with versions < 0.40."));
340 // so... we have the capability... check that the plugin
341 // name of the ID in the group matches what we think it
342 // should be
344 member_list_type members;
345 api40->GetMembers(m_group_name, members);
347 Member *m = members.Find( (*i)->GetMemberId() );
348 if( !m ) {
349 ostringstream oss;
350 oss << _C("Tried to delete non-existent member ID ") << (*i)->GetMemberId() << " (" << (*i)->GetPluginName(api) << ") " << _C("from group") << "'" << m_group_name << "'";
351 throw DeleteError(oss.str());
354 if( m->plugin_name != (*i)->GetPluginName(api) ) {
355 ostringstream oss;
356 oss << _C("Tried to delete member ID ") << (*i)->GetMemberId() << _C(" using plugin '") << (*i)->GetPluginName(api) << _C("' from group '") << m_group_name << _C("', but the existing member uses plugin") << "'" << m->plugin_name << "'";
357 throw DeleteError(oss.str());
360 // so far so good... try deleting it
361 api40->DeleteMember(m_group_name, (*i)->GetMemberId());
364 // remove from our own array
365 erase(i);
368 void Group::Save(OpenSync::API &api)
370 if( GroupExists(api) ) {
371 // groups already exists, so need to confirm that our
372 // connected plugins match the existing member_ids and
373 // plugin names in the group's member list
374 if( !GroupMatchesExistingConfig(api) ) {
375 ostringstream oss;
376 oss << _C("Tried to overwrite group '") << m_group_name << _C("' with a Group set that did not match in ID's and plugin names.");
377 throw SaveError(oss.str());
380 else {
381 // group does not exist, so create it if needed
382 if( size() )
383 api.AddGroup(m_group_name);
386 // cycle through all plugins and save them all
387 iterator b = begin(), e = end();
388 for( ; b != e; ++b ) {
389 Config::Plugin &p = *(*b);
391 if( p.GetMemberId() == -1 ) {
392 // this plugin has never been saved yet, so
393 // add it fresh
394 long newid = api.AddMember(m_group_name,
395 p.GetPluginName(api), "");
396 p.SetMemberId(newid);
399 // save config
400 p.Save(api, m_group_name);
404 bool Group::Compare(const Group &other) const
406 // size of group equal?
407 if( size() != other.size() )
408 return false;
410 // name of group?
411 if( m_group_name != other.m_group_name )
412 return false;
414 // cycle through all plugins, searching for a match in other
415 const_iterator i = begin();
416 for( ; i != end(); ++i ) {
417 bool sametype, equal;
418 bool match = false;
420 // search other for a match
421 const_iterator oi = other.begin();
422 for( ; oi != other.end(); ++oi ) {
423 if( (match = (*i)->Compare(*(*oi), sametype, equal)) )
424 break;
427 if( !match )
428 return false;
431 return true;
434 Group::group_ptr Group::Clone() const
436 group_ptr g( new Group(m_group_name) );
438 // clone all plugins
439 const_iterator b = begin(), e = end();
440 for( ; b != e; ++b ) {
441 plugin_ptr p( (*b)->Clone() );
442 g->push_back(p);
445 return g;
448 }} // namespace OpenSync::Config