Multiple revisions 374570,374581
[asterisk/asterisk.git] / res / res_xmpp.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief XMPP client and component module.
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  * Iksemel http://code.google.com/p/iksemel/
26  *
27  * A reference module for interfacting Asterisk directly as a client or component with
28  * an XMPP/Jabber compliant server.
29  *
30  * This module is based upon the original res_jabber as done by Matt O'Gorman.
31  *
32  */
33
34 /*! 
35  * \li The resource res_xmpp uses the configuration file \ref xmpp.conf
36  * \addtogroup configuration_file Configuration Files
37  */
38
39 /*!
40  * \page xmpp.conf xmpp.conf
41  * \verbinclude xmpp.conf.sample
42  */
43
44 /*** MODULEINFO
45         <depend>iksemel</depend>
46         <use type="external">openssl</use>
47         <support_level>core</support_level>
48  ***/
49
50 #include "asterisk.h"
51
52 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
53
54 #include <ctype.h>
55 #include <iksemel.h>
56
57 #include "asterisk/xmpp.h"
58 #include "asterisk/module.h"
59 #include "asterisk/manager.h"
60 #include "asterisk/app.h"
61 #include "asterisk/message.h"
62 #include "asterisk/manager.h"
63 #include "asterisk/event.h"
64 #include "asterisk/cli.h"
65 #include "asterisk/config_options.h"
66
67 /*** DOCUMENTATION
68         <application name="JabberSend" language="en_US">
69                 <synopsis>
70                         Sends an XMPP message to a buddy.
71                 </synopsis>
72                 <syntax>
73                         <parameter name="account" required="true">
74                                 <para>The local named account to listen on (specified in
75                                 xmpp.conf)</para>
76                         </parameter>
77                         <parameter name="jid" required="true">
78                                 <para>Jabber ID of the buddy to send the message to. It can be a
79                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
80                         </parameter>
81                         <parameter name="message" required="true">
82                                 <para>The message to send.</para>
83                         </parameter>
84                 </syntax>
85                 <description>
86                         <para>Sends the content of <replaceable>message</replaceable> as text message
87                         from the given <replaceable>account</replaceable> to the buddy identified by
88                         <replaceable>jid</replaceable></para>
89                         <para>Example: JabberSend(asterisk,bob@domain.com,Hello world) sends "Hello world"
90                         to <replaceable>bob@domain.com</replaceable> as an XMPP message from the account
91                         <replaceable>asterisk</replaceable>, configured in xmpp.conf.</para>
92                 </description>
93                 <see-also>
94                         <ref type="function">JABBER_STATUS</ref>
95                         <ref type="function">JABBER_RECEIVE</ref>
96                 </see-also>
97         </application>
98         <function name="JABBER_RECEIVE" language="en_US">
99                 <synopsis>
100                         Reads XMPP messages.
101                 </synopsis>
102                 <syntax>
103                         <parameter name="account" required="true">
104                                 <para>The local named account to listen on (specified in
105                                 xmpp.conf)</para>
106                         </parameter>
107                         <parameter name="jid" required="true">
108                                 <para>Jabber ID of the buddy to receive message from. It can be a
109                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
110                         </parameter>
111                         <parameter name="timeout">
112                                 <para>In seconds, defaults to <literal>20</literal>.</para>
113                         </parameter>
114                 </syntax>
115                 <description>
116                         <para>Receives a text message on the given <replaceable>account</replaceable>
117                         from the buddy identified by <replaceable>jid</replaceable> and returns the contents.</para>
118                         <para>Example: ${JABBER_RECEIVE(asterisk,bob@domain.com)} returns an XMPP message
119                         sent from <replaceable>bob@domain.com</replaceable> (or nothing in case of a time out), to
120                         the <replaceable>asterisk</replaceable> XMPP account configured in xmpp.conf.</para>
121                 </description>
122                 <see-also>
123                         <ref type="function">JABBER_STATUS</ref>
124                         <ref type="application">JabberSend</ref>
125                 </see-also>
126         </function>
127         <function name="JABBER_STATUS" language="en_US">
128                 <synopsis>
129                         Retrieves a buddy's status.
130                 </synopsis>
131                 <syntax>
132                         <parameter name="account" required="true">
133                                 <para>The local named account to listen on (specified in
134                                 xmpp.conf)</para>
135                         </parameter>
136                         <parameter name="jid" required="true">
137                                 <para>Jabber ID of the buddy to receive message from. It can be a
138                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
139                         </parameter>
140                 </syntax>
141                 <description>
142                         <para>Retrieves the numeric status associated with the buddy identified
143                         by <replaceable>jid</replaceable>.
144                         If the buddy does not exist in the buddylist, returns 7.</para>
145                         <para>Status will be 1-7.</para>
146                         <para>1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline</para>
147                         <para>If not in roster variable will be set to 7.</para>
148                         <para>Example: ${JABBER_STATUS(asterisk,bob@domain.com)} returns 1 if
149                         <replaceable>bob@domain.com</replaceable> is online. <replaceable>asterisk</replaceable> is
150                         the associated XMPP account configured in xmpp.conf.</para>
151                 </description>
152                 <see-also>
153                         <ref type="function">JABBER_RECEIVE</ref>
154                         <ref type="application">JabberSend</ref>
155                 </see-also>
156         </function>
157         <application name="JabberSendGroup" language="en_US">
158                 <synopsis>
159                         Send a Jabber Message to a specified chat room
160                 </synopsis>
161                 <syntax>
162                         <parameter name="Jabber" required="true">
163                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
164                         </parameter>
165                         <parameter name="RoomJID" required="true">
166                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
167                         </parameter>
168                         <parameter name="Message" required="true">
169                                 <para>Message to be sent to the chat room.</para>
170                         </parameter>
171                         <parameter name="Nickname" required="false">
172                                 <para>The nickname Asterisk uses in the chat room.</para>
173                         </parameter>
174                 </syntax>
175                 <description>
176                         <para>Allows user to send a message to a chat room via XMPP.</para>
177                         <note><para>To be able to send messages to a chat room, a user must have previously joined it. Use the <replaceable>JabberJoin</replaceable> function to do so.</para></note>
178                 </description>
179         </application>
180         <application name="JabberJoin" language="en_US">
181                 <synopsis>
182                         Join a chat room
183                 </synopsis>
184                 <syntax>
185                         <parameter name="Jabber" required="true">
186                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
187                         </parameter>
188                         <parameter name="RoomJID" required="true">
189                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
190                         </parameter>
191                         <parameter name="Nickname" required="false">
192                                 <para>The nickname Asterisk will use in the chat room.</para>
193                                 <note><para>If a different nickname is supplied to an already joined room, the old nick will be changed to the new one.</para></note>
194                         </parameter>
195                 </syntax>
196                 <description>
197                         <para>Allows Asterisk to join a chat room.</para>
198                 </description>
199         </application>
200         <application name="JabberLeave" language="en_US">
201                 <synopsis>
202                         Leave a chat room
203                 </synopsis>
204                 <syntax>
205                         <parameter name="Jabber" required="true">
206                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
207                         </parameter>
208                         <parameter name="RoomJID" required="true">
209                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
210                         </parameter>
211                         <parameter name="Nickname" required="false">
212                                 <para>The nickname Asterisk uses in the chat room.</para>
213                         </parameter>
214                 </syntax>
215                 <description>
216                         <para>Allows Asterisk to leave a chat room.</para>
217                 </description>
218         </application>
219         <application name="JabberStatus" language="en_US">
220                 <synopsis>
221                         Retrieve the status of a jabber list member
222                 </synopsis>
223                 <syntax>
224                         <parameter name="Jabber" required="true">
225                                 <para>Client or transport Asterisk users to connect to Jabber.</para>
226                         </parameter>
227                         <parameter name="JID" required="true">
228                                 <para>XMPP/Jabber JID (Name) of recipient.</para>
229                         </parameter>
230                         <parameter name="Variable" required="true">
231                                 <para>Variable to store the status of requested user.</para>
232                         </parameter>
233                 </syntax>
234                 <description>
235                         <para>This application is deprecated. Please use the JABBER_STATUS() function instead.</para>
236                         <para>Retrieves the numeric status associated with the specified buddy <replaceable>JID</replaceable>.
237                         The return value in the <replaceable>Variable</replaceable>will be one of the following.</para>
238                         <enumlist>
239                                 <enum name="1">
240                                         <para>Online.</para>
241                                 </enum>
242                                 <enum name="2">
243                                         <para>Chatty.</para>
244                                 </enum>
245                                 <enum name="3">
246                                         <para>Away.</para>
247                                 </enum>
248                                 <enum name="4">
249                                         <para>Extended Away.</para>
250                                 </enum>
251                                 <enum name="5">
252                                         <para>Do Not Disturb.</para>
253                                 </enum>
254                                 <enum name="6">
255                                         <para>Offline.</para>
256                                 </enum>
257                                 <enum name="7">
258                                         <para>Not In Roster.</para>
259                                 </enum>
260                         </enumlist>
261                 </description>
262         </application>
263         <manager name="JabberSend" language="en_US">
264                 <synopsis>
265                         Sends a message to a Jabber Client.
266                 </synopsis>
267                 <syntax>
268                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
269                         <parameter name="Jabber" required="true">
270                                 <para>Client or transport Asterisk uses to connect to JABBER.</para>
271                         </parameter>
272                         <parameter name="JID" required="true">
273                                 <para>XMPP/Jabber JID (Name) of recipient.</para>
274                         </parameter>
275                         <parameter name="Message" required="true">
276                                 <para>Message to be sent to the buddy.</para>
277                         </parameter>
278                 </syntax>
279                 <description>
280                         <para>Sends a message to a Jabber Client.</para>
281                 </description>
282         </manager>
283         <info name="XMPPMessageToInfo" language="en_US" tech="XMPP">
284                 <para>Specifying a prefix of <literal>xmpp:</literal> will send the
285                 message as an XMPP chat message.</para>
286         </info>
287 ***/
288
289 /*! \brief Supported general configuration flags */
290 enum {
291         XMPP_AUTOPRUNE = (1 << 0),
292         XMPP_AUTOREGISTER = (1 << 1),
293         XMPP_AUTOACCEPT = (1 << 2),
294         XMPP_DEBUG = (1 << 3),
295         XMPP_USETLS = (1 << 4),
296         XMPP_USESASL = (1 << 5),
297         XMPP_FORCESSL = (1 << 6),
298         XMPP_KEEPALIVE = (1 << 7),
299         XMPP_COMPONENT = (1 << 8),
300         XMPP_SEND_TO_DIALPLAN = (1 << 9),
301         XMPP_DISTRIBUTE_EVENTS = (1 << 10),
302 };
303
304 /*! \brief Supported pubsub configuration flags */
305 enum {
306         XMPP_XEP0248 = (1 << 0),
307         XMPP_PUBSUB = (1 << 1),
308         XMPP_PUBSUB_AUTOCREATE = (1 << 2),
309 };
310
311 /*! \brief Number of buckets for client connections */
312 #define CLIENT_BUCKETS 53
313
314 /*! \brief Number of buckets for buddies (per client) */
315 #define BUDDY_BUCKETS 53
316
317 /*! \brief Number of buckets for resources (per buddy) */
318 #define RESOURCE_BUCKETS 53
319
320 /*! \brief Namespace for TLS support */
321 #define XMPP_TLS_NS "urn:ietf:params:xml:ns:xmpp-tls"
322
323 /*! \brief Status for a disappearing buddy */
324 #define STATUS_DISAPPEAR 6
325
326 /*! \brief Global debug status */
327 static int debug;
328
329 /*! \brief XMPP Global Configuration */
330 struct ast_xmpp_global_config {
331         struct ast_flags general; /*!< General configuration options */
332         struct ast_flags pubsub;  /*!< Pubsub related configuration options */
333 };
334
335 /*! \brief XMPP Client Configuration */
336 struct ast_xmpp_client_config {
337         AST_DECLARE_STRING_FIELDS(
338                 AST_STRING_FIELD(name);        /*!< Name of the client connection */
339                 AST_STRING_FIELD(user);        /*!< Username to use for authentication */
340                 AST_STRING_FIELD(password);    /*!< Password to use for authentication */
341                 AST_STRING_FIELD(server);      /*!< Server hostname */
342                 AST_STRING_FIELD(statusmsg);   /*!< Status message for presence */
343                 AST_STRING_FIELD(pubsubnode);  /*!< Pubsub node */
344                 AST_STRING_FIELD(context);     /*!< Context for incoming messages */
345                 );
346         int port;                       /*!< Port to use when connecting to server */
347         int message_timeout;            /*!< Timeout for messages */
348         int priority;                   /*!< Resource priority */
349         struct ast_flags flags;         /*!< Various options that have been set */
350         enum ikshowtype status;         /*!< Presence status */
351         struct ast_xmpp_client *client; /*!< Pointer to the client */
352         struct ao2_container *buddies;  /*!< Configured buddies */
353 };
354
355 struct xmpp_config {
356         struct ast_xmpp_global_config *global; /*!< Global configuration options */
357         struct ao2_container *clients;         /*!< Configured clients */
358 };
359
360 static AO2_GLOBAL_OBJ_STATIC(globals);
361
362 static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
363 static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
364 static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
365 static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
366
367 static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
368 static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
369
370 /*! \brief Defined handlers for XMPP client states */
371 static const struct xmpp_state_handler {
372         int state;
373         int component;
374         int (*handler)(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
375 } xmpp_state_handlers[] = {
376         { XMPP_STATE_REQUEST_TLS, 0, xmpp_client_request_tls, },
377         { XMPP_STATE_REQUESTED_TLS, 0, xmpp_client_requested_tls, },
378         { XMPP_STATE_AUTHENTICATE, 0, xmpp_client_authenticate, },
379         { XMPP_STATE_AUTHENTICATING, 0, xmpp_client_authenticating, },
380         { XMPP_STATE_AUTHENTICATE, 1, xmpp_component_authenticate, },
381         { XMPP_STATE_AUTHENTICATING, 1, xmpp_component_authenticating, },
382 };
383
384 static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
385 static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
386 static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
387
388 /*! \brief Defined handlers for different PAK types */
389 static const struct xmpp_pak_handler {
390         int type;
391         int (*handler)(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
392 } xmpp_pak_handlers[] = {
393         { IKS_PAK_MESSAGE, xmpp_pak_message, },
394         { IKS_PAK_PRESENCE, xmpp_pak_presence, },
395         { IKS_PAK_S10N, xmpp_pak_s10n, },
396 };
397
398 static const char *app_ajisend = "JabberSend";
399 static const char *app_ajisendgroup = "JabberSendGroup";
400 static const char *app_ajistatus = "JabberStatus";
401 static const char *app_ajijoin = "JabberJoin";
402 static const char *app_ajileave = "JabberLeave";
403
404 static ast_cond_t message_received_condition;
405 static ast_mutex_t messagelock;
406
407 static int xmpp_client_config_post_apply(void *obj, void *arg, int flags);
408
409 /*! \brief Destructor function for configuration */
410 static void ast_xmpp_client_config_destructor(void *obj)
411 {
412         struct ast_xmpp_client_config *cfg = obj;
413         ast_string_field_free_memory(cfg);
414         ao2_cleanup(cfg->client);
415         ao2_cleanup(cfg->buddies);
416 }
417
418 /*! \brief Destroy function for XMPP messages */
419 static void xmpp_message_destroy(struct ast_xmpp_message *message)
420 {
421         if (message->from) {
422                 ast_free(message->from);
423         }
424         if (message->message) {
425                 ast_free(message->message);
426         }
427
428         ast_free(message);
429 }
430
431 /*! \brief Destructor callback function for XMPP client */
432 static void xmpp_client_destructor(void *obj)
433 {
434         struct ast_xmpp_client *client = obj;
435         struct ast_xmpp_message *message;
436
437         ast_xmpp_client_disconnect(client);
438
439         if (client->stack) {
440                 iks_stack_delete(client->stack);
441         }
442
443         ao2_cleanup(client->buddies);
444
445         while ((message = AST_LIST_REMOVE_HEAD(&client->messages, list))) {
446                 xmpp_message_destroy(message);
447         }
448         AST_LIST_HEAD_DESTROY(&client->messages);
449 }
450
451 /*! \brief Hashing function for XMPP buddy */
452 static int xmpp_buddy_hash(const void *obj, const int flags)
453 {
454         const struct ast_xmpp_buddy *buddy = obj;
455         const char *id = obj;
456
457         return ast_str_hash(flags & OBJ_KEY ? id : buddy->id);
458 }
459
460 /*! \brief Comparator function for XMPP buddy */
461 static int xmpp_buddy_cmp(void *obj, void *arg, int flags)
462 {
463         struct ast_xmpp_buddy *buddy1 = obj, *buddy2 = arg;
464         const char *id = arg;
465
466         return !strcmp(buddy1->id, flags & OBJ_KEY ? id : buddy2->id) ? CMP_MATCH | CMP_STOP : 0;
467 }
468
469 /*! \brief Allocator function for ast_xmpp_client */
470 static struct ast_xmpp_client *xmpp_client_alloc(const char *name)
471 {
472         struct ast_xmpp_client *client;
473
474         if (!(client = ao2_alloc(sizeof(*client), xmpp_client_destructor))) {
475                 return NULL;
476         }
477
478         AST_LIST_HEAD_INIT(&client->messages);
479         client->thread = AST_PTHREADT_NULL;
480
481         if (!(client->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
482                 ast_log(LOG_ERROR, "Could not initialize buddy container for '%s'\n", name);
483                 ao2_ref(client, -1);
484                 return NULL;
485         }
486
487         if (ast_string_field_init(client, 512)) {
488                 ast_log(LOG_ERROR, "Could not initialize stringfields for '%s'\n", name);
489                 ao2_ref(client, -1);
490                 return NULL;
491         }
492
493         if (!(client->stack = iks_stack_new(8192, 8192))) {
494                 ast_log(LOG_ERROR, "Could not create an Iksemel stack for '%s'\n", name);
495                 ao2_ref(client, -1);
496                 return NULL;
497         }
498
499         ast_string_field_set(client, name, name);
500
501         client->timeout = 50;
502         client->state = XMPP_STATE_DISCONNECTED;
503         ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
504
505         return client;
506 }
507
508 /*! \brief Find function for configuration */
509 static void *xmpp_config_find(struct ao2_container *tmp_container, const char *category)
510 {
511         return ao2_find(tmp_container, category, OBJ_KEY);
512 }
513
514 /*! \brief Look up existing client or create a new one */
515 static void *xmpp_client_find_or_create(const char *category)
516 {
517         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
518         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
519
520         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, category))) {
521                 return xmpp_client_alloc(category);
522         }
523
524         ao2_ref(clientcfg->client, +1);
525         return clientcfg->client;
526 }
527
528 /*! \brief Allocator function for configuration */
529 static void *ast_xmpp_client_config_alloc(const char *cat)
530 {
531         struct ast_xmpp_client_config *cfg;
532
533         if (!(cfg = ao2_alloc(sizeof(*cfg), ast_xmpp_client_config_destructor))) {
534                 return NULL;
535         }
536
537         if (ast_string_field_init(cfg, 512)) {
538                 ao2_ref(cfg, -1);
539                 return NULL;
540         }
541
542         if (!(cfg->client = xmpp_client_find_or_create(cat))) {
543                 ao2_ref(cfg, -1);
544                 return NULL;
545         }
546
547         if (!(cfg->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
548                 ao2_ref(cfg, -1);
549                 return NULL;
550         }
551
552         ast_string_field_set(cfg, name, cat);
553
554         return cfg;
555 }
556
557 /*! \brief Destructor for XMPP configuration */
558 static void xmpp_config_destructor(void *obj)
559 {
560         struct xmpp_config *cfg = obj;
561         ao2_cleanup(cfg->global);
562         ao2_cleanup(cfg->clients);
563 }
564
565 /*! \brief Hashing function for configuration */
566 static int xmpp_config_hash(const void *obj, const int flags)
567 {
568         const struct ast_xmpp_client_config *cfg = obj;
569         const char *name = (flags & OBJ_KEY) ? obj : cfg->name;
570         return ast_str_case_hash(name);
571 }
572
573 /*! \brief Comparator function for configuration */
574 static int xmpp_config_cmp(void *obj, void *arg, int flags)
575 {
576         struct ast_xmpp_client_config *one = obj, *two = arg;
577         const char *match = (flags & OBJ_KEY) ? arg : two->name;
578         return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
579 }
580
581 /*! \brief Allocator for XMPP configuration */
582 static void *xmpp_config_alloc(void)
583 {
584         struct xmpp_config *cfg;
585
586         if (!(cfg = ao2_alloc(sizeof(*cfg), xmpp_config_destructor))) {
587                 return NULL;
588         }
589
590         if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), NULL))) {
591                 goto error;
592         }
593
594         ast_set_flag(&cfg->global->general, XMPP_AUTOREGISTER | XMPP_AUTOACCEPT | XMPP_USETLS | XMPP_USESASL | XMPP_KEEPALIVE);
595
596         if (!(cfg->clients = ao2_container_alloc(1, xmpp_config_hash, xmpp_config_cmp))) {
597                 goto error;
598         }
599
600         return cfg;
601 error:
602         ao2_ref(cfg, -1);
603         return NULL;
604 }
605
606 static int xmpp_config_prelink(void *newitem)
607 {
608         struct ast_xmpp_client_config *clientcfg = newitem;
609         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
610         RAII_VAR(struct ast_xmpp_client_config *, oldclientcfg, NULL, ao2_cleanup);
611
612         if (ast_strlen_zero(clientcfg->user)) {
613                 ast_log(LOG_ERROR, "No user specified on client '%s'\n", clientcfg->name);
614                 return -1;
615         } else if (ast_strlen_zero(clientcfg->password)) {
616                 ast_log(LOG_ERROR, "No password specified on client '%s'\n", clientcfg->name);
617                 return -1;
618         } else if (ast_strlen_zero(clientcfg->server)) {
619                 ast_log(LOG_ERROR, "No server specified on client '%s'\n", clientcfg->name);
620                 return -1;
621         }
622
623         /* If this is a new connection force a reconnect */
624         if (!cfg || !cfg->clients || !(oldclientcfg = xmpp_config_find(cfg->clients, clientcfg->name))) {
625                 clientcfg->client->reconnect = 1;
626                 return 0;
627         }
628
629         /* If any configuration options are changing that would require reconnecting set the bit so we will do so if possible */
630         if (strcmp(clientcfg->user, oldclientcfg->user) ||
631             strcmp(clientcfg->password, oldclientcfg->password) ||
632             strcmp(clientcfg->server, oldclientcfg->server) ||
633             (clientcfg->port != oldclientcfg->port) ||
634             (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) != ast_test_flag(&oldclientcfg->flags, XMPP_COMPONENT)) ||
635             (clientcfg->priority != oldclientcfg->priority)) {
636                 clientcfg->client->reconnect = 1;
637         } else {
638                 clientcfg->client->reconnect = 0;
639         }
640
641         return 0;
642 }
643
644 static void xmpp_config_post_apply(void)
645 {
646         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
647
648         ao2_callback(cfg->clients, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_config_post_apply, NULL);
649 }
650
651 static struct aco_type global_option = {
652         .type = ACO_GLOBAL,
653         .item_offset = offsetof(struct xmpp_config, global),
654         .category_match = ACO_WHITELIST,
655         .category = "^general$",
656 };
657
658 struct aco_type *global_options[] = ACO_TYPES(&global_option);
659
660 static struct aco_type client_option = {
661         .type = ACO_ITEM,
662         .category_match = ACO_BLACKLIST,
663         .category = "^(general)$",
664         .item_alloc = ast_xmpp_client_config_alloc,
665         .item_find = xmpp_config_find,
666         .item_prelink = xmpp_config_prelink,
667         .item_offset = offsetof(struct xmpp_config, clients),
668 };
669
670 struct aco_type *client_options[] = ACO_TYPES(&client_option);
671
672 struct aco_file res_xmpp_conf = {
673         .filename = "xmpp.conf",
674         .alias = "jabber.conf",
675         .types = ACO_TYPES(&global_option, &client_option),
676 };
677
678 CONFIG_INFO_STANDARD(cfg_info, globals, xmpp_config_alloc,
679                      .files = ACO_FILES(&res_xmpp_conf),
680                      .post_apply_config = xmpp_config_post_apply,
681         );
682
683 /*! \brief Destructor callback function for XMPP resource */
684 static void xmpp_resource_destructor(void *obj)
685 {
686         struct ast_xmpp_resource *resource = obj;
687
688         if (resource->description) {
689                 ast_free(resource->description);
690         }
691 }
692
693 /*! \brief Hashing function for XMPP resource */
694 static int xmpp_resource_hash(const void *obj, const int flags)
695 {
696         const struct ast_xmpp_resource *resource = obj;
697
698         return flags & OBJ_KEY ? -1 : resource->priority;
699 }
700
701 /*! \brief Comparator function for XMPP resource */
702 static int xmpp_resource_cmp(void *obj, void *arg, int flags)
703 {
704         struct ast_xmpp_resource *resource1 = obj, *resource2 = arg;
705         const char *resource = arg;
706
707         return !strcmp(resource1->resource, flags & OBJ_KEY ? resource : resource2->resource) ? CMP_MATCH | CMP_STOP : 0;
708 }
709
710 /*! \brief Destructor callback function for XMPP buddy */
711 static void xmpp_buddy_destructor(void *obj)
712 {
713         struct ast_xmpp_buddy *buddy = obj;
714
715         if (buddy->resources) {
716                 ao2_ref(buddy->resources, -1);
717         }
718 }
719
720 /*! \brief Helper function which returns whether an XMPP client connection is secure or not */
721 static int xmpp_is_secure(struct ast_xmpp_client *client)
722 {
723 #ifdef HAVE_OPENSSL
724         return client->stream_flags & SECURE;
725 #else
726         return 0;
727 #endif
728 }
729
730 struct ast_xmpp_client *ast_xmpp_client_find(const char *name)
731 {
732         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
733         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
734
735         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
736                 return NULL;
737         }
738
739         ao2_ref(clientcfg->client, +1);
740         return clientcfg->client;
741 }
742
743 void ast_xmpp_client_unref(struct ast_xmpp_client *client)
744 {
745         ao2_ref(client, -1);
746 }
747
748 void ast_xmpp_client_lock(struct ast_xmpp_client *client)
749 {
750         ao2_lock(client);
751 }
752
753 void ast_xmpp_client_unlock(struct ast_xmpp_client *client)
754 {
755         ao2_unlock(client);
756 }
757
758 /*! \brief Internal function used to send a message to a user or chatroom */
759 static int xmpp_client_send_message(struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
760 {
761         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
762         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
763         int res = 0;
764         char from[XMPP_MAX_JIDLEN];
765         iks *message_packet;
766
767         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
768             !(message_packet = iks_make_msg(group ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message))) {
769                 return -1;
770         }
771
772         if (!ast_strlen_zero(nick) && ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
773                 snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
774         } else {
775                 snprintf(from, sizeof(from), "%s", client->jid->full);
776         }
777
778         iks_insert_attrib(message_packet, "from", from);
779
780         res = ast_xmpp_client_send(client, message_packet);
781
782         iks_delete(message_packet);
783
784         return res;
785 }
786
787 int ast_xmpp_client_send_message(struct ast_xmpp_client *client, const char *user, const char *message)
788 {
789         return xmpp_client_send_message(client, 0, NULL, user, message);
790 }
791
792 int ast_xmpp_chatroom_invite(struct ast_xmpp_client *client, const char *user, const char *room, const char *message)
793 {
794         int res = 0;
795         iks *invite, *body = NULL, *namespace = NULL;
796
797         if (!(invite = iks_new("message")) || !(body = iks_new("body")) || !(namespace = iks_new("x"))) {
798                 res = -1;
799                 goto done;
800         }
801
802         iks_insert_attrib(invite, "to", user);
803         ast_xmpp_client_lock(client);
804         iks_insert_attrib(invite, "id", client->mid);
805         ast_xmpp_increment_mid(client->mid);
806         ast_xmpp_client_unlock(client);
807         iks_insert_cdata(body, message, 0);
808         iks_insert_node(invite, body);
809         iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
810         iks_insert_attrib(namespace, "jid", room);
811         iks_insert_node(invite, namespace);
812
813         res = ast_xmpp_client_send(client, invite);
814
815 done:
816         iks_delete(namespace);
817         iks_delete(body);
818         iks_delete(invite);
819
820         return res;
821 }
822
823 static int xmpp_client_set_group_presence(struct ast_xmpp_client *client, const char *room, int level, const char *nick)
824 {
825         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
826         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
827         int res = 0;
828         iks *presence = NULL, *x = NULL;
829         char from[XMPP_MAX_JIDLEN], roomid[XMPP_MAX_JIDLEN];
830
831         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
832             !(presence = iks_make_pres(level, NULL)) || !(x = iks_new("x"))) {
833                 res = -1;
834                 goto done;
835         }
836
837         if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
838                 snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
839                 snprintf(roomid, sizeof(roomid), "%s/%s", room, nick);
840         } else {
841                 snprintf(from, sizeof(from), "%s", client->jid->full);
842                 snprintf(roomid, sizeof(roomid), "%s/%s", room, S_OR(nick, client->jid->user));
843         }
844
845         iks_insert_attrib(presence, "to", roomid);
846         iks_insert_attrib(presence, "from", from);
847         iks_insert_attrib(x, "xmlns", "http://jabber.org/protocol/muc");
848         iks_insert_node(presence, x);
849
850         res = ast_xmpp_client_send(client, presence);
851
852 done:
853         iks_delete(x);
854         iks_delete(presence);
855
856         return res;
857 }
858
859 int ast_xmpp_chatroom_join(struct ast_xmpp_client *client, const char *room, const char *nickname)
860 {
861         return xmpp_client_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nickname);
862 }
863
864 int ast_xmpp_chatroom_send(struct ast_xmpp_client *client, const char *nickname, const char *address, const char *message)
865 {
866         return xmpp_client_send_message(client, 1, nickname, address, message);
867 }
868
869 int ast_xmpp_chatroom_leave(struct ast_xmpp_client *client, const char *room, const char *nickname)
870 {
871         return xmpp_client_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nickname);
872 }
873
874 void ast_xmpp_increment_mid(char *mid)
875 {
876         int i = 0;
877
878         for (i = strlen(mid) - 1; i >= 0; i--) {
879                 if (mid[i] != 'z') {
880                         mid[i] = mid[i] + 1;
881                         i = 0;
882                 } else {
883                         mid[i] = 'a';
884                 }
885         }
886 }
887
888 /*!
889  * \brief Create an IQ packet
890  * \param client the configured XMPP client we use to connect to a XMPP server
891  * \param type the type of IQ packet to create
892  * \return iks*
893  */
894 static iks* xmpp_pubsub_iq_create(struct ast_xmpp_client *client, const char *type)
895 {
896         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
897         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
898         iks *request;
899
900         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
901             !(request = iks_new("iq"))) {
902                 return NULL;
903         }
904
905         if (!ast_strlen_zero(clientcfg->pubsubnode)) {
906                 iks_insert_attrib(request, "to", clientcfg->pubsubnode);
907         }
908
909         iks_insert_attrib(request, "from", client->jid->full);
910         iks_insert_attrib(request, "type", type);
911         ast_xmpp_client_lock(client);
912         ast_xmpp_increment_mid(client->mid);
913         iks_insert_attrib(request, "id", client->mid);
914         ast_xmpp_client_unlock(client);
915
916         return request;
917 }
918
919 /*!
920  * \brief Build the skeleton of a publish
921  * \param client the configured XMPP client we use to connect to a XMPP server
922  * \param node Name of the node that will be published to
923  * \param event_type
924  * \return iks *
925  */
926 static iks* xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, const char *node,
927                                                const char *event_type)
928 {
929         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
930         iks *request, *pubsub, *publish, *item;
931
932         if (!cfg || !cfg->global || !(request = xmpp_pubsub_iq_create(client, "set"))) {
933                 return NULL;
934         }
935
936         pubsub = iks_insert(request, "pubsub");
937         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
938         publish = iks_insert(pubsub, "publish");
939         iks_insert_attrib(publish, "node", ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248) ? node : event_type);
940         item = iks_insert(publish, "item");
941         iks_insert_attrib(item, "id", node);
942
943         return item;
944
945 }
946
947 static iks* xmpp_pubsub_build_node_config(iks *pubsub, const char *node_type, const char *collection_name)
948 {
949         iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
950                 *field_deliver_payload, *field_persist_items, *field_access_model,
951                 *field_pubsub_collection;
952         configure = iks_insert(pubsub, "configure");
953         x = iks_insert(configure, "x");
954         iks_insert_attrib(x, "xmlns", "jabber:x:data");
955         iks_insert_attrib(x, "type", "submit");
956         field_owner = iks_insert(x, "field");
957         iks_insert_attrib(field_owner, "var", "FORM_TYPE");
958         iks_insert_attrib(field_owner, "type", "hidden");
959         iks_insert_cdata(iks_insert(field_owner, "value"),
960                          "http://jabber.org/protocol/pubsub#owner", 39);
961         if (node_type) {
962                 field_node_type = iks_insert(x, "field");
963                 iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
964                 iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
965         }
966         field_node_config = iks_insert(x, "field");
967         iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
968         iks_insert_attrib(field_node_config, "type", "hidden");
969         iks_insert_cdata(iks_insert(field_node_config, "value"),
970                          "http://jabber.org/protocol/pubsub#node_config", 45);
971         field_deliver_payload = iks_insert(x, "field");
972         iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
973         iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
974         field_persist_items = iks_insert(x, "field");
975         iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
976         iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
977         field_access_model = iks_insert(x, "field");
978         iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
979         iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
980         if (node_type && !strcasecmp(node_type, "leaf")) {
981                 field_pubsub_collection = iks_insert(x, "field");
982                 iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
983                 iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
984                                  strlen(collection_name));
985         }
986         return configure;
987 }
988
989 /*!
990  * \brief Add Owner affiliations for pubsub node
991  * \param client the configured XMPP client we use to connect to a XMPP server
992  * \param node the name of the node to which to add affiliations
993  * \return void
994  */
995 static void xmpp_pubsub_create_affiliations(struct ast_xmpp_client *client, const char *node)
996 {
997         iks *modify_affiliates = xmpp_pubsub_iq_create(client, "set");
998         iks *pubsub, *affiliations, *affiliate;
999         struct ao2_iterator i;
1000         struct ast_xmpp_buddy *buddy;
1001
1002         if (!modify_affiliates) {
1003                 ast_log(LOG_ERROR, "Could not create IQ for creating affiliations on client '%s'\n", client->name);
1004                 return;
1005         }
1006
1007         pubsub = iks_insert(modify_affiliates, "pubsub");
1008         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
1009         affiliations = iks_insert(pubsub, "affiliations");
1010         iks_insert_attrib(affiliations, "node", node);
1011
1012         i = ao2_iterator_init(client->buddies, 0);
1013         while ((buddy = ao2_iterator_next(&i))) {
1014                 affiliate = iks_insert(affiliations, "affiliation");
1015                 iks_insert_attrib(affiliate, "jid", buddy->id);
1016                 iks_insert_attrib(affiliate, "affiliation", "owner");
1017                 ao2_ref(buddy, -1);
1018         }
1019         ao2_iterator_destroy(&i);
1020
1021         ast_xmpp_client_send(client, modify_affiliates);
1022         iks_delete(modify_affiliates);
1023 }
1024
1025 /*!
1026  * \brief Create a pubsub node
1027  * \param client the configured XMPP client we use to connect to a XMPP server
1028  * \param node_type the type of node to create
1029  * \param name the name of the node to create
1030  * \param collection_name
1031  * \return void
1032  */
1033 static void xmpp_pubsub_create_node(struct ast_xmpp_client *client, const char *node_type, const
1034                                     char *name, const char *collection_name)
1035 {
1036         iks *node, *pubsub, *create;
1037
1038         if (!(node = xmpp_pubsub_iq_create(client, "set"))) {
1039                 return;
1040         }
1041
1042         pubsub = iks_insert(node, "pubsub");
1043         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1044         create = iks_insert(pubsub, "create");
1045         iks_insert_attrib(create, "node", name);
1046         xmpp_pubsub_build_node_config(pubsub, node_type, collection_name);
1047         ast_xmpp_client_send(client, node);
1048         xmpp_pubsub_create_affiliations(client, name);
1049         iks_delete(node);
1050 }
1051
1052 /*!
1053  * \brief Delete a PubSub node
1054  * \param client the configured XMPP client we use to connect to a XMPP server
1055  * \param node_name the name of the node to delete
1056  * return void
1057  */
1058 static void xmpp_pubsub_delete_node(struct ast_xmpp_client *client, const char *node_name)
1059 {
1060         iks *request, *pubsub, *delete;
1061
1062         if (!(request = xmpp_pubsub_iq_create(client, "set"))) {
1063                 return;
1064         }
1065
1066         pubsub = iks_insert(request, "pubsub");
1067         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
1068         delete = iks_insert(pubsub, "delete");
1069         iks_insert_attrib(delete, "node", node_name);
1070         ast_xmpp_client_send(client, request);
1071
1072         iks_delete(delete);
1073         iks_delete(pubsub);
1074         iks_delete(request);
1075 }
1076
1077 /*!
1078  * \brief Create a PubSub collection node.
1079  * \param client the configured XMPP client we use to connect to a XMPP server
1080  * \param collection_name The name to use for this collection
1081  * \return void.
1082  */
1083 static void xmpp_pubsub_create_collection(struct ast_xmpp_client *client, const char *collection_name)
1084 {
1085         xmpp_pubsub_create_node(client, "collection", collection_name, NULL);
1086 }
1087
1088
1089 /*!
1090  * \brief Create a PubSub leaf node.
1091  * \param client the configured XMPP client we use to connect to a XMPP server
1092  * \param collection_name
1093  * \param leaf_name The name to use for this collection
1094  * \return void.
1095  */
1096 static void xmpp_pubsub_create_leaf(struct ast_xmpp_client *client, const char *collection_name,
1097                                     const char *leaf_name)
1098 {
1099         xmpp_pubsub_create_node(client, "leaf", leaf_name, collection_name);
1100 }
1101
1102 /*!
1103  * \brief Publish MWI to a PubSub node
1104  * \param client the configured XMPP client we use to connect to a XMPP server
1105  * \param mailbox The Mailbox
1106  * \param context The Context
1107  * \param oldmsgs Old messages
1108  * \param newmsgs New Messages
1109  * \return void
1110  */
1111 static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char *mailbox,
1112                                     const char *context, const char *oldmsgs, const char *newmsgs)
1113 {
1114         char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT], eid_str[20];
1115         iks *mailbox_node, *request;
1116
1117         snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
1118
1119         if (!(request = xmpp_pubsub_build_publish_skeleton(client, full_mailbox, "message_waiting"))) {
1120                 return;
1121         }
1122
1123         ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
1124         mailbox_node = iks_insert(request, "mailbox");
1125         iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
1126         iks_insert_attrib(mailbox_node, "eid", eid_str);
1127         iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
1128         iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
1129
1130         ast_xmpp_client_send(client, iks_root(request));
1131
1132         iks_delete(request);
1133 }
1134
1135 /*!
1136  * \brief Publish device state to a PubSub node
1137  * \param client the configured XMPP client we use to connect to a XMPP server
1138  * \param device the name of the device whose state to publish
1139  * \param device_state the state to publish
1140  * \return void
1141  */
1142 static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, const char *device,
1143                                              const char *device_state)
1144 {
1145         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1146         iks *request, *state;
1147         char eid_str[20];
1148
1149         if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state"))) {
1150                 return;
1151         }
1152
1153         if (ast_test_flag(&cfg->global->pubsub, XMPP_PUBSUB_AUTOCREATE)) {
1154                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1155                         xmpp_pubsub_create_node(client, "leaf", device, "device_state");
1156                 } else {
1157                         xmpp_pubsub_create_node(client, NULL, device, NULL);
1158                 }
1159         }
1160
1161         ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
1162         state = iks_insert(request, "state");
1163         iks_insert_attrib(state, "xmlns", "http://asterisk.org");
1164         iks_insert_attrib(state, "eid", eid_str);
1165         iks_insert_cdata(state, device_state, strlen(device_state));
1166         ast_xmpp_client_send(client, iks_root(request));
1167         iks_delete(request);
1168 }
1169
1170 /*!
1171  * \brief Callback function for MWI events
1172  * \param ast_event
1173  * \param data void pointer to ast_client structure
1174  * \return void
1175  */
1176 static void xmpp_pubsub_mwi_cb(const struct ast_event *ast_event, void *data)
1177 {
1178         struct ast_xmpp_client *client = data;
1179         const char *mailbox, *context;
1180         char oldmsgs[10], newmsgs[10];
1181
1182         if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
1183                 /* If the event didn't originate from this server, don't send it back out. */
1184                 ast_debug(1, "Returning here\n");
1185                 return;
1186         }
1187
1188         mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
1189         context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
1190         snprintf(oldmsgs, sizeof(oldmsgs), "%d",
1191                  ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
1192         snprintf(newmsgs, sizeof(newmsgs), "%d",
1193                  ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
1194         xmpp_pubsub_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
1195 }
1196
1197 /*!
1198  * \brief Callback function for device state events
1199  * \param ast_event
1200  * \param data void pointer to ast_client structure
1201  * \return void
1202  */
1203 static void xmpp_pubsub_devstate_cb(const struct ast_event *ast_event, void *data)
1204 {
1205         struct ast_xmpp_client *client = data;
1206         const char *device, *device_state;
1207
1208         if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
1209                 /* If the event didn't originate from this server, don't send it back out. */
1210                 ast_debug(1, "Returning here\n");
1211                 return;
1212         }
1213
1214         device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
1215         device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
1216         xmpp_pubsub_publish_device_state(client, device, device_state);
1217 }
1218
1219 /*!
1220  * \brief Unsubscribe from a PubSub node
1221  * \param client the configured XMPP client we use to connect to a XMPP server
1222  * \param node the name of the node to which to unsubscribe from
1223  * \return void
1224  */
1225 static void xmpp_pubsub_unsubscribe(struct ast_xmpp_client *client, const char *node)
1226 {
1227         iks *request = xmpp_pubsub_iq_create(client, "set");
1228         iks *pubsub, *unsubscribe;
1229
1230         if (!request) {
1231                 ast_log(LOG_ERROR, "Could not create IQ when creating pubsub unsubscription on client '%s'\n", client->name);
1232                 return;
1233         }
1234
1235         pubsub = iks_insert(request, "pubsub");
1236         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1237         unsubscribe = iks_insert(pubsub, "unsubscribe");
1238         iks_insert_attrib(unsubscribe, "jid", client->jid->partial);
1239         iks_insert_attrib(unsubscribe, "node", node);
1240
1241         ast_xmpp_client_send(client, request);
1242         iks_delete(request);
1243 }
1244
1245 /*!
1246  * \brief Subscribe to a PubSub node
1247  * \param client the configured XMPP client we use to connect to a XMPP server
1248  * \param node the name of the node to which to subscribe
1249  * \return void
1250  */
1251 static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *node)
1252 {
1253         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1254         iks *request = xmpp_pubsub_iq_create(client, "set");
1255         iks *pubsub, *subscribe;
1256
1257         if (!cfg || !cfg->global || !request) {
1258                 ast_log(LOG_ERROR, "Could not create IQ when creating pubsub subscription on client '%s'\n", client->name);
1259                 return;
1260         }
1261
1262         pubsub = iks_insert(request, "pubsub");
1263         iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1264         subscribe = iks_insert(pubsub, "subscribe");
1265         iks_insert_attrib(subscribe, "jid", client->jid->partial);
1266         iks_insert_attrib(subscribe, "node", node);
1267         if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1268                 iks *options, *x, *sub_options, *sub_type, *sub_depth, *sub_expire;
1269                 options = iks_insert(pubsub, "options");
1270                 x = iks_insert(options, "x");
1271                 iks_insert_attrib(x, "xmlns", "jabber:x:data");
1272                 iks_insert_attrib(x, "type", "submit");
1273                 sub_options = iks_insert(x, "field");
1274                 iks_insert_attrib(sub_options, "var", "FORM_TYPE");
1275                 iks_insert_attrib(sub_options, "type", "hidden");
1276                 iks_insert_cdata(iks_insert(sub_options, "value"),
1277                                  "http://jabber.org/protocol/pubsub#subscribe_options", 51);
1278                 sub_type = iks_insert(x, "field");
1279                 iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
1280                 iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
1281                 sub_depth = iks_insert(x, "field");
1282                 iks_insert_attrib(sub_depth, "var", "pubsub#subscription_depth");
1283                 iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
1284                 sub_expire = iks_insert(x, "field");
1285                 iks_insert_attrib(sub_expire, "var", "pubsub#expire");
1286                 iks_insert_cdata(iks_insert(sub_expire, "value"), "presence", 8);
1287         }
1288         ast_xmpp_client_send(client, request);
1289         iks_delete(request);
1290 }
1291
1292 /*!
1293  * \brief Callback for handling PubSub events
1294  * \param data void pointer to ast_xmpp_client structure
1295  * \param pak A pak
1296  * \return IKS_FILTER_EAT
1297  */
1298 static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
1299 {
1300         char *item_id, *device_state, *context;
1301         int oldmsgs, newmsgs;
1302         iks *item, *item_content;
1303         struct ast_eid pubsub_eid;
1304         struct ast_event *event;
1305         item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
1306         if (!item) {
1307                 ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
1308                 return IKS_FILTER_EAT;
1309         }
1310         item_id = iks_find_attrib(item, "id");
1311         item_content = iks_child(item);
1312         ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
1313         if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
1314                 ast_debug(1, "Returning here, eid of incoming event matches ours!\n");
1315                 return IKS_FILTER_EAT;
1316         }
1317         if (!strcasecmp(iks_name(item_content), "state")) {
1318                 device_state = iks_find_cdata(item, "state");
1319                 if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
1320                                             AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
1321                                             AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
1322                                             AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
1323                                             AST_EVENT_IE_END))) {
1324                         return IKS_FILTER_EAT;
1325                 }
1326         } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
1327                 context = strsep(&item_id, "@");
1328                 sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
1329                 sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
1330                 if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
1331                                             AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
1332                                             AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
1333                                             AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
1334                                             AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
1335                                             &pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
1336                         return IKS_FILTER_EAT;
1337                 }
1338         } else {
1339                 ast_debug(1, "Don't know how to handle PubSub event of type %s\n",
1340                           iks_name(item_content));
1341                 return IKS_FILTER_EAT;
1342         }
1343         ast_event_queue_and_cache(event);
1344         return IKS_FILTER_EAT;
1345 }
1346
1347 static int xmpp_pubsub_handle_error(void *data, ikspak *pak)
1348 {
1349         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1350         char *node_name, *error;
1351         int error_num;
1352         iks *orig_request, *orig_pubsub = iks_find(pak->x, "pubsub");
1353         struct ast_xmpp_client *client = data;
1354
1355         if (!cfg || !cfg->global) {
1356                 ast_log(LOG_ERROR, "No global configuration available\n");
1357                 return IKS_FILTER_EAT;
1358         }
1359
1360         if (!orig_pubsub) {
1361                 ast_log(LOG_ERROR, "Error isn't a PubSub error, why are we here?\n");
1362                 return IKS_FILTER_EAT;
1363         }
1364
1365         orig_request = iks_child(orig_pubsub);
1366         error = iks_find_attrib(iks_find(pak->x, "error"), "code");
1367         node_name = iks_find_attrib(orig_request, "node");
1368
1369         if (!sscanf(error, "%30d", &error_num)) {
1370                 return IKS_FILTER_EAT;
1371         }
1372
1373         if (error_num > 399 && error_num < 500 && error_num != 404) {
1374                 ast_log(LOG_ERROR,
1375                         "Error performing operation on PubSub node %s, %s.\n", node_name, error);
1376                 return IKS_FILTER_EAT;
1377         } else if (error_num > 499 && error_num < 600) {
1378                 ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
1379                 return IKS_FILTER_EAT;
1380         }
1381
1382         if (!strcasecmp(iks_name(orig_request), "publish")) {
1383                 iks *request;
1384
1385                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1386                         if (iks_find(iks_find(orig_request, "item"), "state")) {
1387                                 xmpp_pubsub_create_leaf(client, "device_state", node_name);
1388                         } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
1389                                 xmpp_pubsub_create_leaf(client, "message_waiting", node_name);
1390                         }
1391                 } else {
1392                         xmpp_pubsub_create_node(client, NULL, node_name, NULL);
1393                 }
1394
1395                 if ((request = xmpp_pubsub_iq_create(client, "set"))) {
1396                         iks_insert_node(request, orig_pubsub);
1397                         ast_xmpp_client_send(client, request);
1398                         iks_delete(request);
1399                 } else {
1400                         ast_log(LOG_ERROR, "PubSub publish could not create IQ\n");
1401                 }
1402
1403                 return IKS_FILTER_EAT;
1404         } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
1405                 if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1406                         xmpp_pubsub_create_collection(client, node_name);
1407                 } else {
1408                         xmpp_pubsub_create_node(client, NULL, node_name, NULL);
1409                 }
1410         }
1411
1412         return IKS_FILTER_EAT;
1413 }
1414
1415 /*!
1416  * \brief Initialize collections for event distribution
1417  * \param client the configured XMPP client we use to connect to a XMPP server
1418  * \return void
1419  */
1420 static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
1421 {
1422         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1423         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1424
1425         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
1426                 return;
1427         }
1428
1429         xmpp_pubsub_unsubscribe(client, "device_state");
1430         xmpp_pubsub_unsubscribe(client, "message_waiting");
1431
1432         if (!(client->mwi_sub = ast_event_subscribe(AST_EVENT_MWI, xmpp_pubsub_mwi_cb, "xmpp_pubsub_mwi_subscription",
1433                                                     client, AST_EVENT_IE_END))) {
1434                 return;
1435         }
1436
1437         if (ast_enable_distributed_devstate()) {
1438                 return;
1439         }
1440         
1441
1442         if (!(client->device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
1443                                                              xmpp_pubsub_devstate_cb, "xmpp_pubsub_devstate_subscription", client, AST_EVENT_IE_END))) {
1444                 ast_event_unsubscribe(client->mwi_sub);
1445                 client->mwi_sub = NULL;
1446                 return;
1447         }
1448
1449         ast_event_dump_cache(client->device_state_sub);
1450
1451         xmpp_pubsub_subscribe(client, "device_state");
1452         xmpp_pubsub_subscribe(client, "message_waiting");
1453         iks_filter_add_rule(client->filter, xmpp_pubsub_handle_event, client, IKS_RULE_TYPE,
1454                             IKS_PAK_MESSAGE, IKS_RULE_FROM, clientcfg->pubsubnode, IKS_RULE_DONE);
1455         iks_filter_add_rule(client->filter, xmpp_pubsub_handle_error, client, IKS_RULE_TYPE,
1456                             IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
1457
1458 }
1459
1460 /*! \brief Internal astobj2 callback function which returns the first resource, which is the highest priority one */
1461 static int xmpp_resource_immediate(void *obj, void *arg, int flags)
1462 {
1463         return CMP_MATCH | CMP_STOP;
1464 }
1465
1466 /*
1467  * \internal
1468  * \brief Dial plan function status(). puts the status of watched user
1469  * into a channel variable.
1470  * \param chan ast_channel
1471  * \param data
1472  * \retval 0 success
1473  * \retval -1 error
1474  */
1475 static int xmpp_status_exec(struct ast_channel *chan, const char *data)
1476 {
1477         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1478         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1479         struct ast_xmpp_buddy *buddy;
1480         struct ast_xmpp_resource *resource;
1481         char *s = NULL, status[2];
1482         int stat = 7;
1483         static int deprecation_warning = 0;
1484         AST_DECLARE_APP_ARGS(args,
1485                              AST_APP_ARG(sender);
1486                              AST_APP_ARG(jid);
1487                              AST_APP_ARG(variable);
1488                 );
1489         AST_DECLARE_APP_ARGS(jid,
1490                              AST_APP_ARG(screenname);
1491                              AST_APP_ARG(resource);
1492                 );
1493
1494         if (deprecation_warning++ % 10 == 0) {
1495                 ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
1496         }
1497
1498         if (ast_strlen_zero(data)) {
1499                 ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
1500                 return 0;
1501         }
1502         s = ast_strdupa(data);
1503         AST_STANDARD_APP_ARGS(args, s);
1504
1505         if (args.argc != 3) {
1506                 ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
1507                 return -1;
1508         }
1509
1510         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
1511         if (jid.argc < 1 || jid.argc > 2) {
1512                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
1513                 return -1;
1514         }
1515
1516         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1517                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1518                 return -1;
1519         }
1520
1521         if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
1522                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
1523                 return -1;
1524         }
1525
1526         if (ast_strlen_zero(jid.resource) || !(resource = ao2_find(buddy->resources, jid.resource, OBJ_KEY))) {
1527                 resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
1528         }
1529
1530         ao2_ref(buddy, -1);
1531
1532         if (resource) {
1533                 stat = resource->status;
1534                 ao2_ref(resource, -1);
1535         } else {
1536                 ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
1537         }
1538
1539         snprintf(status, sizeof(status), "%d", stat);
1540         pbx_builtin_setvar_helper(chan, args.variable, status);
1541
1542         return 0;
1543 }
1544
1545 /*!
1546  * \internal
1547  * \brief Dial plan funtcion to retrieve the status of a buddy.
1548  * \param channel The associated ast_channel, if there is one
1549  * \param data The account, buddy JID, and optional timeout
1550  * timeout.
1551  * \retval 0 success
1552  * \retval -1 failure
1553  */
1554 static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
1555 {
1556         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1557         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1558         struct ast_xmpp_buddy *buddy;
1559         struct ast_xmpp_resource *resource;
1560         int stat = 7;
1561         AST_DECLARE_APP_ARGS(args,
1562                              AST_APP_ARG(sender);
1563                              AST_APP_ARG(jid);
1564                 );
1565         AST_DECLARE_APP_ARGS(jid,
1566                              AST_APP_ARG(screenname);
1567                              AST_APP_ARG(resource);
1568                 );
1569
1570         if (ast_strlen_zero(data)) {
1571                 ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
1572                 return 0;
1573         }
1574         AST_STANDARD_APP_ARGS(args, data);
1575
1576         if (args.argc != 2) {
1577                 ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
1578                 return -1;
1579         }
1580
1581         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
1582         if (jid.argc < 1 || jid.argc > 2) {
1583                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
1584                 return -1;
1585         }
1586
1587         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1588                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1589                 return -1;
1590         }
1591
1592         if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
1593                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
1594                 return -1;
1595         }
1596
1597         if (ast_strlen_zero(jid.resource) || !(resource = ao2_find(buddy->resources, jid.resource, OBJ_KEY))) {
1598                 resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
1599         }
1600
1601         ao2_ref(buddy, -1);
1602
1603         if (resource) {
1604                 stat = resource->status;
1605                 ao2_ref(resource, -1);
1606         } else {
1607                 ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
1608         }
1609
1610         snprintf(buf, buflen, "%d", stat);
1611
1612         return 0;
1613 }
1614
1615 static struct ast_custom_function jabberstatus_function = {
1616         .name = "JABBER_STATUS",
1617         .read = acf_jabberstatus_read,
1618 };
1619
1620 /*!
1621  * \brief Application to join a chat room
1622  * \param chan ast_channel
1623  * \param data  Data is sender|jid|nickname.
1624  * \retval 0 success
1625  * \retval -1 error
1626  */
1627 static int xmpp_join_exec(struct ast_channel *chan, const char *data)
1628 {
1629         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1630         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1631         char *s, nick[XMPP_MAX_RESJIDLEN];
1632         AST_DECLARE_APP_ARGS(args,
1633                              AST_APP_ARG(sender);
1634                              AST_APP_ARG(jid);
1635                              AST_APP_ARG(nick);
1636                 );
1637
1638         if (ast_strlen_zero(data)) {
1639                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1640                 return -1;
1641         }
1642         s = ast_strdupa(data);
1643
1644         AST_STANDARD_APP_ARGS(args, s);
1645         if (args.argc < 2 || args.argc > 3) {
1646                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1647                 return -1;
1648         }
1649
1650         if (strchr(args.jid, '/')) {
1651                 ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
1652                 return -1;
1653         }
1654
1655         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1656                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1657                 return -1;
1658         }
1659
1660         if (ast_strlen_zero(args.nick)) {
1661                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1662                         snprintf(nick, sizeof(nick), "asterisk");
1663                 } else {
1664                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1665                 }
1666         } else {
1667                 snprintf(nick, sizeof(nick), "%s", args.nick);
1668         }
1669
1670         if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
1671                 ast_xmpp_chatroom_join(clientcfg->client, args.jid, nick);
1672         } else {
1673                 ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
1674         }
1675
1676         return 0;
1677 }
1678
1679 /*!
1680  * \brief Application to leave a chat room
1681  * \param chan ast_channel
1682  * \param data  Data is sender|jid|nickname.
1683  * \retval 0 success
1684  * \retval -1 error
1685  */
1686 static int xmpp_leave_exec(struct ast_channel *chan, const char *data)
1687 {
1688         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1689         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1690         char *s, nick[XMPP_MAX_RESJIDLEN];
1691         AST_DECLARE_APP_ARGS(args,
1692                              AST_APP_ARG(sender);
1693                              AST_APP_ARG(jid);
1694                              AST_APP_ARG(nick);
1695                 );
1696
1697         if (ast_strlen_zero(data)) {
1698                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1699                 return -1;
1700         }
1701         s = ast_strdupa(data);
1702
1703         AST_STANDARD_APP_ARGS(args, s);
1704         if (args.argc < 2 || args.argc > 3) {
1705                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1706                 return -1;
1707         }
1708
1709         if (strchr(args.jid, '/')) {
1710                 ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
1711                 return -1;
1712         }
1713
1714         if (ast_strlen_zero(args.jid) || !strchr(args.jid, '@')) {
1715                 ast_log(LOG_ERROR, "No jabber ID specified\n");
1716                 return -1;
1717         }
1718
1719         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1720                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1721                 return -1;
1722         }
1723
1724         if (ast_strlen_zero(args.nick)) {
1725                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1726                         snprintf(nick, sizeof(nick), "asterisk");
1727                 } else {
1728                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1729                 }
1730         } else {
1731                 snprintf(nick, sizeof(nick), "%s", args.nick);
1732         }
1733
1734         ast_xmpp_chatroom_leave(clientcfg->client, args.jid, nick);
1735
1736         return 0;
1737 }
1738
1739 /*!
1740  * \internal
1741  * \brief Dial plan function to send a message.
1742  * \param chan ast_channel
1743  * \param data  Data is account,jid,message.
1744  * \retval 0 success
1745  * \retval -1 failure
1746  */
1747 static int xmpp_send_exec(struct ast_channel *chan, const char *data)
1748 {
1749         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1750         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1751         char *s;
1752         AST_DECLARE_APP_ARGS(args,
1753                              AST_APP_ARG(sender);
1754                              AST_APP_ARG(recipient);
1755                              AST_APP_ARG(message);
1756                 );
1757
1758         if (ast_strlen_zero(data)) {
1759                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1760                 return -1;
1761         }
1762         s = ast_strdupa(data);
1763
1764         AST_STANDARD_APP_ARGS(args, s);
1765
1766         if ((args.argc < 3) || ast_strlen_zero(args.message) || !strchr(args.recipient, '@')) {
1767                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1768                 return -1;
1769         }
1770
1771         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1772                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1773                 return -1;
1774         }
1775
1776         ast_xmpp_client_send_message(clientcfg->client, args.recipient, args.message);
1777
1778         return 0;
1779 }
1780
1781 /*!
1782  * \brief Application to send a message to a groupchat.
1783  * \param chan ast_channel
1784  * \param data  Data is sender|groupchat|message.
1785  * \retval 0 success
1786  * \retval -1 error
1787  */
1788 static int xmpp_sendgroup_exec(struct ast_channel *chan, const char *data)
1789 {
1790         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1791         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1792         char *s, nick[XMPP_MAX_RESJIDLEN];
1793         AST_DECLARE_APP_ARGS(args,
1794                              AST_APP_ARG(sender);
1795                              AST_APP_ARG(groupchat);
1796                              AST_APP_ARG(message);
1797                              AST_APP_ARG(nick);
1798                 );
1799
1800         if (ast_strlen_zero(data)) {
1801                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1802                 return -1;
1803         }
1804         s = ast_strdupa(data);
1805
1806         AST_STANDARD_APP_ARGS(args, s);
1807         if ((args.argc < 3) || (args.argc > 4) || ast_strlen_zero(args.message) || !strchr(args.groupchat, '@')) {
1808                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1809                 return -1;
1810         }
1811
1812         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1813                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1814                 return -1;
1815         }
1816
1817         if (ast_strlen_zero(args.nick) || args.argc == 3) {
1818                 if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1819                         snprintf(nick, sizeof(nick), "asterisk");
1820                 } else {
1821                         snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1822                 }
1823         } else {
1824                 snprintf(nick, sizeof(nick), "%s", args.nick);
1825         }
1826
1827         ast_xmpp_chatroom_send(clientcfg->client, nick, args.groupchat, args.message);
1828
1829         return 0;
1830 }
1831
1832 /*!
1833  * \internal
1834  * \brief Dial plan function to receive a message.
1835  * \param channel The associated ast_channel, if there is one
1836  * \param data The account, JID, and optional timeout
1837  * timeout.
1838  * \retval 0 success
1839  * \retval -1 failure
1840  */
1841 static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
1842 {
1843         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1844         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1845         char *aux = NULL, *parse = NULL;
1846         int timeout, jidlen, resourcelen, found = 0;
1847         struct timeval start;
1848         long diff = 0;
1849         struct ast_xmpp_message *message;
1850         AST_DECLARE_APP_ARGS(args,
1851                              AST_APP_ARG(account);
1852                              AST_APP_ARG(jid);
1853                              AST_APP_ARG(timeout);
1854                 );
1855         AST_DECLARE_APP_ARGS(jid,
1856                              AST_APP_ARG(screenname);
1857                              AST_APP_ARG(resource);
1858                 );
1859
1860         if (ast_strlen_zero(data)) {
1861                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
1862                 return -1;
1863         }
1864
1865         parse = ast_strdupa(data);
1866         AST_STANDARD_APP_ARGS(args, parse);
1867
1868         if (args.argc < 2 || args.argc > 3) {
1869                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
1870                 return -1;
1871         }
1872
1873         parse = ast_strdupa(args.jid);
1874         AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
1875         if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > XMPP_MAX_JIDLEN) {
1876                 ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
1877                 return -1;
1878         }
1879
1880         if (ast_strlen_zero(args.timeout)) {
1881                 timeout = 20;
1882         } else {
1883                 sscanf(args.timeout, "%d", &timeout);
1884                 if (timeout <= 0) {
1885                         ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
1886                         return -1;
1887                 }
1888         }
1889
1890         jidlen = strlen(jid.screenname);
1891         resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
1892
1893         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.account))) {
1894                 ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
1895                 return -1;
1896         }
1897
1898         ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
1899
1900         start = ast_tvnow();
1901
1902         if (ast_autoservice_start(chan) < 0) {
1903                 ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", ast_channel_name(chan));
1904                 return -1;
1905         }
1906
1907         /* search the messages list, grab the first message that matches with
1908          * the from JID we're expecting, and remove it from the messages list */
1909         while (diff < timeout) {
1910                 struct timespec ts = { 0, };
1911                 struct timeval wait;
1912                 int res = 0;
1913
1914                 wait = ast_tvadd(start, ast_tv(timeout, 0));
1915                 ts.tv_sec = wait.tv_sec;
1916                 ts.tv_nsec = wait.tv_usec * 1000;
1917
1918                 /* wait up to timeout seconds for an incoming message */
1919                 ast_mutex_lock(&messagelock);
1920                 if (AST_LIST_EMPTY(&clientcfg->client->messages)) {
1921                         res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
1922                 }
1923                 ast_mutex_unlock(&messagelock);
1924                 if (res == ETIMEDOUT) {
1925                         ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
1926                         break;
1927                 }
1928
1929                 AST_LIST_LOCK(&clientcfg->client->messages);
1930                 AST_LIST_TRAVERSE_SAFE_BEGIN(&clientcfg->client->messages, message, list) {
1931                         if (jid.argc == 1) {
1932                                 /* no resource provided, compare bare JIDs */
1933                                 if (strncasecmp(jid.screenname, message->from, jidlen)) {
1934                                         continue;
1935                                 }
1936                         } else {
1937                                 /* resource appended, compare bare JIDs and resources */
1938                                 char *resource = strchr(message->from, '/');
1939                                 if (!resource || strlen(resource) == 0) {
1940                                         ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", message->from);
1941                                         if (strncasecmp(jid.screenname, message->from, jidlen)) {
1942                                                 continue;
1943                                         }
1944                                 } else {
1945                                         resource ++;
1946                                         if (strncasecmp(jid.screenname, message->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
1947                                                 continue;
1948                                         }
1949                                 }
1950                         }
1951                         /* check if the message is not too old */
1952                         if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
1953                                 ast_debug(3, "Found old message from %s, deleting it\n", message->from);
1954                                 AST_LIST_REMOVE_CURRENT(list);
1955                                 xmpp_message_destroy(message);
1956                                 continue;
1957                         }
1958                         found = 1;
1959                         aux = ast_strdupa(message->message);
1960                         AST_LIST_REMOVE_CURRENT(list);
1961                         xmpp_message_destroy(message);
1962                         break;
1963                 }
1964                 AST_LIST_TRAVERSE_SAFE_END;
1965                 AST_LIST_UNLOCK(&clientcfg->client->messages);
1966                 if (found) {
1967                         break;
1968                 }
1969
1970                 /* check timeout */
1971                 diff = ast_tvdiff_ms(ast_tvnow(), start);
1972         }
1973
1974         if (ast_autoservice_stop(chan) < 0) {
1975                 ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", ast_channel_name(chan));
1976         }
1977
1978         /* return if we timed out */
1979         if (!found) {
1980                 ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
1981                 return -1;
1982         }
1983         ast_copy_string(buf, aux, buflen);
1984
1985         return 0;
1986 }
1987
1988 static struct ast_custom_function jabberreceive_function = {
1989         .name = "JABBER_RECEIVE",
1990         .read = acf_jabberreceive_read,
1991 };
1992
1993 /*!
1994  * \internal
1995  * \brief Delete old messages from a given JID
1996  * Messages stored during more than client->message_timeout are deleted
1997  * \param client Asterisk's XMPP client
1998  * \param from the JID we received messages from
1999  * \retval the number of deleted messages
2000  */
2001 static int delete_old_messages(struct ast_xmpp_client *client, char *from)
2002 {
2003         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2004         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2005         int deleted = 0, isold = 0;
2006         struct ast_xmpp_message *message = NULL;
2007
2008         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2009                 return 0;
2010         }
2011
2012         AST_LIST_LOCK(&client->messages);
2013         AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, message, list) {
2014                 if (isold) {
2015                         if (!from || !strncasecmp(from, message->from, strlen(from))) {
2016                                 AST_LIST_REMOVE_CURRENT(list);
2017                                 xmpp_message_destroy(message);
2018                                 deleted++;
2019                         }
2020                 } else if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
2021                         isold = 1;
2022                         if (!from || !strncasecmp(from, message->from, strlen(from))) {
2023                                 AST_LIST_REMOVE_CURRENT(list);
2024                                 xmpp_message_destroy(message);
2025                                 deleted++;
2026                         }
2027                 }
2028         }
2029         AST_LIST_TRAVERSE_SAFE_END;
2030         AST_LIST_UNLOCK(&client->messages);
2031
2032         return deleted;
2033 }
2034
2035 static int xmpp_send_cb(const struct ast_msg *msg, const char *to, const char *from)
2036 {
2037         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2038         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2039         char *sender, *dest;
2040         int res;
2041
2042         sender = ast_strdupa(from);
2043         strsep(&sender, ":");
2044         dest = ast_strdupa(to);
2045         strsep(&dest, ":");
2046
2047         if (ast_strlen_zero(sender)) {
2048                 ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for XMPP\n", from);
2049                 return -1;
2050         }
2051
2052         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, sender))) {
2053                 ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
2054                 return -1;
2055         }
2056
2057         ast_debug(1, "Sending message to '%s' from '%s'\n", dest, clientcfg->name);
2058
2059         if ((res = ast_xmpp_client_send_message(clientcfg->client, dest, ast_msg_get_body(msg))) != IKS_OK) {
2060                 ast_log(LOG_WARNING, "Failed to send XMPP message (%d).\n", res);
2061         }
2062
2063         return res == IKS_OK ? 0 : -1;
2064 }
2065
2066 static const struct ast_msg_tech msg_tech = {
2067         .name = "xmpp",
2068         .msg_send = xmpp_send_cb,
2069 };
2070
2071 /*! \brief Internal function which changes the XMPP client state */
2072 static void xmpp_client_change_state(struct ast_xmpp_client *client, int state)
2073 {
2074         client->state = state;
2075 }
2076
2077 /*! \brief Internal function which creates a buddy on a client */
2078 static struct ast_xmpp_buddy *xmpp_client_create_buddy(struct ao2_container *container, const char *id)
2079 {
2080         struct ast_xmpp_buddy *buddy;
2081
2082         if (!(buddy = ao2_alloc(sizeof(*buddy), xmpp_buddy_destructor))) {
2083                 return NULL;
2084         }
2085
2086         if (!(buddy->resources = ao2_container_alloc(RESOURCE_BUCKETS, xmpp_resource_hash, xmpp_resource_cmp))) {
2087                 ao2_ref(buddy, -1);
2088                 return NULL;
2089         }
2090
2091         ast_copy_string(buddy->id, id, sizeof(buddy->id));
2092
2093         /* Assume we need to subscribe to get their presence until proven otherwise */
2094         buddy->subscribe = 1;
2095
2096         ao2_link(container, buddy);
2097
2098         return buddy;
2099 }
2100
2101 /*! \brief Helper function which unsubscribes a user and removes them from the roster */
2102 static int xmpp_client_unsubscribe_user(struct ast_xmpp_client *client, const char *user)
2103 {
2104         iks *iq, *query = NULL, *item = NULL;
2105
2106         if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, user,
2107                                                        "Goodbye. Your status is no longer required.\n"))) {
2108                 return -1;
2109         }
2110
2111         if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item"))) {
2112                 ast_log(LOG_WARNING, "Could not allocate memory for roster removal of '%s' from client '%s'\n",
2113                         user, client->name);
2114                 goto done;
2115         }
2116
2117         iks_insert_attrib(iq, "from", client->jid->full);
2118         iks_insert_attrib(iq, "type", "set");
2119         iks_insert_attrib(query, "xmlns", "jabber:iq:roster");
2120         iks_insert_node(iq, query);
2121         iks_insert_attrib(item, "jid", user);
2122         iks_insert_attrib(item, "subscription", "remove");
2123         iks_insert_node(query, item);
2124
2125         if (ast_xmpp_client_send(client, iq)) {
2126                 ast_log(LOG_WARNING, "Could not send roster removal request of '%s' from client '%s'\n",
2127                         user, client->name);
2128         }
2129
2130 done:
2131         iks_delete(item);
2132         iks_delete(query);
2133         iks_delete(iq);
2134
2135         return 0;
2136 }
2137
2138 /*! \brief Callback function which subscribes to a user if needed */
2139 static int xmpp_client_subscribe_user(void *obj, void *arg, int flags)
2140 {
2141         struct ast_xmpp_buddy *buddy = obj;
2142         struct ast_xmpp_client *client = arg;
2143
2144         if (!buddy->subscribe) {
2145                 return 0;
2146         }
2147
2148         if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, buddy->id,
2149                                                        "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"))) {
2150                 ast_log(LOG_WARNING, "Could not send subscription for '%s' on client '%s'\n",
2151                         buddy->id, client->name);
2152         }
2153
2154         buddy->subscribe = 0;
2155
2156         return 0;
2157 }
2158
2159 /*! \brief Hook function called when roster is received from server */
2160 static int xmpp_roster_hook(void *data, ikspak *pak)
2161 {
2162         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2163         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2164         struct ast_xmpp_client *client = data;
2165         iks *item;
2166
2167         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2168                 return IKS_FILTER_EAT;
2169         }
2170
2171         for (item = iks_child(pak->query); item; item = iks_next(item)) {
2172                 struct ast_xmpp_buddy *buddy;
2173
2174                 if (iks_strcmp(iks_name(item), "item")) {
2175                         continue;
2176                 }
2177
2178                 if (!(buddy = ao2_find(client->buddies, iks_find_attrib(item, "jid"), OBJ_KEY))) {
2179                         if (ast_test_flag(&clientcfg->flags, XMPP_AUTOPRUNE)) {
2180                                 /* The buddy has not been specified in the configuration file, we no longer
2181                                  * want them on our buddy list or to receive their presence. */
2182                                 if (xmpp_client_unsubscribe_user(client, iks_find_attrib(item, "jid"))) {
2183                                         ast_log(LOG_ERROR, "Could not unsubscribe user '%s' on client '%s'\n",
2184                                                 iks_find_attrib(item, "jid"), client->name);
2185                                 }
2186                                 continue;
2187                         }
2188
2189                         if (!(buddy = xmpp_client_create_buddy(client->buddies, iks_find_attrib(item, "jid")))) {
2190                                 ast_log(LOG_ERROR, "Could not allocate buddy '%s' on client '%s'\n", iks_find_attrib(item, "jid"),
2191                                         client->name);
2192                                 continue;
2193                         }
2194                 }
2195
2196                 /* Determine if we need to subscribe to their presence or not */
2197                 if (!iks_strcmp(iks_find_attrib(item, "subscription"), "none") ||
2198                     !iks_strcmp(iks_find_attrib(item, "subscription"), "from")) {
2199                         buddy->subscribe = 1;
2200                 } else {
2201                         buddy->subscribe = 0;
2202                 }
2203
2204                 ao2_ref(buddy, -1);
2205         }
2206
2207         /* If autoregister is enabled we need to go through every buddy that we need to subscribe to and do so */
2208         if (ast_test_flag(&clientcfg->flags, XMPP_AUTOREGISTER)) {
2209                 ao2_callback(client->buddies, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_subscribe_user, client);
2210         }
2211
2212         xmpp_client_change_state(client, XMPP_STATE_CONNECTED);
2213
2214         return IKS_FILTER_EAT;
2215 }
2216
2217 /*! \brief Internal function which changes the presence status of an XMPP client */
2218 static void xmpp_client_set_presence(struct ast_xmpp_client *client, const char *to, const char *from, int level, const char *desc)
2219 {
2220         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2221         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2222         iks *presence = NULL, *cnode = NULL, *priority = NULL;
2223         char priorityS[10];
2224
2225         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2226             !(presence = iks_make_pres(level, desc)) || !(cnode = iks_new("c")) || !(priority = iks_new("priority"))) {
2227                 ast_log(LOG_ERROR, "Unable to allocate stanzas for setting presence status for client '%s'\n", client->name);
2228                 goto done;
2229         }
2230
2231         if (!ast_strlen_zero(to)) {
2232                 iks_insert_attrib(presence, "to", to);
2233         }
2234
2235         if (!ast_strlen_zero(from)) {
2236                 iks_insert_attrib(presence, "from", from);
2237         }
2238
2239         snprintf(priorityS, sizeof(priorityS), "%d", clientcfg->priority);
2240         iks_insert_cdata(priority, priorityS, strlen(priorityS));
2241         iks_insert_node(presence, priority);
2242         iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
2243         iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
2244         iks_insert_attrib(cnode, "ext", "voice-v1 video-v1 camera-v1");
2245         iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
2246         iks_insert_node(presence, cnode);
2247         ast_xmpp_client_send(client, presence);
2248
2249 done:
2250         iks_delete(cnode);
2251         iks_delete(presence);
2252         iks_delete(priority);
2253 }
2254
2255 /*! \brief Hook function called when client receives a service discovery get message */
2256 static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak)
2257 {
2258         struct ast_xmpp_client *client = data;
2259         iks *iq, *disco = NULL, *ident = NULL, *google = NULL, *jingle = NULL, *ice = NULL, *rtp = NULL, *audio = NULL, *video = NULL, *query = NULL;
2260
2261         if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(ident = iks_new("identity")) || !(disco = iks_new("feature")) ||
2262             !(google = iks_new("feature")) || !(jingle = iks_new("feature")) || !(ice = iks_new("feature")) || !(rtp = iks_new("feature")) ||
2263             !(audio = iks_new("feature")) || !(video = iks_new("feature"))) {
2264                 ast_log(LOG_ERROR, "Could not allocate memory for responding to service discovery request from '%s' on client '%s'\n",
2265                         pak->from->full, client->name);
2266                 goto end;
2267         }
2268
2269         iks_insert_attrib(iq, "from", client->jid->full);
2270
2271         if (pak->from) {
2272                 iks_insert_attrib(iq, "to", pak->from->full);
2273         }
2274
2275         iks_insert_attrib(iq, "type", "result");
2276         iks_insert_attrib(iq, "id", pak->id);
2277         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2278         iks_insert_attrib(ident, "category", "client");
2279         iks_insert_attrib(ident, "type", "pc");
2280         iks_insert_attrib(ident, "name", "asterisk");
2281         iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
2282
2283         iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
2284         iks_insert_attrib(jingle, "var", "urn:xmpp:jingle:1");
2285         iks_insert_attrib(ice, "var", "urn:xmpp:jingle:transports:ice-udp:1");
2286         iks_insert_attrib(rtp, "var", "urn:xmpp:jingle:apps:rtp:1");
2287         iks_insert_attrib(audio, "var", "urn:xmpp:jingle:apps:rtp:audio");
2288         iks_insert_attrib(video, "var", "urn:xmpp:jingle:apps:rtp:video");
2289         iks_insert_node(iq, query);
2290         iks_insert_node(query, ident);
2291         iks_insert_node(query, google);
2292         iks_insert_node(query, disco);
2293         iks_insert_node(query, jingle);
2294         iks_insert_node(query, ice);
2295         iks_insert_node(query, rtp);
2296         iks_insert_node(query, audio);
2297         iks_insert_node(query, video);
2298         ast_xmpp_client_send(client, iq);
2299
2300 end:
2301         iks_delete(query);
2302         iks_delete(video);
2303         iks_delete(audio);
2304         iks_delete(rtp);
2305         iks_delete(ice);
2306         iks_delete(jingle);
2307         iks_delete(google);
2308         iks_delete(ident);
2309         iks_delete(disco);
2310         iks_delete(iq);
2311
2312         return IKS_FILTER_EAT;
2313 }
2314
2315 /*! \brief Hook function called when client receives a service discovery result message */
2316 static int xmpp_client_service_discovery_result_hook(void *data, ikspak *pak)
2317 {
2318         struct ast_xmpp_client *client = data;
2319         struct ast_xmpp_buddy *buddy;
2320         struct ast_xmpp_resource *resource;
2321
2322         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
2323                 return IKS_FILTER_EAT;
2324         }
2325
2326         if (!(resource = ao2_find(buddy->resources, pak->from->resource, OBJ_KEY))) {
2327                 ao2_ref(buddy, -1);
2328                 return IKS_FILTER_EAT;
2329         }
2330
2331         ao2_lock(resource);
2332
2333         if (iks_find_with_attrib(pak->query, "feature", "var", "urn:xmpp:jingle:1")) {
2334                 resource->caps.jingle = 1;
2335         }
2336
2337         ao2_unlock(resource);
2338
2339         ao2_ref(resource, -1);
2340         ao2_ref(buddy, -1);
2341
2342         return IKS_FILTER_EAT;
2343 }
2344
2345 /*! \brief Hook function called when client finishes authenticating with the server */
2346 static int xmpp_connect_hook(void *data, ikspak *pak)
2347 {
2348         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2349         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2350         struct ast_xmpp_client *client = data;
2351         iks *roster;
2352
2353         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2354                 return -1;
2355         }
2356
2357         client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
2358
2359         if (ast_test_flag(&clientcfg->flags, XMPP_DISTRIBUTE_EVENTS)) {
2360                 xmpp_init_event_distribution(client);
2361         }
2362
2363         if (!(roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER))) {
2364                 ast_log(LOG_ERROR, "Unable to allocate memory for roster request for client '%s'\n", client->name);
2365                 return -1;
2366         }
2367
2368         iks_filter_add_rule(client->filter, xmpp_client_service_discovery_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
2369         iks_filter_add_rule(client->filter, xmpp_client_service_discovery_result_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
2370
2371         iks_insert_attrib(roster, "id", "roster");
2372         ast_xmpp_client_send(client, roster);
2373
2374         iks_filter_remove_hook(client->filter, xmpp_connect_hook);
2375         iks_filter_add_rule(client->filter, xmpp_roster_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
2376
2377         xmpp_client_set_presence(client, NULL, client->jid->full, clientcfg->status, clientcfg->statusmsg);
2378         xmpp_client_change_state(client, XMPP_STATE_ROSTER);
2379
2380         return IKS_FILTER_EAT;
2381 }
2382
2383 /*! \brief Logging hook function */
2384 static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incoming)
2385 {
2386         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2387         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2388         struct ast_xmpp_client *client = data;
2389
2390         if (!ast_strlen_zero(xmpp)) {
2391                 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
2392         }
2393
2394         if (!debug && (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) || !ast_test_flag(&clientcfg->flags, XMPP_DEBUG))) {
2395                 return;
2396         }
2397
2398         if (!incoming) {
2399                 if (strlen(xmpp) == 1) {
2400                         if (option_debug > 2  && xmpp[0] == ' ') {
2401                                 ast_verbose("\n<--- XMPP keep alive from '%s' --->\n", client->name);
2402                         }
2403                 } else {
2404                         ast_verbose("\n<--- XMPP sent to '%s' --->\n%s\n<------------->\n", client->name, xmpp);
2405                 }
2406         } else {
2407                 ast_verbose("\n<--- XMPP received from '%s' --->\n%s\n<------------->\n", client->name, xmpp);
2408         }
2409 }
2410
2411 /*! \brief Internal function which sends a raw message */
2412 static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
2413 {
2414         int ret;
2415 #ifdef HAVE_OPENSSL
2416         int len = strlen(message);
2417
2418         if (xmpp_is_secure(client)) {
2419                 ret = SSL_write(client->ssl_session, message, len);
2420                 if (ret) {
2421                         /* Log the message here, because iksemel's logHook is
2422                            unaccessible */
2423                         xmpp_log_hook(client, message, len, 0);
2424                         return IKS_OK;
2425                 }
2426         }
2427 #endif
2428         /* If needed, data will be sent unencrypted, and logHook will
2429            be called inside iks_send_raw */
2430         ret = iks_send_raw(client->parser, message);
2431         if (ret != IKS_OK) {
2432                 return ret;
2433         }
2434
2435         return IKS_OK;
2436 }
2437
2438 /*! \brief Helper function which sends an XMPP stream header to the server */
2439 static int xmpp_send_stream_header(struct ast_xmpp_client *client, const struct ast_xmpp_client_config *cfg, const char *to)
2440 {
2441         char *namespace = ast_test_flag(&cfg->flags, XMPP_COMPONENT) ? "jabber:component:accept" : "jabber:client";
2442         char msg[91 + strlen(namespace) + 6 + strlen(to) + 16 + 1];
2443
2444         snprintf(msg, sizeof(msg), "<?xml version='1.0'?>"
2445                  "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
2446                  "%s' to='%s' version='1.0'>", namespace, to);
2447
2448         return xmpp_client_send_raw_message(client, msg);
2449 }
2450
2451 int ast_xmpp_client_send(struct ast_xmpp_client *client, iks *stanza)
2452 {
2453         return xmpp_client_send_raw_message(client, iks_string(iks_stack(stanza), stanza));
2454 }
2455
2456 /*! \brief Internal function called when we need to request TLS support */
2457 static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2458 {
2459         /* If the client connection is already secure we can jump straight to authenticating */
2460         if (xmpp_is_secure(client)) {
2461                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2462                 return 0;
2463         }
2464
2465 #ifndef HAVE_OPENSSL
2466         ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL is not available.\n", client->name);
2467         return -1;
2468 #else
2469         if (iks_send_raw(client->parser, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>") == IKS_NET_TLSFAIL) {
2470                 ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be started.\n", client->name);
2471                 return -1;
2472         }
2473
2474         client->stream_flags |= TRY_SECURE;
2475
2476         xmpp_client_change_state(client, XMPP_STATE_REQUESTED_TLS);
2477
2478         return 0;
2479 #endif
2480 }
2481
2482 /*! \brief Internal function called when we receive a response to our TLS initiation request */
2483 static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2484 {
2485 #ifdef HAVE_OPENSSL
2486         int sock;
2487 #endif
2488
2489         if (!strcmp(iks_name(node), "success")) {
2490                 /* TLS is up and working, we can move on to authenticating now */
2491                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2492                 return 0;
2493         } else if (!strcmp(iks_name(node), "failure")) {
2494                 /* TLS negotiation was a failure, close it on down! */
2495                 return -1;
2496         } else if (strcmp(iks_name(node), "proceed")) {
2497                 /* Ignore any other responses */
2498                 return 0;
2499         }
2500
2501 #ifndef HAVE_OPENSSL
2502         ast_log(LOG_ERROR, "Somehow we managed to try to start TLS negotiation on client '%s' without OpenSSL support, disconnecting\n", client->name);
2503         return -1;
2504 #else
2505         client->ssl_method = SSLv3_method();
2506         if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
2507                 goto failure;
2508         }
2509
2510         if (!(client->ssl_session = SSL_new(client->ssl_context))) {
2511                 goto failure;
2512         }
2513
2514         sock = iks_fd(client->parser);
2515         if (!SSL_set_fd(client->ssl_session, sock)) {
2516                 goto failure;
2517         }
2518
2519         if (!SSL_connect(client->ssl_session)) {
2520                 goto failure;
2521         }
2522
2523         client->stream_flags &= (~TRY_SECURE);
2524         client->stream_flags |= SECURE;
2525
2526         if (xmpp_send_stream_header(client, cfg, client->jid->server) != IKS_OK) {
2527                 ast_log(LOG_ERROR, "TLS connection for client '%s' could not be established, failed to send stream header after negotiation\n",
2528                         client->name);
2529                 return -1;
2530         }
2531
2532         ast_debug(1, "TLS connection for client '%s' started with server\n", client->name);
2533
2534         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
2535
2536         return 0;
2537
2538 failure:
2539         ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL initialization failed.\n", client->name);
2540         return -1;
2541 #endif
2542 }
2543
2544 /*! \brief Internal function called when we need to authenticate using non-SASL */
2545 static int xmpp_client_authenticate_digest(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2546 {
2547         iks *iq = NULL, *query = NULL;
2548         char buf[41], sidpass[100];
2549
2550         if (!(iq = iks_new("iq")) || !(query = iks_insert(iq, "query"))) {
2551                 ast_log(LOG_ERROR, "Stanzas could not be allocated for authentication on client '%s'\n", client->name);
2552                 iks_delete(iq);
2553                 return -1;
2554         }
2555
2556         iks_insert_attrib(iq, "type", "set");
2557         iks_insert_cdata(iks_insert(query, "username"), client->jid->user, 0);
2558         iks_insert_cdata(iks_insert(query, "resource"), client->jid->resource, 0);
2559
2560         iks_insert_attrib(query, "xmlns", "jabber:iq:auth");
2561         snprintf(sidpass, sizeof(sidpass), "%s%s", iks_find_attrib(node, "id"), cfg->password);
2562         ast_sha1_hash(buf, sidpass);
2563         iks_insert_cdata(iks_insert(query, "digest"), buf, 0);
2564
2565         ast_xmpp_client_lock(client);
2566         iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
2567         iks_insert_attrib(iq, "id", client->mid);
2568         ast_xmpp_increment_mid(client->mid);
2569         ast_xmpp_client_unlock(client);
2570
2571         iks_insert_attrib(iq, "to", client->jid->server);
2572
2573         ast_xmpp_client_send(client, iq);
2574
2575         iks_delete(iq);
2576
2577         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2578
2579         return 0;
2580 }
2581
2582 /*! \brief Internal function called when we need to authenticate using SASL */
2583 static int xmpp_client_authenticate_sasl(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2584 {
2585         int features, len = strlen(client->jid->user) + strlen(cfg->password) + 3;
2586         iks *auth;
2587         char combined[len];
2588         char base64[(len + 2) * 4 / 3];
2589
2590         if (strcmp(iks_name(node), "stream:features")) {
2591                 /* Ignore anything beside stream features */
2592                 return 0;
2593         }
2594
2595         features = iks_stream_features(node);
2596
2597         if ((features & IKS_STREAM_SASL_MD5) && !xmpp_is_secure(client)) {
2598                 if (iks_start_sasl(client->parser, IKS_SASL_DIGEST_MD5, (char*)client->jid->user, (char*)cfg->password) != IKS_OK) {
2599                         ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL DIGEST-MD5 but could not\n", client->name);
2600                         return -1;
2601                 }
2602
2603                 xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2604                 return 0;
2605         }
2606
2607         /* Our only other available option is plain so if they don't support it, bail out now */
2608         if (!(features & IKS_STREAM_SASL_PLAIN)) {
2609                 ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL PLAIN but server does not support it\n", client->name);
2610                 return -1;
2611         }
2612
2613         if (!(auth = iks_new("auth"))) {
2614                 ast_log(LOG_ERROR, "Could not allocate memory for SASL PLAIN authentication for client '%s'\n", client->name);
2615                 return -1;
2616         }
2617
2618         iks_insert_attrib(auth, "xmlns", IKS_NS_XMPP_SASL);
2619         iks_insert_attrib(auth, "mechanism", "PLAIN");
2620
2621         if (strchr(client->jid->user, '/')) {
2622                 char *user = ast_strdupa(client->jid->user);
2623
2624                 snprintf(combined, sizeof(combined), "%c%s%c%s", 0, strsep(&user, "/"), 0, cfg->password);
2625         } else {
2626                 snprintf(combined, sizeof(combined), "%c%s%c%s", 0, client->jid->user, 0, cfg->password);
2627         }
2628
2629         ast_base64encode(base64, (const unsigned char *) combined, len - 1, (len + 2) * 4 / 3);
2630         iks_insert_cdata(auth, base64, 0);
2631
2632         ast_xmpp_client_send(client, auth);
2633
2634         iks_delete(auth);
2635
2636         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2637
2638         return 0;
2639 }
2640
2641 /*! \brief Internal function called when we need to authenticate */
2642 static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2643 {
2644         return ast_test_flag(&cfg->flags, XMPP_USESASL) ? xmpp_client_authenticate_sasl(client, cfg, type, node) : xmpp_client_authenticate_digest(client, cfg, type, node);
2645 }
2646
2647 /*! \brief Internal function called when we are authenticating */
2648 static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2649 {
2650         int features;
2651
2652         if (!strcmp(iks_name(node), "success")) {
2653                 /* Authentication was a success, yay! */
2654                 xmpp_send_stream_header(client, cfg, client->jid->server);
2655
2656                 return 0;
2657         } else if (!strcmp(iks_name(node), "failure")) {
2658                 /* Authentication was a bust, disconnect and reconnect later */
2659                 return -1;
2660         } else if (strcmp(iks_name(node), "stream:features")) {
2661                 /* Ignore any other responses */
2662                 return 0;
2663         }
2664
2665         features = iks_stream_features(node);
2666
2667         if (features & IKS_STREAM_BIND) {
2668                 iks *auth;
2669
2670                 if (!(auth = iks_make_resource_bind(client->jid))) {
2671                         ast_log(LOG_ERROR, "Failed to allocate memory for stream bind on client '%s'\n", client->name);
2672                         return -1;
2673                 }
2674
2675                 ast_xmpp_client_lock(client);
2676                 iks_insert_attrib(auth, "id", client->mid);
2677                 ast_xmpp_increment_mid(client->mid);
2678                 ast_xmpp_client_unlock(client);
2679                 ast_xmpp_client_send(client, auth);
2680
2681                 iks_delete(auth);
2682
2683                 iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
2684         }
2685
2686         if (features & IKS_STREAM_SESSION) {
2687                 iks *auth;
2688
2689                 if (!(auth = iks_make_session())) {
2690                         ast_log(LOG_ERROR, "Failed to allocate memory for stream session on client '%s'\n", client->name);
2691                         return -1;
2692                 }
2693
2694                 iks_insert_attrib(auth, "id", "auth");
2695                 ast_xmpp_client_lock(client);
2696                 ast_xmpp_increment_mid(client->mid);
2697                 ast_xmpp_client_unlock(client);
2698                 ast_xmpp_client_send(client, auth);
2699
2700                 iks_delete(auth);
2701
2702                 iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
2703         }
2704
2705         return 0;
2706 }
2707
2708 /*! \brief Internal function called when we should authenticate as a component */
2709 static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2710 {
2711         char secret[160], shasum[320], message[344];
2712         ikspak *pak = iks_packet(node);
2713
2714         snprintf(secret, sizeof(secret), "%s%s", pak->id, cfg->password);
2715         ast_sha1_hash(shasum, secret);
2716         snprintf(message, sizeof(message), "<handshake>%s</handshake>", shasum);
2717
2718         if (xmpp_client_send_raw_message(client, message) != IKS_OK) {
2719                 ast_log(LOG_ERROR, "Unable to send handshake for component '%s'\n", client->name);
2720                 return -1;
2721         }
2722
2723         xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
2724
2725         return 0;
2726 }
2727
2728 /*! \brief Hook function called when component receives a service discovery get message */
2729 static int xmpp_component_service_discovery_get_hook(void *data, ikspak *pak)
2730 {
2731         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2732         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2733         struct ast_xmpp_client *client = data;
2734         iks *iq = NULL, *query = NULL, *identity = NULL, *disco = NULL, *reg = NULL, *commands = NULL, *gateway = NULL;
2735         iks *version = NULL, *vcard = NULL, *search = NULL, *item = NULL;
2736         char *node;
2737
2738         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2739             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(identity = iks_new("identity")) || !(disco = iks_new("feature")) ||
2740             !(reg = iks_new("feature")) || !(commands = iks_new("feature")) || !(gateway = iks_new("feature")) || !(version = iks_new("feature")) ||
2741             !(vcard = iks_new("feature")) || !(search = iks_new("search")) || !(item = iks_new("item"))) {
2742                 ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery get response to '%s' on component '%s'\n",
2743                         pak->from->partial, client->name);
2744                 goto done;
2745         }
2746
2747         iks_insert_attrib(iq, "from", clientcfg->user);
2748         iks_insert_attrib(iq, "to", pak->from->full);
2749         iks_insert_attrib(iq, "id", pak->id);
2750         iks_insert_attrib(iq, "type", "result");
2751
2752         if (!(node = iks_find_attrib(pak->query, "node"))) {
2753                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2754                 iks_insert_attrib(identity, "category", "gateway");
2755                 iks_insert_attrib(identity, "type", "pstn");
2756                 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
2757                 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
2758                 iks_insert_attrib(reg, "var", "jabber:iq:register");
2759                 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2760                 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
2761                 iks_insert_attrib(version, "var", "jabber:iq:version");
2762                 iks_insert_attrib(vcard, "var", "vcard-temp");
2763                 iks_insert_attrib(search, "var", "jabber:iq:search");
2764
2765                 iks_insert_node(iq, query);
2766                 iks_insert_node(query, identity);
2767                 iks_insert_node(query, disco);
2768                 iks_insert_node(query, reg);
2769                 iks_insert_node(query, commands);
2770                 iks_insert_node(query, gateway);
2771                 iks_insert_node(query, version);
2772                 iks_insert_node(query, vcard);
2773                 iks_insert_node(query, search);
2774         } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
2775                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2776                 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2777                 iks_insert_attrib(item, "node", "confirmaccount");
2778                 iks_insert_attrib(item, "name", "Confirm account");
2779                 iks_insert_attrib(item, "jid", clientcfg->user);
2780
2781                 iks_insert_node(iq, query);
2782                 iks_insert_node(query, item);
2783         } else if (!strcasecmp(node, "confirmaccount")) {
2784                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2785                 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2786
2787                 iks_insert_node(iq, query);
2788                 iks_insert_node(query, commands);
2789         } else {
2790                 ast_debug(3, "Unsupported service discovery info request received with node '%s' on component '%s'\n",
2791                           node, client->name);
2792                 goto done;
2793         }
2794
2795         if (ast_xmpp_client_send(client, iq)) {
2796                 ast_log(LOG_WARNING, "Could not send response to service discovery request on component '%s'\n",
2797                         client->name);
2798         }
2799
2800 done:
2801         iks_delete(search);
2802         iks_delete(vcard);
2803         iks_delete(version);
2804         iks_delete(gateway);
2805         iks_delete(commands);
2806         iks_delete(reg);
2807         iks_delete(disco);
2808         iks_delete(identity);
2809         iks_delete(query);
2810         iks_delete(iq);
2811
2812         return IKS_FILTER_EAT;
2813 }
2814
2815 /*! \brief Hook function called when the component is queried about registration */
2816 static int xmpp_component_register_get_hook(void *data, ikspak *pak)
2817 {
2818         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2819         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2820         struct ast_xmpp_client *client = data;
2821         iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL, *instructions = NULL;
2822         struct ast_xmpp_buddy *buddy;
2823         char *node;
2824
2825         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2826             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(error = iks_new("error")) || !(notacceptable = iks_new("not-acceptable")) ||
2827             !(instructions = iks_new("instructions"))) {
2828                 ast_log(LOG_ERROR, "Failed to allocate stanzas for register get response to '%s' on component '%s'\n",
2829                         pak->from->partial, client->name);
2830                 goto done;
2831         }
2832
2833         iks_insert_attrib(iq, "from", clientcfg->user);
2834         iks_insert_attrib(iq, "to", pak->from->full);
2835         iks_insert_attrib(iq, "id", pak->id);
2836         iks_insert_attrib(iq, "type", "result");
2837         iks_insert_attrib(query, "xmlns", "jabber:iq:register");
2838         iks_insert_node(iq, query);
2839
2840         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
2841                 iks_insert_attrib(error, "code", "406");
2842                 iks_insert_attrib(error, "type", "modify");
2843                 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
2844
2845                 iks_insert_node(iq, error);
2846                 iks_insert_node(error, notacceptable);
2847
2848                 ast_log(LOG_ERROR, "Received register attempt from '%s' but buddy is not configured on component '%s'\n",
2849                         pak->from->partial, client->name);
2850         } else if (!(node = iks_find_attrib(pak->query, "node"))) {
2851                 iks_insert_cdata(instructions, "Welcome to Asterisk - the Open Source PBX.\n", 0);
2852                 iks_insert_node(query, instructions);
2853                 ao2_ref(buddy, -1);
2854         } else {
2855                 ast_log(LOG_WARNING, "Received register get to component '%s' using unsupported node '%s' from '%s'\n",
2856                         client->name, node, pak->from->partial);
2857                 ao2_ref(buddy, -1);
2858                 goto done;
2859         }
2860
2861         if (ast_xmpp_client_send(client, iq)) {
2862                 ast_log(LOG_WARNING, "Could not send response to '%s' for received register get on component '%s'\n",
2863                         pak->from->partial, client->name);
2864         }
2865
2866 done:
2867         iks_delete(instructions);
2868         iks_delete(notacceptable);
2869         iks_delete(error);
2870         iks_delete(query);
2871         iks_delete(iq);
2872
2873         return IKS_FILTER_EAT;
2874 }
2875
2876 /*! \brief Hook function called when someone registers to the component */
2877 static int xmpp_component_register_set_hook(void *data, ikspak *pak)
2878 {
2879         struct ast_xmpp_client *client = data;
2880         iks *iq, *presence = NULL, *x = NULL;
2881
2882         if (!(iq = iks_new("iq")) || !(presence = iks_new("presence")) || !(x = iks_new("x"))) {
2883                 ast_log(LOG_ERROR, "Failed to allocate stanzas for register set response to '%s' on component '%s'\n",
2884                         pak->from->partial, client->name);
2885                 goto done;
2886         }
2887
2888         iks_insert_attrib(iq, "from", client->jid->full);
2889         iks_insert_attrib(iq, "to", pak->from->full);
2890         iks_insert_attrib(iq, "id", pak->id);
2891         iks_insert_attrib(iq, "type", "result");
2892
2893         if (ast_xmpp_client_send(client, iq)) {
2894                 ast_log(LOG_WARNING, "Could not send response to '%s' for received register set on component '%s'\n",
2895                         pak->from->partial, client->name);
2896                 goto done;
2897         }
2898
2899         iks_insert_attrib(presence, "from", client->jid->full);
2900         iks_insert_attrib(presence, "to", pak->from->partial);
2901         ast_xmpp_client_lock(client);
2902         iks_insert_attrib(presence, "id", client->mid);
2903         ast_xmpp_increment_mid(client->mid);
2904         ast_xmpp_client_unlock(client);
2905         iks_insert_attrib(presence, "type", "subscribe");
2906         iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
2907
2908         iks_insert_node(presence, x);
2909
2910         if (ast_xmpp_client_send(client, presence)) {
2911                 ast_log(LOG_WARNING, "Could not send subscription to '%s' on component '%s'\n",
2912                         pak->from->partial, client->name);
2913         }
2914
2915 done:
2916         iks_delete(x);
2917         iks_delete(presence);
2918         iks_delete(iq);
2919
2920         return IKS_FILTER_EAT;
2921 }
2922
2923 /*! \brief Hook function called when we receive a service discovery items request */
2924 static int xmpp_component_service_discovery_items_hook(void *data, ikspak *pak)
2925 {
2926         RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2927         RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2928         struct ast_xmpp_client *client = data;
2929         iks *iq = NULL, *query = NULL, *item = NULL, *feature = NULL;
2930         char *node;
2931
2932         if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2933             !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item")) || !(feature = iks_new("feature"))) {
2934                 ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery items response to '%s' on component '%s'\n",
2935                         pak->from->partial, client->name);
2936                 goto done;
2937         }
2938
2939         iks_insert_attrib(iq, "from", clientcfg->user);
2940         iks_insert_attrib(iq, "to", pak->from->full);
2941         iks_insert_attrib(iq, "id", pak->id);
2942         iks_insert_attrib(iq, "type", "result");
2943         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2944         iks_insert_node(iq, query);
2945
2946         if (!(node = iks_find_attrib(pak->query, "node"))) {
2947                 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
2948                 iks_insert_attrib(item, "name", "Asterisk Commands");
2949                 iks_insert_attrib(item, "jid", clientcfg->user);
2950
2951                 iks_insert_node(query, item);
2952         } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
2953                 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2954         } else {
2955                 ast_log(LOG_WARNING, "Received service discovery items request to component '%s' using unsupported node '%s' from '%s'\n",
2956                         client->name, node, pak->from->partial);
2957                 goto done;
2958         }
2959
2960         if (ast_xmpp_client_send(client, iq)) {
2961                 ast_log(LOG_WARNING, "Could not send response to service discovery items request from '%s' on component '%s'\n",
2962                         pak->from->partial, client->name);
2963         }
2964
2965 done:
2966         iks_delete(feature);
2967         iks_delete(item);
2968         iks_delete(query);
2969         iks_delete(iq);
2970
2971         return IKS_FILTER_EAT;
2972 }
2973
2974 /*! \brief Internal function called when we authenticated as a component */
2975 static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2976 {
2977         if (strcmp(iks_name(node), "handshake")) {
2978                 ast_log(LOG_ERROR, "Failed to authenticate component '%s'\n", client->name);
2979                 return -1;
2980         }
2981
2982         iks_filter_add_rule(client->filter, xmpp_component_service_discovery_items_hook, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
2983
2984         iks_filter_add_rule(client->filter, xmpp_component_service_discovery_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
2985
2986         /* This uses the client service discovery result hook on purpose, as the code is common between both */
2987         iks_filter_add_rule(client->filter, xmpp_client_service_discovery_result_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
2988
2989         iks_filter_add_rule(client->filter, xmpp_component_register_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
2990         iks_filter_add_rule(client->filter, xmpp_component_register_set_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
2991
2992         xmpp_client_change_state(client, XMPP_STATE_CONNECTED);
2993
2994         return 0;
2995 }
2996
2997 /*! \brief Internal function called when a message is received */
2998 static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
2999 {
3000         struct ast_xmpp_message *message;
3001         char *body;
3002         int deleted = 0;
3003
3004         ast_debug(3, "XMPP client '%s' received a message\n", client->name);
3005
3006         if (!(body = iks_find_cdata(pak->x, "body"))) {
3007                 /* Message contains no body, ignore it. */
3008                 return 0;
3009         }
3010
3011         if (!(message = ast_calloc(1, sizeof(*message)))) {
3012                 return -1;
3013         }
3014
3015         message->arrived = ast_tvnow();
3016
3017         message->message = ast_strdup(body);
3018
3019         ast_copy_string(message->id, S_OR(pak->id, ""), sizeof(message->id));
3020         message->from = !ast_strlen_zero(pak->from->full) ? ast_strdup(pak->from->full) : NULL;
3021
3022         if (ast_test_flag(&cfg->flags, XMPP_SEND_TO_DIALPLAN)) {
3023                 struct ast_msg *msg;
3024
3025                 if ((msg = ast_msg_alloc())) {
3026                         int res;
3027
3028                         ast_xmpp_client_lock(client);
3029
3030                         res = ast_msg_set_to(msg, "xmpp:%s", cfg->user);
3031                         res |= ast_msg_set_from(msg, "xmpp:%s", message->from);
3032                         res |= ast_msg_set_body(msg, "%s", message->message);
3033                         res |= ast_msg_set_context(msg, "%s", cfg->context);
3034
3035                         ast_xmpp_client_unlock(client);
3036
3037                         if (res) {
3038                                 ast_msg_destroy(msg);
3039                         } else {
3040                                 ast_msg_queue(msg);
3041                         }
3042                 }
3043         }
3044
3045         /* remove old messages received from this JID
3046          * and insert received message */
3047         deleted = delete_old_messages(client, pak->from->partial);
3048         ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
3049         AST_LIST_LOCK(&client->messages);
3050         AST_LIST_INSERT_HEAD(&client->messages, message, list);
3051         AST_LIST_UNLOCK(&client->messages);
3052
3053         /* wake up threads waiting for messages */
3054         ast_mutex_lock(&messagelock);
3055         ast_cond_broadcast(&message_received_condition);
3056         ast_mutex_unlock(&messagelock);
3057
3058         return 0;
3059 }
3060
3061 /*! \brief Helper function which sends a discovery information request to a user */
3062 static int xmpp_client_send_disco_info_request(struct ast_xmpp_client *client, const char *to, const char *from)
3063 {
3064         iks *iq, *query;
3065         int res;
3066
3067         if (!(iq = iks_new("iq")) || !(query = iks_new("query"))) {
3068                 iks_delete(iq);
3069                 return -1;
3070         }
3071
3072         iks_insert_attrib(iq, "type", "get");
3073         iks_insert_attrib(iq, "to", to);
3074         iks_insert_attrib(iq, "from", from);
3075         ast_xmpp_client_lock(client);
3076         iks_insert_attrib(iq, "id", client->mid);
3077         ast_xmpp_increment_mid(client->mid);
3078         ast_xmpp_client_unlock(client);
3079         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
3080         iks_insert_node(iq, query);
3081
3082         res = ast_xmpp_client_send(client, iq);
3083
3084         iks_delete(query);
3085         iks_delete(iq);
3086
3087         return res;
3088 }
3089
3090 /*! \brief Internal function called when a presence message is received */
3091 static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
3092 {
3093         struct ast_xmpp_buddy *buddy;
3094         struct ast_xmpp_resource *resource;
3095         char *type = iks_find_attrib(pak->x, "type");
3096         int status = pak->show ? pak->show : STATUS_DISAPPEAR;
3097
3098         /* If no resource is available this is a general buddy presence update, which we will ignore */
3099         if (!pak->from->resource) {
3100                 return 0;
3101         }
3102
3103         if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
3104                 /* Only output the message if it is not about us */
3105                 if (strcmp(client->jid->partial, pak->from->partial)) {
3106                         ast_log(LOG_WARNING, "Received presence information about '%s' despite not having them in roster on client '%s'\n",
3107                                 pak->from->partial, client->name);
3108                 }
3109                 return 0;
3110         }
3111
3112         /* If this is a component presence probe request answer immediately with our presence status */
3113         if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) {
3114                 xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
3115         }
3116
3117         ao2_lock(buddy->resources);
3118
3119         if (!(resource = ao2_find(buddy->resources, pak->from->resource, OBJ_KEY | OBJ_NOLOCK))) {
3120                 /* Only create the new resource if it is not going away - in reality this should not happen */
3121                 if (status != STATUS_DISAPPEAR) {
3122                         if (!(resource = ao2_alloc(sizeof(*resource), xmpp_resource_destructor))) {
3123                                 ast_log(LOG_ERROR, "Could not allocate resource object for resource '%s' of buddy '%s' on client '%s'\n",
3124                                         pak->from->resource, buddy->id, client->name);
3125                                 ao2_unlock(buddy->resources);
3126                                 ao2_ref(buddy, -1);
3127                                 return 0;
3128                         }
3129
3130                         ast_copy_string(resource->resource, pak->from->resource, sizeof(resource->resource));
3131                 }
3132         } else {
3133                 /* We unlink the resource in case the priority changes or in case they are going away */
3134                 ao2_unlink_flags(buddy->resources, resource, OBJ_NOLOCK);
3135         }
3136
3137         /* Only update the resource and add it back in if it is not going away */
3138         if (resource && (status != STATUS_DISAPPEAR)) {
3139                 char *node, *ver;
3140
3141                 /* Try to get the XMPP spec node, and fall back to Google if not found */
3142                 if (!(node = iks_find_attrib(iks_find(pak->x, "c"), "node"))) {
3143                         node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
3144                 }
3145
3146                 if (!(ver = iks_find_attrib(iks_find(pak->x, "c"), "ver"))) {
3147                         ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
3148                 }
3149
3150                 if (resource->description) {
3151                         ast_free(resource->description);
3152                 }
3153
3154                 if ((node && strcmp(resource->caps.node, node)) || (ver && strcmp(resource->caps.version, ver))) {
3155                         ast_copy_string(resource->caps.node, node, sizeof(resource->caps.node));
3156                         ast_copy_string(resource->caps.version, ver, sizeof(resource->caps.version));
3157
3158                         /* Google Talk places the capabilities information directly in presence, so see if it is there */
3159                         if (iks_find_with_attrib(pak->x, "c", "node", "http://www.google.com/xmpp/client/caps") ||
3160                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.google.com/xmpp/client/caps") ||
3161                             iks_find_with_attrib(pak->x, "c", "node", "http://www.android.com/gtalk/client/caps") ||
3162                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.android.com/gtalk/client/caps") ||
3163                             iks_find_with_attrib(pak->x, "c", "node", "http://mail.google.com/xmpp/client/caps") ||
3164                             iks_find_with_attrib(pak->x, "caps:c", "node", "http://mail.google.com/xmpp/client/caps")) {
3165                                 resource->caps.google = 1;
3166                         }
3167
3168                         /* To discover if the buddy supports Jingle we need to query, so do so */
3169                         if (xmpp_client_send_disco_info_request(client, pak->from->full, client->jid->full)) {
3170                                 ast_log(LOG_WARNING, "Could not send discovery information request to resource '%s' of buddy '%s' on client '%s', capabilities may be incomplete\n", resource->resource, buddy->id, client->name);
3171                         }
3172                 }
3173
3174                 resource->status = status;
3175                 resource->description = ast_strdup(iks_find_cdata(pak->x, "status"));
3176                 resource->priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
3177
3178                 ao2_link_flags(buddy->resources, resource, OBJ_NOLOCK);
3179
3180                 manager_event(EVENT_FLAG_USER, "JabberStatus",
3181                               "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
3182                               "\r\nDescription: %s\r\n",
3183                               client->name, pak->from->partial, resource->resource, resource->status,
3184                               resource->priority, S_OR(resource->description, ""));
3185
3186                 ao2_ref(resource, -1);
3187         } else {
3188                 /* This will get hit by presence coming in for an unknown resource, and also when a resource goes away */
3189                 if (resource) {
3190                         ao2_ref(resource, -1);
3191                 }
3192
3193                 manager_event(EVENT_FLAG_USER, "JabberStatus",
3194                               "Account: %s\r\nJID: %s\r\nStatus: %d\r\n",
3195                               client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
3196         }
3197
3198         ao2_unlock(buddy->resources);
3199
3200         ao2_ref(buddy, -1);
3201
3202         return 0;
3203 }
3204
3205 /*! \brief Internal function called when a subscription message is received */
3206 static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg,iks *node, ikspak *pak)
3207 {
3208         struct ast_xmpp_buddy *buddy;
3209
3210         switch (pak->subtype) {
3211         case IKS_TYPE_SUBSCRIBE:
3212                 if (ast_test_flag(&cfg->flags, XMPP_AUTOREGISTER)) {
3213                         iks *presence, *status = NULL;
3214
3215                         if ((presence = iks_new("presence")) && (status = iks_new("status"))) {
3216                                 iks_insert_attrib(presence, "type", "subscribed");
3217                                 iks_insert_attrib(presence, "to", pak->from->full);
3218                                 iks_insert_attrib(presence, "from", client->jid->full);
3219
3220                                 if (pak->id) {
3221                                         iks_insert_attrib(presence, "id", pak->id);
3222                                 }
3223
3224                                 iks_insert_cdata(status, "Asterisk has approved your subscription", 0);
3225                                 iks_insert_node(presence, status);
3226
3227                                 if (ast_xmpp_client_send(client, presence)) {
3228                                         ast_log(LOG_ERROR, "Could not send subscription acceptance to '%s' from client '%s'\n",
3229                                                 pak->from->partial, client->name);
3230                                 }
3231                         } else {
3232                                 ast_log(LOG_ERROR, "Could not allocate presence stanzas for accepting subscription from '%s' to client '%s'\n",
3233                                         pak->from->partial, client->name);
3234                         }
3235
3236                         iks_delete(status);
3237                         iks_delete(presence);
3238                 }
3239
3240                 if (ast_test_flag(&cfg->flags, XMPP_COMPONENT)) {
3241                         xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
3242                 }
3243                 /* This purposely flows through so we have the subscriber amongst our buddies */
3244         case IKS_TYPE_SUBSCRIBED:
3245                 ao2_lock(client->buddies);
3246
3247                 if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY | OBJ_NOLOCK))) {
3248                         buddy = xmpp_client_create_buddy(client->buddies, pak->from->partial);
3249                 }
3250