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