1/*
2 This file is part of kabc.
3 Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21#include "resourcecached.h"
22
23#include <kabc/vcardconverter.h>
24
25#include <kdebug.h>
26#include <klocalizedstring.h>
27#include <kstandarddirs.h>
28
29#include <QtCore/QFile>
30
31using namespace KABC;
32
33class ResourceCached::Private
34{
35 public:
36 Private( ResourceCached *parent )
37 : mParent( parent ), mIdMapper( QLatin1String( "kabc/uidmaps/" ) )
38 {
39 }
40
41 void loadChangesCache( QMap<QString, KABC::Addressee> &map, const QString &type );
42 void saveChangesCache( const QMap<QString, KABC::Addressee> &map, const QString &type );
43
44 ResourceCached *mParent;
45 KRES::IdMapper mIdMapper;
46
47 QMap<QString, KABC::Addressee> mAddedAddressees;
48 QMap<QString, KABC::Addressee> mChangedAddressees;
49 QMap<QString, KABC::Addressee> mDeletedAddressees;
50};
51
52void ResourceCached::Private::saveChangesCache( const QMap<QString, KABC::Addressee> &map,
53 const QString &type )
54{
55 QFile file( mParent->changesCacheFile( type ) );
56
57 const KABC::Addressee::List list = map.values();
58 if ( list.isEmpty() ) {
59 file.remove();
60 } else {
61 if ( !file.open( QIODevice::WriteOnly ) ) {
62 kError( 5700 ) << "Can't open changes cache file '" << file.fileName() << "' for saving.";
63 return;
64 }
65
66 KABC::VCardConverter converter;
67 const QByteArray vCards = converter.createVCards( list );
68 file.write( vCards );
69 }
70}
71
72void ResourceCached::Private::loadChangesCache( QMap<QString, KABC::Addressee> &map,
73 const QString &type )
74{
75 QFile file( mParent->changesCacheFile( type ) );
76 if ( !file.open( QIODevice::ReadOnly ) ) {
77 return;
78 }
79
80 KABC::VCardConverter converter;
81
82 const KABC::Addressee::List list = converter.parseVCards( file.readAll() );
83 KABC::Addressee::List::ConstIterator it;
84 KABC::Addressee::List::ConstIterator end( list.end() );
85 for ( it = list.begin(); it != end; ++it ) {
86 map.insert( ( *it ).uid(), *it );
87 }
88
89 file.close();
90}
91
92ResourceCached::ResourceCached()
93 : KABC::Resource(), d( new Private( this ) )
94{
95}
96
97ResourceCached::ResourceCached( const KConfigGroup &group )
98 : KABC::Resource( group ), d( new Private( this ) )
99{
100}
101
102ResourceCached::~ResourceCached()
103{
104 delete d;
105}
106
107void ResourceCached::writeConfig( KConfigGroup &group )
108{
109 KABC::Resource::writeConfig( group );
110}
111
112void ResourceCached::insertAddressee( const Addressee &addr )
113{
114 if ( !mAddrMap.contains( addr.uid() ) ) { // new contact
115 if ( d->mDeletedAddressees.contains( addr.uid() ) ) {
116 // it was first removed, then added, so it's an update...
117 d->mDeletedAddressees.remove( addr.uid() );
118
119 mAddrMap.insert( addr.uid(), addr );
120 d->mChangedAddressees.insert( addr.uid(), addr );
121 return;
122 }
123
124 mAddrMap.insert( addr.uid(), addr );
125 d->mAddedAddressees.insert( addr.uid(), addr );
126 } else {
127 KABC::Addressee oldAddressee = mAddrMap.find( addr.uid() ).value();
128 if ( oldAddressee != addr ) {
129 mAddrMap.remove( addr.uid() );
130 mAddrMap.insert( addr.uid(), addr );
131 d->mChangedAddressees.insert( addr.uid(), addr );
132 }
133 }
134}
135
136void ResourceCached::removeAddressee( const Addressee &addr )
137{
138 if ( d->mAddedAddressees.contains( addr.uid() ) ) {
139 d->mAddedAddressees.remove( addr.uid() );
140 return;
141 }
142
143 if ( d->mDeletedAddressees.find( addr.uid() ) == d->mDeletedAddressees.end() ) {
144 d->mDeletedAddressees.insert( addr.uid(), addr );
145 }
146
147 mAddrMap.remove( addr.uid() );
148}
149
150bool ResourceCached::loadFromCache()
151{
152 mAddrMap.clear();
153
154 setIdMapperIdentifier();
155 d->mIdMapper.load();
156
157 // load cache
158 QFile file( cacheFile() );
159 if ( !file.open( QIODevice::ReadOnly ) ) {
160 return false;
161 }
162
163 KABC::VCardConverter converter;
164 KABC::Addressee::List list = converter.parseVCards( file.readAll() );
165 KABC::Addressee::List::Iterator it;
166
167 for ( it = list.begin(); it != list.end(); ++it ) {
168 ( *it ).setResource( this );
169 ( *it ).setChanged( false );
170 mAddrMap.insert( ( *it ).uid(), *it );
171 }
172
173 file.close();
174 return true;
175}
176
177void ResourceCached::saveToCache()
178{
179 setIdMapperIdentifier();
180 d->mIdMapper.save();
181
182 // save cache
183 QFile file( cacheFile() );
184 if ( !file.open( QIODevice::WriteOnly ) ) {
185 return;
186 }
187
188 KABC::Addressee::List list = mAddrMap.values();
189
190 KABC::VCardConverter converter;
191 QByteArray vCard = converter.createVCards( list );
192 file.write( vCard );
193 file.close();
194}
195
196void ResourceCached::cleanUpCache( const KABC::Addressee::List &addrList )
197{
198 // load cache
199 QFile file( cacheFile() );
200 if ( !file.open( QIODevice::ReadOnly ) ) {
201 return;
202 }
203
204 KABC::VCardConverter converter;
205 KABC::Addressee::List list = converter.parseVCards( file.readAll() );
206 KABC::Addressee::List::Iterator cacheIt;
207 KABC::Addressee::List::ConstIterator it;
208
209 for ( cacheIt = list.begin(); cacheIt != list.end(); ++cacheIt ) {
210 bool found = false;
211 for ( it = addrList.begin(); it != addrList.end(); ++it ) {
212 if ( ( *it ).uid() == ( *cacheIt ).uid() ) {
213 found = true;
214 }
215 }
216
217 if ( !found ) {
218 d->mIdMapper.removeRemoteId( d->mIdMapper.remoteId( ( *cacheIt ).uid() ) );
219 mAddrMap.remove( ( *cacheIt ).uid() );
220 }
221 }
222
223 file.close();
224}
225
226KRES::IdMapper &ResourceCached::idMapper()
227{
228 return d->mIdMapper;
229}
230
231bool ResourceCached::hasChanges() const
232{
233 return !( d->mAddedAddressees.isEmpty() &&
234 d->mChangedAddressees.isEmpty() &&
235 d->mDeletedAddressees.isEmpty() );
236}
237
238void ResourceCached::clearChanges()
239{
240 d->mAddedAddressees.clear();
241 d->mChangedAddressees.clear();
242 d->mDeletedAddressees.clear();
243}
244
245void ResourceCached::clearChange( const KABC::Addressee &addr )
246{
247 d->mAddedAddressees.remove( addr.uid() );
248 d->mChangedAddressees.remove( addr.uid() );
249 d->mDeletedAddressees.remove( addr.uid() );
250}
251
252void ResourceCached::clearChange( const QString &uid )
253{
254 d->mAddedAddressees.remove( uid );
255 d->mChangedAddressees.remove( uid );
256 d->mDeletedAddressees.remove( uid );
257}
258
259KABC::Addressee::List ResourceCached::addedAddressees() const
260{
261 return d->mAddedAddressees.values();
262}
263
264KABC::Addressee::List ResourceCached::changedAddressees() const
265{
266 return d->mChangedAddressees.values();
267}
268
269KABC::Addressee::List ResourceCached::deletedAddressees() const
270{
271 return d->mDeletedAddressees.values();
272}
273
274QString ResourceCached::cacheFile() const
275{
276 return KStandardDirs::locateLocal( "cache", QLatin1String( "kabc/kresources/" ) + identifier() );
277}
278
279QString ResourceCached::changesCacheFile( const QString &type ) const
280{
281 return KStandardDirs::locateLocal( "cache", QLatin1String( "kabc/changescache/" ) + identifier() +
282 QLatin1Char( '_' ) + type );
283}
284
285void ResourceCached::saveChangesCache()
286{
287 d->saveChangesCache( d->mAddedAddressees, QLatin1String( "added" ) );
288 d->saveChangesCache( d->mDeletedAddressees, QLatin1String( "deleted" ) );
289 d->saveChangesCache( d->mChangedAddressees, QLatin1String( "changed" ) );
290}
291
292void ResourceCached::loadChangesCache()
293{
294 d->loadChangesCache( d->mAddedAddressees, QLatin1String( "added" ) );
295 d->loadChangesCache( d->mDeletedAddressees, QLatin1String( "deleted" ) );
296 d->loadChangesCache( d->mChangedAddressees, QLatin1String( "changed" ) );
297}
298
299void ResourceCached::setIdMapperIdentifier()
300{
301 d->mIdMapper.setIdentifier( type() + QLatin1Char( '_' ) + identifier() );
302}
303
304