1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2010-2013 Licq developers <licq-dev@googlegroups.com>
4 *
5 * Please refer to the COPYRIGHT file distributed with this source
6 * distribution for the names of the individual contributors.
7 *
8 * Licq is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Licq is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Licq; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <boost/foreach.hpp>
24
25 #include "client.h"
26 #include "owner.h"
27 #include "plugin.h"
28 #include "sessionmanager.h"
29 #include "user.h"
30 #include "vcard.h"
31
32 #include <licq/contactlist/usermanager.h>
33 #include <licq/event.h>
34 #include <licq/logging/log.h>
35 #include <licq/oneventmanager.h>
36 #include <licq/plugin/pluginmanager.h>
37 #include <licq/protocolsignal.h>
38 #include <licq/statistics.h>
39 #include <licq/userevents.h>
40
41 using namespace LicqJabber;
42
43 using Licq::OnEventData;
44 using Licq::gOnEventManager;
45 using Licq::gLog;
46 using std::string;
47
Plugin()48 Plugin::Plugin()
49 : myClient(NULL)
50 {
51 gLog.debug("Using gloox version %s", gloox::GLOOX_VERSION.c_str());
52 }
53
~Plugin()54 Plugin::~Plugin()
55 {
56 delete myClient;
57 }
58
run()59 int Plugin::run()
60 {
61 myMainLoop.addRawFile(getReadPipe(), this);
62 myMainLoop.run();
63 return 0;
64 }
65
rawFileEvent(int,int fd,int)66 void Plugin::rawFileEvent(int /*id*/, int fd, int /*revents*/)
67 {
68 char ch;
69 ::read(fd, &ch, sizeof(ch));
70
71 switch (ch)
72 {
73 case PipeSignal:
74 processSignal(popSignal().get());
75 break;
76 case PipeShutdown:
77 doLogoff();
78 myMainLoop.quit();
79 break;
80 default:
81 gLog.error("Unknown command %c", ch);
82 break;
83 }
84 }
85
processSignal(const Licq::ProtocolSignal * signal)86 void Plugin::processSignal(const Licq::ProtocolSignal* signal)
87 {
88 assert(signal != NULL);
89
90 switch (signal->signal())
91 {
92 case Licq::ProtocolSignal::SignalLogon:
93 doLogon(dynamic_cast<const Licq::ProtoLogonSignal*>(signal));
94 break;
95 case Licq::ProtocolSignal::SignalLogoff:
96 doLogoff();
97 break;
98 case Licq::ProtocolSignal::SignalChangeStatus:
99 doChangeStatus(
100 dynamic_cast<const Licq::ProtoChangeStatusSignal*>(signal));
101 break;
102 case Licq::ProtocolSignal::SignalAddUser:
103 doAddUser(dynamic_cast<const Licq::ProtoAddUserSignal*>(signal));
104 break;
105 case Licq::ProtocolSignal::SignalRemoveUser:
106 doRemoveUser(dynamic_cast<const Licq::ProtoRemoveUserSignal*>(signal));
107 break;
108 case Licq::ProtocolSignal::SignalRenameUser:
109 doRenameUser(dynamic_cast<const Licq::ProtoRenameUserSignal*>(signal));
110 break;
111 case Licq::ProtocolSignal::SignalChangeUserGroups:
112 doChangeUserGroups(
113 dynamic_cast<const Licq::ProtoChangeUserGroupsSignal*>(signal));
114 break;
115 case Licq::ProtocolSignal::SignalSendMessage:
116 doSendMessage(dynamic_cast<const Licq::ProtoSendMessageSignal*>(signal));
117 break;
118 case Licq::ProtocolSignal::SignalNotifyTyping:
119 doNotifyTyping(
120 dynamic_cast<const Licq::ProtoTypingNotificationSignal*>(signal));
121 break;
122 case Licq::ProtocolSignal::SignalGrantAuth:
123 doGrantAuth(dynamic_cast<const Licq::ProtoGrantAuthSignal*>(signal));
124 break;
125 case Licq::ProtocolSignal::SignalRefuseAuth:
126 doRefuseAuth(dynamic_cast<const Licq::ProtoRefuseAuthSignal*>(signal));
127 break;
128 case Licq::ProtocolSignal::SignalRequestInfo:
129 doGetInfo(dynamic_cast<const Licq::ProtoRequestInfo*>(signal));
130 break;
131 case Licq::ProtocolSignal::SignalUpdateInfo:
132 doUpdateInfo(dynamic_cast<const Licq::ProtoUpdateInfoSignal*>(signal));
133 break;
134 case Licq::ProtocolSignal::SignalRequestPicture:
135 doGetPicture(dynamic_cast<const Licq::ProtoRequestPicture*>(signal));
136 break;
137 case Licq::ProtocolSignal::SignalRequestAuth:
138 doRequestAuth(dynamic_cast<const Licq::ProtoRequestAuthSignal*>(signal));
139 break;
140 case Licq::ProtocolSignal::SignalRenameGroup:
141 doRenameGroup(dynamic_cast<const Licq::ProtoRenameGroupSignal*>(signal));
142 break;
143 default:
144 gLog.error("Unknown signal %u", signal->signal());
145 /* Unsupported action, if it has an eventId, cancel it */
146 if (signal->eventId() != 0)
147 Licq::gPluginManager.pushPluginEvent(
148 new Licq::Event(signal, Licq::Event::ResultUnsupported));
149 break;
150 }
151 }
152
doLogon(const Licq::ProtoLogonSignal * signal)153 void Plugin::doLogon(const Licq::ProtoLogonSignal* signal)
154 {
155 unsigned status = signal->status();
156 if (status == User::OfflineStatus)
157 return;
158
159 string username;
160 string password;
161 string host;
162 int port;
163 string resource;
164 gloox::TLSPolicy tlsPolicy;
165 {
166 OwnerReadGuard owner(signal->userId());
167 if (!owner.isLocked())
168 {
169 gLog.error("No owner set");
170 return;
171 }
172
173 username = owner->accountId();
174 password = owner->password();
175 host = owner->serverHost();
176 port = owner->serverPort();
177 resource = owner->resource();
178 tlsPolicy = owner->tlsPolicy();
179 }
180
181 if (myClient == NULL)
182 myClient = new Client(myMainLoop, signal->userId(), username, password,
183 host, port, resource, tlsPolicy);
184 else
185 myClient->setPassword(password);
186
187 if (!myClient->isConnected())
188 {
189 if (!myClient->connect(status))
190 {
191 delete myClient;
192 myClient = NULL;
193 return;
194 }
195 }
196 }
197
doChangeStatus(const Licq::ProtoChangeStatusSignal * signal)198 void Plugin::doChangeStatus(const Licq::ProtoChangeStatusSignal* signal)
199 {
200 assert(myClient != NULL);
201 myClient->changeStatus(signal->status());
202 }
203
doLogoff()204 void Plugin::doLogoff()
205 {
206 if (myClient == NULL)
207 return;
208
209 delete myClient;
210 myClient = NULL;
211 }
212
doSendMessage(const Licq::ProtoSendMessageSignal * signal)213 void Plugin::doSendMessage(const Licq::ProtoSendMessageSignal* signal)
214 {
215 assert(myClient != NULL);
216
217 bool isUrgent = (signal->flags() & Licq::ProtocolSignal::SendUrgent);
218
219 myClient->getSessionManager()->sendMessage(
220 signal->userId().accountId(), signal->message(), isUrgent);
221
222 Licq::EventMsg* message = new Licq::EventMsg(
223 signal->message().c_str(), Licq::EventMsg::TimeNow,
224 Licq::EventMsg::FlagSender);
225
226 Licq::Event* event =
227 new Licq::Event(signal, Licq::Event::ResultAcked, message);
228 event->myCommand = Licq::Event::CommandMessage;
229
230 if (event->m_pUserEvent)
231 {
232 UserWriteGuard user(signal->userId());
233 if (user.isLocked())
234 {
235 event->m_pUserEvent->AddToHistory(*user, false);
236 user->SetLastSentEvent();
237 gOnEventManager.performOnEvent(OnEventData::OnEventMsgSent, *user);
238 }
239 Licq::gStatistics.increase(Licq::Statistics::EventsSentCounter);
240 }
241
242 Licq::gPluginManager.pushPluginEvent(event);
243 }
244
doNotifyTyping(const Licq::ProtoTypingNotificationSignal * signal)245 void Plugin::doNotifyTyping(const Licq::ProtoTypingNotificationSignal* signal)
246 {
247 assert(myClient != NULL);
248
249 myClient->getSessionManager()->notifyTyping(
250 signal->userId().accountId(), signal->active());
251 }
252
doGetInfo(const Licq::ProtoRequestInfo * signal)253 void Plugin::doGetInfo(const Licq::ProtoRequestInfo* signal)
254 {
255 assert(myClient != NULL);
256 myClient->getVCard(signal->userId().accountId());
257
258 Licq::gPluginManager.pushPluginEvent(new Licq::Event(signal));
259 }
260
doUpdateInfo(const Licq::ProtoUpdateInfoSignal * signal)261 void Plugin::doUpdateInfo(const Licq::ProtoUpdateInfoSignal* signal)
262 {
263 assert(myClient != NULL);
264 OwnerReadGuard owner(signal->userId());
265 if (!owner.isLocked())
266 {
267 gLog.error("No owner set");
268 return;
269 }
270
271 UserToVCard vcard(*owner);
272 myClient->setOwnerVCard(vcard);
273
274 Licq::gPluginManager.pushPluginEvent(new Licq::Event(signal));
275 }
276
doGetPicture(const Licq::ProtoRequestPicture * signal)277 void Plugin::doGetPicture(const Licq::ProtoRequestPicture* signal)
278 {
279 assert(myClient != NULL);
280 myClient->getVCard(signal->userId().accountId());
281
282 Licq::gPluginManager.pushPluginEvent(new Licq::Event(signal));
283 }
284
doAddUser(const Licq::ProtoAddUserSignal * signal)285 void Plugin::doAddUser(const Licq::ProtoAddUserSignal* signal)
286 {
287 assert(myClient != NULL);
288 const Licq::UserId userId = signal->userId();
289 gloox::StringList groupNames;
290 getUserGroups(userId, groupNames);
291 myClient->addUser(userId.accountId(), groupNames, true);
292 }
293
doChangeUserGroups(const Licq::ProtoChangeUserGroupsSignal * signal)294 void Plugin::doChangeUserGroups(
295 const Licq::ProtoChangeUserGroupsSignal* signal)
296 {
297 assert(myClient != NULL);
298 const Licq::UserId userId = signal->userId();
299 gloox::StringList groupNames;
300 getUserGroups(userId, groupNames);
301 myClient->changeUserGroups(userId.accountId(), groupNames);
302 }
303
doRemoveUser(const Licq::ProtoRemoveUserSignal * signal)304 void Plugin::doRemoveUser(const Licq::ProtoRemoveUserSignal* signal)
305 {
306 assert(myClient != NULL);
307 myClient->removeUser(signal->userId().accountId());
308 Licq::gUserManager.removeLocalUser(signal->userId());
309 }
310
doRenameUser(const Licq::ProtoRenameUserSignal * signal)311 void Plugin::doRenameUser(const Licq::ProtoRenameUserSignal* signal)
312 {
313 assert(myClient != NULL);
314 string newName;
315 {
316 UserReadGuard u(signal->userId());
317 if (!u.isLocked())
318 return;
319 newName = u->getAlias();
320 }
321
322 myClient->renameUser(signal->userId().accountId(), newName);
323 }
324
doGrantAuth(const Licq::ProtoGrantAuthSignal * signal)325 void Plugin::doGrantAuth(const Licq::ProtoGrantAuthSignal* signal)
326 {
327 assert(myClient != NULL);
328 myClient->grantAuthorization(signal->userId().accountId());
329
330 Licq::gPluginManager.pushPluginEvent(new Licq::Event(signal));
331 }
332
doRefuseAuth(const Licq::ProtoRefuseAuthSignal * signal)333 void Plugin::doRefuseAuth(const Licq::ProtoRefuseAuthSignal* signal)
334 {
335 assert(myClient != NULL);
336 myClient->refuseAuthorization(signal->userId().accountId());
337
338 Licq::gPluginManager.pushPluginEvent(new Licq::Event(signal));
339 }
340
doRequestAuth(const Licq::ProtoRequestAuthSignal * signal)341 void Plugin::doRequestAuth(const Licq::ProtoRequestAuthSignal* signal)
342 {
343 assert(myClient != NULL);
344 myClient->requestAuthorization(
345 signal->userId().accountId(), signal->message());
346 }
347
doRenameGroup(const Licq::ProtoRenameGroupSignal * signal)348 void Plugin::doRenameGroup(const Licq::ProtoRenameGroupSignal* signal)
349 {
350 Licq::UserListGuard userList(signal->userId());
351 BOOST_FOREACH(Licq::User* licqUser, **userList)
352 {
353 Licq::UserReadGuard user(licqUser);
354
355 if (!user->isInGroup(signal->groupId()))
356 continue;
357
358 // User is member of renamed group, get complete group list and update
359 // server
360 gloox::StringList groupNames;
361 const Licq::UserGroupList& groups = user->GetGroups();
362 BOOST_FOREACH(int groupId, groups)
363 {
364 string groupName = Licq::gUserManager.GetGroupNameFromGroup(groupId);
365 if (!groupName.empty())
366 groupNames.push_back(groupName);
367 }
368 myClient->changeUserGroups(user->id().accountId(), groupNames);
369 }
370 }
371
getUserGroups(const Licq::UserId & userId,gloox::StringList & retGroupNames)372 void Plugin::getUserGroups(const Licq::UserId& userId,
373 gloox::StringList& retGroupNames)
374 {
375 UserReadGuard user(userId);
376 if (!user.isLocked())
377 return;
378
379 const Licq::UserGroupList& groups = user->GetGroups();
380 BOOST_FOREACH(int groupId, groups)
381 {
382 string groupName = Licq::gUserManager.GetGroupNameFromGroup(groupId);
383 if (!groupName.empty())
384 retGroupNames.push_back(groupName);
385 }
386 }
387