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