1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2000-2014 Licq developers <licq-dev@googlegroups.com>
4 *
5 * Licq is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Licq is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Licq; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "rms.h"
21 #include "pluginversion.h"
22
23 #include <boost/foreach.hpp>
24 #include <cctype>
25 #include <climits>
26 #include <cstdio>
27 #include <cstring>
28 #include <sstream>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <cerrno>
33
34 #include <licq/buffer.h>
35 #include <licq/contactlist/group.h>
36 #include <licq/contactlist/owner.h>
37 #include <licq/contactlist/user.h>
38 #include <licq/contactlist/usermanager.h>
39 #include <licq/daemon.h>
40 #include <licq/event.h>
41 #include <licq/icq/icq.h>
42 #include <licq/inifile.h>
43 #include <licq/logging/log.h>
44 #include <licq/logging/logservice.h>
45 #include <licq/logging/logutils.h>
46 #include <licq/mainloop.h>
47 #include <licq/plugin/pluginmanager.h>
48 #include <licq/pluginsignal.h>
49 #include <licq/protocolmanager.h>
50 #include <licq/translator.h>
51 #include <licq/userevents.h>
52
53 using Licq::UserId;
54 using Licq::gLog;
55 using Licq::gPluginManager;
56 using Licq::gProtocolManager;
57 using Licq::gUserManager;
58 using std::string;
59
60 CLicqRMS *licqRMS = NULL;
61
62 // 100 - information
63 const unsigned short CODE_QUIT = 100;
64 const unsigned short CODE_HELP = 101;
65 const unsigned short CODE_COMMANDxSTART = 102;
66 const unsigned short CODE_LOG = 103;
67 // 200 - fulfilled
68 const unsigned short CODE_HELLO = 200;
69 const unsigned short CODE_USERxINFO = 201;
70 const unsigned short CODE_STATUS = 202;
71 const unsigned short CODE_RESULTxSUCCESS = 203;
72 const unsigned short CODE_LISTxUSER = 204;
73 const unsigned short CODE_LISTxGROUP = 205;
74 const unsigned short CODE_LISTxDONE = 206;
75 const unsigned short CODE_LOGxTYPE = 207;
76 const unsigned short CODE_VIEWxMSG = 208;
77 const unsigned short CODE_VIEWxURL = 209;
78 const unsigned short CODE_VIEWxCHAT= 210;
79 const unsigned short CODE_VIEWxFILE = 211;
80 const unsigned short CODE_STATUSxDONE = 212;
81 const unsigned short CODE_VIEWxTIME = 220;
82 const unsigned short CODE_VIEWxFLAGS = 221;
83 const unsigned short CODE_VIEWxTEXTxSTART = 222;
84 const unsigned short CODE_VIEWxTEXTxEND = 223;
85 const unsigned short CODE_ADDUSERxDONE = 224;
86 const unsigned short CODE_REMUSERxDONE = 225;
87 const unsigned short CODE_SECURExOPEN = 226;
88 const unsigned short CODE_SECURExCLOSE = 227;
89 const unsigned short CODE_SECURExSTAT = 228;
90 const unsigned short CODE_NOTIFYxON = 229;
91 const unsigned short CODE_NOTIFYxOFF = 230;
92 const unsigned short CODE_HISTORYxEND = 231;
93 const unsigned short CODE_VIEWxUNKNOWN = 299;
94 // 300 - further action required
95 const unsigned short CODE_ENTERxUIN = 300;
96 const unsigned short CODE_ENTERxPASSWORD = 301;
97 const unsigned short CODE_ENTERxTEXT = 302;
98 const unsigned short CODE_ENTERxLINE = 303;
99 // 400 - client error
100 const unsigned short CODE_INVALID = 400;
101 const unsigned short CODE_INVALIDxCOMMAND = 401;
102 const unsigned short CODE_INVALIDxUSER = 402;
103 const unsigned short CODE_INVALIDxSTATUS = 403;
104 const unsigned short CODE_EVENTxCANCELLED = 404;
105 const unsigned short CODE_VIEWxNONE = 405;
106 // 500 - server error
107 const unsigned short CODE_EVENTxTIMEDOUT = 500;
108 const unsigned short CODE_EVENTxFAILED = 501;
109 const unsigned short CODE_EVENTxERROR = 502;
110 const unsigned short CODE_ADDUSERxERROR = 503;
111 const unsigned short CODE_SECURExNOTCOMPILED = 504;
112
113 const unsigned short CODE_NOTIFYxSTATUS = 600;
114 const unsigned short CODE_NOTIFYxMESSAGE = 601;
115
116 const unsigned short STATE_UIN = 1;
117 const unsigned short STATE_PASSWORD = 2;
118 const unsigned short STATE_COMMAND = 3;
119 const unsigned short STATE_ENTERxMESSAGE = 4;
120 const unsigned short STATE_ENTERxURLxDESCRIPTION = 5;
121 const unsigned short STATE_ENTERxURL = 6;
122 const unsigned short STATE_ENTERxAUTOxRESPONSE = 7;
123
124 #define NEXT_WORD(s) while (*s != '\0' && *s == ' ') s++;
125
126 struct Command
127 {
128 const char *name;
129 int (CRMSClient::*fcn)();
130 const char *help;
131 };
132
133 static struct Command commands[] =
134 {
135 { "ADDUSER", &CRMSClient::Process_ADDUSER,
136 "Add user to contact list { <id>[.<protocol>] }." },
137 { "AR", &CRMSClient::Process_AR,
138 "Set your (or a user custom) auto response { [ <id>[.<protocol>] ] }." },
139 { "GROUPS", &CRMSClient::Process_GROUPS,
140 "Show list of groups." },
141 { "HELP", &CRMSClient::Process_HELP,
142 "Print out help on commands." },
143 { "HISTORY", &CRMSClient::Process_HISTORY,
144 "View history of specific user { <id>[.<protocol>] [<length>] [<offset>]}." },
145 { "INFO", &CRMSClient::Process_INFO,
146 "Print out user information. Argument is the id and protocol, or none for personal." },
147 { "LIST", &CRMSClient::Process_LIST,
148 "List users { [ <group #> ] [ <online|offline|all> ] [ <format> ] }." },
149 { "LOG", &CRMSClient::Process_LOG,
150 "Dump log messages { <log types> }." },
151 { "MESSAGE", &CRMSClient::Process_MESSAGE,
152 "Send a message { <id>[.<protocol>] }." },
153 { "QUIT", &CRMSClient::Process_QUIT,
154 "Close the connection. With an argument of 1 causes the plugin to unload." },
155 { "REMUSER", &CRMSClient::Process_REMUSER,
156 "Remove user from contact list { <id>[.<protocol>] }." },
157 { "SECURE", &CRMSClient::Process_SECURE,
158 "Open/close/check secure channel { <uin> [ <open|close> ] } ." },
159 { "STATUS", &CRMSClient::Process_STATUS,
160 "Set or show status. Argument is new status and protocol, or blank to display current. { [ <status>[.<protocol>] ] }." },
161 { "TERM", &CRMSClient::Process_TERM,
162 "Terminate the licq daemon." },
163 { "VIEW", &CRMSClient::Process_VIEW,
164 "View event (next or specific user) { [ <id>[.<protocol>] ] }." },
165 { "URL", &CRMSClient::Process_URL,
166 "Send a url { <id>[.<protocol>] }." },
167 { "NOTIFY", &CRMSClient::Process_NOTIFY,
168 "Notify events" },
169 };
170
171 static const unsigned short NUM_COMMANDS = sizeof(commands)/sizeof(*commands);
172
173 /*---------------------------------------------------------------------------
174 * CLicqRMS::Constructor
175 *-------------------------------------------------------------------------*/
CLicqRMS(const std::string & configFile)176 CLicqRMS::CLicqRMS(const std::string& configFile)
177 : m_bEnabled(true),
178 myPort(0),
179 myConfigFile(configFile)
180 {
181 licqRMS = this;
182 server = NULL;
183 }
184
185
186 /*---------------------------------------------------------------------------
187 * CLicqRMS::Destructor
188 *-------------------------------------------------------------------------*/
~CLicqRMS()189 CLicqRMS::~CLicqRMS()
190 {
191 delete server;
192 ClientList::iterator iter;
193 for (iter = clients.begin(); iter != clients.end(); iter++)
194 delete *iter;
195 }
196
197 /*---------------------------------------------------------------------------
198 * CLicqRMS::Shutdown
199 *-------------------------------------------------------------------------*/
Shutdown()200 void CLicqRMS::Shutdown()
201 {
202 gLog.info("Shutting down remote manager server");
203
204 if (myLogSink)
205 Licq::gLogService.unregisterLogSink(myLogSink);
206 }
207
init(int argc,char ** argv)208 bool CLicqRMS::init(int argc, char** argv)
209 {
210 //char *LocaleVal = new char;
211 //LocaleVal = setlocale (LC_ALL, "");
212 //bindtextdomain (PACKAGE, LOCALEDIR);
213 //textdomain (PACKAGE);
214
215 // parse command line for arguments
216 int i = 0;
217 while ( (i = getopt(argc, argv, "dp:")) > 0)
218 {
219 switch (i)
220 {
221 case 'd': // enable
222 m_bEnabled = false;
223 break;
224 case 'p':
225 myPort = atol(optarg);
226 break;
227 }
228 }
229 return true;
230 }
231
232 /*---------------------------------------------------------------------------
233 * CLicqRMS::Run
234 *-------------------------------------------------------------------------*/
run()235 int CLicqRMS::run()
236 {
237 setSignalMask(Licq::PluginSignal::SignalAll);
238
239 Licq::IniFile conf(myConfigFile);
240 if (conf.loadFile())
241 {
242 conf.setSection("RMS");
243
244 // Ignore port in config if given on command line
245 if (myPort == 0)
246 conf.get("Port", myPort, 0);
247
248 string protocolStr;
249 conf.get("AuthProtocol", protocolStr, "ICQ");
250 conf.get("AuthUser", myAuthUser);
251 if (protocolStr == "Config")
252 {
253 // Get password from config file
254 conf.get("AuthPassword", myAuthPassword);
255
256 // Make sure we got something instead of opening a security problem
257 if (myAuthUser.empty() || myAuthPassword.empty())
258 {
259 gLog.warning("Missing value for AuthUser or AuthPassword in configuration, "
260 "login will not be possible.");
261 }
262 }
263 else
264 {
265 // Parse protocol id
266 unsigned long protocolId = Licq::protocolId_fromString(protocolStr);
267 if (protocolId == 0 || myAuthUser.empty())
268 {
269 // Invalid
270 gLog.warning("Invalid value for AuthProtocol or AuthUser in configuration, "
271 "login will not be possible");
272 }
273 else
274 myAuthOwnerId = Licq::UserId(protocolId, myAuthUser);
275 }
276 }
277
278 server = new Licq::TCPSocket();
279
280 if (Licq::gDaemon.tcpPortsLow() != 0 && myPort == 0)
281 {
282 if (!Licq::gDaemon.StartTCPServer(server))
283 {
284 Shutdown();
285 return 1;
286 }
287 }
288 else
289 {
290 if (!server->StartServer(myPort))
291 {
292 gLog.error("Could not start server on port %u, "
293 "maybe this port is already in use?", myPort);
294 Shutdown();
295 return 1;
296 };
297 }
298
299 gLog.info("RMS server started on port %d", server->getLocalPort());
300 myMainLoop.addSocket(server, this);
301 myMainLoop.addRawFile(getReadPipe(), this);
302
303 myMainLoop.run();
304
305 Shutdown();
306 return 0;
307 }
308
isEnabled() const309 bool CLicqRMS::isEnabled() const
310 {
311 return m_bEnabled;
312 }
313
rawFileEvent(int,int fd,int)314 void CLicqRMS::rawFileEvent(int /*id*/, int fd, int /* revents */)
315 {
316 if (fd == getReadPipe())
317 ProcessPipe();
318 else if (myLogSink && fd == myLogSink->getReadPipe())
319 ProcessLog();
320 }
321
setupLogSink()322 void CLicqRMS::setupLogSink()
323 {
324 if (!myLogSink)
325 {
326 myLogSink.reset(new Licq::PluginLogSink);
327 Licq::gLogService.registerLogSink(myLogSink);
328 myMainLoop.addRawFile(myLogSink->getReadPipe(), this);
329 }
330
331 unsigned int mask = 0;
332 BOOST_FOREACH(CRMSClient* client, clients)
333 mask |= client->myLogLevelsBitmask;
334 myLogSink->setLogLevelsFromBitmask(mask);
335 }
336
deleteClient(CRMSClient * client)337 void CLicqRMS::deleteClient(CRMSClient* client)
338 {
339 delete client;
340
341 for (ClientList::iterator iter = clients.begin(); iter != clients.end(); ++iter)
342 if (*iter == client)
343 {
344 clients.erase(iter);
345 break;
346 }
347
348 if (myLogSink)
349 setupLogSink();
350 }
351
352 /*---------------------------------------------------------------------------
353 * CLicqRMS::ProcessPipe
354 *-------------------------------------------------------------------------*/
ProcessPipe()355 void CLicqRMS::ProcessPipe()
356 {
357 char buf;
358 read(getReadPipe(), &buf, 1);
359 switch (buf)
360 {
361 case PipeSignal:
362 if (m_bEnabled)
363 ProcessSignal(popSignal().get());
364 else
365 popSignal();
366 break;
367
368 case PipeEvent:
369 // An event is pending (should never happen)
370 if (m_bEnabled)
371 ProcessEvent(popEvent().get());
372 else
373 popEvent();
374 break;
375
376 case PipeShutdown:
377 gLog.info("Exiting");
378 myMainLoop.quit();
379 break;
380
381 case PipeDisable:
382 gLog.info("Disabling");
383 m_bEnabled = false;
384 break;
385
386 case PipeEnable:
387 gLog.info("Enabling");
388 m_bEnabled = true;
389 break;
390
391 default:
392 gLog.warning("Unknown notification type from daemon: %c", buf);
393 }
394 }
395
396
397 /*---------------------------------------------------------------------------
398 * CLicqRMS::ProcessLog
399 *-------------------------------------------------------------------------*/
ProcessLog()400 void CLicqRMS::ProcessLog()
401 {
402 using namespace Licq::LogUtils;
403
404 Licq::LogSink::Message::Ptr message = myLogSink->popMessage();
405 const char* level = levelToShortString(message->level);
406 const std::string time = timeToString(message->time);
407
408 BOOST_FOREACH(CRMSClient* client, clients)
409 {
410 if (levelInBitmask(message->level, client->myLogLevelsBitmask))
411 {
412 if (packetInBitmask(client->myLogLevelsBitmask)
413 && !message->packet.empty())
414 {
415 ::fprintf(client->fs, "%d %s [%s] %s: %s\n%s\n",
416 CODE_LOG, time.c_str(), level,
417 message->sender.c_str(), message->text.c_str(),
418 packetToString(message).c_str());
419 }
420 else
421 {
422 ::fprintf(client->fs, "%d %s [%s] %s: %s\n",
423 CODE_LOG, time.c_str(), level,
424 message->sender.c_str(), message->text.c_str());
425 }
426 ::fflush(client->fs);
427 }
428 }
429 }
430
431
432 /*---------------------------------------------------------------------------
433 * CLicqRMS::ProcessSignal
434 *-------------------------------------------------------------------------*/
ProcessSignal(const Licq::PluginSignal * s)435 void CLicqRMS::ProcessSignal(const Licq::PluginSignal* s)
436 {
437 switch (s->signal())
438 {
439 case Licq::PluginSignal::SignalUser:
440 if (s->subSignal() == Licq::PluginSignal::UserStatus)
441 {
442 Licq::UserReadGuard u(s->userId());
443 if (u.isLocked())
444 {
445 ClientList::iterator iter;
446 for (iter = clients.begin(); iter != clients.end(); iter++)
447 {
448 if ((*iter)->m_bNotify)
449 {
450 fprintf((*iter)->fs, "%d %s\n", CODE_NOTIFYxSTATUS, u->usprintf("%u %P %-20a %3m %s").c_str());
451 fflush((*iter)->fs);
452 }
453 }
454 }
455 break;
456 }
457 else if (s->subSignal() == Licq::PluginSignal::UserEvents)
458 {
459 Licq::UserReadGuard u(s->userId());
460 if (u.isLocked())
461 {
462 ClientList::iterator iter;
463 for (iter = clients.begin(); iter != clients.end(); iter++)
464 {
465 if ((*iter)->m_bNotify)
466 {
467 fprintf((*iter)->fs, "%d %s\n", CODE_NOTIFYxMESSAGE, u->usprintf("%u %P %3m").c_str());
468 fflush((*iter)->fs);
469 }
470 }
471 }
472 }
473 default:
474 break;
475
476 }
477 }
478
479 /*---------------------------------------------------------------------------
480 * CLicqRMS::ProcessEvent
481 *-------------------------------------------------------------------------*/
ProcessEvent(const Licq::Event * e)482 void CLicqRMS::ProcessEvent(const Licq::Event* e)
483 {
484 ClientList ::iterator iter;
485 for (iter = clients.begin(); iter != clients.end(); iter++)
486 {
487 if ((*iter)->ProcessEvent(e))
488 break;
489 }
490 }
491
socketEvent(int,Licq::INetSocket * inetSocket,int)492 void CLicqRMS::socketEvent(int /*id*/, Licq::INetSocket* inetSocket, int /* revents */)
493 {
494 if (inetSocket == server)
495 {
496 server->Lock();
497 clients.push_back(new CRMSClient(server));
498 server->Unlock();
499 }
500 }
501
502 /*---------------------------------------------------------------------------
503 * CRMSClient::constructor
504 *-------------------------------------------------------------------------*/
CRMSClient(Licq::TCPSocket * sin)505 CRMSClient::CRMSClient(Licq::TCPSocket* sin)
506 : myLogLevelsBitmask(0)
507 {
508 sin->RecvConnection(sock);
509 licqRMS->myMainLoop.addSocket(&sock, this);
510
511 gLog.info("Client connected from %s", sock.getRemoteIpString().c_str());
512 fs = fdopen(sock.Descriptor(), "r+");
513 fprintf(fs, "Licq Remote Management Server v" PLUGIN_VERSION_STRING "\n"
514 "%d Enter your UIN:\n", CODE_ENTERxUIN);
515 fflush(fs);
516
517 m_szCheckId = 0;
518 m_nState = STATE_UIN;
519 data_line_pos = 0;
520 m_bNotify = false;
521 }
522
523
524 /*---------------------------------------------------------------------------
525 * CRMSClient::destructor
526 *-------------------------------------------------------------------------*/
~CRMSClient()527 CRMSClient::~CRMSClient()
528 {
529 licqRMS->myMainLoop.removeSocket(&sock);
530 sock.CloseConnection();
531
532 if (m_szCheckId)
533 free(m_szCheckId);
534 }
535
socketEvent(int,Licq::INetSocket *,int)536 void CRMSClient::socketEvent(int /*id*/, Licq::INetSocket* /*inetSocket*/, int /*revents*/)
537 {
538 if (Activity() == -1)
539 {
540 licqRMS->deleteClient(this);
541 }
542 }
543
544 /*---------------------------------------------------------------------------
545 * CRMSClient::ParseUser
546 *-------------------------------------------------------------------------*/
ParseUser(const string & strData)547 void CRMSClient::ParseUser(const string& strData)
548 {
549 myUserId = UserId();
550 unsigned long protocolId = 0;
551 string accountId;
552
553 size_t pos = strData.rfind('.');
554 if (pos != string::npos)
555 {
556 // Protocol specified
557 protocolId = Licq::protocolId_fromString(strData.substr(pos+1));
558 accountId = strData.substr(0, pos-1);
559 }
560 else
561 accountId = strData;
562
563 // Try and find an existing user that matches
564 Licq::UserListGuard userList(protocolId);
565 BOOST_FOREACH(const Licq::User* user, **userList)
566 {
567 if (user->accountId() == accountId)
568 {
569 myUserId = user->id();
570 return;
571 }
572 }
573
574 if (protocolId != 0)
575 {
576 // Use first owner for protocol
577 Licq::OwnerListGuard ownerList(protocolId);
578 if (!ownerList->empty())
579 {
580 myUserId = Licq::UserId((*ownerList->begin())->id(), accountId);
581 return;
582 }
583 }
584
585 // Failed
586 myUserId = Licq::UserId();
587 }
588
589 /*---------------------------------------------------------------------------
590 * CRMSClient::ProcessEvent
591 *-------------------------------------------------------------------------*/
ProcessEvent(const Licq::Event * e)592 bool CRMSClient::ProcessEvent(const Licq::Event* e)
593 {
594 TagList::iterator iter;
595 for (iter = tags.begin(); iter != tags.end(); iter++)
596 {
597 if ( e->Equals(*iter) ) break;
598 }
599 if (iter == tags.end()) return false;
600
601 unsigned long tag = *iter;
602 tags.erase(iter);
603
604 unsigned short nCode = 0;
605 const char *szr = NULL;
606 switch(e->Result())
607 {
608 case Licq::Event::ResultAcked:
609 case Licq::Event::ResultSuccess:
610 nCode = CODE_RESULTxSUCCESS;
611 szr = "done";
612 break;
613 case Licq::Event::ResultTimedout:
614 nCode = CODE_EVENTxTIMEDOUT;
615 szr = "timed out";
616 break;
617 case Licq::Event::ResultFailed:
618 case Licq::Event::ResultUnsupported:
619 nCode = CODE_EVENTxFAILED;
620 szr = "failed";
621 break;
622 case Licq::Event::ResultError:
623 nCode = CODE_EVENTxERROR;
624 szr = "error";
625 break;
626 case Licq::Event::ResultCancelled:
627 nCode = CODE_EVENTxCANCELLED;
628 szr = "cancelled";
629 break;
630 }
631 fprintf(fs, "%d [%ld] Event %s.\n", nCode, tag, szr);
632 fflush(fs);
633
634 return true;
635 }
636
637
638 /*---------------------------------------------------------------------------
639 * CRMSClient::Activity
640 *-------------------------------------------------------------------------*/
Activity()641 int CRMSClient::Activity()
642 {
643 Licq::Buffer buf;
644 if (!sock.receive(buf))
645 {
646 gLog.info("Client %s disconnected", sock.getRemoteIpString().c_str());
647 return -1;
648 }
649
650 char* in = buf.getDataStart();
651 char* last = buf.getDataPosWrite();
652
653 do
654 {
655 while (in != last && *in != '\n')
656 {
657 if (!iscntrl(*in) && data_line_pos < MAX_LINE_LENGTH)
658 data_line[data_line_pos++] = *in;
659 in++;
660 }
661
662 if (in != last && *in == '\n')
663 {
664 data_line[data_line_pos] = '\0';
665 in++;
666 if (StateMachine() == -1) return -1;
667
668 data_line_pos = 0;
669 }
670
671 } while (in != last);
672
673 data_line[data_line_pos] = '\0';
674
675 return 0;
676 }
677
678
679 /*---------------------------------------------------------------------------
680 * CRMSClient::StateMachine
681 *-------------------------------------------------------------------------*/
StateMachine()682 int CRMSClient::StateMachine()
683 {
684 switch(m_nState)
685 {
686 case STATE_UIN:
687 {
688 myLoginUser = data_line;
689 fprintf(fs, "%d Enter your password:\n", CODE_ENTERxPASSWORD);
690 fflush(fs);
691 m_nState = STATE_PASSWORD;
692 break;
693 }
694 case STATE_PASSWORD:
695 {
696 bool ok = false;
697 string name;
698 if (licqRMS->myAuthOwnerId.isValid())
699 {
700 // Check against protocol owner
701 Licq::OwnerReadGuard o(licqRMS->myAuthOwnerId);
702 if (!o.isLocked())
703 return -1;
704 ok = (myLoginUser == o->accountId() && data_line == o->password());
705 name = o->getAlias();
706 }
707 else if (!licqRMS->myAuthUser.empty() && !licqRMS->myAuthPassword.empty())
708 {
709 // User and password specified in RMS config
710 ok = (myLoginUser == licqRMS->myAuthUser &&
711 data_line == licqRMS->myAuthPassword);
712 name = myLoginUser;
713 }
714
715 if (!ok)
716 {
717 gLog.info("Client failed validation from %s",
718 sock.getRemoteIpString().c_str());
719 fprintf(fs, "%d Invalid ID/Password.\n", CODE_INVALID);
720 fflush(fs);
721 return -1;
722 }
723 gLog.info("Client validated from %s",
724 sock.getRemoteIpString().c_str());
725 fprintf(fs, "%d Hello %s. Type HELP for assistance.\n", CODE_HELLO,
726 name.c_str());
727 fflush(fs);
728 m_nState = STATE_COMMAND;
729 break;
730 }
731 case STATE_COMMAND:
732 {
733 if (ProcessCommand() == -1) return -1;
734 break;
735 }
736 case STATE_ENTERxMESSAGE:
737 {
738 if (AddLineToText())
739 return Process_MESSAGE_text();
740 break;
741 }
742 case STATE_ENTERxURLxDESCRIPTION:
743 {
744 if (AddLineToText())
745 return Process_URL_text();
746 break;
747 }
748 case STATE_ENTERxURL:
749 {
750 return Process_URL_url();
751 }
752 case STATE_ENTERxAUTOxRESPONSE:
753 {
754 if (AddLineToText())
755 return Process_AR_text();
756 break;
757 }
758 }
759 return 0;
760 }
761
762
763 /*---------------------------------------------------------------------------
764 * CRMSClient::AddLineToText
765 *-------------------------------------------------------------------------*/
AddLineToText()766 bool CRMSClient::AddLineToText()
767 {
768 if (data_line[0] == '.' && data_line[1] == '\0') return true;
769
770 myText += data_line;
771 myText += "\n";
772
773 return false;
774 }
775
776
777 /*---------------------------------------------------------------------------
778 * CRMSClient::ProcessCommand
779 *-------------------------------------------------------------------------*/
ProcessCommand()780 int CRMSClient::ProcessCommand()
781 {
782 data_arg = data_line;
783 while (*data_arg != '\0' && *data_arg != ' ') data_arg++;
784 if (*data_arg == ' ')
785 {
786 *data_arg++ = '\0';
787 NEXT_WORD(data_arg);
788 }
789
790 for (unsigned short i = 0; i < NUM_COMMANDS; i++)
791 {
792 if (strcasecmp(commands[i].name, data_line) == 0)
793 return (this->*(commands[i].fcn))();
794 }
795
796 fprintf(fs, "%d Invalid command. Type HELP for assistance.\n",
797 CODE_INVALIDxCOMMAND);
798 return fflush(fs);
799 }
800
801
802 /*---------------------------------------------------------------------------
803 * CRMSClient::Process_INFO
804 *-------------------------------------------------------------------------*/
Process_INFO()805 int CRMSClient::Process_INFO()
806 {
807 ParseUser(data_arg);
808
809 //XXX Handle the case when we have the owner
810
811 // Print the user info
812 Licq::UserReadGuard u(myUserId);
813 if (!u.isLocked())
814 {
815 fprintf(fs, "%d No such user.\n", CODE_INVALIDxUSER);
816 return fflush(fs);
817 }
818
819 fprintf(fs, "%d %s Alias: %s\n", CODE_USERxINFO, u->accountId().c_str(),
820 u->getAlias().c_str());
821 fprintf(fs, "%d %s Status: %s\n", CODE_USERxINFO, u->accountId().c_str(),
822 u->statusString().c_str());
823 fprintf(fs, "%d %s First Name: %s\n", CODE_USERxINFO, u->accountId().c_str(),
824 u->getFirstName().c_str());
825 fprintf(fs, "%d %s Last Name: %s\n", CODE_USERxINFO, u->accountId().c_str(),
826 u->getLastName().c_str());
827 fprintf(fs, "%d %s Email 1: %s\n", CODE_USERxINFO, u->accountId().c_str(),
828 u->getUserInfoString("Email1").c_str());
829 fprintf(fs, "%d %s Email 2: %s\n", CODE_USERxINFO, u->accountId().c_str(),
830 u->getUserInfoString("Email2").c_str());
831
832 return fflush(fs);
833 }
834
835
836 /*---------------------------------------------------------------------------
837 * CRMSClient::Process_STATUS
838 *
839 * Command:
840 * STATUS [ status | protocol ]
841 *
842 * Response:
843 *
844 *-------------------------------------------------------------------------*/
Process_STATUS()845 int CRMSClient::Process_STATUS()
846 {
847 // Show status
848 if (data_arg[0] == '\0')
849 {
850 Licq::OwnerListGuard ownerList;
851 BOOST_FOREACH(const Licq::Owner* owner, **ownerList)
852 {
853 Licq::ProtocolPlugin::Ptr protocol = Licq::gPluginManager.getProtocolPlugin(owner->protocolId());
854 Licq::OwnerReadGuard o(owner);
855 fprintf(fs, "%d %s %s %s\n", CODE_STATUS, o->accountId().c_str(),
856 protocol->name().c_str(), o->statusString().c_str());
857 }
858 fprintf(fs, "%d\n", CODE_STATUSxDONE);
859 return fflush(fs);
860 }
861
862 // Set status
863 string strData(data_arg);
864 string::size_type nPos = strData.find_last_of(".");
865 string status;
866
867 // Get a list of owners first since we can't call changeStatus with list locked
868 std::list<Licq::UserId> owners;
869 if (nPos == string::npos)
870 {
871 status = data_arg;
872
873 Licq::OwnerListGuard ownerList;
874 BOOST_FOREACH(const Licq::Owner* o, **ownerList)
875 owners.push_back(o->id());
876 }
877 else
878 {
879 status = string(strData, 0, nPos);
880 string param(strData, nPos+1);
881 unsigned long protocolId = Licq::protocolId_fromString(param);
882
883 Licq::OwnerListGuard ownerList;
884 BOOST_FOREACH(const Licq::Owner* o, **ownerList)
885 if (o->protocolId() == protocolId || o->accountId() == param)
886 owners.push_back(o->id());
887 }
888
889 BOOST_FOREACH(const Licq::UserId& ownerId, owners)
890 changeStatus(ownerId, status);
891
892 fprintf(fs, "%d Done setting status\n", CODE_STATUSxDONE);
893 return fflush(fs);
894 }
895
changeStatus(const Licq::UserId & ownerId,const string & strStatus)896 int CRMSClient::changeStatus(const Licq::UserId& ownerId, const string& strStatus)
897 {
898 unsigned status;
899 if (!Licq::User::stringToStatus(strStatus, status))
900 {
901 fprintf(fs, "%d Invalid status.\n", CODE_INVALIDxSTATUS);
902 return -1;
903 }
904 if (status == Licq::User::OfflineStatus)
905 {
906 fprintf(fs, "%d [0] Logging off %s.\n", CODE_COMMANDxSTART, strStatus.c_str());
907 fflush(fs);
908 gProtocolManager.setStatus(ownerId, Licq::User::OfflineStatus);
909 fprintf(fs, "%d [0] Event done.\n", CODE_STATUSxDONE);
910 return 0;
911 }
912 else
913 {
914 bool b;
915 {
916 Licq::OwnerReadGuard o(ownerId);
917 if (!o.isLocked())
918 {
919 fprintf(fs, "%d Invalid protocol.\n", CODE_INVALIDxUSER);
920 return -1;
921 }
922 b = !o->isOnline();
923 }
924 unsigned long tag = gProtocolManager.setStatus(ownerId, status);
925 if (b)
926 fprintf(fs, "%d [%ld] Logging on to %s.\n", CODE_COMMANDxSTART, tag, strStatus.c_str());
927 else
928 fprintf(fs, "%d [%ld] Setting status for %s.\n", CODE_COMMANDxSTART, tag, strStatus.c_str());
929 tags.push_back(tag);
930 }
931 return 0;
932 }
933
934 /*---------------------------------------------------------------------------
935 * CRMSClient::Process_QUIT
936 *-------------------------------------------------------------------------*/
Process_QUIT()937 int CRMSClient::Process_QUIT()
938 {
939 fprintf(fs, "%d Sayonara.\n", CODE_QUIT);
940 fflush(fs);
941 if (strtoul(data_arg, (char**)NULL, 10) > 0)
942 licqRMS->myMainLoop.quit();
943 return -1;
944 }
945
946
947 /*---------------------------------------------------------------------------
948 * CRMSClient::Process_TERM
949 *-------------------------------------------------------------------------*/
Process_TERM()950 int CRMSClient::Process_TERM()
951 {
952 Licq::gDaemon.Shutdown();
953 return -1;
954 }
955
956
957 /*---------------------------------------------------------------------------
958 * CRMSClient::Process_HELP
959 *-------------------------------------------------------------------------*/
Process_HELP()960 int CRMSClient::Process_HELP()
961 {
962 for (unsigned short i = 0; i < NUM_COMMANDS; i++)
963 {
964 fprintf(fs, "%d %s: %s\n", CODE_HELP, commands[i].name, commands[i].help);
965 }
966 return fflush(fs);
967 }
968
969
970 /*---------------------------------------------------------------------------
971 * CRMSClient::Process_GROUPS
972 *
973 * Command:
974 * GROUPS
975 * Prints out the list of groups as follows.
976 *
977 * Response:
978 * CODE_LISTxGROUP 000 All Users
979 * CODE_LISTxGROUP 001 First Group
980 * ...
981 * CODE_LISTxDONE
982 *
983 *-------------------------------------------------------------------------*/
Process_GROUPS()984 int CRMSClient::Process_GROUPS()
985 {
986 fprintf(fs, "%d 000 All Users\n", CODE_LISTxGROUP);
987 int i = 1;
988 Licq::GroupListGuard groupList;
989 BOOST_FOREACH(const Licq::Group* group, **groupList)
990 {
991 Licq::GroupReadGuard pGroup(group);
992 fprintf(fs, "%d %03d %s\n", CODE_LISTxGROUP, i, pGroup->name().c_str());
993 ++i;
994 }
995 fprintf(fs, "%d\n", CODE_LISTxDONE);
996
997 return fflush(fs);
998 }
999
Process_HISTORY()1000 int CRMSClient::Process_HISTORY()
1001 {
1002 char* s = strtok(data_arg, " ");
1003 if (s == NULL)
1004 {
1005 fprintf(fs, "%d Invalid User.\n", CODE_INVALIDxUSER);
1006 return fflush(fs);
1007 }
1008 ParseUser(s);
1009
1010 int length = 10;
1011 s = strtok(NULL, " ");
1012 if (s != NULL)
1013 length = atoi(s);
1014
1015 int offset = 0;
1016 s = strtok(NULL, " ");
1017 if (s != NULL)
1018 offset = atoi(s);
1019
1020 Licq::HistoryList history;
1021 string userAlias;
1022 string ownerAlias = "me";
1023
1024 {
1025 Licq::UserReadGuard u(myUserId);
1026 if (!u.isLocked())
1027 {
1028 fprintf(fs, "%d Invalid User (%s).\n", CODE_INVALIDxUSER, myUserId.toString().c_str());
1029 return fflush(fs);
1030 }
1031 if (!u->GetHistory(history))
1032 {
1033 fprintf(fs, "%d Cannot load history file.\n", CODE_EVENTxERROR);
1034 return fflush(fs);
1035 }
1036
1037 if (u->isUser())
1038 {
1039 userAlias = u->getAlias();
1040 Licq::OwnerReadGuard o(myUserId.ownerId());
1041 if (o.isLocked())
1042 ownerAlias = o->getAlias();
1043 }
1044 else
1045 {
1046 userAlias = "system";
1047 ownerAlias = u->getAlias();
1048 }
1049 }
1050
1051 int counter = 0;
1052 Licq::HistoryList::reverse_iterator it;
1053 for (it = history.rbegin(); it != history.rend(); ++it)
1054 {
1055 ++counter;
1056 if (counter < offset || counter > offset + length)
1057 continue;
1058
1059 printUserEvent(*it, ((*it)->isReceiver() ? userAlias : ownerAlias));
1060 }
1061 fprintf(fs, "%d End.\n", CODE_HISTORYxEND);
1062 return fflush(fs);
1063 }
1064
1065
1066 /*---------------------------------------------------------------------------
1067 * CRMSClient::Process_LIST
1068 *
1069 * Command:
1070 * LIST [ group ] [ online|offline|all ] [ format ]
1071 * All options are optional and can be left out arbitrarily, ie
1072 * "LIST all" is a valid call and will print all online and offline users.
1073 * <format> is a printf style string using the user % symbols as
1074 * documented in HINTS. The default is "%u %P %-20a %3m %s"
1075 * and prints out users as follows.
1076 *
1077 * Response:
1078 * CODE_LISTxUSER 5550000 Licq AnAlias 2 Online
1079 * The default line contains the uin, protocol, alias, number of new
1080 * messages and status all column and white space deliminated. Note that
1081 * the alias may contain white space.
1082 * CODE_LISTxUSER ...
1083 * ...
1084 * CODE_LISTxDONE
1085 *
1086 *-------------------------------------------------------------------------*/
Process_LIST()1087 int CRMSClient::Process_LIST()
1088 {
1089 unsigned short nGroup = 0;
1090 if (isdigit(*data_arg))
1091 {
1092 nGroup = strtoul(data_arg, (char**)NULL, 10);
1093 while (*data_arg != '\0' && *data_arg != ' ') data_arg++;
1094 NEXT_WORD(data_arg);
1095 }
1096
1097 unsigned short n = 3;
1098 if (strncasecmp(data_arg, "online", 6) == 0)
1099 {
1100 n = 1;
1101 data_arg += 6;
1102 }
1103 else if (strncasecmp(data_arg, "offline", 7) == 0)
1104 {
1105 n = 2;
1106 data_arg += 7;
1107 }
1108 else if (strncasecmp(data_arg, "all", 3) == 0)
1109 {
1110 n = 3;
1111 data_arg += 3;
1112 }
1113 NEXT_WORD(data_arg);
1114
1115 string format;
1116 if (*data_arg == '\0')
1117 format = "%u %P %-20a %3m %s";
1118 else
1119 format = data_arg;
1120
1121 Licq::UserListGuard userList;
1122 BOOST_FOREACH(const Licq::User* user, **userList)
1123 {
1124 Licq::UserReadGuard pUser(user);
1125 if (pUser->isInGroup(nGroup) &&
1126 ((!pUser->isOnline() && n&2) || (pUser->isOnline() && n&1)))
1127 {
1128 fprintf(fs, "%d %s\n", CODE_LISTxUSER, pUser->usprintf(format).c_str());
1129 }
1130 }
1131 fprintf(fs, "%d\n", CODE_LISTxDONE);
1132
1133 return fflush(fs);
1134 }
1135
1136
1137
1138 /*---------------------------------------------------------------------------
1139 * CRMSClient::Process_MESSAGE
1140 *
1141 * Command:
1142 * MESSAGE <id>[.<protocol>]
1143 *
1144 * Response:
1145 * CODE_ENTERxTEXT | CODE_INVALIDxUSER
1146 * At which point the message should be entered line by line and
1147 * terminated by entering a "." on a line by itself. Invalid user
1148 * means the uin was invalid (< 10000) and the message was aborted.
1149 * CODE_COMMANDxSTART
1150 * < ...time... >
1151 * CODE_RESULTxSUCCESS | CODE_EVENTxTIMEDOUT | CODE_EVENTxERROR
1152 *-------------------------------------------------------------------------*/
Process_MESSAGE()1153 int CRMSClient::Process_MESSAGE()
1154 {
1155 fprintf(fs, "%d Enter message, terminate with a . on a line by itself:\n",
1156 CODE_ENTERxTEXT);
1157
1158 ParseUser(data_arg);
1159
1160 myText.clear();
1161
1162 m_nState = STATE_ENTERxMESSAGE;
1163 return fflush(fs);
1164 }
1165
Process_MESSAGE_text()1166 int CRMSClient::Process_MESSAGE_text()
1167 {
1168 //XXX Give a tag...
1169 myText.erase(myText.size() - 1);
1170 unsigned long tag = gProtocolManager.sendMessage(myUserId,
1171 Licq::gTranslator.toUtf8(myText));
1172
1173 fprintf(fs, "%d [%ld] Sending message to %s.\n", CODE_COMMANDxSTART,
1174 tag, myUserId.toString().c_str());
1175
1176 tags.push_back(tag);
1177 m_nState = STATE_COMMAND;
1178
1179 return fflush(fs);
1180 }
1181
1182
1183
1184 /*---------------------------------------------------------------------------
1185 * CRMSClient::Process_URL
1186 *
1187 * Command:
1188 * URL <id>[.<protocol>]
1189 *
1190 * Response:
1191 * CODE_ENTERxLINE | CODE_INVALIDxUSER
1192 * At which point the url should be entered on a line by itself.
1193 * Invalid user means the uin was invalid (< 10000) and the url
1194 * was aborted.
1195 * CODE_ENTERxTEXT
1196 * Now the description should be entered and terminated by a "." on
1197 * a line by itself.
1198 * CODE_COMMANDxSTART
1199 * < ...time... >
1200 * CODE_RESULTxSUCCESS | CODE_EVENTxTIMEDOUT | CODE_EVENTxERROR
1201 *-------------------------------------------------------------------------*/
Process_URL()1202 int CRMSClient::Process_URL()
1203 {
1204 ParseUser(data_arg);
1205
1206 myText.clear();
1207
1208 m_nState = STATE_ENTERxURL;
1209 return fflush(fs);
1210 }
1211
1212
Process_URL_url()1213 int CRMSClient::Process_URL_url()
1214 {
1215 myLine = data_line;
1216
1217 fprintf(fs, "%d Enter description, terminate with a . on a line by itself:\n",
1218 CODE_ENTERxTEXT);
1219
1220 myText.clear();
1221
1222 m_nState = STATE_ENTERxURLxDESCRIPTION;
1223 return fflush(fs);
1224 }
1225
1226
Process_URL_text()1227 int CRMSClient::Process_URL_text()
1228 {
1229 unsigned long tag = gProtocolManager.sendUrl(myUserId, myLine,
1230 Licq::gTranslator.toUtf8(myText));
1231
1232 fprintf(fs, "%d [%ld] Sending URL to %s.\n", CODE_COMMANDxSTART,
1233 tag, myUserId.toString().c_str());
1234
1235 tags.push_back(tag);
1236 m_nState = STATE_COMMAND;
1237
1238 return fflush(fs);
1239 }
1240
1241
1242 /*---------------------------------------------------------------------------
1243 * CRMSClient::Process_AR
1244 *
1245 * Command:
1246 * AR [ <id>[.<protocol>] ]
1247 *
1248 * Response:
1249 * CODE_ENTERxTEXT | CODE_INVALIDxUIN
1250 * At which point the auto response should be entered line by line and
1251 * terminated by entering a "." on a line by itself.
1252 * CODE_RESULTxSUCCESS
1253 *-------------------------------------------------------------------------*/
Process_AR()1254 int CRMSClient::Process_AR()
1255 {
1256 if (data_arg[0] == '\0')
1257 {
1258 // Clear user id to set general auto response
1259 myUserId = Licq::UserId();
1260 }
1261 else
1262 {
1263 // Parameter is user id to set custom autoresponse for
1264 ParseUser(data_arg);
1265
1266 if (!myUserId.isValid())
1267 {
1268 fprintf(fs, "%d Invalid User.\n", CODE_INVALIDxUSER);
1269 return fflush(fs);
1270 }
1271 }
1272
1273 fprintf(fs, "%d Enter %sauto response, terminate with a . on a line by itself:\n",
1274 CODE_ENTERxTEXT, myUserId.isValid() ? "custom " : "");
1275
1276 myText.clear();
1277
1278 m_nState = STATE_ENTERxAUTOxRESPONSE;
1279 return fflush(fs);
1280 }
1281
Process_AR_text()1282 int CRMSClient::Process_AR_text()
1283 {
1284 string textUtf8 = Licq::gTranslator.toUtf8(myText);
1285
1286 if (!myUserId.isValid())
1287 {
1288 Licq::OwnerListGuard ownerList;
1289 BOOST_FOREACH(Licq::Owner* owner, **ownerList)
1290 {
1291 Licq::OwnerWriteGuard o(owner);
1292 o->setAutoResponse(textUtf8);
1293 o->save(Licq::Owner::SaveOwnerInfo);
1294 }
1295 }
1296 else
1297 {
1298 Licq::UserWriteGuard u(myUserId);
1299 if (u.isLocked())
1300 u->setCustomAutoResponse(textUtf8);
1301 }
1302
1303 fprintf(fs, "%d Auto response saved.\n", CODE_RESULTxSUCCESS);
1304 m_nState = STATE_COMMAND;
1305 return fflush(fs);
1306 }
1307
1308
1309 /*---------------------------------------------------------------------------
1310 * CRMSClient::Process_LOG
1311 *
1312 * Command:
1313 * LOG <log types>
1314 *
1315 * Response:
1316 * CODE_LOG 12:04:34.042 [TCP] Message from ...
1317 * ...
1318 *-------------------------------------------------------------------------*/
Process_LOG()1319 int CRMSClient::Process_LOG()
1320 {
1321 unsigned short lt = strtoul(data_arg, (char**)NULL, 10);
1322 myLogLevelsBitmask = Licq::LogUtils::convertOldBitmaskToNew(lt);
1323
1324 licqRMS->setupLogSink();
1325
1326 fprintf(fs, "%d Log type set to %d.\n", CODE_LOGxTYPE, lt);
1327
1328 return fflush(fs);
1329 }
1330
1331 /*---------------------------------------------------------------------------
1332 * CRMSClient::Process_NOTIFY
1333 *
1334 * Command:
1335 * NOTIFY
1336 *
1337 * Response:
1338 * CODE_NOTIFYxON|CODE_NOTIFYxOFF
1339 * ...
1340 *-------------------------------------------------------------------------*/
Process_NOTIFY()1341 int CRMSClient::Process_NOTIFY()
1342 {
1343 m_bNotify = !m_bNotify;
1344
1345 if (m_bNotify)
1346 fprintf(fs, "%d Notify set ON.\n", CODE_NOTIFYxON);
1347 else
1348 fprintf(fs, "%d Notify set OFF.\n", CODE_NOTIFYxOFF);
1349
1350 return fflush(fs);
1351 }
1352
1353 /*---------------------------------------------------------------------------
1354 * CRMSClient::Process_VIEW
1355 *
1356 * Command:
1357 * VIEW [ <id>[.<protocol> ]
1358 *
1359 * Response:
1360 *
1361 *-------------------------------------------------------------------------*/
Process_VIEW()1362 int CRMSClient::Process_VIEW()
1363 {
1364 if (*data_arg != '\0')
1365 {
1366 ParseUser(data_arg);
1367 }
1368 else
1369 {
1370 // XXX Check system messages first
1371
1372 // Check user messages now
1373 Licq::UserListGuard userList;
1374 BOOST_FOREACH(const Licq::User* user, **userList)
1375 {
1376 Licq::UserReadGuard pUser(user);
1377 if(pUser->NewMessages() > 0)
1378 {
1379 myUserId = pUser->id();
1380 break;
1381 }
1382 }
1383
1384 if (!myUserId.isValid())
1385 {
1386 fprintf(fs, "%d No new messages.\n", CODE_VIEWxNONE);
1387 return fflush(fs);
1388 }
1389 }
1390
1391 Licq::UserWriteGuard u(myUserId);
1392 if (!u.isLocked())
1393 {
1394 fprintf(fs, "%d No such user.\n", CODE_INVALIDxUSER);
1395 return fflush(fs);
1396 }
1397
1398 Licq::UserEvent* e = u->EventPop();
1399 printUserEvent(e, u->getAlias());
1400
1401 return fflush(fs);
1402 }
1403
printUserEvent(const Licq::UserEvent * e,const string & alias)1404 void CRMSClient::printUserEvent(const Licq::UserEvent* e, const string& alias)
1405 {
1406 if (e == NULL)
1407 {
1408 fprintf(fs, "%d Invalid event\n", CODE_EVENTxERROR);
1409 return;
1410 }
1411
1412 std::ostringstream eventHeader;
1413 switch (e->eventType())
1414 {
1415 case Licq::UserEvent::TypeMessage:
1416 eventHeader << CODE_VIEWxMSG << " Message";
1417 break;
1418
1419 case Licq::UserEvent::TypeUrl:
1420 eventHeader << CODE_VIEWxURL << " URL";
1421 break;
1422
1423 case Licq::UserEvent::TypeChat:
1424 eventHeader << CODE_VIEWxCHAT << " Chat Request";
1425 break;
1426
1427 case Licq::UserEvent::TypeFile:
1428 eventHeader << CODE_VIEWxFILE << " File Request";
1429 break;
1430
1431 default:
1432 eventHeader << CODE_VIEWxUNKNOWN << " Unknown Event";
1433 }
1434
1435 eventHeader << " from ";
1436 eventHeader << alias;
1437 eventHeader << "\n";
1438
1439 // Write out the event header
1440 fputs(eventHeader.str().c_str(), fs);
1441
1442 // Timestamp
1443 char szTime[25];
1444 time_t nMessageTime = e->Time();
1445 struct tm* pTM = localtime(&nMessageTime);
1446 strftime(szTime, 25, "%Y-%m-%d %H:%M:%S", pTM);
1447 fprintf(fs, "%d Sent At %s\n", CODE_VIEWxTIME, szTime);
1448
1449 // Message
1450 fprintf(fs, "%d Message Start\n", CODE_VIEWxTEXTxSTART);
1451 fputs(e->textLoc().c_str(), fs);
1452 fprintf(fs, "\n%d Message Complete\n", CODE_VIEWxTEXTxEND);
1453 }
1454
1455 /*---------------------------------------------------------------------------
1456 * CRMSClient::Process_ADDUSER
1457 *
1458 * Command:
1459 * ADDUSER <id> <protocol>
1460 *
1461 * Response:
1462 *
1463 *-------------------------------------------------------------------------*/
Process_ADDUSER()1464 int CRMSClient::Process_ADDUSER()
1465 {
1466 ParseUser(data_arg);
1467
1468 if (!myUserId.isValid())
1469 {
1470 fprintf(fs, "%d Invalid UIN.\n", CODE_INVALIDxUSER);
1471 }
1472 else if (gUserManager.addUser(myUserId) != 0)
1473 {
1474 fprintf(fs, "%d User added\n", CODE_ADDUSERxDONE);
1475 }
1476 else
1477 {
1478 fprintf(fs, "%d User not added\n", CODE_ADDUSERxERROR);
1479 }
1480
1481 return fflush(fs);
1482 }
1483
1484 /*---------------------------------------------------------------------------
1485 * CRMSClient::Process_REMUSER
1486 *
1487 * Command:
1488 * REMUSER <uin>
1489 *
1490 * Response:
1491 *
1492 *-------------------------------------------------------------------------*/
Process_REMUSER()1493 int CRMSClient::Process_REMUSER()
1494 {
1495 ParseUser(data_arg);
1496
1497 if (myUserId.isValid() && gUserManager.userExists(myUserId))
1498 {
1499 gUserManager.removeUser(myUserId);
1500 fprintf(fs, "%d User removed\n", CODE_REMUSERxDONE);
1501 }
1502 else
1503 {
1504 fprintf(fs, "%d Invalid UIN.\n", CODE_INVALIDxUSER);
1505 }
1506
1507 return fflush(fs);
1508 }
1509
1510 /*---------------------------------------------------------------------------
1511 * CRMSClient::Process_SECURE
1512 *
1513 * Command:
1514 * SECURE <uin> <what>
1515 *
1516 * Response:
1517 *
1518 *-------------------------------------------------------------------------*/
Process_SECURE()1519 int CRMSClient::Process_SECURE()
1520 {
1521 if (!Licq::gDaemon.haveCryptoSupport())
1522 {
1523 fprintf(fs, "%d Licq secure channel not compiled. Please recompile with OpenSSL.\n", CODE_SECURExNOTCOMPILED);
1524 return fflush(fs);
1525 }
1526
1527 ParseUser(data_arg);
1528
1529 if (!myUserId.isValid())
1530 {
1531 fprintf(fs, "%d Invalid UIN.\n", CODE_INVALIDxUSER);
1532 return fflush(fs);
1533 }
1534 while (*data_arg != '\0' && *data_arg != ' ') data_arg++;
1535 NEXT_WORD(data_arg);
1536
1537 if (strncasecmp(data_arg, "open", 4) == 0)
1538 {
1539 fprintf(fs, "%d Opening secure connection.\n", CODE_SECURExOPEN);
1540 gProtocolManager.secureChannelOpen(myUserId);
1541 }
1542 else
1543 if (strncasecmp(data_arg, "close", 5) == 0)
1544 {
1545 fprintf(fs, "%d Closing secure connection.\n", CODE_SECURExCLOSE);
1546 gProtocolManager.secureChannelClose(myUserId);
1547 }
1548 else
1549 {
1550 Licq::UserReadGuard u(myUserId);
1551 if (u.isLocked())
1552 {
1553 if (u->Secure() == 0)
1554 fprintf(fs, "%d Status: secure connection is closed.\n", CODE_SECURExSTAT);
1555 if (u->Secure() == 1)
1556 fprintf(fs, "%d Status: secure connection is open.\n", CODE_SECURExSTAT);
1557 }
1558 }
1559
1560 return fflush(fs);
1561 }
1562