1 /*
2 * %kadu copyright begin%
3 * Copyright 2010, 2011 Piotr Galiszewski (piotr.galiszewski@kadu.im)
4 * Copyright 2009 Bartłomiej Zimoń (uzi18@o2.pl)
5 * Copyright 2010, 2011, 2012, 2013 Bartosz Brachaczek (b.brachaczek@gmail.com)
6 * Copyright 2009, 2010, 2011, 2012, 2013, 2014 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
7 * %kadu copyright end%
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
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. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "buddy-manager.h"
24
25 #include "accounts/account.h"
26 #include "buddies/buddy-list.h"
27 #include "buddies/buddy-storage.h"
28 #include "configuration/configuration-api.h"
29 #include "configuration/configuration-manager.h"
30 #include "configuration/configuration.h"
31 #include "contacts/contact-manager.h"
32 #include "contacts/contact.h"
33 #include "core/core.h"
34 #include "roster/roster.h"
35 #include "storage/storage-point.h"
36 #include "debug.h"
37
BuddyManager(QObject * parent)38 BuddyManager::BuddyManager(QObject *parent) :
39 SimpleManager<Buddy>{parent}
40 {
41 }
42
~BuddyManager()43 BuddyManager::~BuddyManager()
44 {
45 }
46
setBuddyStorage(BuddyStorage * buddyStorage)47 void BuddyManager::setBuddyStorage(BuddyStorage *buddyStorage)
48 {
49 m_buddyStorage = buddyStorage;
50 }
51
setConfigurationManager(ConfigurationManager * configurationManager)52 void BuddyManager::setConfigurationManager(ConfigurationManager *configurationManager)
53 {
54 m_configurationManager = configurationManager;
55 }
56
setConfiguration(Configuration * configuration)57 void BuddyManager::setConfiguration(Configuration *configuration)
58 {
59 m_configuration = configuration;
60 }
61
setContactManager(ContactManager * contactManager)62 void BuddyManager::setContactManager(ContactManager *contactManager)
63 {
64 m_contactManager = contactManager;
65 }
66
init()67 void BuddyManager::init()
68 {
69 m_configurationManager->registerStorableObject(this);
70 }
71
done()72 void BuddyManager::done()
73 {
74 m_configurationManager->unregisterStorableObject(this);
75 }
76
load()77 void BuddyManager::load()
78 {
79 QMutexLocker locker(&mutex());
80
81 SimpleManager<Buddy>::load();
82 }
83
loadStubFromStorage(const std::shared_ptr<StoragePoint> & storagePoint)84 Buddy BuddyManager::loadStubFromStorage(const std::shared_ptr<StoragePoint> &storagePoint)
85 {
86 return m_buddyStorage->loadStubFromStorage(storagePoint);
87 }
88
itemAboutToBeAdded(Buddy buddy)89 void BuddyManager::itemAboutToBeAdded(Buddy buddy)
90 {
91 QMutexLocker locker(&mutex());
92
93 connect(buddy, SIGNAL(updated()), this, SLOT(buddyDataUpdated()));
94 connect(buddy, SIGNAL(buddySubscriptionChanged()), this, SLOT(buddySubscriptionChanged()));
95
96 connect(buddy, SIGNAL(contactAboutToBeAdded(Contact)),
97 this, SLOT(buddyContactAboutToBeAdded(Contact)));
98 connect(buddy, SIGNAL(contactAdded(Contact)),
99 this, SLOT(buddyContactAdded(Contact)));
100 connect(buddy, SIGNAL(contactAboutToBeRemoved(Contact)),
101 this, SLOT(buddyContactAboutToBeRemoved(Contact)));
102 connect(buddy, SIGNAL(contactRemoved(Contact)),
103 this, SLOT(buddyContactRemoved(Contact)));
104
105 emit buddyAboutToBeAdded(buddy);
106 }
107
itemAdded(Buddy buddy)108 void BuddyManager::itemAdded(Buddy buddy)
109 {
110 emit buddyAdded(buddy);
111 }
112
itemAboutToBeRemoved(Buddy buddy)113 void BuddyManager::itemAboutToBeRemoved(Buddy buddy)
114 {
115 foreach (const Contact &contact, buddy.contacts())
116 contact.setOwnerBuddy(Buddy::null);
117
118 emit buddyAboutToBeRemoved(buddy);
119 }
120
itemRemoved(Buddy buddy)121 void BuddyManager::itemRemoved(Buddy buddy)
122 {
123 QMutexLocker locker(&mutex());
124
125 disconnect(buddy, 0, this, 0);
126
127 emit buddyRemoved(buddy);
128 }
129
mergeValue(const QString & destination,const QString & source) const130 QString BuddyManager::mergeValue(const QString &destination, const QString &source) const
131 {
132 if (destination.isEmpty())
133 return source;
134 else
135 return destination;
136 }
137
mergeBuddies(Buddy destination,Buddy source)138 void BuddyManager::mergeBuddies(Buddy destination, Buddy source)
139 {
140 QMutexLocker locker(&mutex());
141
142 if (destination == source)
143 return;
144
145 ensureLoaded();
146
147 destination.setEmail(mergeValue(destination.email(), source.email()));
148 destination.setHomePhone(mergeValue(destination.homePhone(), source.homePhone()));
149 destination.setMobile(mergeValue(destination.mobile(), source.mobile()));
150 destination.setWebsite(mergeValue(destination.website(), source.website()));
151
152 // we need to move contacts before removing source buddy as this would cause
153 // these contacts to detach and remove from roster
154 // i think this is another reason why we should not automate too much
155 // we should just manually delete all contacts when buddy is removed
156
157 foreach (const Contact &contact, source.contacts())
158 contact.setOwnerBuddy(destination);
159
160 removeItem(source);
161
162 source.setAnonymous(true);
163 // each item that stores pointer to "source" will now use the same uuid as "destination"
164 source.data()->setUuid(destination.uuid());
165
166 m_configurationManager->flush();
167 }
168
byDisplay(const QString & display,NotFoundAction action)169 Buddy BuddyManager::byDisplay(const QString &display, NotFoundAction action)
170 {
171 QMutexLocker locker(&mutex());
172
173 ensureLoaded();
174
175 if (display.isEmpty())
176 return Buddy::null;
177
178 foreach (const Buddy &buddy, items())
179 {
180 if (display == buddy.display())
181 return buddy;
182 }
183
184 if (ActionReturnNull == action)
185 return Buddy::null;
186
187 auto buddy = m_buddyStorage->create();
188 buddy.setDisplay(display);
189
190 if (ActionCreateAndAdd == action)
191 addItem(buddy);
192
193 return buddy;
194 }
195
byId(Account account,const QString & id,NotFoundAction action)196 Buddy BuddyManager::byId(Account account, const QString &id, NotFoundAction action)
197 {
198 QMutexLocker locker(&mutex());
199
200 ensureLoaded();
201
202 auto contact = m_contactManager->byId(account, id, action);
203 if (contact.isNull())
204 return Buddy::null;
205
206 return byContact(contact, action);
207 }
208
byContact(Contact contact,NotFoundAction action)209 Buddy BuddyManager::byContact(Contact contact, NotFoundAction action)
210 {
211 QMutexLocker locker(&mutex());
212
213 ensureLoaded();
214
215 if (!contact)
216 return Buddy::null;
217
218 if (ActionReturnNull == action || !contact.isAnonymous())
219 return contact.ownerBuddy();
220
221 if (!contact.ownerBuddy())
222 contact.setOwnerBuddy(m_buddyStorage->create());
223
224 if (ActionCreateAndAdd == action)
225 addItem(contact.ownerBuddy());
226
227 return contact.ownerBuddy();
228 }
229
byUuid(const QUuid & uuid)230 Buddy BuddyManager::byUuid(const QUuid &uuid)
231 {
232 QMutexLocker locker(&mutex());
233
234 ensureLoaded();
235
236 if (uuid.isNull())
237 return m_buddyStorage->create();
238
239 foreach (const Buddy &buddy, items())
240 if (buddy.uuid() == uuid)
241 return buddy;
242
243 return m_buddyStorage->create();
244 }
245
removeBuddyIfEmpty(Buddy buddy,bool checkOnlyForContacts)246 void BuddyManager::removeBuddyIfEmpty(Buddy buddy, bool checkOnlyForContacts)
247 {
248 if (!buddy)
249 return;
250
251 if (buddy.isEmpty(checkOnlyForContacts))
252 removeItem(buddy);
253 }
254
clearOwnerAndRemoveEmptyBuddy(Contact contact,bool checkBuddyOnlyForOtherContacts)255 void BuddyManager::clearOwnerAndRemoveEmptyBuddy(Contact contact, bool checkBuddyOnlyForOtherContacts)
256 {
257 if (!contact)
258 return;
259
260 Buddy owner = contact.ownerBuddy();
261 contact.setOwnerBuddy(Buddy::null);
262 removeBuddyIfEmpty(owner, checkBuddyOnlyForOtherContacts);
263 }
264
buddies(Account account,bool includeAnonymous)265 BuddyList BuddyManager::buddies(Account account, bool includeAnonymous)
266 {
267 QMutexLocker locker(&mutex());
268
269 ensureLoaded();
270
271 BuddyList result;
272
273 foreach (const Buddy &buddy, items())
274 if (buddy.hasContact(account) && (includeAnonymous || !buddy.isAnonymous()))
275 result << buddy;
276
277 return result;
278 }
279
buddyDataUpdated()280 void BuddyManager::buddyDataUpdated()
281 {
282 QMutexLocker locker(&mutex());
283
284 Buddy buddy(sender());
285 if (!buddy.isNull())
286 emit buddyUpdated(buddy);
287 }
288
buddySubscriptionChanged()289 void BuddyManager::buddySubscriptionChanged()
290 {
291 QMutexLocker locker(&mutex());
292
293 Buddy buddy(sender());
294 if (!buddy.isNull())
295 emit buddySubscriptionChanged(buddy);
296 }
297
buddyContactAboutToBeAdded(const Contact & contact)298 void BuddyManager::buddyContactAboutToBeAdded(const Contact &contact)
299 {
300 QMutexLocker locker(&mutex());
301
302 Buddy buddy(sender());
303 if (!buddy.isNull())
304 emit buddyContactAboutToBeAdded(buddy, contact);
305 }
306
buddyContactAdded(const Contact & contact)307 void BuddyManager::buddyContactAdded(const Contact &contact)
308 {
309 QMutexLocker locker(&mutex());
310
311 Buddy buddy(sender());
312 if (!buddy.isNull())
313 emit buddyContactAdded(buddy, contact);
314 }
315
buddyContactAboutToBeRemoved(const Contact & contact)316 void BuddyManager::buddyContactAboutToBeRemoved(const Contact &contact)
317 {
318 QMutexLocker locker(&mutex());
319
320 Buddy buddy(sender());
321 if (!buddy.isNull())
322 emit buddyContactAboutToBeRemoved(buddy, contact);
323 }
324
buddyContactRemoved(const Contact & contact)325 void BuddyManager::buddyContactRemoved(const Contact &contact)
326 {
327 QMutexLocker locker(&mutex());
328
329 Buddy buddy(sender());
330 if (!buddy.isNull())
331 emit buddyContactRemoved(buddy, contact);
332 }
333
334 #include "moc_buddy-manager.cpp"
335