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