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