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