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