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