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