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