2 // \file environment.cc
3 // Container / environment class for the sync module.
7 Copyright (C) 2006-2010, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
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.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "environment.h"
33 //////////////////////////////////////////////////////////////////////////////
36 DatabaseSyncState::DatabaseSyncState(OSyncMember
*pm
, const char *description
)
41 m_CacheFilename
= m_MapFilename
=
42 osync_member_get_configdir(pm
);
43 m_CacheFilename
+= "/barry_" + m_Desc
+ "_cache.txt";
44 m_MapFilename
+= "/barry_" + m_Desc
+ "_idmap.txt";
47 DatabaseSyncState::~DatabaseSyncState()
51 bool DatabaseSyncState::LoadCache()
53 Trace
trace("LoadCache", m_Desc
.c_str());
56 std::ifstream
ifs(m_CacheFilename
.c_str());
61 uint32_t recordId
= 0;
64 m_Cache
[recordId
] = false;
69 m_Cache
.clear(); // assume full sync
70 trace
.log("Load failed!");
76 bool DatabaseSyncState::SaveCache()
78 Trace
trace("SaveCache", m_Desc
.c_str());
80 std::ofstream
ofs(m_CacheFilename
.c_str());
84 cache_type::const_iterator i
= m_Cache
.begin();
85 for( ; i
!= m_Cache
.end(); ++i
) {
86 ofs
<< i
->first
<< std::endl
;
88 return !ofs
.bad() && !ofs
.fail();
91 bool DatabaseSyncState::LoadMap()
93 return m_IdMap
.Load(m_MapFilename
.c_str());
96 bool DatabaseSyncState::SaveMap()
98 return m_IdMap
.Save(m_MapFilename
.c_str());
101 // cycle through the map and search the state table for each rid,
102 // and remove any that do not exist
103 void DatabaseSyncState::CleanupMap()
105 idmap::iterator i
= m_IdMap
.begin();
106 for( ; i
!= m_IdMap
.end(); ++i
) {
107 if( !m_Table
.GetIndex(i
->second
) ) {
108 // Record Id does not exist in state table, so it is
109 // not needed anymore in the ID map
118 /// Searches for the given record ID, and returns the mapped UID. If not
119 /// found, it creates a new UID and returns it without mapping it.
121 std::string
DatabaseSyncState::Map2Uid(uint32_t recordId
) const
123 // search the idmap for the UID
125 idmap::const_iterator mapped_id
;
126 if( m_IdMap
.RidExists(recordId
, &mapped_id
) ) {
127 uid
= mapped_id
->first
;
130 // not mapped, map it ourselves
131 char *puid
= g_strdup_printf("%s-%u", m_Desc
.c_str(), recordId
);
138 unsigned long DatabaseSyncState::GetMappedRecordId(const std::string
&uid
)
140 Trace
trace("DatabaseSyncState::GetMappedRecordId()", m_Desc
.c_str());
142 // if already in map, use the matching rid
143 idmap::const_iterator it
;
144 if( m_IdMap
.UidExists(uid
, &it
) ) {
145 trace
.logf("found existing uid in map: %lu", it
->second
);
149 // nothing in the map, so try to convert the string to a number
150 unsigned long RecordId
;
151 if( sscanf(uid
.c_str(), "%lu", &RecordId
) != 0 ) {
152 trace
.logf("parsed uid as: %lu", RecordId
);
153 if( m_IdMap
.Map(uid
, RecordId
) != m_IdMap
.end() )
156 trace
.logf("parsed uid already exists in map, skipping");
159 // create one of our own, if we get here...
160 // do this in a loop to keep going until we find an ID that's unique
162 RecordId
= m_Table
.MakeNewRecordId();
163 } while( m_IdMap
.Map(uid
, RecordId
) == m_IdMap
.end() );
165 trace
.logf("made new record id: %lu", RecordId
);
171 //////////////////////////////////////////////////////////////////////////////
172 // BarryEnvironment Public API
174 BarryEnvironment::BarryEnvironment(OSyncMember
*pm
)
179 m_IConverter("UTF-8"),
182 m_CalendarSync(pm
, "calendar"),
183 m_ContactsSync(pm
, "contacts")
187 BarryEnvironment::~BarryEnvironment()
193 void BarryEnvironment::DoConnect()
197 // Override the timeout due to a firmware issue... sometimes
198 // the firmware will hang during a Reconnect, and fail to
199 // respond to a Desktop::Open(). To work around this, we
200 // set the default timeout to 15 seconds so that we find this
201 // failure early enough to fix it within opensync's 30 second timeout.
202 // Then if we get such a timeout, we do the Reconnect again and
203 // hope for the best... this often fixes it.
205 if( !m_ProbeResult
.get() )
206 throw std::logic_error("Tried to use empty ProbeResult");
207 m_pCon
= new Barry::Controller(*m_ProbeResult
, 15000);
208 m_pDesktop
= new Barry::Mode::Desktop(*m_pCon
, m_IConverter
);
209 m_pDesktop
->Open(m_password
.c_str());
211 // Save the DBIDs and DBNames of the databases we will work with
212 if( m_CalendarSync
.m_Sync
) {
213 m_CalendarSync
.m_dbName
= Barry::Calendar::GetDBName();
214 m_CalendarSync
.m_dbId
= m_pDesktop
->GetDBID(Barry::Calendar::GetDBName());
217 if( m_ContactsSync
.m_Sync
) {
218 m_ContactsSync
.m_dbId
= m_pDesktop
->GetDBID(Barry::Contact::GetDBName());
219 m_ContactsSync
.m_dbName
= Barry::Contact::GetDBName();
223 void BarryEnvironment::Connect(const Barry::ProbeResult
&result
)
227 // save result in case we need to reconnect later
228 m_ProbeResult
.reset( new Barry::ProbeResult(result
) );
233 void BarryEnvironment::Reconnect()
243 // let the device settle... this seems to help prevent the
244 // firmware hang, and therefore ultimately speeds up the sync
247 // FIXME - temporary fix for odd reconnect message... without this
248 // probe, the reconnect will often fail on newer Blackberries
249 // due to an unexpected close socket message. It is unclear
250 // if this is really a message from the device, but until then,
251 // we add this probe.
254 int i
= probe
.FindActive(m_ProbeResult
->m_pin
);
256 m_ProbeResult
.reset( new Barry::ProbeResult(probe
.Get(i
)) );
263 catch( Usb::Timeout
& ) {
268 std::cout
<< "Timeout in Reconnect()... trying again" << std::endl
;
273 void BarryEnvironment::Disconnect()
282 void BarryEnvironment::ClearDirtyFlags(Barry::RecordStateTable
&table
,
283 const std::string
&dbname
)
285 Trace
trace("ClearDirtyFlags");
287 unsigned int dbId
= m_pDesktop
->GetDBID(dbname
);
289 Barry::RecordStateTable::StateMapType::const_iterator i
= table
.StateMap
.begin();
290 for( ; i
!= table
.StateMap
.end(); ++i
) {
291 if( i
->second
.Dirty
) {
292 trace
.logf("Clearing dirty flag for db %u, index %u",
294 m_pDesktop
->ClearDirty(dbId
, i
->first
);
299 void BarryEnvironment::ClearCalendarDirtyFlags()
301 Trace
trace("ClearCalendarDirtyFlags");
302 ClearDirtyFlags(m_CalendarSync
.m_Table
, Barry::Calendar::GetDBName());
305 void BarryEnvironment::ClearContactsDirtyFlags()
307 Trace
trace("ClearContactsDirtyFlags");
308 ClearDirtyFlags(m_ContactsSync
.m_Table
, Barry::Contact::GetDBName());
311 DatabaseSyncState
* BarryEnvironment::GetSyncObject(OSyncChange
*change
)
313 Trace
trace("BarryEnvironment::GetSyncObject()");
315 OSyncObjType
*type
= osync_change_get_objtype(change
);
316 const char *name
= osync_objtype_get_name(type
);
317 if( strcmp(name
, "event") == 0 ) {
318 return &m_CalendarSync
;
320 else if( strcmp(name
, "contact") == 0 ) {
321 return &m_ContactsSync
;
328 void BarryEnvironment::ParseConfig(const char *data
, int size
)
330 Trace
trace("ParseConfig");
332 m_ConfigData
.assign(data
, size
);
334 // The config data should contain:
335 // - Keyword: DebugMode
336 // - if the single word "DebugMode" is found, enable Debug
338 // - Keyword: Device <pin> ...
339 // - PIN of device to sync with
340 // - or a flag that says "autoconfig with first device found"
341 // which will autodetect, and update the config
342 // automatically with the found PIN... all future syncs
343 // will then have a PIN
344 // - checkboxes for (both can be on):
345 // - sync calendar items
348 std::istringstream
iss(m_ConfigData
);
350 while( std::getline(iss
, line
) ) {
355 std::istringstream
ils(line
);
356 int cal
= 0, con
= 0;
361 if( key
== "DebugMode" ) {
364 else if( key
== "Device" ) {
365 ils
>> std::hex
>> m_pin
>> cal
>> con
;
367 std::ostringstream oss
;
368 oss
<< std::hex
<< m_pin
;
369 trace
.log(oss
.str().c_str());
372 m_CalendarSync
.m_Sync
= true;
373 trace
.log("calendar syncing enabled");
377 m_ContactsSync
.m_Sync
= true;
378 trace
.log("contacts syncing enabled");
381 else if ( key
== "Password" ) {
383 trace
.log("using password from config file");
388 //void BarryEnvironment::BuildConfig()
390 // FIXME - build back into one long string