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