1 /*
2  * %kadu copyright begin%
3  * Copyright 2009, 2010, 2011 Piotr Galiszewski (piotr.galiszewski@kadu.im)
4  * Copyright 2009 Wojciech Treter (juzefwt@gmail.com)
5  * Copyright 2009 Bartłomiej Zimoń (uzi18@o2.pl)
6  * Copyright 2011, 2012, 2013 Bartosz Brachaczek (b.brachaczek@gmail.com)
7  * Copyright 2008, 2009, 2010, 2011, 2012, 2013, 2014 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
8  * %kadu copyright end%
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
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. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "contact-manager.h"
25 
26 #include "buddies/buddy-manager.h"
27 #include "buddies/buddy-storage.h"
28 #include "buddies/buddy.h"
29 #include "configuration/configuration-manager.h"
30 #include "configuration/configuration.h"
31 #include "configuration/deprecated-configuration-api.h"
32 #include "contacts/contact-storage.h"
33 #include "core/myself.h"
34 #include "message/unread-message-repository.h"
35 #include "misc/change-notifier-lock.h"
36 #include "parser/parser.h"
37 #include "protocols/protocol-factory.h"
38 #include "protocols/protocol.h"
39 #include "roster/roster-entry-state.h"
40 #include "roster/roster-entry.h"
41 #include "debug.h"
42 
43 #include <QtCore/QPair>
44 #include <QtCore/QTimer>
45 
ContactManager(QObject * parent)46 ContactManager::ContactManager(QObject *parent) :
47 		SimpleManager<Contact>{parent}
48 {
49 }
50 
~ContactManager()51 ContactManager::~ContactManager()
52 {
53 }
54 
setBuddyStorage(BuddyStorage * buddyStorage)55 void ContactManager::setBuddyStorage(BuddyStorage *buddyStorage)
56 {
57 	m_buddyStorage = buddyStorage;
58 }
59 
setConfigurationManager(ConfigurationManager * configurationManager)60 void ContactManager::setConfigurationManager(ConfigurationManager *configurationManager)
61 {
62 	m_configurationManager = configurationManager;
63 }
64 
setConfiguration(Configuration * configuration)65 void ContactManager::setConfiguration(Configuration *configuration)
66 {
67 	m_configuration = configuration;
68 }
69 
setContactStorage(ContactStorage * contactStorage)70 void ContactManager::setContactStorage(ContactStorage *contactStorage)
71 {
72 	m_contactStorage = contactStorage;
73 }
74 
setMyself(Myself * myself)75 void ContactManager::setMyself(Myself *myself)
76 {
77 	m_myself = myself;
78 }
79 
setParser(Parser * parser)80 void ContactManager::setParser(Parser *parser)
81 {
82 	m_parser = parser;
83 }
84 
setUnreadMessageRepository(UnreadMessageRepository * unreadMessageRepository)85 void ContactManager::setUnreadMessageRepository(UnreadMessageRepository *unreadMessageRepository)
86 {
87 	m_unreadMessageRepository = unreadMessageRepository;
88 }
89 
init()90 void ContactManager::init()
91 {
92 	// needed for QueuedConnection
93 	qRegisterMetaType<Contact>("Contact");
94 
95 	foreach (const Message &message, m_unreadMessageRepository->allUnreadMessages())
96 		unreadMessageAdded(message);
97 
98 	connect(m_unreadMessageRepository, SIGNAL(unreadMessageAdded(Message)), this, SLOT(unreadMessageAdded(Message)));
99 	connect(m_unreadMessageRepository, SIGNAL(unreadMessageRemoved(Message)), this, SLOT(unreadMessageRemoved(Message)));
100 
101 	m_configurationManager->registerStorableObject(this);
102 
103 	ensureLoaded();
104 }
105 
done()106 void ContactManager::done()
107 {
108 	disconnect(m_unreadMessageRepository, 0, this, 0);
109 
110 	foreach (const Message &message, m_unreadMessageRepository->allUnreadMessages())
111 		unreadMessageRemoved(message);
112 
113 	m_configurationManager->unregisterStorableObject(this);
114 }
115 
unreadMessageAdded(const Message & message)116 void ContactManager::unreadMessageAdded(const Message &message)
117 {
118 	const Contact &contact = message.messageSender();
119 	contact.setUnreadMessagesCount(contact.unreadMessagesCount() + 1);
120 }
121 
unreadMessageRemoved(const Message & message)122 void ContactManager::unreadMessageRemoved(const Message &message)
123 {
124 	const Contact &contact = message.messageSender();
125 	quint16 unreadMessagesCount = contact.unreadMessagesCount();
126 	if (unreadMessagesCount > 0)
127 		contact.setUnreadMessagesCount(unreadMessagesCount - 1);
128 }
129 
itemAboutToBeAdded(Contact item)130 void ContactManager::itemAboutToBeAdded(Contact item)
131 {
132 	QMutexLocker locker(&mutex());
133 
134 	connect(item, SIGNAL(updated()), this, SLOT(contactDataUpdated()));
135 	emit contactAboutToBeAdded(item);
136 }
137 
itemAdded(Contact item)138 void ContactManager::itemAdded(Contact item)
139 {
140 	if (!item)
141 		return;
142 
143 	QMutexLocker locker(&mutex());
144 
145 	emit contactAdded(item);
146 
147 	if (m_myself->buddy() == item.ownerBuddy())
148 		item.rosterEntry()->setSynchronized();
149 }
150 
itemAboutToBeRemoved(Contact item)151 void ContactManager::itemAboutToBeRemoved(Contact item)
152 {
153 	QMutexLocker locker(&mutex());
154 
155 	disconnect(item, SIGNAL(updated()), this, SLOT(contactDataUpdated()));
156 	emit contactAboutToBeRemoved(item);
157 }
158 
itemRemoved(Contact item)159 void ContactManager::itemRemoved(Contact item)
160 {
161 	emit contactRemoved(item);
162 }
163 
byId(Account account,const QString & id,NotFoundAction action)164 Contact ContactManager::byId(Account account, const QString &id, NotFoundAction action)
165 {
166 	QMutexLocker locker(&mutex());
167 
168 	ensureLoaded();
169 
170 	if (id.isEmpty() || account.isNull())
171 		return Contact::null;
172 
173 	foreach (const Contact &contact, items())
174 		if (account == contact.contactAccount() && id == contact.id())
175 			return contact;
176 
177 	if (action == ActionReturnNull)
178 		return Contact::null;
179 
180 	Contact contact = m_contactStorage->create();
181 
182 	ChangeNotifierLock lock(contact.rosterEntry()->hasLocalChangesNotifier(), ChangeNotifierLock::ModeForget); // don't emit dirty signals
183 	contact.setId(id);
184 	contact.setContactAccount(account);
185 
186 	if (action == ActionCreateAndAdd)
187 		addItem(contact);
188 
189 	auto buddy = m_buddyStorage->create();
190 	contact.setOwnerBuddy(buddy);
191 
192 	return contact;
193 }
194 
contacts(Account account,AnonymousInclusion inclusion)195 QVector<Contact> ContactManager::contacts(Account account, AnonymousInclusion inclusion)
196 {
197 	QMutexLocker locker(&mutex());
198 
199 	ensureLoaded();
200 
201 	QVector<Contact> contacts;
202 
203 	if (account.isNull())
204 		return contacts;
205 
206 	foreach (const Contact &contact, items())
207 		if (account == contact.contactAccount() && ((IncludeAnonymous == inclusion) || !contact.isAnonymous()))
208 			contacts.append(contact);
209 
210 	return contacts;
211 }
212 
contactDataUpdated()213 void ContactManager::contactDataUpdated()
214 {
215 	QMutexLocker locker(&mutex());
216 
217 	Contact contact(sender());
218 	if (!contact.isNull())
219 		emit contactUpdated(contact);
220 }
221 
222 // This is needed to fix up configurations broken by bug #2222 (present in 0.9.x).
223 // It can be removed when we will stop supporting upgrades from 0.9.x.
removeDuplicateContacts()224 void ContactManager::removeDuplicateContacts()
225 {
226 	QMap<QPair<Account, QString>, Contact> uniqueContacts;
227 
228 	foreach (const Contact &contact, items())
229 	{
230 		QMap<QPair<Account, QString>, Contact>::iterator it = uniqueContacts.find(qMakePair(contact.contactAccount(), contact.id()));
231 		if (it != uniqueContacts.end())
232 		{
233 			if (it->isAnonymous())
234 			{
235 				removeItem(*it);
236 				it->setUuid(contact.uuid());
237 				*it = contact;
238 			}
239 			else
240 			{
241 				removeItem(contact);
242 				contact.setUuid(it->uuid());
243 			}
244 		}
245 		else
246 			uniqueContacts.insert(qMakePair(contact.contactAccount(), contact.id()), contact);
247 	}
248 
249 	m_configuration->deprecatedApi()->writeEntry("General", "ContactsImportedFrom0_9", true);
250 }
251 
loaded()252 void ContactManager::loaded()
253 {
254 	SimpleManager<Contact>::loaded();
255 
256 	if (!m_configuration->deprecatedApi()->readBoolEntry("General", "ContactsImportedFrom0_9", false))
257 		// delay it so that everything needed will be loaded when we call this method
258 		QTimer::singleShot(0, this, SLOT(removeDuplicateContacts()));
259 }
260 
loadStubFromStorage(const std::shared_ptr<StoragePoint> & storagePoint)261 Contact ContactManager::loadStubFromStorage(const std::shared_ptr<StoragePoint> &storagePoint)
262 {
263 	return m_contactStorage->loadStubFromStorage(storagePoint);
264 }
265 
266 #include "moc_contact-manager.cpp"
267