1
2 /*
3 * This code is OBSOLETE and about to be removed.
4 * No further features will be added.
5 */
6
7 extern "C" {
8 #include "climm.h"
9 #include <sys/types.h>
10 #include <errno.h>
11 #if HAVE_SYS_STAT_H
12 #include <sys/stat.h>
13 #endif
14 #if HAVE_WINSOCK2_H
15 #include <winsock2.h>
16 #endif
17 #include <fcntl.h>
18 #include "xmpp_base.h"
19 #include "connection.h"
20 #include "contact.h"
21 #include "conv.h"
22 #include "oscar_dc.h"
23 #include "util_io.h"
24 #include "im_response.h"
25 #include "im_request.h"
26 #include "util_ui.h"
27 #include "util_rl.h"
28 #include "buildmark.h"
29 #include "preferences.h"
30 #include "oscar_dc_file.h"
31 }
32
33 #include <cassert>
34 #include <map>
35 #include <gloox/gloox.h>
36 #include <gloox/client.h>
37 #include <gloox/connectionlistener.h>
38 #include <gloox/disco.h>
39 #include <gloox/discohandler.h>
40 #include <gloox/messagehandler.h>
41 #include <gloox/subscriptionhandler.h>
42 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
43 #include <gloox/connectiontcpbase.h>
44 #endif
45 #ifdef CLIMM_XMPP_FILE_TRANSFER
46 #include <gloox/socks5bytestream.h>
47 #include <gloox/siprofilefthandler.h>
48 #include <gloox/socks5bytestreamdatahandler.h>
49 #include <gloox/siprofileft.h>
50 #endif
51 #include <gloox/presencehandler.h>
52 #include <gloox/tag.h>
53 #include <gloox/stanza.h>
54 #include <gloox/disco.h>
55
56 extern "C" {
57 static jump_conn_f XMPPCallbackDispatch;
58 static jump_conn_f XMPPCallbackClose;
59 #ifdef CLIMM_XMPP_FILE_TRANSFER
60 static jump_conn_f XMPPFTCallbackDispatch;
61 static jump_conn_f XMPPFTCallbackClose;
62 static void XMPPCallBackFileAccept (Event *event);
63 #endif
64 //void PeerFileIODispatchClose (Connection *ffile);
65 }
66
67 #ifdef CLIMM_XMPP_FILE_TRANSFER
68 std::map<UWORD, std::string> l_tSeqTranslate;
69 std::map<const std::string, std::string> sid2id;
70 #endif
71
72 class CLIMMXMPP: public gloox::ConnectionListener, public gloox::MessageHandler,
73 public gloox::PresenceHandler, public gloox::SubscriptionHandler,
74 public gloox::DiscoHandler, public gloox::IqHandler,
75 #ifdef CLIMM_XMPP_FILE_TRANSFER
76 public gloox::SIProfileFTHandler,
77 public gloox::SOCKS5BytestreamDataHandler,
78 #endif
79
80 public gloox::LogHandler {
81 private :
82 Server *m_serv;
83 gloox::Client *m_client;
84 char *m_stamp;
85 #ifdef CLIMM_XMPP_FILE_TRANSFER
86 gloox::SIProfileFT *m_pFT;
87 #endif
88
89 void handleMessage2 (gloox::Stanza *t, gloox::JID from, std::string tof, std::string id, gloox::StanzaSubType subtype);
90 void handleXEP8 (gloox::Tag *t);
91 bool handleXEP22and85 (gloox::Tag *t, Contact *cfrom, gloox::JID from, std::string tof, std::string id);
92 void handleXEP22a (gloox::Tag *XEP22, Contact *cfrom);
93 void handleXEP22b (gloox::Tag *XEP22, gloox::JID from, std::string tof, std::string id);
94 void handleXEP22c (gloox::JID from, std::string tof, std::string id, std::string type);
95 void handleXEP27 (gloox::Tag *t);
96 void handleXEP71 (gloox::Tag *t);
97 void handleXEP115 (gloox::Tag *t, Contact *contr);
98 void handleXEP153 (gloox::Tag *t, Contact *contr);
99 void handleGoogleNosave (gloox::Tag *t);
100 void handleGoogleSig (gloox::Tag *t);
101 void handleGoogleChatstate (gloox::Tag *t);
102 void handleXEP136 (gloox::Tag *t);
103 time_t handleXEP91 (gloox::Tag *t);
104 void handlePresence2 (gloox::Tag *s, gloox::JID from, gloox::JID to, std::string msg);
105
106 public :
107 CLIMMXMPP (Server *serv);
108 virtual ~CLIMMXMPP ();
109 virtual void onConnect ();
110 virtual void onDisconnect (gloox::ConnectionError e);
111 virtual void onResourceBindError (gloox::ResourceBindError error);
112 virtual void onSessionCreateError (gloox::SessionCreateError error);
113 virtual bool onTLSConnect (const gloox::CertInfo &info);
114 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
115 virtual void handleMessage (gloox::Stanza *stanza, gloox::MessageSession *session = NULL);
116 #else
117 virtual void handleMessage (gloox::Stanza *stanza);
118 #endif
119 #ifdef CLIMM_XMPP_FILE_TRANSFER
120 virtual void handleFTRequestError (gloox::Stanza *stanza);
121 virtual void handleFTSOCKS5Bytestream (gloox::SOCKS5Bytestream *s5b);
122 virtual void handleFTRequest (const gloox::JID & from, const std::string & id, const std::string & sid,
123 const std::string & name, long size, const std::string & hash, const std::string & date,
124 const std::string & mimetype, const std::string & desc, int stypes, long offset, long length);
125 void XMPPAcceptDenyFT (gloox::JID contact, std::string id, std::string sid, const char *reason);
handleFTRequestError(gloox::Stanza *,const std::string &)126 virtual void handleFTRequestError(gloox::Stanza*, const std::string&) {}
127 virtual void handleSOCKS5Data (gloox::SOCKS5Bytestream *s5b, const std::string &data);
128 virtual void handleSOCKS5Error (gloox::SOCKS5Bytestream *s5b, gloox::Stanza *stanza);
129 virtual void handleSOCKS5Open (gloox::SOCKS5Bytestream *s5b);
130 virtual void handleSOCKS5Close (gloox::SOCKS5Bytestream *s5b);
131 #endif
132 virtual void handlePresence (gloox::Stanza *stanza);
133 virtual void handleSubscription (gloox::Stanza *stanza);
134 virtual void handleLog (gloox::LogLevel level, gloox::LogArea area, const std::string &message);
135
136 // GMail support
137 void sendIqGmail (int64_t newer = 0ULL, std::string newertid = "", std::string q = "", bool isauto = 1);
138 void sendIqTime (void);
139 std::string gmail_new_newertid;
140 std::string gmail_newertid;
141 std::string gmail_query;
142 int64_t gmail_new_newer;
143 int64_t gmail_newer;
144
145 // IqHandler
146 virtual bool handleIq (gloox::Stanza *stanza);
147 virtual bool handleIqID (gloox::Stanza *stanza, int context);
148
149 // DiscoHandler
150 virtual void handleDiscoInfoResult (gloox::Stanza *stanza, int context);
151 virtual void handleDiscoItemsResult (gloox::Stanza *stanza, int context);
152 virtual void handleDiscoError (gloox::Stanza *stanza, int context);
153 virtual bool handleDiscoSet (gloox::Stanza *stanza);
154
getClient()155 gloox::Client *getClient () { return m_client; }
156 UBYTE XMPPSendmsg (Server *conn, Contact *cont, Message *msg);
157 void XMPPSetstatus (Server *serv, Contact *cont, status_t status, const char *msg);
158 void XMPPAuthorize (Server *serv, Contact *cont, auth_t how, const char *msg);
159 };
160
getXMPPClient(Server * serv)161 static inline CLIMMXMPP *getXMPPClient (Server *serv)
162 {
163 return serv ? (CLIMMXMPP *)serv->xmpp_private : NULL;
164 }
165
StatusToGlooxstatus(status_t & status)166 static gloox::Presence StatusToGlooxstatus (status_t &status)
167 {
168 switch (status)
169 {
170 case ims_online: return gloox::PresenceAvailable; break;
171 case ims_ffc: return gloox::PresenceChat; break;
172 case ims_away: return gloox::PresenceAway; break;
173 case ims_occ: status = ims_dnd;
174 case ims_dnd: return gloox::PresenceDnd; break;
175 case ims_na: return gloox::PresenceXa; break;
176 case ims_offline: status = ims_inv;
177 default: return gloox::PresenceUnavailable; break;
178 }
179 }
180
CLIMMXMPP(Server * serv)181 CLIMMXMPP::CLIMMXMPP (Server *serv)
182 {
183 m_serv = serv;
184 m_stamp = (char *)malloc (15);
185 time_t now = time (NULL);
186 strftime (m_stamp, 15, "%Y%m%d%H%M%S", gmtime (&now));
187 assert (serv->passwd);
188 assert (*serv->passwd);
189 m_client = new gloox::Client (gloox::JID (serv->screen), serv->passwd, serv->conn->port);
190 m_client->setResource ("climm");
191 if (serv->conn->server)
192 m_client->setServer (serv->conn->server);
193
194 m_client->disableRoster ();
195 m_client->registerConnectionListener (this);
196 m_client->registerMessageHandler (this);
197 m_client->registerSubscriptionHandler (this);
198 m_client->registerPresenceHandler (this);
199 m_client->logInstance ().registerLogHandler (gloox::LogLevelDebug, gloox::LogAreaAll, this);
200 m_client->disco()->setVersion ("climm", s_sprintf ("%s gloox", BuildVersionStr), BuildPlatformStr);
201 m_client->disco()->setIdentity ("client", "console");
202 m_client->disco()->registerDiscoHandler (this);
203 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
204 m_client->setPresence (StatusToGlooxstatus (m_serv->status), 5);
205
206 #ifdef CLIMM_XMPP_FILE_TRANSFER
207 m_pFT = new gloox::SIProfileFT (m_client, this);
208 //m_pFT->addStreamHost (gloox::JID ("proxy.jabber.org"), "208.245.212.98", 7777);
209 #endif
210
211 #else
212 m_client->setAutoPresence (false);
213 m_client->setInitialPriority (5);
214 #endif
215
216 gmail_new_newer = 0ULL;
217 gmail_newer = 0ULL;
218
219 m_client->connect (false);
220 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
221 // Yes http proxy is now avail in gloox, but not used in climm, so != NULL
222 serv->conn->sok = dynamic_cast<gloox::ConnectionTCPBase *>(m_client->connectionImpl())->socket();
223 #else
224 serv->conn->sok = m_client->fileDescriptor ();
225 #endif
226 }
227
~CLIMMXMPP()228 CLIMMXMPP::~CLIMMXMPP ()
229 {
230 s_free (m_stamp);
231 }
232
onDisconnect(gloox::ConnectionError e)233 void CLIMMXMPP::onDisconnect (gloox::ConnectionError e)
234 {
235 m_serv->conn->connect = 0;
236 if (m_serv->conn->sok != -1)
237 close (m_serv->conn->sok);
238 m_serv->conn->sok = -1;
239 switch (e)
240 {
241 case gloox::ConnNoError:
242 rl_printf ("#onDisconnect: NoError.\n");
243 break;
244 case gloox::ConnStreamError:
245 {
246 std::string sET = m_client->streamErrorText();
247 rl_printf ("#onDisconnect: Error %d: ConnStreamError: Error %d: %s\n",
248 e, m_client->streamError(), sET.c_str());
249 }
250 break;
251 case gloox::ConnStreamClosed:
252 case gloox::ConnIoError:
253 IMCallBackReconn (m_serv->conn);
254 return;
255
256 case gloox::ConnOutOfMemory: rl_printf ("#onDisconnect: Error OutOfMemory %d.\n", e); break;
257 case gloox::ConnNoSupportedAuth: rl_printf ("#onDisconnect: Error NoSupportedAuth %d.\n", e); break;
258 case gloox::ConnTlsFailed: rl_printf ("#onDisconnect: Error TlsFailed %d.\n", e); break;
259 case gloox::ConnAuthenticationFailed: rl_printf ("#onDisconnect: Error AuthenticationFailed %d.\n", e);
260 s_repl (&m_serv->passwd, NULL);
261 break;
262 case gloox::ConnUserDisconnected: return;
263 case gloox::ConnNotConnected: rl_printf ("#onDisconnect: Error NotConnected %d.\n", e); break;
264 default:
265 rl_printf ("#onDisconnect: Error %d.\n", e);
266 }
267 }
268
onResourceBindError(gloox::ResourceBindError e)269 void CLIMMXMPP::onResourceBindError (gloox::ResourceBindError e)
270 {
271 rl_printf ("#onResourceBindError: Error %d.\n", e);
272 }
273
onSessionCreateError(gloox::SessionCreateError e)274 void CLIMMXMPP::onSessionCreateError (gloox::SessionCreateError e)
275 {
276 rl_printf ("#onSessionCreateError: Error %d.\n", e);
277 }
278
onTLSConnect(const gloox::CertInfo & info)279 bool CLIMMXMPP::onTLSConnect (const gloox::CertInfo &info)
280 {
281 return TRUE;
282 }
283
DropChild(gloox::Tag * s,gloox::Tag * c)284 static bool DropChild (gloox::Tag *s, gloox::Tag *c)
285 {
286 if (s->children().size())
287 s->setCData ("");
288 s->children().remove (c);
289 delete c;
290 }
291
DropAttrib(gloox::Tag * s,const std::string & a)292 static bool DropAttrib (gloox::Tag *s, const std::string &a)
293 {
294 if (s->children().size())
295 s->setCData ("");
296 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
297 s->attributes().remove (gloox::Tag::Attribute (a, s->findAttribute (a)));
298 #else
299 s->attributes().erase (a);
300 #endif
301 }
302
DropCData(gloox::Tag * s)303 static bool DropCData (gloox::Tag *s)
304 {
305 s->setCData ("");
306 }
307
CheckInvalid(gloox::Tag * s)308 static bool CheckInvalid (gloox::Tag *s)
309 {
310 if (!s->attributes().size() && !s->children().size() && s->cdata().empty())
311 {
312 if (s->parent())
313 DropChild (s->parent(), s);
314 return true;
315 }
316 return false;
317 }
318
DropAllChilds(gloox::Tag * s,const std::string & a)319 static void DropAllChilds (gloox::Tag *s, const std::string &a)
320 {
321 gloox::Tag::TagList::const_iterator it;
322 for (it = s->children().begin(); it != s->children().end(); ++it)
323 {
324 if ((*it)->name() == a)
325 {
326 gloox::Tag *b = *it;
327 DropCData (b);
328 DropAttrib (b, "xml:lang");
329 if (CheckInvalid (b))
330 return (DropAllChilds (s, a));
331 }
332 }
333 }
334
DropAllChildsTree(gloox::Tag * s,const std::string & a)335 static void DropAllChildsTree (gloox::Tag *s, const std::string &a)
336 {
337 gloox::Tag::TagList::const_iterator it;
338 if (a.empty ())
339 {
340 s->attributes().clear();
341 for (it = s->children().begin(); it != s->children().end(); it = s->children().begin())
342 {
343 gloox::Tag *b = *it;
344 DropCData (b);
345 DropAllChildsTree (b, "");
346 CheckInvalid (b);
347 }
348 }
349 else
350 {
351 for (it = s->children().begin(); it != s->children().end(); ++it)
352 {
353 while ((*it)->name() == a)
354 {
355 gloox::Tag *b = *it;
356 DropCData (b);
357 DropAllChildsTree (b, "");
358 CheckInvalid (b);
359 it = s->children().begin();
360 }
361 }
362 }
363 }
364
__SkipChar(const char ** s,char c)365 static int __SkipChar (const char **s, char c)
366 {
367 if (**s == c && **s)
368 (*s)++;
369 if (**s)
370 return *((*s)++) - '0';
371 return 0;
372 }
373
ParseUTCDate(std::string str)374 static time_t ParseUTCDate (std::string str)
375 {
376 const char *s = str.c_str();
377 struct tm tm;
378 tm.tm_year = __SkipChar (&s, 0) * 1000;
379 tm.tm_year += __SkipChar (&s, 0) * 100;
380 tm.tm_year += __SkipChar (&s, 0) * 10;
381 tm.tm_year += __SkipChar (&s, 0) - 1900;
382 tm.tm_mon = __SkipChar (&s, '-') * 10;
383 tm.tm_mon += __SkipChar (&s, 0) - 1;
384 tm.tm_mday = __SkipChar (&s, '-') * 10;
385 tm.tm_mday += __SkipChar (&s, 0);
386 tm.tm_hour = __SkipChar (&s, 'T') * 10;
387 tm.tm_hour += __SkipChar (&s, 0);
388 tm.tm_min = __SkipChar (&s, ':') * 10;
389 tm.tm_min += __SkipChar (&s, 0);
390 tm.tm_sec = __SkipChar (&s, ':') * 10;
391 if (!*s)
392 return -1;
393 tm.tm_sec += __SkipChar (&s, 0);
394 if (*s)
395 return -1;
396 return timegm (&tm);
397 }
398
findNamespacedChild(gloox::Tag * tag,const char * childname,const char * childnamespace)399 static gloox::Tag *findNamespacedChild (gloox::Tag *tag, const char *childname, const char *childnamespace)
400 {
401 gloox::Tag::TagList::const_iterator it = tag->children ().begin ();
402 while (it != tag->children ().end())
403 {
404 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
405 gloox::Tag::AttributeList::const_iterator ait = (*it)->attributes().begin ();
406 #else
407 gloox::StringMap::iterator ait = (*it)->attributes().begin ();
408 #endif
409 while (ait != (*it)->attributes().end ())
410 {
411 if ((*ait).first == "xmlns" && (*ait).second == childnamespace)
412 {
413 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
414 (*it)->attributes ().remove (*ait);
415 #else
416 (*it)->attributes ().erase (ait);
417 #endif
418 return *it;
419 }
420 if (!(*ait).first.compare (0, 6, "xmlns:") && (*ait).second == childnamespace)
421 {
422 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
423 (*it)->attributes ().remove (*ait);
424 #else
425 (*it)->attributes ().erase (ait);
426 #endif
427 return *it;
428 }
429 ait++;
430 }
431 it++;
432 }
433 return NULL;
434 }
435
GetBothContacts(const gloox::JID & j,Server * conn,Contact ** b,Contact ** f,bool crea)436 static void GetBothContacts (const gloox::JID &j, Server *conn, Contact **b, Contact **f, bool crea)
437 {
438 Contact *bb, *ff, **t;
439 std::string jb = j.bare();
440 std::string jr = j.resource();
441
442 if ((bb = ContactFindScreen (conn->contacts, jb.c_str())))
443 {
444 if (!(ff = ContactFindScreenP (conn->contacts, bb, jr.c_str())))
445 {
446 ff = ContactScreenP (conn, bb, jr.c_str());
447 }
448 }
449 else
450 {
451 bb = ContactScreen (conn, jb.c_str());
452 if (crea)
453 ContactCreate (conn, bb);
454 ff = ContactScreenP (conn, bb, jr.c_str());
455 }
456 assert (bb);
457 if (ff)
458 {
459 /* make ff the firstchild or the firstchild->next of bb */
460 if (!bb->firstchild)
461 bb->firstchild = ff;
462 else if (bb->firstchild != ff && bb->firstchild->next != ff)
463 {
464 for (t = &bb->firstchild; *t; t = &((*t)->next))
465 if (*t == ff)
466 {
467 *t = ff->next;
468 ff->next = bb->firstchild->next;
469 bb->firstchild->next = ff;
470 t = NULL;
471 break;
472 }
473 if (t)
474 {
475 ff->next = bb->firstchild->next;
476 bb->firstchild->next = ff;
477 }
478 }
479 }
480 else
481 ff = bb;
482 *b = bb;
483 *f = ff;
484 }
485
486
CLIMMXMPPSave(Server * serv,const char * text,char in)487 void CLIMMXMPPSave (Server *serv, const char *text, char in)
488 {
489 const char *data;
490 size_t rc;
491
492 if (serv->logfd < 0)
493 {
494 const char *dir, *file;
495 dir = s_sprintf ("%sdebug", PrefUserDir (prG));
496 mkdir (dir, 0700);
497 dir = s_sprintf ("%sdebug" _OS_PATHSEPSTR "packets.xmpp.%s", PrefUserDir (prG), serv->screen);
498 mkdir (dir, 0700);
499 file = s_sprintf ("%sdebug" _OS_PATHSEPSTR "packets.xmpp.%s/%lu", PrefUserDir (prG), serv->screen, time (NULL));
500 serv->logfd = open (file, O_WRONLY | O_CREAT | O_APPEND, 0600);
501 }
502 if (serv->logfd < 0)
503 return;
504
505 data = s_sprintf ("%s %s%s\n", s_now, in & 1 ? "<<<" : ">>>", in & 2 ? " residual:" : "");
506 rc = write (serv->logfd, data, strlen (data));
507
508 text = s_ind (text);
509 rc = write (serv->logfd, text, strlen (text));
510 rc = write (serv->logfd, "\n", 1);
511 }
512
513
handleXEP8(gloox::Tag * t)514 void CLIMMXMPP::handleXEP8 (gloox::Tag *t)
515 {
516 if (gloox::Tag *avatar = findNamespacedChild (t, "x", "jabber:x:avatar"))
517 {
518 if (gloox::Tag *hash = avatar->findChild ("hash"))
519 {
520 DropCData (hash);
521 CheckInvalid (hash);
522 }
523 CheckInvalid (avatar);
524 }
525 }
526
handleXEP22a(gloox::Tag * XEP22,Contact * cfrom)527 void CLIMMXMPP::handleXEP22a (gloox::Tag *XEP22, Contact *cfrom)
528 {
529 std::string refid;
530 int ref = -1;
531 int_msg_t type;
532
533 if (gloox::Tag *tid = XEP22->findChild ("id"))
534 {
535 refid = tid->cdata();
536 DropCData (tid);
537 CheckInvalid (tid);
538 }
539 if (!strncmp (refid.c_str(), "xmpp-", 5) && !strncmp (refid.c_str() + 5, m_stamp, 14)
540 && strlen (refid.c_str()) > 19 && refid.c_str()[19] == '-')
541 sscanf (refid.c_str() + 20, "%x", &ref);
542
543 if (gloox::Tag *dotag = XEP22->findChild ("offline"))
544 {
545 type = INT_MSGOFF;
546 CheckInvalid (dotag);
547 }
548 else if (gloox::Tag *dotag = XEP22->findChild ("paused"))
549 {
550 CheckInvalid (dotag);
551 IMIntMsg (cfrom, NOW, ims_offline, INT_MSGNOCOMP, "");
552 ref = -1;
553 }
554 else if (gloox::Tag *dotag = XEP22->findChild ("delivered"))
555 {
556 type = INT_MSGACK_TYPE2;
557 CheckInvalid (dotag);
558 }
559 else if (gloox::Tag *dotag = XEP22->findChild ("displayed"))
560 {
561 type = INT_MSGDISPL;
562 CheckInvalid (dotag);
563 }
564 else if (gloox::Tag *dotag = XEP22->findChild ("composing"))
565 {
566 CheckInvalid (dotag);
567 IMIntMsg (cfrom, NOW, ims_offline, INT_MSGCOMP, "");
568 ref = -1;
569 }
570 else
571 ref = -1;
572
573 if (ref != -1)
574 {
575 Event *event = QueueDequeue (m_serv->conn, QUEUE_XMPP_RESEND_ACK, ref);
576 if (event)
577 {
578 Message *msg = (Message *)event->data;
579 assert (msg);
580 if (msg->send_message && !msg->otrinjected)
581 {
582 msg->type = type;
583 // assert (msg->cont == cfrom); ->parent
584 IMIntMsgMsg (msg, NOW, ims_offline);
585 }
586 event->attempts += 5;
587 QueueEnqueue (event);
588 }
589 }
590
591 CheckInvalid (XEP22);
592 }
593
handleXEP22c(gloox::JID from,std::string tof,std::string id,std::string type)594 void CLIMMXMPP::handleXEP22c (gloox::JID from, std::string tof, std::string id, std::string type)
595 {
596 gloox::Stanza *msg = gloox::Stanza::createMessageStanza (from, "");
597 msg->addAttribute ("id", s_sprintf ("ack-%s-%x", m_stamp, m_serv->xmpp_sequence++));
598 std::string res = m_client->resource();
599 msg->addAttribute ("from", s_sprintf ("%s/%s", m_serv->screen, res.c_str()));
600 gloox::Tag *x = new gloox::Tag (msg, "x");
601 x->addAttribute ("xmlns", "jabber:x:event");
602 new gloox::Tag (x, type);
603 new gloox::Tag (x, "id", id);
604 m_client->send (msg);
605 }
606
handleXEP22b(gloox::Tag * XEP22,gloox::JID from,std::string tof,std::string id)607 void CLIMMXMPP::handleXEP22b (gloox::Tag *XEP22, gloox::JID from, std::string tof, std::string id)
608 {
609 if (gloox::Tag *dotag = XEP22->findChild ("delivered"))
610 {
611 handleXEP22c (from, tof, id, "delivered");
612 CheckInvalid (dotag);
613 }
614 if (gloox::Tag *dotag = XEP22->findChild ("displayed"))
615 {
616 handleXEP22c (from, tof, id, "displayed");
617 CheckInvalid (dotag);
618 }
619 if (gloox::Tag *dotag = XEP22->findChild ("composing"))
620 {
621 CheckInvalid (dotag);
622 }
623 if (gloox::Tag *dotag = XEP22->findChild ("offline"))
624 {
625 CheckInvalid (dotag);
626 }
627 }
628
handleXEP22and85(gloox::Tag * t,Contact * cfrom,gloox::JID from,std::string tof,std::string id)629 bool CLIMMXMPP::handleXEP22and85 (gloox::Tag *t, Contact *cfrom, gloox::JID from, std::string tof, std::string id)
630 {
631 bool ret = false;
632 if (gloox::Tag *XEP22 = findNamespacedChild (t, "x", "jabber:x:event"))
633 {
634 ret = true;
635 if (!t->hasChild ("body"))
636 handleXEP22a (XEP22, cfrom);
637 else
638 handleXEP22b (XEP22, from, tof, id);
639 }
640 if (gloox::Tag *address = findNamespacedChild (t, "addresses", "http://jabber.org/protocol/address"))
641 {
642 DropAllChildsTree (address, "address");
643 CheckInvalid (address);
644 ret = true;
645 }
646
647 if (gloox::Tag *active = findNamespacedChild (t, "active", "http://jabber.org/protocol/chatstates"))
648 {
649 CheckInvalid (active);
650 ret = true;
651 }
652 if (gloox::Tag *composing = findNamespacedChild (t, "composing", "http://jabber.org/protocol/chatstates"))
653 {
654 CheckInvalid (composing);
655 IMIntMsg (cfrom, NOW, ims_offline, INT_MSGCOMP, "");
656 ret = true;
657 }
658 if (gloox::Tag *paused = findNamespacedChild (t, "paused", "http://jabber.org/protocol/chatstates"))
659 {
660 CheckInvalid (paused);
661 IMIntMsg (cfrom, NOW, ims_offline, INT_MSGNOCOMP, "");
662 ret = true;
663 }
664 if (gloox::Tag *inactive = findNamespacedChild (t, "inactive", "http://jabber.org/protocol/chatstates"))
665 {
666 CheckInvalid (inactive);
667 ret = true;
668 }
669 if (gloox::Tag *gone = findNamespacedChild (t, "gone", "http://jabber.org/protocol/chatstates"))
670 {
671 CheckInvalid (gone);
672 ret = true;
673 }
674 if (ret && !t->hasChild ("body"))
675 return true;
676 return false;
677 }
678
handleXEP27(gloox::Tag * t)679 void CLIMMXMPP::handleXEP27 (gloox::Tag *t)
680 {
681 if (gloox::Tag *sig = findNamespacedChild (t, "x", "jabber:x:signed"))
682 {
683 DropCData (sig);
684 CheckInvalid (sig);
685 }
686 }
687
handleXEP71(gloox::Tag * t)688 void CLIMMXMPP::handleXEP71 (gloox::Tag *t)
689 {
690 if (gloox::Tag *xhtmlim = findNamespacedChild (t, "html", "http://jabber.org/protocol/xhtml-im"))
691 {
692 DropAllChildsTree (xhtmlim, "body");
693 CheckInvalid (xhtmlim);
694 }
695 }
696
697
handleXEP91(gloox::Tag * t)698 time_t CLIMMXMPP::handleXEP91 (gloox::Tag *t)
699 {
700 time_t date = NOW;
701 if (gloox::Tag *delay = findNamespacedChild (t, "x", "jabber:x:delay"))
702 {
703 struct tm;
704 std::string dfrom = delay->findAttribute ("from");
705 std::string stamp = delay->findAttribute ("stamp");
706 date = ParseUTCDate (stamp);
707 if (date != NOW)
708 DropAttrib (delay, "stamp");
709 DropAttrib (delay, "from");
710 CheckInvalid (delay);
711 }
712 return date;
713 }
714
handleXEP115(gloox::Tag * t,Contact * contr)715 void CLIMMXMPP::handleXEP115 (gloox::Tag *t, Contact *contr)
716 {
717 gloox::Tag *caps;
718 if ((caps = findNamespacedChild (t, "c", "http://jabber.org/protocol/caps")))
719 {
720 std::string node = caps->findAttribute ("node");
721 std::string ver = caps->findAttribute ("ver");
722 std::string ext = caps->findAttribute ("ext");
723 if (!strcmp (node.c_str(), "http://www.climm.org/xmpp/caps"))
724 node = "climm";
725 else if (!strcmp (node.c_str(), "http://mail.google.com/xmpp/client/caps"))
726 node = "GoogleMail";
727 else if (!strcmp (node.c_str(), "http://www.google.com/xmpp/client/caps"))
728 node = "GoogleTalk";
729 else if (!strcmp (node.c_str(), "http://pidgin.im/caps"))
730 node = "Pidgin";
731 else if (!strcmp (node.c_str(), "http://gaim.sf.net/caps"))
732 node = "Gaim";
733 else if (!strcmp (node.c_str(), "http://kopete.kde.org/jabber/caps"))
734 node = "Kopete";
735 else if (!strcmp (node.c_str(), "http://psi-im.org/caps"))
736 node = "Psi";
737 else if (!strcmp (node.c_str(), "http://miranda-im.org/caps"))
738 node = "Miranda";
739 else if (!strcmp (node.c_str(), "apple:ichat:caps") || !strcmp (node.c_str(), "http://www.apple.com/ichat/caps"))
740 node = "iChat";
741 else if (!strcmp (node.c_str(), "http://telepathy.freedesktop.org/caps"))
742 node = "Telepathy";
743 else if (!strcmp (node.c_str(), "http://talkgadget.google.com/client/caps"))
744 node = "TalkGadget";
745 else if (!strcmp (node.c_str(), "http://trillian.im/caps"))
746 node = "Trillian";
747 s_repl (&contr->cap_string, ext.c_str ());
748 s_repl (&contr->version, s_sprintf ("%s %s", node.c_str(), ver.c_str()));
749 DropAttrib (caps, "ver");
750 DropAttrib (caps, "ext");
751 DropAttrib (caps, "node");
752 CheckInvalid (caps);
753 }
754 }
755
handleXEP136(gloox::Tag * t)756 void CLIMMXMPP::handleXEP136 (gloox::Tag *t)
757 {
758 if (gloox::Tag *arc = findNamespacedChild (t, "record", "http://jabber.org/protocol/archive"))
759 {
760 DropAttrib (arc, "otr");
761 CheckInvalid (arc);
762 }
763 }
764
handleXEP153(gloox::Tag * t,Contact * contr)765 void CLIMMXMPP::handleXEP153 (gloox::Tag *t, Contact *contr)
766 {
767 if (gloox::Tag *vcard = findNamespacedChild (t, "x", "vcard-temp:x:update"))
768 {
769 if (gloox::Tag *photo = vcard->findChild ("photo"))
770 {
771 DropCData (photo);
772 CheckInvalid (photo);
773 }
774 if (gloox::Tag *nick = vcard->findChild ("nickname"))
775 {
776 std::string nickname = nick->cdata();
777 ContactAddAlias (contr, nickname.c_str());
778 DropCData (nick);
779 CheckInvalid (nick);
780 }
781 CheckInvalid (vcard);
782 }
783 }
784
handleGoogleNosave(gloox::Tag * t)785 void CLIMMXMPP::handleGoogleNosave (gloox::Tag *t)
786 {
787 if (gloox::Tag *nosave = findNamespacedChild (t, "x", "google:nosave"))
788 {
789 DropAttrib (nosave, "value");
790 CheckInvalid (nosave);
791 }
792 }
793
handleGoogleSig(gloox::Tag * t)794 void CLIMMXMPP::handleGoogleSig (gloox::Tag *t)
795 {
796 if (gloox::Tag *sig = findNamespacedChild (t, "google-mail-signature", "google:metadata"))
797 {
798 DropCData (sig);
799 CheckInvalid (sig);
800 }
801 }
802
handleGoogleChatstate(gloox::Tag * t)803 void CLIMMXMPP::handleGoogleChatstate(gloox::Tag *t)
804 {
805 if (gloox::Tag *chat = findNamespacedChild (t, "active", "http://jabber.org/protocol/chatstates"))
806 CheckInvalid (chat);
807 }
808
809
handleMessage2(gloox::Stanza * t,gloox::JID from,std::string tof,std::string id,gloox::StanzaSubType subtype)810 void CLIMMXMPP::handleMessage2 (gloox::Stanza *t, gloox::JID from, std::string tof, std::string id, gloox::StanzaSubType subtype)
811 {
812 Contact *cto = ContactScreen (m_serv, tof.c_str());
813 std::string subtypeval = t->findAttribute ("type");
814 std::string body = t->body();
815 std::string subject = t->subject();
816 std::string html;
817 gloox::Tag *htmltag = findNamespacedChild (t, "html", "http://jabber.org/protocol/xhtml-im");
818 if (htmltag)
819 htmltag = findNamespacedChild (htmltag, "body", "http://www.w3.org/1999/xhtml");
820 if (htmltag)
821 html = htmltag->cdata();
822 DropAttrib (t, "type");
823 time_t delay;
824 Contact *contb, *contr;
825
826 GetBothContacts (from, m_serv, &contb, &contr, 0);
827
828 DropAllChilds (t, "subject");
829 DropAllChilds (t, "thread");
830 handleXEP71 (t);
831 handleGoogleNosave (t);
832 handleGoogleSig (t);
833 handleGoogleChatstate (t);
834 handleXEP136 (t);
835 delay = handleXEP91 (t);
836 handleXEP115 (t, contr); // entity capabilities (used also for client version)
837 if (handleXEP22and85 (t, contr, from, tof, id))
838 return;
839 DropAllChilds (t, "body");
840
841 Opt *opt = OptSetVals (NULL, CO_ORIGIN, CV_ORIGIN_v8, CO_MSGTYPE, MSG_NORM, CO_MSGTEXT, body.c_str(), 0);
842 if (!subject.empty())
843 opt = OptSetVals (opt, CO_MSGTYPE, MSG_NORM_SUBJ, CO_SUBJECT, subject.c_str(), 0);
844 if (!strcmp (html.c_str(), body.c_str()))
845 opt = OptSetVals (opt, CO_SAMEHTML, 1);
846 IMSrvMsgFat (contr, delay, opt);
847
848 if (gloox::Tag *x = t->findChild ("x"))
849 CheckInvalid (x);
850 }
851
852 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
handleMessage(gloox::Stanza * s,gloox::MessageSession * session)853 void CLIMMXMPP::handleMessage (gloox::Stanza *s, gloox::MessageSession *session)
854 #else
855 void CLIMMXMPP::handleMessage (gloox::Stanza *s)
856 #endif
857 {
858 assert (s);
859 assert (s->type() == gloox::StanzaMessage);
860
861 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
862 gloox::Stanza *t = new gloox::Stanza (s);
863 #else
864 gloox::Stanza *t = s->clone();
865 #endif
866
867 if (t->subtype() == gloox::StanzaMessageError)
868 DropAllChildsTree (t, "");
869 else
870 handleMessage2 (t, s->from(), s->to().full(), s->id(), s->subtype ());
871
872 DropAttrib (t, "from");
873 DropAttrib (t, "to");
874 DropAttrib (t, "id");
875 DropAttrib (t, "xml:lang");
876 if (t->hasAttribute ("xmlns", "jabber:client"))
877 DropAttrib (t, "xmlns");
878 if (!CheckInvalid (t))
879 {
880 std::string txml = t->xml();
881 CLIMMXMPPSave (m_serv, txml.c_str(), 3);
882 }
883 delete t;
884 }
885
handlePresence2(gloox::Tag * s,gloox::JID from,gloox::JID to,std::string msg)886 void CLIMMXMPP::handlePresence2 (gloox::Tag *s, gloox::JID from, gloox::JID to, std::string msg)
887 {
888 ContactGroup *tcg;
889 Contact *contb, *contr, *c;
890 status_t status;
891 std::string pri;
892 time_t delay;
893 std::string statustext;
894
895 GetBothContacts (from, m_serv, &contb, &contr, 1);
896
897 if (gloox::Tag *priority = s->findChild ("priority"))
898 {
899 pri = priority->cdata();
900 DropCData (priority);
901 CheckInvalid (priority);
902 }
903
904 delay = handleXEP91 (s);
905
906 handleXEP115 (s, contr); // entity capabilities (used also for client version)
907 handleXEP153 (s, contb); // vcard-based avatar, nickname
908 handleXEP27 (s); // OpenPGP signature (obsolete)
909 handleXEP8 (s); // iq-based avatar (obsolete)
910
911 if (s->hasAttribute ("type", "unavailable") || s->hasAttribute ("type", "error"))
912 {
913 if (s->hasAttribute ("type", "error"))
914 {
915 s_repl (&contr->version, "");
916 s_repl (&contr->cap_string, NULL);
917 }
918 status = ims_offline;
919 DropAttrib (s, "type");
920
921 IMOffline (contr);
922 return;
923 }
924 else if (gloox::Tag *show = s->findChild ("show"))
925 {
926 if (show->cdata() == "chat") status = ims_ffc;
927 else if (show->cdata() == "dnd") status = ims_dnd;
928 else if (show->cdata() == "xa") status = ims_na;
929 else if (show->cdata() == "away") status = ims_away;
930 else
931 return;
932 DropCData (show);
933 CheckInvalid (show);
934 }
935 else
936 status = ims_online;
937 if (gloox::Tag *stat = s->findChild ("status"))
938 {
939 statustext = stat->cdata ();
940 IMOnline (contr, status, imf_none, status, statustext.c_str());
941 }
942 else
943 IMOnline (contr, status, imf_none, status, NULL);
944 }
945
handlePresence(gloox::Stanza * s)946 void CLIMMXMPP::handlePresence (gloox::Stanza *s)
947 {
948 assert (s);
949 assert (s->type() == gloox::StanzaPresence);
950
951 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
952 gloox::Stanza *t = new gloox::Stanza(s);
953 #else
954 gloox::Stanza *t = s->clone();
955 #endif
956
957 if (t->subtype() == gloox::StanzaPresenceError)
958 DropAllChildsTree (t, "");
959 else
960 handlePresence2 (t, s->from(), s->to(), s->status());
961
962 DropAttrib (t, "from");
963 DropAttrib (t, "to");
964 DropAttrib (t, "id");
965 DropAttrib (t, "xml:lang");
966 if (t->hasAttribute ("xmlns", "jabber:client"))
967 DropAttrib (t, "xmlns");
968 DropAllChilds (t, "status");
969
970 if (!CheckInvalid (t))
971 {
972 std::string txml = t->xml();
973 CLIMMXMPPSave (m_serv, txml.c_str(), 3);
974 }
975 delete t;
976 }
977
handleSubscription(gloox::Stanza * s)978 void CLIMMXMPP::handleSubscription (gloox::Stanza *s)
979 {
980 assert (s);
981 assert (s->type() == gloox::StanzaS10n);
982 rl_printf ("handleSubscription from:<%s> to:<%s> type:<%d> id:<%s> status:<%s> prio:<%d> body:<%s> subj:<%s> thread:<%s> pres:<%d> xml:<%s>\n",
983 s->from().full().c_str(), s->to().full().c_str(), s->subtype(),
984 s->id().c_str(), s->status().c_str(), s->priority(),
985 s->body().c_str(), s->subject().c_str(),
986 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION >= 0x000900
987 s->thread().c_str(), s->presence(),
988 #else
989 s->thread().c_str(), s->show(),
990 #endif
991 s->xml().c_str());
992 }
993
handleLog(gloox::LogLevel level,gloox::LogArea area,const std::string & message)994 void CLIMMXMPP::handleLog (gloox::LogLevel level, gloox::LogArea area, const std::string &message)
995 {
996 const char *lt = "";
997 const char *la = "";
998 switch (area)
999 {
1000 case gloox::LogAreaClassParser: la = "parser"; break;
1001 #if defined(LIBGLOOX_VERSION) && LIBGLOOX_VERSION < 0x000900
1002 case gloox::LogAreaClassConnection: la = "conn"; break;
1003 #endif
1004 case gloox::LogAreaClassClient: la = "client"; break;
1005 case gloox::LogAreaClassClientbase: la = "clbase"; break;
1006 case gloox::LogAreaClassComponent: la = "comp"; break;
1007 case gloox::LogAreaClassDns: la = "dns"; break;
1008 case gloox::LogAreaXmlIncoming: la = "xmlin"; break;
1009 case gloox::LogAreaXmlOutgoing: la = "xmlout"; break;
1010 case gloox::LogAreaUser: la = "user"; break;
1011 }
1012 switch (level)
1013 {
1014 case gloox::LogLevelDebug: lt = "debug"; break;
1015 case gloox::LogLevelWarning: lt = "warn"; break;
1016 case gloox::LogLevelError: lt = "error"; break;
1017 }
1018 if (area == gloox::LogAreaXmlIncoming)
1019 {
1020 if (ServerPrefVal (m_serv, CO_LOGSTREAM))
1021 CLIMMXMPPSave (m_serv, message.c_str(), 1);
1022 DebugH (DEB_XMPPIN, "%s/%s: %s", lt, la, message.c_str());
1023 }
1024 else if (area == gloox::LogAreaXmlOutgoing)
1025 {
1026 if (ServerPrefVal (m_serv, CO_LOGSTREAM))
1027 CLIMMXMPPSave (m_serv, message.c_str(), 0);
1028 DebugH (DEB_XMPPOUT, "%s/%s: %s", lt, la, message.c_str());
1029 }
1030 else
1031 DebugH (DEB_XMPPOTHER, "%s/%s: %s", lt, la, message.c_str());
1032 }
1033
1034 /***************** Time Query *******************/
1035
sendIqTime(void)1036 void CLIMMXMPP::sendIqTime (void)
1037 {
1038 gloox::Tag *iq = new gloox::Tag ("iq");
1039 iq->addAttribute ("type", "get");
1040 iq->addAttribute ("to", m_client->jid().bare ());
1041 iq->addAttribute ("id", s_sprintf ("time-%s-%x", m_stamp, m_serv->xmpp_sequence++));
1042 gloox::Tag *qq = new gloox::Tag (iq, "time");
1043 qq->addAttribute ("xmlns", "urn:xmpp:time");
1044 m_client->send (iq);
1045 }
1046
sendIqTimeReqs(Event * event)1047 static void sendIqTimeReqs (Event *event)
1048 {
1049 if (!event->conn)
1050 {
1051 EventD (event);
1052 return;
1053 }
1054 CLIMMXMPP *j = getXMPPClient (event->conn->serv);
1055 assert (j);
1056 j->sendIqTime ();
1057 event->due += 300;
1058 QueueEnqueue (event);
1059 }
1060
1061 /****************** GoogleMail ******************/
1062
sendIqGmail(int64_t newer,std::string newertid,std::string q,bool isauto)1063 void CLIMMXMPP::sendIqGmail (int64_t newer, std::string newertid, std::string q, bool isauto)
1064 {
1065 gloox::Tag *iq = new gloox::Tag ("iq");
1066 iq->addAttribute ("type", "get");
1067 iq->addAttribute ("from", m_client->jid().full ());
1068 iq->addAttribute ("to", m_client->jid().bare ());
1069 iq->addAttribute ("id", s_sprintf ("%s-%s-%x", isauto ? "mail" : "mailq", m_stamp, m_serv->xmpp_sequence++));
1070 if (newer == 1000ULL)
1071 {
1072 newer = gmail_newer;
1073 newertid = gmail_newertid;
1074 q = gmail_query;
1075 }
1076 if (isauto)
1077 {
1078 newer = gmail_new_newer;
1079 newertid = gmail_new_newertid;
1080 }
1081 else
1082 gmail_query = q;
1083 gloox::Tag *qq = new gloox::Tag (iq, "query");
1084 qq->addAttribute ("xmlns", "google:mail:notify");
1085 if (newer != 0)
1086 qq->addAttribute ("newer-than-time", s_sprintf ("%llu", newer));
1087 if (*newertid.c_str ())
1088 qq->addAttribute ("newer-than-tid", newertid);
1089 if (*q.c_str ())
1090 qq->addAttribute ("q", q);
1091 m_client->send (iq);
1092 }
1093
sendIqGmailReqs(Event * event)1094 static void sendIqGmailReqs (Event *event)
1095 {
1096 if (!event->conn)
1097 {
1098 EventD (event);
1099 return;
1100 }
1101 CLIMMXMPP *j = getXMPPClient (event->conn->serv);
1102 assert (j);
1103 j->sendIqGmail ((event->due - 300ULL)*1000ULL, "", "", 1);
1104 event->due += 300;
1105 QueueEnqueue (event);
1106 }
1107
1108 /******************************************/
1109
onConnect()1110 void CLIMMXMPP::onConnect ()
1111 {
1112 m_serv->conn->connect = CONNECT_OK | CONNECT_SELECT_R;
1113
1114 XMPPSetstatus (m_serv, NULL, m_serv->status, m_serv->conn->cont->status_message);
1115
1116 gloox::Tag *iq = new gloox::Tag ("iq");
1117 iq->addAttribute ("type", "get");
1118 iq->addAttribute ("from", m_client->jid().full ());
1119 iq->addAttribute ("id", s_sprintf ("roster-%s-%x", m_stamp, m_serv->xmpp_sequence++));
1120 gloox::Tag *qq = new gloox::Tag (iq, "query");
1121 qq->addAttribute ("xmlns", "jabber:iq:roster");
1122 m_client->send (iq);
1123
1124 QueueEnqueueData2 (m_serv->conn, QUEUE_SRV_KEEPALIVE, 0, 300, NULL, &sendIqTimeReqs, NULL);
1125
1126 m_client->disco()->getDiscoInfo (m_client->jid().server(), "", this, 0);
1127 // m_client->send (gloox::Stanza::createPresenceStanza (gloox::JID (""), "", gloox::PresenceChat));
1128 }
1129
1130 /****************** IqHandler **********/
1131
handleIq(gloox::Stanza * stanza)1132 bool CLIMMXMPP::handleIq (gloox::Stanza *stanza)
1133 {
1134 if (stanza->subtype() == gloox::StanzaIqError)
1135 DropAllChildsTree (stanza, "");
1136
1137 if (gloox::Tag *mb = findNamespacedChild (stanza, "mailbox", "google:mail:notify"))
1138 {
1139 int n = 0;
1140 int ismail = 0;
1141 if (mb->hasAttribute ("total-matched"))
1142 {
1143 std::string a = mb->findAttribute ("total-matched");
1144 n = atoi (a.c_str());
1145 }
1146 std::string from = stanza->from().bare();
1147 std::string id = stanza->id();
1148 if (!strncmp (id.c_str (), "mail-", 5))
1149 {
1150 ismail = 1;
1151 if (n || !strcmp (id.c_str () + strlen (id.c_str()) - 2, "-0"))
1152 rl_printf (i18n (2738, "Found %d new mails for %s.\n"), n, from.c_str());
1153 }
1154 else
1155 rl_printf (i18n (2739, "Found %d mails for %s.\n"), n, from.c_str());
1156 if (!n)
1157 return true;
1158 gloox::Tag::TagList ml = mb->children ();
1159 gloox::Tag::TagList::iterator mlit = ml.begin();
1160 std::string ntid;
1161 Contact *cont = m_serv->conn->cont;
1162 for ( ; mlit != ml.end(); mlit++)
1163 {
1164 if ((*mlit)->name() != "mail-thread-info")
1165 continue;
1166 std::string sub = (*mlit)->findChild ("subject")->cdata();
1167 std::string snip = (*mlit)->findChild ("snippet")->cdata();
1168 std::string dato = (*mlit)->findAttribute ("date");
1169 ntid = (*mlit)->findAttribute ("tid");
1170 time_t t = atoll (dato.c_str ()) / 1000ULL;
1171 rl_printf ("%s ", s_time (&t));
1172 rl_printf ("%s%s %s%s%s", COLMESSAGE, sub.c_str (), COLQUOTE, COLSINGLE, snip.c_str ());
1173 rl_print ("\n");
1174 gloox::Tag::TagList mls = (*mlit)->findChild ("senders")->children ();
1175 gloox::Tag::TagList::iterator mlsit = mls.begin ();
1176 for ( ; mlsit !=mls.end(); mlsit++)
1177 {
1178 if ((*mlsit)->name() != "sender")
1179 continue;
1180 if (!ismail || (*mlsit)->hasAttribute ("unread", "1"))
1181 {
1182 std::string email = (*mlsit)->findAttribute ("address");
1183 std::string name = (*mlsit)->findAttribute ("name");
1184 rl_printf (" %s%s%s <%s%s%s>\n", COLQUOTE, name.c_str(), COLNONE, COLCONTACT, email.c_str(), COLNONE);
1185 }
1186 }
1187 }
1188 std::string foundnewer = mb->findAttribute ("result-time");
1189 if (ismail)
1190 {
1191 gmail_new_newer = atoll (foundnewer.c_str ());
1192 gmail_new_newertid = ntid;
1193 }
1194 else
1195 {
1196 gmail_newer = atoll (foundnewer.c_str ());
1197 gmail_newertid = ntid;
1198 }
1199 return true;
1200 }
1201 CLIMMXMPPSave (m_serv, stanza->xml().c_str(), 3);
1202 return 0;
1203 }
1204
handleIqID(gloox::Stanza * stanza,int context)1205 bool CLIMMXMPP::handleIqID (gloox::Stanza *stanza, int context)
1206 {
1207 return 0;
1208 }
1209
1210 /****************** DiscoHandler ****************/
1211
handleDiscoInfoResult(gloox::Stanza * stanza,int context)1212 void CLIMMXMPP::handleDiscoInfoResult (gloox::Stanza *stanza, int context)
1213 {
1214 if (stanza->from().server() == m_client->jid().server())
1215 {
1216 gloox::Tag *id = stanza->findChild ("query");
1217 if (id)
1218 {
1219 if (id->hasChild ("feature", "var", "google:mail:notify"))
1220 {
1221 sendIqGmail ();
1222 QueueEnqueueData2 (m_serv->conn, QUEUE_XMPP_GMAIL, 0, 300, NULL, &sendIqGmailReqs, NULL);
1223 m_client->registerIqHandler (this, "google:mail:notify");
1224 }
1225 return;
1226 }
1227 }
1228 CLIMMXMPPSave (m_serv, stanza->xml().c_str(), 3);
1229 }
1230
handleDiscoItemsResult(gloox::Stanza * stanza,int context)1231 void CLIMMXMPP::handleDiscoItemsResult (gloox::Stanza *stanza, int context)
1232 {
1233 CLIMMXMPPSave (m_serv, stanza->xml().c_str(), 3);
1234 }
1235
handleDiscoError(gloox::Stanza * stanza,int context)1236 void CLIMMXMPP::handleDiscoError (gloox::Stanza *stanza, int context)
1237 {
1238 CLIMMXMPPSave (m_serv, stanza->xml().c_str(), 3);
1239 }
1240
handleDiscoSet(gloox::Stanza * stanza)1241 bool CLIMMXMPP::handleDiscoSet (gloox::Stanza *stanza)
1242 {
1243 CLIMMXMPPSave (m_serv, stanza->xml().c_str(), 3);
1244 return 0;
1245 }
1246
1247 /**************/
1248
SnacCallbackXmpp(Event * event)1249 static void SnacCallbackXmpp (Event *event)
1250 {
1251 Message *msg = (Message *)event->data;
1252
1253 assert (event);
1254 assert (msg);
1255 assert (event->cont);
1256
1257 if (event->attempts < 5)
1258 {
1259 if (msg->send_message && !msg->otrinjected)
1260 {
1261 msg->type = INT_MSGACK_V8;
1262 // IMIntMsgMsg (msg, NOW, ims_offline);
1263 }
1264 event->attempts = 20;
1265 event->due = time (NULL) + 600;
1266 QueueEnqueue (event);
1267 }
1268 else
1269 {
1270 MsgD (msg);
1271 event->data = NULL;
1272 EventD (event);
1273 }
1274 }
1275
SnacCallbackXmppCancel(Event * event)1276 static void SnacCallbackXmppCancel (Event *event)
1277 {
1278 Message *msg = (Message *)event->data;
1279 if (msg->send_message && !msg->otrinjected)
1280 rl_printf (i18n (2234, "Message %s discarded - lost session.\n"),
1281 msg->plain_message ? msg->plain_message : msg->send_message);
1282 MsgD (msg);
1283 event->data = NULL;
1284 EventD (event);
1285 }
1286
XMPPSendmsg(Server * serv,Contact * cont,Message * msg)1287 UBYTE CLIMMXMPP::XMPPSendmsg (Server *serv, Contact *cont, Message *msg)
1288 {
1289 assert (serv == m_serv);
1290
1291 assert (cont);
1292 assert (msg->send_message);
1293
1294 if (~m_serv->conn->connect & CONNECT_OK)
1295 return RET_DEFER;
1296 if (msg->type != MSG_NORM)
1297 return RET_DEFER;
1298
1299 gloox::Stanza *msgs = gloox::Stanza::createMessageStanza (gloox::JID (cont->screen), msg->send_message);
1300 msgs->addAttribute ("id", s_sprintf ("xmpp-%s-%x", m_stamp, ++m_serv->xmpp_sequence));
1301
1302 std::string res = m_client->resource();
1303 msgs->addAttribute ("from", s_sprintf ("%s/%s", serv->screen, res.c_str()));
1304 gloox::Tag *x = new gloox::Tag (msgs, "x");
1305 x->addAttribute ("xmlns", "jabber:x:event");
1306 new gloox::Tag (x, "offline");
1307 new gloox::Tag (x, "delivered");
1308 new gloox::Tag (x, "displayed");
1309 new gloox::Tag (x, "composing");
1310 m_client->send (msgs);
1311
1312 Event *event = QueueEnqueueData2 (serv->conn, QUEUE_XMPP_RESEND_ACK, m_serv->xmpp_sequence, 120, msg, &SnacCallbackXmpp, &SnacCallbackXmppCancel);
1313 event->cont = cont;
1314
1315 return RET_OK;
1316 }
1317
XMPPSetstatus(Server * serv,Contact * cont,status_t status,const char * msg)1318 void CLIMMXMPP::XMPPSetstatus (Server *serv, Contact *cont, status_t status, const char *msg)
1319 {
1320 gloox::Presence p = StatusToGlooxstatus (status);
1321 gloox::JID j = cont ? gloox::JID (cont->screen) : gloox::JID ();
1322
1323 gloox::Stanza *pres = gloox::Stanza::createPresenceStanza (j, msg ? msg : "", p);
1324 if (p != gloox::PresenceUnavailable)
1325 {
1326 gloox::Tag *vers = new gloox::Tag (pres, "c");
1327 vers->addAttribute ("xmlns", "http://jabber.org/protocol/caps");
1328 vers->addAttribute ("node", "http://www.climm.org/xmpp/caps");
1329 vers->addAttribute ("ver", s_sprintf ("%s gloox", BuildVersionStr));
1330 // vers->addAttribute ("ext", "ext1 ext2");
1331 }
1332 s_repl (&serv->conn->cont->status_message, msg);
1333 m_client->send (pres);
1334 m_serv->status = status;
1335 m_serv->nativestatus = p;
1336 }
1337
XMPPAuthorize(Server * serv,Contact * cont,auth_t how,const char * msg)1338 void CLIMMXMPP::XMPPAuthorize (Server *serv, Contact *cont, auth_t how, const char *msg)
1339 {
1340 gloox::JID j = gloox::JID (cont->screen);
1341 gloox::Tag *pres = new gloox::Tag ("presence");
1342 std::string res = m_client->resource();
1343 pres->addAttribute ("from", s_sprintf ("%s/%s", serv->screen, res.c_str()));
1344 while (cont->parent && cont->parent->serv == cont->serv)
1345 cont = cont->parent;
1346 pres->addAttribute ("to", cont->screen);
1347 pres->addAttribute ("type", how == auth_grant ? "subscribed"
1348 : how == auth_deny ? "unsubscribed"
1349 : how == auth_req ? "subscribe"
1350 : "unsubscribe");
1351 if (msg)
1352 new gloox::Tag (pres, "status", msg);
1353 m_client->send (pres);
1354 }
1355
1356 #ifdef CLIMM_XMPP_FILE_TRANSFER
1357
handleSOCKS5Data(gloox::SOCKS5Bytestream * s5b,const std::string & data)1358 void CLIMMXMPP::handleSOCKS5Data (gloox::SOCKS5Bytestream *s5b, const std::string &data)
1359 {
1360 Contact *cont, *contr;
1361 Connection *fpeer;
1362
1363 GetBothContacts (s5b->initiator().full(), m_serv, &cont, &contr, 0);
1364 fpeer = ServerFindChild (m_serv, contr, TYPE_XMPPDIRECT);
1365 assert (fpeer);
1366
1367 int len = write (fpeer->xmpp_file->sok, data.c_str(), data.length());
1368 if (len != data.length())
1369 {
1370 rl_log_for (contr->screen, COLCONTACT);
1371 rl_printf (i18n (2575, "Error writing to file (%lu bytes written out of %u).\n"), (long unsigned int)len, data.length());
1372 }
1373 fpeer->xmpp_file->xmpp_file_done += len;
1374 if (fpeer->xmpp_file->xmpp_file_len == fpeer->xmpp_file->xmpp_file_done)
1375 {
1376 ReadLinePromptReset ();
1377 rl_log_for (cont->screen, COLCONTACT);
1378 rl_print (i18n (2166, "Finished receiving file.\n"));
1379 #if HAVE_FSYNC
1380 fsync (fpeer->xmpp_file->sok);
1381 #endif
1382 close (fpeer->xmpp_file->sok);
1383 fpeer->xmpp_file->sok = -1;
1384 }
1385 else if (fpeer->xmpp_file->xmpp_file_len)
1386 {
1387 ReadLinePromptUpdate (s_sprintf ("[%s%ld %02d%%%s] %s%s",
1388 COLINCOMING, fpeer->xmpp_file->xmpp_file_done, (int)((100.0 * fpeer->xmpp_file->xmpp_file_done) / fpeer->xmpp_file->xmpp_file_len),
1389 COLNONE, COLSERVER, i18n (2467, "climm>")));
1390 }
1391 }
1392
handleSOCKS5Error(gloox::SOCKS5Bytestream * s5b,gloox::Stanza * stanza)1393 void CLIMMXMPP::handleSOCKS5Error (gloox::SOCKS5Bytestream *s5b, gloox::Stanza *stanza)
1394 {
1395 }
1396
handleSOCKS5Open(gloox::SOCKS5Bytestream * s5b)1397 void CLIMMXMPP::handleSOCKS5Open (gloox::SOCKS5Bytestream *s5b)
1398 {
1399 }
1400
handleSOCKS5Close(gloox::SOCKS5Bytestream * s5b)1401 void CLIMMXMPP::handleSOCKS5Close (gloox::SOCKS5Bytestream *s5b)
1402 {
1403 Contact *cont, *contr;
1404 Connection *fpeer;
1405
1406 GetBothContacts (s5b->initiator(), m_serv, &cont, &contr, 0);
1407 fpeer = ServerFindChild (m_serv, contr, TYPE_XMPPDIRECT);
1408 assert (fpeer);
1409 ConnectionD (fpeer);
1410 }
1411
handleFTRequestError(gloox::Stanza * stanza)1412 void CLIMMXMPP::handleFTRequestError (gloox::Stanza *stanza)
1413 {
1414 rl_printf (i18n (2234, "Message %s discarded - lost session.\n"), stanza->errorText().c_str());
1415 }
1416
handleFTSOCKS5Bytestream(gloox::SOCKS5Bytestream * s5b)1417 void CLIMMXMPP::handleFTSOCKS5Bytestream (gloox::SOCKS5Bytestream *s5b)
1418 {
1419 strc_t name;
1420 int len, off;
1421 Contact *cont, *contr;
1422 GetBothContacts (s5b->initiator(), m_serv, &cont, &contr, 0);
1423 s5b->registerSOCKS5BytestreamDataHandler (this);
1424 rl_printf (i18n (2709, "Opening file listener connection at %slocalhost%s:%s%p%s... "),
1425 COLQUOTE, COLNONE, COLQUOTE, s5b->connectionImpl(), COLNONE);
1426 if (s5b->connect())
1427 {
1428 rl_print (i18n (1634, "ok.\n"));
1429 gloox::ConnectionTCPBase *conn = dynamic_cast<gloox::ConnectionTCPBase *>(s5b->connectionImpl());
1430 if (!conn)
1431 return;
1432 Connection *child = ServerFindChild (m_serv, contr, TYPE_XMPPDIRECT);
1433 if (!child)
1434 return;
1435
1436 /**
1437 * Insert socket into climms TCP handler
1438 */
1439 child->sok = conn->socket();
1440 child->connect = CONNECT_OK | CONNECT_SELECT_R;
1441 child->xmpp_file_private = s5b;
1442 }
1443 }
1444
handleFTRequest(const gloox::JID & from,const std::string & id,const std::string & sid,const std::string & name,long size,const std::string & hash,const std::string & date,const std::string & mimetype,const std::string & desc,int stypes,long offset,long length)1445 void CLIMMXMPP::handleFTRequest (const gloox::JID & from, const std::string & id, const std::string & sid,
1446 const std::string & name, long size, const std::string & hash, const std::string & date,
1447 const std::string & mimetype, const std::string & desc, int stypes, long offset, long length)
1448 {
1449 Contact *cont, *contr;
1450 // Build a nicer description
1451 std::string pretty = name;
1452
1453 if (desc.size())
1454 pretty += " (" + desc + ")";
1455
1456 UWORD seq = ++m_serv->xmpp_file_seq;
1457 l_tSeqTranslate[seq] = sid;
1458 sid2id[sid] = id; //This will be changed in the 1.0 release of gloox :)
1459 GetBothContacts (from, m_serv, &cont, &contr, 0);
1460
1461 Opt *opt2 = OptC ();
1462 OptSetVal (opt2, CO_BYTES, size);
1463 OptSetStr (opt2, CO_MSGTEXT, pretty.c_str());
1464 OptSetVal (opt2, CO_REF, seq);
1465 OptSetVal (opt2, CO_MSGTYPE, MSG_FILE);
1466 IMSrvMsgFat (contr, NOW, opt2);
1467 opt2 = OptC ();
1468 OptSetVal (opt2, CO_FILEACCEPT, 0);
1469 OptSetStr (opt2, CO_REFUSE, i18n (2514, "refused (ignored)"));
1470 Event *e1 = QueueEnqueueData (m_serv->conn, QUEUE_USERFILEACK, seq, time (NULL) + 120,
1471 NULL, cont, opt2, &PeerFileTO); //Timeout Handler
1472 QueueEnqueueDep (m_serv->conn, 0, seq, e1,
1473 NULL, contr, opt2, XMPPCallBackFileAccept); // Route whatever there ;)
1474
1475 // Prepare a FileListener
1476 Connection *child = ServerChild (m_serv, contr, TYPE_XMPPDIRECT);
1477 if (!child)
1478 return; //Failed
1479
1480 /**
1481 * Insert socket into climms TCP handler
1482 */
1483 child->sok = -1;
1484 child->connect = CONNECT_FAIL;
1485 child->dispatch = &XMPPFTCallbackDispatch;
1486 child->close = &XMPPFTCallbackClose;
1487
1488 /**
1489 * Create the output file
1490 */
1491 Connection *ffile = ServerChild (m_serv, contr, TYPE_FILEXMPP);
1492 char buf[200], *p;
1493 str_s filename = { (char *)name.c_str(), name.length(), name.length() };
1494 int pos = 0;
1495
1496 assert (ffile);
1497 pos = snprintf (buf, sizeof (buf), "%sfiles" _OS_PATHSEPSTR "%s" _OS_PATHSEPSTR,
1498 PrefUserDir (prG), cont->screen);
1499 snprintf (buf + pos, sizeof (buf) - pos, "%s", (ConvFrom (&filename, ENC_UTF8))->txt);
1500 for (p = buf + pos; *p; p++)
1501 if (*p == '/')
1502 *p = '_';
1503 child->xmpp_file = ffile;
1504 s_repl (&ffile->server, buf);
1505 ffile->connect = CONNECT_FAIL;
1506 ffile->xmpp_file_len = size;
1507 ffile->xmpp_file_done = offset;
1508 }
1509
XMPPAcceptDenyFT(gloox::JID contact,std::string id,std::string sid,const char * reason)1510 void CLIMMXMPP::XMPPAcceptDenyFT (gloox::JID contact, std::string id, std::string sid, const char *reason)
1511 {
1512 Connection *conn;
1513 if (!reason)
1514 return m_pFT->acceptFT (contact, id, gloox::SIProfileFT::FTTypeS5B);
1515 m_pFT->declineFT (contact, id, gloox::SIManager::RequestRejected, reason);
1516 }
1517
XMPPFTCallbackClose(Connection * conn)1518 void XMPPFTCallbackClose (Connection *conn)
1519 {
1520 if (conn->sok == -1)
1521 return;
1522
1523 gloox::SOCKS5Bytestream *s = (gloox::SOCKS5Bytestream *)(conn->xmpp_file_private);
1524 conn->sok = -1;
1525 }
1526
XMPPFTCallbackDispatch(Connection * conn)1527 void XMPPFTCallbackDispatch (Connection *conn)
1528 {
1529 if (conn->sok == -1)
1530 return;
1531
1532 gloox::SOCKS5Bytestream *s = (gloox::SOCKS5Bytestream *)(conn->xmpp_file_private);
1533 if (!s)
1534 {
1535 rl_printf ("#Avoid spinning.\n");
1536 conn->sok = -1;
1537 return;
1538 }
1539
1540 s->recv (0);
1541 }
1542
1543 #endif
1544
XMPPCallBackTimeout(Event * event)1545 static void XMPPCallBackTimeout (Event *event)
1546 {
1547 Connection *conn = event->conn;
1548
1549 if (!conn)
1550 {
1551 EventD (event);
1552 return;
1553 }
1554 assert (conn->serv);
1555 assert (conn->serv->type == TYPE_XMPP_SERVER);
1556 if (~conn->connect & CONNECT_OK)
1557 rl_print ("# XMPP timeout\n");
1558 EventD (event);
1559 }
1560
XMPPLogin(Server * serv)1561 Event *XMPPLogin (Server *serv)
1562 {
1563 const char *sp;
1564 Event *event;
1565
1566 assert (serv->type == TYPE_XMPP_SERVER);
1567
1568 if (!serv->screen || !serv->passwd)
1569 return NULL;
1570 if (!strchr (serv->screen, '@'))
1571 {
1572 const char *jid;
1573 if (!serv->conn->server)
1574 serv->conn->server = strdup ("jabber.com");
1575 jid = s_sprintf ("%s@%s", serv->screen, serv->conn->server);
1576 s_repl (&serv->screen, jid);
1577 }
1578
1579 XMPPCallbackClose (serv->conn);
1580
1581 sp = s_sprintf ("%s", s_wordquote (s_sprintf ("%s:%lu", serv->conn->server, serv->conn->port)));
1582 rl_printf (i18n (2620, "Opening XMPP connection for %s at %s...\n"),
1583 s_wordquote (serv->screen), sp);
1584
1585 if (!serv->conn->port)
1586 serv->conn->port = ~0;
1587
1588 serv->conn->reconnect = NULL;
1589 serv->conn->close = &XMPPCallbackClose;
1590 serv->conn->dispatch = &XMPPCallbackDispatch;
1591
1592 if ((event = QueueDequeue2 (serv->conn, QUEUE_DEP_WAITLOGIN, 0, NULL)))
1593 {
1594 event->attempts++;
1595 event->due = time (NULL) + 10 * event->attempts + 10;
1596 event->callback = &XMPPCallBackTimeout;
1597 QueueEnqueue (event);
1598 }
1599 else
1600 event = QueueEnqueueData (serv->conn, QUEUE_DEP_WAITLOGIN, 0, time (NULL) + 5,
1601 NULL, serv->conn->cont, NULL, &XMPPCallBackTimeout);
1602
1603 CLIMMXMPP *l = new CLIMMXMPP (serv);
1604 serv->xmpp_private = l;
1605 serv->conn->connect |= CONNECT_SELECT_R;
1606
1607 return event;
1608 }
1609
XMPPCallbackDispatch(Connection * conn)1610 void XMPPCallbackDispatch (Connection *conn)
1611 {
1612 if (conn->sok == -1)
1613 return;
1614
1615 CLIMMXMPP *j = getXMPPClient (conn->serv);
1616 if (!j)
1617 {
1618 rl_printf ("#Avoid spinning.\n");
1619 conn->sok = -1;
1620 return;
1621 }
1622
1623 j->getClient()->recv (0);
1624 }
1625
XMPPCallbackClose(Connection * conn)1626 void XMPPCallbackClose (Connection *conn)
1627 {
1628 if (!conn)
1629 return;
1630
1631 CLIMMXMPP *j = getXMPPClient (conn->serv);
1632 if (!j && conn->sok == -1)
1633 return;
1634 if (!j)
1635 {
1636 rl_printf ("#Avoid spinning.\n");
1637 conn->sok = -1;
1638 return;
1639 }
1640
1641 QueueCancel (conn);
1642 j->getClient()->disconnect ();
1643 conn->serv->xmpp_private = NULL;
1644 delete j;
1645 }
1646
1647 #ifdef CLIMM_XMPP_FILE_TRANSFER
XMPPCallBackFileAccept(Event * event)1648 void XMPPCallBackFileAccept (Event *event)
1649 {
1650 Connection *conn = event->conn;
1651 Contact *id, *res = NULL;
1652 CLIMMXMPP *j;
1653 UDWORD opt_acc;
1654 std::string seq, sid;
1655 char *reason = NULL;
1656
1657 std::map<UWORD, std::string>::iterator l_it;
1658 l_it = l_tSeqTranslate.find (event->seq);
1659 if (l_it != l_tSeqTranslate.end())
1660 sid = l_tSeqTranslate[event->seq];
1661
1662 seq = sid2id[sid];
1663
1664 if (!conn)
1665 {
1666 EventD (event);
1667 return;
1668 }
1669 j = getXMPPClient (conn->serv);
1670 assert (conn->serv);
1671 assert (conn->serv->type == TYPE_XMPP_SERVER);
1672 assert (event->cont);
1673 assert (event->cont->parent);
1674
1675 res = event->cont;
1676 id = res->parent;
1677
1678 assert (id);
1679
1680 OptGetVal (event->opt, CO_FILEACCEPT, &opt_acc);
1681 if (!opt_acc)
1682 OptGetStr (event->opt, CO_REFUSE, (const char **)&reason);
1683 else
1684 {
1685 Connection *conn = ServerFindChild (event->conn->serv, event->cont, TYPE_XMPPDIRECT);
1686 Connection *ffile = conn->xmpp_file;
1687 Contact *cont = res->parent;
1688 assert (ffile->type == TYPE_FILEXMPP);
1689 ffile->sok = open (ffile->server, O_CREAT | O_WRONLY | (ffile->xmpp_file_done ? O_APPEND : O_TRUNC), 0660);
1690 if (ffile->sok == -1)
1691 {
1692 int rc = errno;
1693 if (rc == ENOENT)
1694 {
1695 mkdir (s_sprintf ("%sfiles", PrefUserDir (prG)), 0700);
1696 mkdir (s_sprintf ("%sfiles" _OS_PATHSEPSTR "%s", PrefUserDir (prG), cont->screen), 0700);
1697 ffile->sok = open (ffile->server, O_CREAT | O_WRONLY | (ffile->xmpp_file_done ? O_APPEND : O_TRUNC), 0660);
1698 }
1699 if (ffile->sok == -1)
1700 {
1701 rl_log_for (cont->screen, COLCONTACT);
1702 rl_printf (i18n (2083, "Cannot open file %s: %s (%d).\n"),
1703 ffile->server, strerror (rc), rc);
1704 ConnectionD (conn);
1705 return;
1706 }
1707 }
1708 ffile->connect = CONNECT_OK;
1709 }
1710 j->XMPPAcceptDenyFT (gloox::JID (std::string (id->screen) + "/" + res->screen), seq, sid, reason);
1711 event->opt = NULL;
1712 EventD (QueueDequeueEvent (event->wait));
1713 EventD (event);
1714 }
1715 #endif
1716
XMPPSendmsg(Server * serv,Contact * cont,Message * msg)1717 UBYTE XMPPSendmsg (Server *serv, Contact *cont, Message *msg)
1718 {
1719 CLIMMXMPP *j = getXMPPClient (serv);
1720 assert (j);
1721 return j->XMPPSendmsg (serv, cont, msg);
1722 }
1723
XMPPSetstatus(Server * serv,Contact * cont,status_t status,const char * msg)1724 void XMPPSetstatus (Server *serv, Contact *cont, status_t status, const char *msg)
1725 {
1726 CLIMMXMPP *j = getXMPPClient (serv);
1727 assert (j);
1728 j->XMPPSetstatus (serv, cont, status, msg);
1729 }
1730
XMPPAuthorize(Server * serv,Contact * cont,auth_t how,const char * msg)1731 void XMPPAuthorize (Server *serv, Contact *cont, auth_t how, const char *msg)
1732 {
1733 CLIMMXMPP *j = getXMPPClient (serv);
1734 assert (j);
1735 assert (cont);
1736 j->XMPPAuthorize (serv, cont, how, msg);
1737 }
1738
XMPPGoogleMail(Server * serv,time_t since,const char * query)1739 void XMPPGoogleMail (Server *serv, time_t since, const char *query)
1740 {
1741 CLIMMXMPP *j = getXMPPClient (serv);
1742 assert (j);
1743 assert (query);
1744 j->sendIqGmail (since * 1000ULL, "", query, 0);
1745 }
1746