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