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