Asterisk - The Open Source Telephony Project  21.4.1
res_xmpp.c
Go to the documentation of this file.
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
35  * \addtogroup configuration_file Configuration Files
36  */
37 
38 /*!
39  * \page xmpp.conf xmpp.conf
40  * \verbinclude xmpp.conf.sample
41  */
42 
43 /*** MODULEINFO
44  <depend>iksemel</depend>
45  <use type="external">openssl</use>
46  <support_level>core</support_level>
47  ***/
48 
49 #include "asterisk.h"
50 
51 #include <ctype.h>
52 #include <iksemel.h>
53 
54 #include "asterisk/xmpp.h"
55 #include "asterisk/module.h"
56 #include "asterisk/manager.h"
57 #include "asterisk/app.h"
58 #include "asterisk/mwi.h"
59 #include "asterisk/message.h"
60 #include "asterisk/manager.h"
61 #include "asterisk/cli.h"
63 #include "asterisk/json.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>The example below sends "Hello world" to
88  <replaceable>bob@domain.com</replaceable> as an XMPP message from the account
89  <replaceable>asterisk</replaceable>, configured in xmpp.conf.</para>
90  <example title="Send 'Hello world' to Bob">
91  same => n,JabberSend(asterisk,bob@domain.com,Hello world)
92  </example>
93  </description>
94  <see-also>
95  <ref type="function" module="res_xmpp">JABBER_STATUS</ref>
96  <ref type="function" module="res_xmpp">JABBER_RECEIVE</ref>
97  </see-also>
98  </application>
99  <function name="JABBER_RECEIVE" language="en_US" module="res_xmpp">
100  <synopsis>
101  Reads XMPP messages.
102  </synopsis>
103  <syntax>
104  <parameter name="account" required="true">
105  <para>The local named account to listen on (specified in
106  xmpp.conf)</para>
107  </parameter>
108  <parameter name="jid" required="true">
109  <para>Jabber ID of the buddy to receive message from. It can be a
110  bare JID (username@domain) or a full JID (username@domain/resource).</para>
111  </parameter>
112  <parameter name="timeout">
113  <para>In seconds, defaults to <literal>20</literal>.</para>
114  </parameter>
115  </syntax>
116  <description>
117  <para>Receives a text message on the given <replaceable>account</replaceable>
118  from the buddy identified by <replaceable>jid</replaceable> and returns the contents.</para>
119  <para>The example below returns an XMPP message sent from
120  <replaceable>bob@domain.com</replaceable> (or nothing in case of a time out), to
121  the <replaceable>asterisk</replaceable> XMPP account configured in xmpp.conf.</para>
122  <example title="Receive a message">
123  same => n,Set(msg=${JABBER_RECEIVE(asterisk,bob@domain.com)})
124  </example>
125  </description>
126  <see-also>
127  <ref type="function" module="res_xmpp">JABBER_STATUS</ref>
128  <ref type="application" module="res_xmpp">JabberSend</ref>
129  </see-also>
130  </function>
131  <function name="JABBER_STATUS" language="en_US" module="res_xmpp">
132  <synopsis>
133  Retrieves a buddy's status.
134  </synopsis>
135  <syntax>
136  <parameter name="account" required="true">
137  <para>The local named account to listen on (specified in
138  xmpp.conf)</para>
139  </parameter>
140  <parameter name="jid" required="true">
141  <para>Jabber ID of the buddy to receive message from. It can be a
142  bare JID (username@domain) or a full JID (username@domain/resource).</para>
143  </parameter>
144  </syntax>
145  <description>
146  <para>Retrieves the numeric status associated with the buddy identified
147  by <replaceable>jid</replaceable>. The return value will be one of the
148  following.</para>
149  <enumlist>
150  <enum name="1">
151  <para>Online</para>
152  </enum>
153  <enum name="2">
154  <para>Chatty</para>
155  </enum>
156  <enum name="3">
157  <para>Away</para>
158  </enum>
159  <enum name="4">
160  <para>Extended Away</para>
161  </enum>
162  <enum name="5">
163  <para>Do Not Disturb</para>
164  </enum>
165  <enum name="6">
166  <para>Offline</para>
167  </enum>
168  <enum name="7">
169  <para>Not In Roster</para>
170  </enum>
171  </enumlist>
172  </description>
173  <see-also>
174  <ref type="function" module="res_xmpp">JABBER_RECEIVE</ref>
175  <ref type="application" module="res_xmpp">JabberSend</ref>
176  </see-also>
177  </function>
178  <application name="JabberSendGroup" language="en_US" module="res_xmpp">
179  <synopsis>
180  Send a Jabber Message to a specified 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="Message" required="true">
190  <para>Message to be sent to the chat room.</para>
191  </parameter>
192  <parameter name="Nickname" required="false">
193  <para>The nickname Asterisk uses in the chat room.</para>
194  </parameter>
195  </syntax>
196  <description>
197  <para>Allows user to send a message to a chat room via XMPP.</para>
198  <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>
199  </description>
200  </application>
201  <application name="JabberJoin" language="en_US" module="res_xmpp">
202  <synopsis>
203  Join a chat room
204  </synopsis>
205  <syntax>
206  <parameter name="Jabber" required="true">
207  <para>Client or transport Asterisk uses to connect to Jabber.</para>
208  </parameter>
209  <parameter name="RoomJID" required="true">
210  <para>XMPP/Jabber JID (Name) of chat room.</para>
211  </parameter>
212  <parameter name="Nickname" required="false">
213  <para>The nickname Asterisk will use in the chat room.</para>
214  <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>
215  </parameter>
216  </syntax>
217  <description>
218  <para>Allows Asterisk to join a chat room.</para>
219  </description>
220  </application>
221  <application name="JabberLeave" language="en_US" module="res_xmpp">
222  <synopsis>
223  Leave a chat room
224  </synopsis>
225  <syntax>
226  <parameter name="Jabber" required="true">
227  <para>Client or transport Asterisk uses to connect to Jabber.</para>
228  </parameter>
229  <parameter name="RoomJID" required="true">
230  <para>XMPP/Jabber JID (Name) of chat room.</para>
231  </parameter>
232  <parameter name="Nickname" required="false">
233  <para>The nickname Asterisk uses in the chat room.</para>
234  </parameter>
235  </syntax>
236  <description>
237  <para>Allows Asterisk to leave a chat room.</para>
238  </description>
239  </application>
240  <manager name="JabberSend" language="en_US" module="res_xmpp">
241  <synopsis>
242  Sends a message to a Jabber Client.
243  </synopsis>
244  <syntax>
245  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
246  <parameter name="Jabber" required="true">
247  <para>Client or transport Asterisk uses to connect to JABBER.</para>
248  </parameter>
249  <parameter name="JID" required="true">
250  <para>XMPP/Jabber JID (Name) of recipient.</para>
251  </parameter>
252  <parameter name="Message" required="true">
253  <para>Message to be sent to the buddy.</para>
254  </parameter>
255  </syntax>
256  <description>
257  <para>Sends a message to a Jabber Client.</para>
258  </description>
259  </manager>
260  <info name="MessageDestinationInfo" language="en_US" tech="XMPP">
261  <para>Specifying a prefix of <literal>xmpp:</literal> will send the
262  message as an XMPP chat message.</para>
263  </info>
264  <info name="MessageFromInfo" language="en_US" tech="XMPP">
265  <para>Specifying a prefix of <literal>xmpp:</literal> will specify the
266  account defined in <literal>xmpp.conf</literal> to send the message from.
267  Note that this field is required for XMPP messages.</para>
268  </info>
269  <info name="MessageToInfo" language="en_US" tech="XMPP">
270  <para>Ignored</para>
271  </info>
272  <configInfo name="res_xmpp" language="en_US">
273  <synopsis>XMPP Messaging</synopsis>
274  <configFile name="xmpp.conf">
275  <configObject name="global">
276  <synopsis>Global configuration settings</synopsis>
277  <configOption name="debug">
278  <synopsis>Enable/disable XMPP message debugging</synopsis>
279  </configOption>
280  <configOption name="autoprune">
281  <synopsis>Auto-remove users from buddy list.</synopsis>
282  <description><para>Auto-remove users from buddy list. Depending on the setup
283  (e.g., using your personal Gtalk account for a test) this could cause loss of
284  the contact list.
285  </para></description>
286  </configOption>
287  <configOption name="autoregister">
288  <synopsis>Auto-register users from buddy list</synopsis>
289  </configOption>
290  <configOption name="collection_nodes">
291  <synopsis>Enable support for XEP-0248 for use with distributed device state</synopsis>
292  </configOption>
293  <configOption name="pubsub_autocreate">
294  <synopsis>Whether or not the PubSub server supports/is using auto-create for nodes</synopsis>
295  </configOption>
296  <configOption name="auth_policy">
297  <synopsis>Whether to automatically accept or deny users' subscription requests</synopsis>
298  </configOption>
299  </configObject>
300  <configObject name="client">
301  <synopsis>Configuration options for an XMPP client</synopsis>
302  <configOption name="username">
303  <synopsis>XMPP username with optional resource</synopsis>
304  </configOption>
305  <configOption name="secret">
306  <synopsis>XMPP password</synopsis>
307  </configOption>
308  <configOption name="refresh_token">
309  <synopsis>Google OAuth 2.0 refresh token</synopsis>
310  </configOption>
311  <configOption name="oauth_clientid">
312  <synopsis>Google OAuth 2.0 application's client id</synopsis>
313  </configOption>
314  <configOption name="oauth_secret">
315  <synopsis>Google OAuth 2.0 application's secret</synopsis>
316  </configOption>
317  <configOption name="serverhost">
318  <synopsis>Route to server, e.g. talk.google.com</synopsis>
319  </configOption>
320  <configOption name="statusmessage">
321  <synopsis>Custom status message</synopsis>
322  </configOption>
323  <configOption name="pubsub_node">
324  <synopsis>Node for publishing events via PubSub</synopsis>
325  </configOption>
326  <configOption name="context">
327  <synopsis>Dialplan context to send incoming messages to</synopsis>
328  </configOption>
329  <configOption name="priority">
330  <synopsis>XMPP resource priority</synopsis>
331  </configOption>
332  <configOption name="port">
333  <synopsis>XMPP server port</synopsis>
334  </configOption>
335  <configOption name="timeout">
336  <synopsis>Timeout in seconds to hold incoming messages</synopsis>
337  <description><para>Timeout (in seconds) on the message stack. Messages stored longer
338  than this value will be deleted by Asterisk. This option applies to incoming messages only
339  which are intended to be processed by the <literal>JABBER_RECEIVE</literal> dialplan function.
340  </para></description>
341  </configOption>
342  <configOption name="debug">
343  <synopsis>Enable debugging</synopsis>
344  </configOption>
345  <configOption name="type">
346  <synopsis>Connection is either a client or a component</synopsis>
347  </configOption>
348  <configOption name="distribute_events">
349  <synopsis>Whether or not to distribute events using this connection</synopsis>
350  </configOption>
351  <configOption name="usetls">
352  <synopsis>Whether to use TLS for the connection or not</synopsis>
353  </configOption>
354  <configOption name="usesasl">
355  <synopsis>Whether to use SASL for the connection or not</synopsis>
356  </configOption>
357  <configOption name="forceoldssl">
358  <synopsis>Force the use of old-style SSL for the connection</synopsis>
359  </configOption>
360  <configOption name="keepalive">
361  <synopsis>If enabled, periodically send an XMPP message from this client with an empty message</synopsis>
362  </configOption>
363  <configOption name="autoprune">
364  <synopsis>Auto-remove users from buddy list.</synopsis>
365  <description><para>Auto-remove users from buddy list. Depending on the setup
366  (e.g., using your personal Gtalk account for a test) this could cause loss of
367  the contact list.
368  </para></description>
369  </configOption>
370  <configOption name="autoregister">
371  <synopsis>Auto-register users bfrom buddy list</synopsis>
372  </configOption>
373  <configOption name="auth_policy">
374  <synopsis>Whether to automatically accept or deny users' subscription requests</synopsis>
375  </configOption>
376  <configOption name="sendtodialplan">
377  <synopsis>Send incoming messages into the dialplan</synopsis>
378  </configOption>
379  <configOption name="status">
380  <synopsis>Default XMPP status for the client</synopsis>
381  <description><para>Can be one of the following XMPP statuses:</para>
382  <enumlist>
383  <enum name="chat"/>
384  <enum name="available"/>
385  <enum name="away"/>
386  <enum name="xaway"/>
387  <enum name="dnd"/>
388  </enumlist>
389  </description>
390  </configOption>
391  <configOption name="buddy">
392  <synopsis>Manual addition of buddy to list</synopsis>
393  <description><para>
394  Manual addition of buddy to the buddy list. For distributed events, these buddies are
395  automatically added in the whitelist as 'owners' of the node(s).
396  </para></description>
397  </configOption>
398  </configObject>
399  </configFile>
400  </configInfo>
401 ***/
402 
403 /*! \brief Supported general configuration flags */
404 enum {
405  XMPP_AUTOPRUNE = (1 << 0),
406  XMPP_AUTOREGISTER = (1 << 1),
407  XMPP_AUTOACCEPT = (1 << 2),
408  XMPP_DEBUG = (1 << 3),
409  XMPP_USETLS = (1 << 4),
410  XMPP_USESASL = (1 << 5),
411  XMPP_FORCESSL = (1 << 6),
412  XMPP_KEEPALIVE = (1 << 7),
413  XMPP_COMPONENT = (1 << 8),
414  XMPP_SEND_TO_DIALPLAN = (1 << 9),
415  XMPP_DISTRIBUTE_EVENTS = (1 << 10),
416 };
417 
418 /*! \brief Supported pubsub configuration flags */
419 enum {
420  XMPP_XEP0248 = (1 << 0),
421  XMPP_PUBSUB = (1 << 1),
422  XMPP_PUBSUB_AUTOCREATE = (1 << 2),
423 };
424 
425 /*! \brief Number of buckets for client connections */
426 #define CLIENT_BUCKETS 53
427 
428 /*! \brief Number of buckets for buddies (per client) */
429 #define BUDDY_BUCKETS 53
430 
431 /*! \brief Number of buckets for resources (per buddy) */
432 #define RESOURCE_BUCKETS 53
433 
434 /*! \brief Namespace for TLS support */
435 #define XMPP_TLS_NS "urn:ietf:params:xml:ns:xmpp-tls"
436 
437 /*! \brief Status for a disappearing buddy */
438 #define STATUS_DISAPPEAR 6
439 
440 /*! \brief Global debug status */
441 static int debug;
442 
443 /*! \brief XMPP Global Configuration */
445  struct ast_flags general; /*!< General configuration options */
446  struct ast_flags pubsub; /*!< Pubsub related configuration options */
447 };
448 
449 /*! \brief XMPP Client Configuration */
452  AST_STRING_FIELD(name); /*!< Name of the client connection */
453  AST_STRING_FIELD(user); /*!< Username to use for authentication */
454  AST_STRING_FIELD(password); /*!< Password to use for authentication */
455  AST_STRING_FIELD(refresh_token); /*!< Refresh token to use for OAuth authentication */
456  AST_STRING_FIELD(oauth_clientid); /*!< Client ID to use for OAuth authentication */
457  AST_STRING_FIELD(oauth_secret); /*!< Secret to use for OAuth authentication */
458  AST_STRING_FIELD(server); /*!< Server hostname */
459  AST_STRING_FIELD(statusmsg); /*!< Status message for presence */
460  AST_STRING_FIELD(pubsubnode); /*!< Pubsub node */
461  AST_STRING_FIELD(context); /*!< Context for incoming messages */
462  );
463  int port; /*!< Port to use when connecting to server */
464  int message_timeout; /*!< Timeout for messages */
465  int priority; /*!< Resource priority */
466  struct ast_flags flags; /*!< Various options that have been set */
467  struct ast_flags mod_flags; /*!< Global options that have been modified */
468  enum ikshowtype status; /*!< Presence status */
469  struct ast_xmpp_client *client; /*!< Pointer to the client */
470  struct ao2_container *buddies; /*!< Configured buddies */
471 };
472 
473 struct xmpp_config {
474  struct ast_xmpp_global_config *global; /*!< Global configuration options */
475  struct ao2_container *clients; /*!< Configured clients */
476 };
477 
478 static AO2_GLOBAL_OBJ_STATIC(globals);
479 
480 static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
481 static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
482 static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
483 static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
484 
485 static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
486 static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
487 
488 /*! \brief Defined handlers for XMPP client states */
489 static const struct xmpp_state_handler {
490  int state;
491  int component;
492  int (*handler)(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node);
493 } xmpp_state_handlers[] = {
500 };
501 
502 static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
503 static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
504 static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
505 
506 /*! \brief Defined handlers for different PAK types */
507 static const struct xmpp_pak_handler {
508  int type;
509  int (*handler)(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak);
510 } xmpp_pak_handlers[] = {
511  { IKS_PAK_MESSAGE, xmpp_pak_message, },
512  { IKS_PAK_PRESENCE, xmpp_pak_presence, },
513  { IKS_PAK_S10N, xmpp_pak_s10n, },
514 };
515 
516 static const char *app_ajisend = "JabberSend";
517 static const char *app_ajisendgroup = "JabberSendGroup";
518 static const char *app_ajistatus = "JabberStatus";
519 static const char *app_ajijoin = "JabberJoin";
520 static const char *app_ajileave = "JabberLeave";
521 
522 static ast_cond_t message_received_condition;
523 static ast_mutex_t messagelock;
524 
525 static int xmpp_client_config_post_apply(void *obj, void *arg, int flags);
526 static int fetch_access_token(struct ast_xmpp_client_config *cfg);
527 
528 /*! \brief Destructor function for configuration */
529 static void ast_xmpp_client_config_destructor(void *obj)
530 {
531  struct ast_xmpp_client_config *cfg = obj;
533  ao2_cleanup(cfg->client);
534  ao2_cleanup(cfg->buddies);
535 }
536 
537 /*! \brief Destroy function for XMPP messages */
539 {
540  if (message->from) {
541  ast_free(message->from);
542  }
543  if (message->message) {
544  ast_free(message->message);
545  }
546 
547  ast_free(message);
548 }
549 
550 /*! \brief Destructor callback function for XMPP client */
551 static void xmpp_client_destructor(void *obj)
552 {
553  struct ast_xmpp_client *client = obj;
554  struct ast_xmpp_message *message;
555 
557 
559  client->endpoint = NULL;
560 
561  if (client->filter) {
562  iks_filter_delete(client->filter);
563  }
564 
565  if (client->stack) {
566  iks_stack_delete(client->stack);
567  }
568 
569  ao2_cleanup(client->buddies);
570 
571  while ((message = AST_LIST_REMOVE_HEAD(&client->messages, list))) {
572  xmpp_message_destroy(message);
573  }
574  AST_LIST_HEAD_DESTROY(&client->messages);
575 }
576 
577 /*! \brief Hashing function for XMPP buddy */
578 static int xmpp_buddy_hash(const void *obj, const int flags)
579 {
580  const struct ast_xmpp_buddy *buddy = obj;
581  const char *id = obj;
582 
583  return ast_str_hash(flags & OBJ_KEY ? id : buddy->id);
584 }
585 
586 /*! \brief Comparator function for XMPP buddy */
587 static int xmpp_buddy_cmp(void *obj, void *arg, int flags)
588 {
589  struct ast_xmpp_buddy *buddy1 = obj, *buddy2 = arg;
590  const char *id = arg;
591 
592  return !strcmp(buddy1->id, flags & OBJ_KEY ? id : buddy2->id) ? CMP_MATCH | CMP_STOP : 0;
593 }
594 
595 /*! \brief Internal function which changes the XMPP client state */
596 static void xmpp_client_change_state(struct ast_xmpp_client *client, int state)
597 {
598  if (state == client->state) {
599  return;
600  }
601  client->state = state;
602  if (client->state == XMPP_STATE_DISCONNECTED) {
604  } else if (client->state == XMPP_STATE_CONNECTED) {
606  }
607 }
608 
609 /*! \brief Allocator function for ast_xmpp_client */
610 static struct ast_xmpp_client *xmpp_client_alloc(const char *name)
611 {
612  struct ast_xmpp_client *client;
613 
614  if (!(client = ao2_alloc(sizeof(*client), xmpp_client_destructor))) {
615  return NULL;
616  }
617 
618  AST_LIST_HEAD_INIT(&client->messages);
619  client->thread = AST_PTHREADT_NULL;
620 
621  client->endpoint = ast_endpoint_create("XMPP", name);
622  if (!client->endpoint) {
623  ao2_ref(client, -1);
624  return NULL;
625  }
626 
629  if (!client->buddies) {
630  ast_log(LOG_ERROR, "Could not initialize buddy container for '%s'\n", name);
631  ao2_ref(client, -1);
632  return NULL;
633  }
634 
635  if (ast_string_field_init(client, 512)) {
636  ast_log(LOG_ERROR, "Could not initialize stringfields for '%s'\n", name);
637  ao2_ref(client, -1);
638  return NULL;
639  }
640 
641  if (!(client->stack = iks_stack_new(8192, 8192))) {
642  ast_log(LOG_ERROR, "Could not create an Iksemel stack for '%s'\n", name);
643  ao2_ref(client, -1);
644  return NULL;
645  }
646 
647  ast_string_field_set(client, name, name);
648 
649  client->timeout = 50;
651  ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
652 
653  return client;
654 }
655 
656 /*! \brief Find function for configuration */
657 static void *xmpp_config_find(struct ao2_container *tmp_container, const char *category)
658 {
659  return ao2_find(tmp_container, category, OBJ_KEY);
660 }
661 
662 /*! \brief Look up existing client or create a new one */
663 static void *xmpp_client_find_or_create(const char *category)
664 {
665  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
666  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
667 
668  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, category))) {
669  return xmpp_client_alloc(category);
670  }
671 
672  ao2_ref(clientcfg->client, +1);
673  return clientcfg->client;
674 }
675 
676 /*! \brief Allocator function for configuration */
677 static void *ast_xmpp_client_config_alloc(const char *cat)
678 {
679  struct ast_xmpp_client_config *cfg;
680 
681  if (!(cfg = ao2_alloc(sizeof(*cfg), ast_xmpp_client_config_destructor))) {
682  return NULL;
683  }
684 
685  if (ast_string_field_init(cfg, 512)) {
686  ao2_ref(cfg, -1);
687  return NULL;
688  }
689 
690  if (!(cfg->client = xmpp_client_find_or_create(cat))) {
691  ao2_ref(cfg, -1);
692  return NULL;
693  }
694 
697  if (!cfg->buddies) {
698  ao2_ref(cfg, -1);
699  return NULL;
700  }
701 
702  ast_string_field_set(cfg, name, cat);
703 
704  return cfg;
705 }
706 
707 /*! \brief Destructor for XMPP configuration */
708 static void xmpp_config_destructor(void *obj)
709 {
710  struct xmpp_config *cfg = obj;
711  ao2_cleanup(cfg->global);
712  ao2_cleanup(cfg->clients);
713 }
714 
715 /*! \brief Comparator function for configuration */
716 static int xmpp_config_cmp(void *obj, void *arg, int flags)
717 {
718  struct ast_xmpp_client_config *one = obj, *two = arg;
719  const char *match = (flags & OBJ_KEY) ? arg : two->name;
720  return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
721 }
722 
723 /*! \brief Allocator for XMPP configuration */
724 static void *xmpp_config_alloc(void)
725 {
726  struct xmpp_config *cfg;
727 
728  if (!(cfg = ao2_alloc(sizeof(*cfg), xmpp_config_destructor))) {
729  return NULL;
730  }
731 
732  if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), NULL))) {
733  goto error;
734  }
735 
737  NULL, xmpp_config_cmp);
738  if (!cfg->clients) {
739  goto error;
740  }
741 
742  return cfg;
743 error:
744  ao2_ref(cfg, -1);
745  return NULL;
746 }
747 
748 static int xmpp_config_prelink(void *newitem)
749 {
750  struct ast_xmpp_client_config *clientcfg = newitem;
751  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
752  RAII_VAR(struct ast_xmpp_client_config *, oldclientcfg, NULL, ao2_cleanup);
753 
754  if (ast_strlen_zero(clientcfg->user)) {
755  ast_log(LOG_ERROR, "No user specified on client '%s'\n", clientcfg->name);
756  return -1;
757  } else if (ast_strlen_zero(clientcfg->password) && ast_strlen_zero(clientcfg->refresh_token)) {
758  ast_log(LOG_ERROR, "No password or refresh_token specified on client '%s'\n", clientcfg->name);
759  return -1;
760  } else if (ast_strlen_zero(clientcfg->server)) {
761  ast_log(LOG_ERROR, "No server specified on client '%s'\n", clientcfg->name);
762  return -1;
763  } else if (!ast_strlen_zero(clientcfg->refresh_token) &&
764  (ast_strlen_zero(clientcfg->oauth_clientid) || ast_strlen_zero(clientcfg->oauth_secret))) {
765  ast_log(LOG_ERROR, "No oauth_clientid or oauth_secret specified, so client '%s' can't be used\n", clientcfg->name);
766  return -1;
767  }
768 
769  /* If this is a new connection force a reconnect */
770  if (!cfg || !cfg->clients || !(oldclientcfg = xmpp_config_find(cfg->clients, clientcfg->name))) {
771  clientcfg->client->reconnect = 1;
772  return 0;
773  }
774 
775  /* If any configuration options are changing that would require reconnecting set the bit so we will do so if possible */
776  if (strcmp(clientcfg->user, oldclientcfg->user) ||
777  strcmp(clientcfg->password, oldclientcfg->password) ||
778  strcmp(clientcfg->refresh_token, oldclientcfg->refresh_token) ||
779  strcmp(clientcfg->oauth_clientid, oldclientcfg->oauth_clientid) ||
780  strcmp(clientcfg->oauth_secret, oldclientcfg->oauth_secret) ||
781  strcmp(clientcfg->server, oldclientcfg->server) ||
782  (clientcfg->port != oldclientcfg->port) ||
783  (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) != ast_test_flag(&oldclientcfg->flags, XMPP_COMPONENT)) ||
784  (clientcfg->priority != oldclientcfg->priority)) {
785  clientcfg->client->reconnect = 1;
786  } else {
787  clientcfg->client->reconnect = 0;
788  }
789 
790  return 0;
791 }
792 
793 static void xmpp_config_post_apply(void)
794 {
795  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
796 
797  ao2_callback(cfg->clients, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_config_post_apply, NULL);
798 }
799 
800 static struct aco_type global_option = {
801  .type = ACO_GLOBAL,
802  .name = "global",
803  .item_offset = offsetof(struct xmpp_config, global),
804  .category_match = ACO_WHITELIST_EXACT,
805  .category = "general",
806 };
807 
808 struct aco_type *global_options[] = ACO_TYPES(&global_option);
809 
810 static struct aco_type client_option = {
811  .type = ACO_ITEM,
812  .name = "client",
813  .category_match = ACO_BLACKLIST_EXACT,
814  .category = "general",
815  .item_alloc = ast_xmpp_client_config_alloc,
816  .item_find = xmpp_config_find,
817  .item_prelink = xmpp_config_prelink,
818  .item_offset = offsetof(struct xmpp_config, clients),
819 };
820 
821 struct aco_type *client_options[] = ACO_TYPES(&client_option);
822 
823 struct aco_file res_xmpp_conf = {
824  .filename = "xmpp.conf",
825  .alias = "jabber.conf",
826  .types = ACO_TYPES(&global_option, &client_option),
827 };
828 
829 CONFIG_INFO_STANDARD(cfg_info, globals, xmpp_config_alloc,
830  .files = ACO_FILES(&res_xmpp_conf),
831  .post_apply_config = xmpp_config_post_apply,
832  );
833 
834 /*! \brief Destructor callback function for XMPP resource */
835 static void xmpp_resource_destructor(void *obj)
836 {
837  struct ast_xmpp_resource *resource = obj;
838 
839  if (resource->description) {
840  ast_free(resource->description);
841  }
842 }
843 
844 /*! \brief Hashing function for XMPP resource */
845 static int xmpp_resource_hash(const void *obj, const int flags)
846 {
847  const struct ast_xmpp_resource *resource = obj;
848 
849  return flags & OBJ_KEY ? -1 : resource->priority;
850 }
851 
852 /*! \brief Comparator function for XMPP resource */
853 static int xmpp_resource_cmp(void *obj, void *arg, int flags)
854 {
855  struct ast_xmpp_resource *resource1 = obj;
856  const char *resource = arg;
857 
858  return !strcmp(resource1->resource, resource) ? CMP_MATCH | CMP_STOP : 0;
859 }
860 
861 /*! \brief Destructor callback function for XMPP buddy */
862 static void xmpp_buddy_destructor(void *obj)
863 {
864  struct ast_xmpp_buddy *buddy = obj;
865 
866  if (buddy->resources) {
867  ao2_ref(buddy->resources, -1);
868  }
869 }
870 
871 /*! \brief Helper function which returns whether an XMPP client connection is secure or not */
872 static int xmpp_is_secure(struct ast_xmpp_client *client)
873 {
874 #ifdef HAVE_OPENSSL
875  return client->stream_flags & SECURE;
876 #else
877  return 0;
878 #endif
879 }
880 
882 {
883  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
884  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
885 
886  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
887  return NULL;
888  }
889 
890  ao2_ref(clientcfg->client, +1);
891  return clientcfg->client;
892 }
893 
895 {
896  ao2_ref(client, -1);
897 }
898 
900 {
901  ao2_lock(client);
902 }
903 
905 {
906  ao2_unlock(client);
907 }
908 
909 /*! \brief Internal function used to send a message to a user or chatroom */
910 static int xmpp_client_send_message(struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
911 {
912  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
913  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
914  int res = 0;
915  char from[XMPP_MAX_JIDLEN];
916  iks *message_packet;
917 
918  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
919  !(message_packet = iks_make_msg(group ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message))) {
920  return -1;
921  }
922 
923  if (!ast_strlen_zero(nick) && ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
924  snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
925  } else {
926  snprintf(from, sizeof(from), "%s", client->jid->full);
927  }
928 
929  iks_insert_attrib(message_packet, "from", from);
930 
931  res = ast_xmpp_client_send(client, message_packet);
932 
933  iks_delete(message_packet);
934 
935  return res;
936 }
937 
938 int ast_xmpp_client_send_message(struct ast_xmpp_client *client, const char *user, const char *message)
939 {
940  return xmpp_client_send_message(client, 0, NULL, user, message);
941 }
942 
943 int ast_xmpp_chatroom_invite(struct ast_xmpp_client *client, const char *user, const char *room, const char *message)
944 {
945  int res = 0;
946  iks *invite, *body = NULL, *namespace = NULL;
947 
948  if (!(invite = iks_new("message")) || !(body = iks_new("body")) || !(namespace = iks_new("x"))) {
949  res = -1;
950  goto done;
951  }
952 
953  iks_insert_attrib(invite, "to", user);
954  ast_xmpp_client_lock(client);
955  iks_insert_attrib(invite, "id", client->mid);
956  ast_xmpp_increment_mid(client->mid);
957  ast_xmpp_client_unlock(client);
958  iks_insert_cdata(body, message, 0);
959  iks_insert_node(invite, body);
960  iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
961  iks_insert_attrib(namespace, "jid", room);
962  iks_insert_node(invite, namespace);
963 
964  res = ast_xmpp_client_send(client, invite);
965 
966 done:
967  iks_delete(namespace);
968  iks_delete(body);
969  iks_delete(invite);
970 
971  return res;
972 }
973 
974 static int xmpp_client_set_group_presence(struct ast_xmpp_client *client, const char *room, int level, const char *nick)
975 {
976  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
977  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
978  int res = 0;
979  iks *presence = NULL, *x = NULL;
980  char from[XMPP_MAX_JIDLEN], roomid[XMPP_MAX_JIDLEN];
981 
982  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
983  !(presence = iks_make_pres(level, NULL)) || !(x = iks_new("x"))) {
984  res = -1;
985  goto done;
986  }
987 
988  if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
989  snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
990  snprintf(roomid, sizeof(roomid), "%s/%s", room, nick);
991  } else {
992  snprintf(from, sizeof(from), "%s", client->jid->full);
993  snprintf(roomid, sizeof(roomid), "%s/%s", room, S_OR(nick, client->jid->user));
994  }
995 
996  iks_insert_attrib(presence, "to", roomid);
997  iks_insert_attrib(presence, "from", from);
998  iks_insert_attrib(x, "xmlns", "http://jabber.org/protocol/muc");
999  iks_insert_node(presence, x);
1000 
1001  res = ast_xmpp_client_send(client, presence);
1002 
1003 done:
1004  iks_delete(x);
1005  iks_delete(presence);
1006 
1007  return res;
1008 }
1009 
1010 int ast_xmpp_chatroom_join(struct ast_xmpp_client *client, const char *room, const char *nickname)
1011 {
1012  return xmpp_client_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nickname);
1013 }
1014 
1015 int ast_xmpp_chatroom_send(struct ast_xmpp_client *client, const char *nickname, const char *address, const char *message)
1016 {
1017  return xmpp_client_send_message(client, 1, nickname, address, message);
1018 }
1019 
1020 int ast_xmpp_chatroom_leave(struct ast_xmpp_client *client, const char *room, const char *nickname)
1021 {
1022  return xmpp_client_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nickname);
1023 }
1024 
1025 void ast_xmpp_increment_mid(char *mid)
1026 {
1027  int i = 0;
1028 
1029  for (i = strlen(mid) - 1; i >= 0; i--) {
1030  if (mid[i] != 'z') {
1031  mid[i] = mid[i] + 1;
1032  i = 0;
1033  } else {
1034  mid[i] = 'a';
1035  }
1036  }
1037 }
1038 
1039 /*!
1040  * \brief Create an IQ packet
1041  * \param client the configured XMPP client we use to connect to a XMPP server
1042  * \param type the type of IQ packet to create
1043  * \return iks *
1044  */
1045 static iks* xmpp_pubsub_iq_create(struct ast_xmpp_client *client, const char *type)
1046 {
1047  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1048  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1049  iks *request;
1050 
1051  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
1052  !(request = iks_new("iq"))) {
1053  return NULL;
1054  }
1055 
1056  if (!ast_strlen_zero(clientcfg->pubsubnode)) {
1057  iks_insert_attrib(request, "to", clientcfg->pubsubnode);
1058  }
1059 
1060  iks_insert_attrib(request, "from", client->jid->full);
1061  iks_insert_attrib(request, "type", type);
1062  ast_xmpp_client_lock(client);
1063  ast_xmpp_increment_mid(client->mid);
1064  iks_insert_attrib(request, "id", client->mid);
1065  ast_xmpp_client_unlock(client);
1066 
1067  return request;
1068 }
1069 
1070 /*!
1071  * \brief Build the skeleton of a publish
1072  * \param client the configured XMPP client we use to connect to a XMPP server
1073  * \param node Name of the node that will be published to
1074  * \param event_type, cachable
1075  * \return iks *
1076  */
1077 static iks* xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, const char *node,
1078  const char *event_type, unsigned int cachable)
1079 {
1080  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1081  iks *request, *pubsub, *publish, *item;
1082 
1083  if (!cfg || !cfg->global || !(request = xmpp_pubsub_iq_create(client, "set"))) {
1084  return NULL;
1085  }
1086 
1087  pubsub = iks_insert(request, "pubsub");
1088  iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1089  publish = iks_insert(pubsub, "publish");
1090  iks_insert_attrib(publish, "node", ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248) ? node : event_type);
1091  item = iks_insert(publish, "item");
1092  iks_insert_attrib(item, "id", node);
1093 
1094  if (cachable == AST_DEVSTATE_NOT_CACHABLE) {
1095  iks *options, *x, *field_form_type, *field_persist;
1096 
1097  options = iks_insert(pubsub, "publish-options");
1098  x = iks_insert(options, "x");
1099  iks_insert_attrib(x, "xmlns", "jabber:x:data");
1100  iks_insert_attrib(x, "type", "submit");
1101  field_form_type = iks_insert(x, "field");
1102  iks_insert_attrib(field_form_type, "var", "FORM_TYPE");
1103  iks_insert_attrib(field_form_type, "type", "hidden");
1104  iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0);
1105  field_persist = iks_insert(x, "field");
1106  iks_insert_attrib(field_persist, "var", "pubsub#persist_items");
1107  iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1);
1108  }
1109 
1110  return item;
1111 
1112 }
1113 
1114 static iks* xmpp_pubsub_build_node_config(iks *pubsub, const char *node_type, const char *collection_name)
1115 {
1116  iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
1117  *field_deliver_payload, *field_persist_items, *field_access_model,
1118  *field_pubsub_collection;
1119  configure = iks_insert(pubsub, "configure");
1120  x = iks_insert(configure, "x");
1121  iks_insert_attrib(x, "xmlns", "jabber:x:data");
1122  iks_insert_attrib(x, "type", "submit");
1123  field_owner = iks_insert(x, "field");
1124  iks_insert_attrib(field_owner, "var", "FORM_TYPE");
1125  iks_insert_attrib(field_owner, "type", "hidden");
1126  iks_insert_cdata(iks_insert(field_owner, "value"),
1127  "http://jabber.org/protocol/pubsub#owner", 39);
1128  if (node_type) {
1129  field_node_type = iks_insert(x, "field");
1130  iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
1131  iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
1132  }
1133  field_node_config = iks_insert(x, "field");
1134  iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
1135  iks_insert_attrib(field_node_config, "type", "hidden");
1136  iks_insert_cdata(iks_insert(field_node_config, "value"),
1137  "http://jabber.org/protocol/pubsub#node_config", 45);
1138  field_deliver_payload = iks_insert(x, "field");
1139  iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
1140  iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
1141  field_persist_items = iks_insert(x, "field");
1142  iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
1143  iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
1144  field_access_model = iks_insert(x, "field");
1145  iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
1146  iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
1147  if (node_type && !strcasecmp(node_type, "leaf")) {
1148  field_pubsub_collection = iks_insert(x, "field");
1149  iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
1150  iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
1151  strlen(collection_name));
1152  }
1153  return configure;
1154 }
1155 
1156 /*!
1157  * \brief Add Owner affiliations for pubsub node
1158  * \param client the configured XMPP client we use to connect to a XMPP server
1159  * \param node the name of the node to which to add affiliations
1160  */
1161 static void xmpp_pubsub_create_affiliations(struct ast_xmpp_client *client, const char *node)
1162 {
1163  iks *modify_affiliates = xmpp_pubsub_iq_create(client, "set");
1164  iks *pubsub, *affiliations, *affiliate;
1165  struct ao2_iterator i;
1166  struct ast_xmpp_buddy *buddy;
1167 
1168  if (!modify_affiliates) {
1169  ast_log(LOG_ERROR, "Could not create IQ for creating affiliations on client '%s'\n", client->name);
1170  return;
1171  }
1172 
1173  pubsub = iks_insert(modify_affiliates, "pubsub");
1174  iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
1175  affiliations = iks_insert(pubsub, "affiliations");
1176  iks_insert_attrib(affiliations, "node", node);
1177 
1178  i = ao2_iterator_init(client->buddies, 0);
1179  while ((buddy = ao2_iterator_next(&i))) {
1180  affiliate = iks_insert(affiliations, "affiliation");
1181  iks_insert_attrib(affiliate, "jid", buddy->id);
1182  iks_insert_attrib(affiliate, "affiliation", "owner");
1183  ao2_ref(buddy, -1);
1184  }
1186 
1187  ast_xmpp_client_send(client, modify_affiliates);
1188  iks_delete(modify_affiliates);
1189 }
1190 
1191 /*!
1192  * \brief Create a pubsub node
1193  * \param client the configured XMPP client we use to connect to a XMPP server
1194  * \param node_type the type of node to create
1195  * \param name the name of the node to create
1196  * \param collection_name
1197  */
1198 static void xmpp_pubsub_create_node(struct ast_xmpp_client *client, const char *node_type, const
1199  char *name, const char *collection_name)
1200 {
1201  iks *node, *pubsub, *create;
1202 
1203  if (!(node = xmpp_pubsub_iq_create(client, "set"))) {
1204  return;
1205  }
1206 
1207  pubsub = iks_insert(node, "pubsub");
1208  iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1209  create = iks_insert(pubsub, "create");
1210  iks_insert_attrib(create, "node", name);
1211  xmpp_pubsub_build_node_config(pubsub, node_type, collection_name);
1212  ast_xmpp_client_send(client, node);
1213  xmpp_pubsub_create_affiliations(client, name);
1214  iks_delete(node);
1215 }
1216 
1217 /*!
1218  * \brief Delete a PubSub node
1219  * \param client the configured XMPP client we use to connect to a XMPP server
1220  * \param node_name the name of the node to delete
1221  */
1222 static void xmpp_pubsub_delete_node(struct ast_xmpp_client *client, const char *node_name)
1223 {
1224  iks *request, *pubsub, *delete;
1225 
1226  if (!(request = xmpp_pubsub_iq_create(client, "set"))) {
1227  return;
1228  }
1229 
1230  pubsub = iks_insert(request, "pubsub");
1231  iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
1232  delete = iks_insert(pubsub, "delete");
1233  iks_insert_attrib(delete, "node", node_name);
1234  ast_xmpp_client_send(client, request);
1235 
1236  iks_delete(request);
1237 }
1238 
1239 /*!
1240  * \brief Create a PubSub collection node.
1241  * \param client the configured XMPP client we use to connect to a XMPP server
1242  * \param collection_name The name to use for this collection
1243  */
1244 static void xmpp_pubsub_create_collection(struct ast_xmpp_client *client, const char *collection_name)
1245 {
1246  xmpp_pubsub_create_node(client, "collection", collection_name, NULL);
1247 }
1248 
1249 
1250 /*!
1251  * \brief Create a PubSub leaf node.
1252  * \param client the configured XMPP client we use to connect to a XMPP server
1253  * \param collection_name
1254  * \param leaf_name The name to use for this collection
1255  */
1256 static void xmpp_pubsub_create_leaf(struct ast_xmpp_client *client, const char *collection_name,
1257  const char *leaf_name)
1258 {
1259  xmpp_pubsub_create_node(client, "leaf", leaf_name, collection_name);
1260 }
1261 
1262 /*!
1263  * \brief Publish MWI to a PubSub node
1264  * \param client the configured XMPP client we use to connect to a XMPP server
1265  * \param mailbox The mailbox identifier
1266  * \param oldmsgs Old messages
1267  * \param newmsgs New Messages
1268  */
1269 static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char *mailbox,
1270  const char *oldmsgs, const char *newmsgs)
1271 {
1272  char eid_str[20];
1273  iks *mailbox_node, *request;
1274 
1275  request = xmpp_pubsub_build_publish_skeleton(client, mailbox, "message_waiting",
1277  if (!request) {
1278  return;
1279  }
1280 
1281  ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
1282  mailbox_node = iks_insert(request, "mailbox");
1283  iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
1284  iks_insert_attrib(mailbox_node, "eid", eid_str);
1285  iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
1286  iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
1287 
1288  ast_xmpp_client_send(client, iks_root(request));
1289 
1290  iks_delete(request);
1291 }
1292 
1293 /*!
1294  * \brief Publish device state to a PubSub node
1295  * \param client the configured XMPP client we use to connect to a XMPP server
1296  * \param device the name of the device whose state to publish
1297  * \param device_state the state to publish
1298  * \param cachable
1299  */
1300 static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, const char *device,
1301  const char *device_state, unsigned int cachable)
1302 {
1303  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1304  iks *request, *state;
1305  char eid_str[20], cachable_str[2];
1306 
1307  if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state", cachable))) {
1308  return;
1309  }
1310 
1311  if (ast_test_flag(&cfg->global->pubsub, XMPP_PUBSUB_AUTOCREATE)) {
1312  if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1313  xmpp_pubsub_create_node(client, "leaf", device, "device_state");
1314  } else {
1315  xmpp_pubsub_create_node(client, NULL, device, NULL);
1316  }
1317  }
1318 
1319  ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
1320  state = iks_insert(request, "state");
1321  iks_insert_attrib(state, "xmlns", "http://asterisk.org");
1322  iks_insert_attrib(state, "eid", eid_str);
1323  snprintf(cachable_str, sizeof(cachable_str), "%u", cachable);
1324  iks_insert_attrib(state, "cachable", cachable_str);
1325  iks_insert_cdata(state, device_state, strlen(device_state));
1326  ast_xmpp_client_send(client, iks_root(request));
1327  iks_delete(request);
1328 }
1329 
1330 /*!
1331  * \brief Callback function for MWI events
1332  * \param data void pointer to ast_client structure
1333  * \param sub, msg
1334  */
1335 static void xmpp_pubsub_mwi_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
1336 {
1337  struct ast_xmpp_client *client = data;
1338  char oldmsgs[10], newmsgs[10];
1339  struct ast_mwi_state *mwi_state;
1340 
1342  return;
1343  }
1344 
1345  mwi_state = stasis_message_data(msg);
1346 
1347  if (ast_eid_cmp(&ast_eid_default, &mwi_state->eid)) {
1348  /* If the event didn't originate from this server, don't send it back out. */
1349  return;
1350  }
1351 
1352  snprintf(oldmsgs, sizeof(oldmsgs), "%d", mwi_state->old_msgs);
1353  snprintf(newmsgs, sizeof(newmsgs), "%d", mwi_state->new_msgs);
1354  xmpp_pubsub_publish_mwi(client, mwi_state->uniqueid, oldmsgs, newmsgs);
1355 }
1356 
1357 /*!
1358  * \brief Callback function for device state events
1359  * \param data void pointer to ast_client structure
1360  * \param sub, msg
1361  */
1362 static void xmpp_pubsub_devstate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
1363 {
1364  struct ast_xmpp_client *client = data;
1365  struct ast_device_state_message *dev_state;
1366 
1368  return;
1369  }
1370 
1371  dev_state = stasis_message_data(msg);
1372  if (!dev_state->eid || ast_eid_cmp(&ast_eid_default, dev_state->eid)) {
1373  /* If the event is aggregate or didn't originate from this server, don't send it out. */
1374  return;
1375  }
1376 
1377  xmpp_pubsub_publish_device_state(client, dev_state->device, ast_devstate_str(dev_state->state), dev_state->cachable);
1378 }
1379 
1380 /*!
1381  * \brief Unsubscribe from a PubSub node
1382  * \param client the configured XMPP client we use to connect to a XMPP server
1383  * \param node the name of the node to which to unsubscribe from
1384  */
1385 static void xmpp_pubsub_unsubscribe(struct ast_xmpp_client *client, const char *node)
1386 {
1387  iks *request = xmpp_pubsub_iq_create(client, "set");
1388  iks *pubsub, *unsubscribe;
1389 
1390  if (!request) {
1391  ast_log(LOG_ERROR, "Could not create IQ when creating pubsub unsubscription on client '%s'\n", client->name);
1392  return;
1393  }
1394 
1395  pubsub = iks_insert(request, "pubsub");
1396  iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1397  unsubscribe = iks_insert(pubsub, "unsubscribe");
1398  iks_insert_attrib(unsubscribe, "jid", client->jid->partial);
1399  iks_insert_attrib(unsubscribe, "node", node);
1400 
1401  ast_xmpp_client_send(client, request);
1402  iks_delete(request);
1403 }
1404 
1405 /*!
1406  * \brief Subscribe to a PubSub node
1407  * \param client the configured XMPP client we use to connect to a XMPP server
1408  * \param node the name of the node to which to subscribe
1409  */
1410 static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *node)
1411 {
1412  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1413  iks *request = xmpp_pubsub_iq_create(client, "set");
1414  iks *pubsub, *subscribe;
1415 
1416  if (!cfg || !cfg->global || !request) {
1417  ast_log(LOG_ERROR, "Could not create IQ when creating pubsub subscription on client '%s'\n", client->name);
1418  return;
1419  }
1420 
1421  pubsub = iks_insert(request, "pubsub");
1422  iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
1423  subscribe = iks_insert(pubsub, "subscribe");
1424  iks_insert_attrib(subscribe, "jid", client->jid->partial);
1425  iks_insert_attrib(subscribe, "node", node);
1426  if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1427  iks *options, *x, *sub_options, *sub_type, *sub_depth, *sub_expire;
1428  options = iks_insert(pubsub, "options");
1429  x = iks_insert(options, "x");
1430  iks_insert_attrib(x, "xmlns", "jabber:x:data");
1431  iks_insert_attrib(x, "type", "submit");
1432  sub_options = iks_insert(x, "field");
1433  iks_insert_attrib(sub_options, "var", "FORM_TYPE");
1434  iks_insert_attrib(sub_options, "type", "hidden");
1435  iks_insert_cdata(iks_insert(sub_options, "value"),
1436  "http://jabber.org/protocol/pubsub#subscribe_options", 51);
1437  sub_type = iks_insert(x, "field");
1438  iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
1439  iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
1440  sub_depth = iks_insert(x, "field");
1441  iks_insert_attrib(sub_depth, "var", "pubsub#subscription_depth");
1442  iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
1443  sub_expire = iks_insert(x, "field");
1444  iks_insert_attrib(sub_expire, "var", "pubsub#expire");
1445  iks_insert_cdata(iks_insert(sub_expire, "value"), "presence", 8);
1446  }
1447  ast_xmpp_client_send(client, request);
1448  iks_delete(request);
1449 }
1450 
1451 /*!
1452  * \brief Callback for handling PubSub events
1453  * \param data void pointer to ast_xmpp_client structure
1454  * \param pak A pak
1455  * \retval IKS_FILTER_EAT
1456  */
1457 static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
1458 {
1459  char *item_id, *device_state, *mailbox, *cachable_str;
1460  int oldmsgs, newmsgs;
1461  iks *item, *item_content;
1462  struct ast_eid pubsub_eid;
1463  unsigned int cachable = AST_DEVSTATE_CACHABLE;
1464  item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
1465  if (!item) {
1466  ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
1467  return IKS_FILTER_EAT;
1468  }
1469  item_id = iks_find_attrib(item, "id");
1470  item_content = iks_child(item);
1471  ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
1472  if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
1473  ast_debug(1, "Returning here, eid of incoming event matches ours!\n");
1474  return IKS_FILTER_EAT;
1475  }
1476  if (!strcasecmp(iks_name(item_content), "state")) {
1477  if ((cachable_str = iks_find_attrib(item_content, "cachable"))) {
1478  sscanf(cachable_str, "%30u", &cachable);
1479  }
1480  device_state = iks_find_cdata(item, "state");
1482  ast_devstate_val(device_state),
1484  &pubsub_eid);
1485  return IKS_FILTER_EAT;
1486  } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
1487  mailbox = strsep(&item_id, "@");
1488  sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
1489  sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
1490 
1491  ast_publish_mwi_state_full(mailbox, item_id, newmsgs, oldmsgs, NULL, &pubsub_eid);
1492 
1493  return IKS_FILTER_EAT;
1494  } else {
1495  ast_debug(1, "Don't know how to handle PubSub event of type %s\n",
1496  iks_name(item_content));
1497  return IKS_FILTER_EAT;
1498  }
1499 
1500  return IKS_FILTER_EAT;
1501 }
1502 
1503 static int xmpp_pubsub_handle_error(void *data, ikspak *pak)
1504 {
1505  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1506  char *node_name, *error;
1507  int error_num;
1508  iks *orig_request, *orig_pubsub = iks_find(pak->x, "pubsub");
1509  struct ast_xmpp_client *client = data;
1510 
1511  if (!cfg || !cfg->global) {
1512  ast_log(LOG_ERROR, "No global configuration available\n");
1513  return IKS_FILTER_EAT;
1514  }
1515 
1516  if (!orig_pubsub) {
1517  ast_debug(1, "Error isn't a PubSub error, why are we here?\n");
1518  return IKS_FILTER_EAT;
1519  }
1520 
1521  orig_request = iks_child(orig_pubsub);
1522  error = iks_find_attrib(iks_find(pak->x, "error"), "code");
1523  node_name = iks_find_attrib(orig_request, "node");
1524 
1525  if (!sscanf(error, "%30d", &error_num)) {
1526  return IKS_FILTER_EAT;
1527  }
1528 
1529  if (error_num > 399 && error_num < 500 && error_num != 404) {
1530  ast_log(LOG_ERROR,
1531  "Error performing operation on PubSub node %s, %s.\n", node_name, error);
1532  return IKS_FILTER_EAT;
1533  } else if (error_num > 499 && error_num < 600) {
1534  ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
1535  return IKS_FILTER_EAT;
1536  }
1537 
1538  if (!strcasecmp(iks_name(orig_request), "publish")) {
1539  iks *request;
1540 
1541  if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1542  if (iks_find(iks_find(orig_request, "item"), "state")) {
1543  xmpp_pubsub_create_leaf(client, "device_state", node_name);
1544  } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
1545  xmpp_pubsub_create_leaf(client, "message_waiting", node_name);
1546  }
1547  } else {
1548  xmpp_pubsub_create_node(client, NULL, node_name, NULL);
1549  }
1550 
1551  if ((request = xmpp_pubsub_iq_create(client, "set"))) {
1552  iks_insert_node(request, orig_pubsub);
1553  ast_xmpp_client_send(client, request);
1554  iks_delete(request);
1555  } else {
1556  ast_log(LOG_ERROR, "PubSub publish could not create IQ\n");
1557  }
1558 
1559  return IKS_FILTER_EAT;
1560  } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
1561  if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
1562  xmpp_pubsub_create_collection(client, node_name);
1563  } else {
1564  xmpp_pubsub_create_node(client, NULL, node_name, NULL);
1565  }
1566  }
1567 
1568  return IKS_FILTER_EAT;
1569 }
1570 
1571 static int cached_devstate_cb(void *obj, void *arg, int flags)
1572 {
1573  struct stasis_message *msg = obj;
1574  struct ast_xmpp_client *client = arg;
1575  xmpp_pubsub_devstate_cb(client, client->device_state_sub, msg);
1576  return 0;
1577 }
1578 
1579 /*!
1580  * \brief Initialize collections for event distribution
1581  * \param client the configured XMPP client we use to connect to a XMPP server
1582  */
1584 {
1585  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1586  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1587  RAII_VAR(struct ao2_container *, cached, NULL, ao2_cleanup);
1588 
1589  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
1590  return;
1591  }
1592 
1593  xmpp_pubsub_unsubscribe(client, "device_state");
1594  xmpp_pubsub_unsubscribe(client, "message_waiting");
1595 
1596  if (!(client->mwi_sub = stasis_subscribe_pool(ast_mwi_topic_all(), xmpp_pubsub_mwi_cb, client))) {
1597  return;
1598  }
1601 
1602  if (!(client->device_state_sub = stasis_subscribe(ast_device_state_topic_all(), xmpp_pubsub_devstate_cb, client))) {
1603  client->mwi_sub = stasis_unsubscribe(client->mwi_sub);
1604  return;
1605  }
1608 
1609  cached = stasis_cache_dump(ast_device_state_cache(), NULL);
1610  ao2_callback(cached, OBJ_NODATA, cached_devstate_cb, client);
1611 
1612  xmpp_pubsub_subscribe(client, "device_state");
1613  xmpp_pubsub_subscribe(client, "message_waiting");
1614  iks_filter_add_rule(client->filter, xmpp_pubsub_handle_event, client, IKS_RULE_TYPE,
1615  IKS_PAK_MESSAGE, IKS_RULE_FROM, clientcfg->pubsubnode, IKS_RULE_DONE);
1616  iks_filter_add_rule(client->filter, xmpp_pubsub_handle_error, client, IKS_RULE_TYPE,
1617  IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
1618 
1619 }
1620 
1621 /*! \brief Internal astobj2 callback function which returns the first resource, which is the highest priority one */
1622 static int xmpp_resource_immediate(void *obj, void *arg, int flags)
1623 {
1624  return CMP_MATCH | CMP_STOP;
1625 }
1626 
1627 #define BUDDY_OFFLINE 6
1628 #define BUDDY_NOT_IN_ROSTER 7
1629 
1630 static int get_buddy_status(struct ast_xmpp_client_config *clientcfg, char *screenname, char *resource)
1631 {
1632  int status = BUDDY_OFFLINE;
1633  struct ast_xmpp_resource *res;
1634  struct ast_xmpp_buddy *buddy = ao2_find(clientcfg->client->buddies, screenname, OBJ_KEY);
1635 
1636  if (!buddy) {
1637  return BUDDY_NOT_IN_ROSTER;
1638  }
1639 
1640  res = ao2_callback(
1641  buddy->resources,
1642  0,
1643  ast_strlen_zero(resource) ? xmpp_resource_immediate : xmpp_resource_cmp,
1644  resource);
1645 
1646  if (res) {
1647  status = res->status;
1648  }
1649 
1650  ao2_cleanup(res);
1651  ao2_cleanup(buddy);
1652 
1653  return status;
1654 }
1655 
1656 /*!
1657  * \internal
1658  * \brief Dial plan funtcion to retrieve the status of a buddy.
1659  * \param chan The associated ast_channel, if there is one
1660  * \param data The account, buddy JID, and optional timeout
1661  * \param name, buf, buflen
1662  *
1663  * \retval 0 success
1664  * \retval -1 failure
1665  */
1666 static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
1667 {
1668  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1669  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1670  AST_DECLARE_APP_ARGS(args,
1671  AST_APP_ARG(sender);
1672  AST_APP_ARG(jid);
1673  );
1675  AST_APP_ARG(screenname);
1676  AST_APP_ARG(resource);
1677  );
1678 
1679  if (ast_strlen_zero(data)) {
1680  ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
1681  return 0;
1682  }
1683  AST_STANDARD_APP_ARGS(args, data);
1684 
1685  if (args.argc != 2) {
1686  ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
1687  return -1;
1688  }
1689 
1690  AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
1691  if (jid.argc < 1 || jid.argc > 2) {
1692  ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
1693  return -1;
1694  }
1695 
1696  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1697  ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1698  return -1;
1699  }
1700 
1701  snprintf(buf, buflen, "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource));
1702 
1703  return 0;
1704 }
1705 
1706 static struct ast_custom_function jabberstatus_function = {
1707  .name = "JABBER_STATUS",
1708  .read = acf_jabberstatus_read,
1709 };
1710 
1711 /*!
1712  * \brief Application to join a chat room
1713  * \param chan ast_channel
1714  * \param data Data is sender|jid|nickname.
1715  * \retval 0 success
1716  * \retval -1 error
1717  */
1718 static int xmpp_join_exec(struct ast_channel *chan, const char *data)
1719 {
1720  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1721  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1722  char *s, nick[XMPP_MAX_RESJIDLEN];
1723  AST_DECLARE_APP_ARGS(args,
1724  AST_APP_ARG(sender);
1725  AST_APP_ARG(jid);
1726  AST_APP_ARG(nick);
1727  );
1728 
1729  if (ast_strlen_zero(data)) {
1730  ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1731  return -1;
1732  }
1733  s = ast_strdupa(data);
1734 
1735  AST_STANDARD_APP_ARGS(args, s);
1736  if (args.argc < 2 || args.argc > 3) {
1737  ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1738  return -1;
1739  }
1740 
1741  if (strchr(args.jid, '/')) {
1742  ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
1743  return -1;
1744  }
1745 
1746  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1747  ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1748  return -1;
1749  }
1750 
1751  if (ast_strlen_zero(args.nick)) {
1752  if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1753  snprintf(nick, sizeof(nick), "asterisk");
1754  } else {
1755  snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1756  }
1757  } else {
1758  snprintf(nick, sizeof(nick), "%s", args.nick);
1759  }
1760 
1761  if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
1762  ast_xmpp_chatroom_join(clientcfg->client, args.jid, nick);
1763  } else {
1764  ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
1765  }
1766 
1767  return 0;
1768 }
1769 
1770 /*!
1771  * \brief Application to leave a chat room
1772  * \param chan ast_channel
1773  * \param data Data is sender|jid|nickname.
1774  * \retval 0 success
1775  * \retval -1 error
1776  */
1777 static int xmpp_leave_exec(struct ast_channel *chan, const char *data)
1778 {
1779  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1780  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1781  char *s, nick[XMPP_MAX_RESJIDLEN];
1782  AST_DECLARE_APP_ARGS(args,
1783  AST_APP_ARG(sender);
1784  AST_APP_ARG(jid);
1785  AST_APP_ARG(nick);
1786  );
1787 
1788  if (ast_strlen_zero(data)) {
1789  ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1790  return -1;
1791  }
1792  s = ast_strdupa(data);
1793 
1794  AST_STANDARD_APP_ARGS(args, s);
1795  if (args.argc < 2 || args.argc > 3) {
1796  ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1797  return -1;
1798  }
1799 
1800  if (strchr(args.jid, '/')) {
1801  ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
1802  return -1;
1803  }
1804 
1805  if (ast_strlen_zero(args.jid) || !strchr(args.jid, '@')) {
1806  ast_log(LOG_ERROR, "No jabber ID specified\n");
1807  return -1;
1808  }
1809 
1810  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1811  ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1812  return -1;
1813  }
1814 
1815  if (ast_strlen_zero(args.nick)) {
1816  if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1817  snprintf(nick, sizeof(nick), "asterisk");
1818  } else {
1819  snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1820  }
1821  } else {
1822  snprintf(nick, sizeof(nick), "%s", args.nick);
1823  }
1824 
1825  ast_xmpp_chatroom_leave(clientcfg->client, args.jid, nick);
1826 
1827  return 0;
1828 }
1829 
1830 /*!
1831  * \internal
1832  * \brief Dial plan function to send a message.
1833  * \param chan ast_channel
1834  * \param data Data is account,jid,message.
1835  * \retval 0 success
1836  * \retval -1 failure
1837  */
1838 static int xmpp_send_exec(struct ast_channel *chan, const char *data)
1839 {
1840  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1841  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1842  char *s;
1843  AST_DECLARE_APP_ARGS(args,
1844  AST_APP_ARG(sender);
1845  AST_APP_ARG(recipient);
1847  );
1848 
1849  if (ast_strlen_zero(data)) {
1850  ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1851  return -1;
1852  }
1853  s = ast_strdupa(data);
1854 
1855  AST_STANDARD_APP_ARGS(args, s);
1856 
1857  if ((args.argc < 3) || ast_strlen_zero(args.message) || !strchr(args.recipient, '@')) {
1858  ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1859  return -1;
1860  }
1861 
1862  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1863  ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1864  return -1;
1865  }
1866 
1867  ast_xmpp_client_send_message(clientcfg->client, args.recipient, args.message);
1868 
1869  return 0;
1870 }
1871 
1872 /*!
1873  * \brief Application to send a message to a groupchat.
1874  * \param chan ast_channel
1875  * \param data Data is sender|groupchat|message.
1876  * \retval 0 success
1877  * \retval -1 error
1878  */
1879 static int xmpp_sendgroup_exec(struct ast_channel *chan, const char *data)
1880 {
1881  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1882  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1883  char *s, nick[XMPP_MAX_RESJIDLEN];
1884  AST_DECLARE_APP_ARGS(args,
1885  AST_APP_ARG(sender);
1886  AST_APP_ARG(groupchat);
1888  AST_APP_ARG(nick);
1889  );
1890 
1891  if (ast_strlen_zero(data)) {
1892  ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1893  return -1;
1894  }
1895  s = ast_strdupa(data);
1896 
1897  AST_STANDARD_APP_ARGS(args, s);
1898  if ((args.argc < 3) || (args.argc > 4) || ast_strlen_zero(args.message) || !strchr(args.groupchat, '@')) {
1899  ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1900  return -1;
1901  }
1902 
1903  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
1904  ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1905  return -1;
1906  }
1907 
1908  if (ast_strlen_zero(args.nick) || args.argc == 3) {
1909  if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
1910  snprintf(nick, sizeof(nick), "asterisk");
1911  } else {
1912  snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
1913  }
1914  } else {
1915  snprintf(nick, sizeof(nick), "%s", args.nick);
1916  }
1917 
1918  ast_xmpp_chatroom_send(clientcfg->client, nick, args.groupchat, args.message);
1919 
1920  return 0;
1921 }
1922 
1923 /*!
1924  * \internal
1925  * \brief Dial plan function to receive a message.
1926  * \param chan The associated ast_channel, if there is one
1927  * \param data The account, JID, and optional timeout
1928  * \param name, buf, buflen
1929  *
1930  * \retval 0 success
1931  * \retval -1 failure
1932  */
1933 static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
1934 {
1935  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1936  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
1937  char *parse = NULL;
1938  int timeout, jidlen, resourcelen, found = 0;
1939  struct timeval start;
1940  long diff = 0;
1941  struct ast_xmpp_message *message;
1942  AST_DECLARE_APP_ARGS(args,
1943  AST_APP_ARG(account);
1944  AST_APP_ARG(jid);
1945  AST_APP_ARG(timeout);
1946  );
1948  AST_APP_ARG(screenname);
1949  AST_APP_ARG(resource);
1950  );
1951 
1952  if (ast_strlen_zero(data)) {
1953  ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
1954  return -1;
1955  }
1956 
1957  parse = ast_strdupa(data);
1958  AST_STANDARD_APP_ARGS(args, parse);
1959 
1960  if (args.argc < 2 || args.argc > 3) {
1961  ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
1962  return -1;
1963  }
1964 
1965  parse = ast_strdupa(args.jid);
1966  AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
1967  if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > XMPP_MAX_JIDLEN) {
1968  ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
1969  return -1;
1970  }
1971 
1972  if (ast_strlen_zero(args.timeout)) {
1973  timeout = 20;
1974  } else {
1975  sscanf(args.timeout, "%d", &timeout);
1976  if (timeout <= 0) {
1977  ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
1978  return -1;
1979  }
1980  }
1981 
1982  jidlen = strlen(jid.screenname);
1983  resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
1984 
1985  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.account))) {
1986  ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
1987  return -1;
1988  }
1989 
1990  ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
1991 
1992  start = ast_tvnow();
1993 
1994  if (chan && ast_autoservice_start(chan) < 0) {
1995  ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", ast_channel_name(chan));
1996  return -1;
1997  }
1998 
1999  /* search the messages list, grab the first message that matches with
2000  * the from JID we're expecting, and remove it from the messages list */
2001  while (diff < timeout) {
2002  struct timespec ts = { 0, };
2003  struct timeval wait;
2004  int res = 0;
2005 
2006  wait = ast_tvadd(start, ast_tv(timeout, 0));
2007  ts.tv_sec = wait.tv_sec;
2008  ts.tv_nsec = wait.tv_usec * 1000;
2009 
2010  /* wait up to timeout seconds for an incoming message */
2011  ast_mutex_lock(&messagelock);
2012  if (AST_LIST_EMPTY(&clientcfg->client->messages)) {
2013  res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
2014  }
2015  ast_mutex_unlock(&messagelock);
2016  if (res == ETIMEDOUT) {
2017  ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
2018  break;
2019  }
2020 
2021  AST_LIST_LOCK(&clientcfg->client->messages);
2022  AST_LIST_TRAVERSE_SAFE_BEGIN(&clientcfg->client->messages, message, list) {
2023  if (jid.argc == 1) {
2024  /* no resource provided, compare bare JIDs */
2025  if (strncasecmp(jid.screenname, message->from, jidlen)) {
2026  continue;
2027  }
2028  } else {
2029  /* resource appended, compare bare JIDs and resources */
2030  char *resource = strchr(message->from, '/');
2031  if (!resource || strlen(resource) == 0) {
2032  ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", message->from);
2033  if (strncasecmp(jid.screenname, message->from, jidlen)) {
2034  continue;
2035  }
2036  } else {
2037  resource ++;
2038  if (strncasecmp(jid.screenname, message->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
2039  continue;
2040  }
2041  }
2042  }
2043  /* check if the message is not too old */
2044  if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
2045  ast_debug(3, "Found old message from %s, deleting it\n", message->from);
2047  xmpp_message_destroy(message);
2048  continue;
2049  }
2050  found = 1;
2051  ast_copy_string(buf, message->message, buflen);
2053  xmpp_message_destroy(message);
2054  break;
2055  }
2057  AST_LIST_UNLOCK(&clientcfg->client->messages);
2058  if (found) {
2059  break;
2060  }
2061 
2062  /* check timeout */
2063  diff = ast_tvdiff_ms(ast_tvnow(), start);
2064  }
2065 
2066  if (chan && ast_autoservice_stop(chan) < 0) {
2067  ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", ast_channel_name(chan));
2068  }
2069 
2070  /* return if we timed out */
2071  if (!found) {
2072  ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
2073  return -1;
2074  }
2075 
2076  return 0;
2077 }
2078 
2079 static struct ast_custom_function jabberreceive_function = {
2080  .name = "JABBER_RECEIVE",
2081  .read = acf_jabberreceive_read,
2082 };
2083 
2084 /*!
2085  * \internal
2086  * \brief Delete old messages from a given JID
2087  * Messages stored during more than client->message_timeout are deleted
2088  * \param client Asterisk's XMPP client
2089  * \param from the JID we received messages from
2090  * \retval the number of deleted messages
2091  */
2092 static int delete_old_messages(struct ast_xmpp_client *client, char *from)
2093 {
2094  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2095  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2096  int deleted = 0, isold = 0;
2097  struct ast_xmpp_message *message = NULL;
2098 
2099  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2100  return 0;
2101  }
2102 
2103  AST_LIST_LOCK(&client->messages);
2104  AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, message, list) {
2105  if (isold) {
2106  if (!from || !strncasecmp(from, message->from, strlen(from))) {
2108  xmpp_message_destroy(message);
2109  deleted++;
2110  }
2111  } else if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
2112  isold = 1;
2113  if (!from || !strncasecmp(from, message->from, strlen(from))) {
2115  xmpp_message_destroy(message);
2116  deleted++;
2117  }
2118  }
2119  }
2121  AST_LIST_UNLOCK(&client->messages);
2122 
2123  return deleted;
2124 }
2125 
2126 static int xmpp_send_cb(const struct ast_msg *msg, const char *to, const char *from)
2127 {
2128  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2129  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2130  char *sender, *dest;
2131  int res;
2132 
2133  sender = ast_strdupa(from);
2134  strsep(&sender, ":");
2135  dest = ast_strdupa(to);
2136  strsep(&dest, ":");
2137 
2138  if (ast_strlen_zero(sender)) {
2139  ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for XMPP\n", from);
2140  return -1;
2141  }
2142 
2143  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, sender))) {
2144  ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
2145  return -1;
2146  }
2147 
2148  ast_debug(1, "Sending message to '%s' from '%s'\n", dest, clientcfg->name);
2149 
2150  if ((res = ast_xmpp_client_send_message(clientcfg->client, dest, ast_msg_get_body(msg))) != IKS_OK) {
2151  ast_log(LOG_WARNING, "Failed to send XMPP message (%d).\n", res);
2152  }
2153 
2154  return res == IKS_OK ? 0 : -1;
2155 }
2156 
2157 static const struct ast_msg_tech msg_tech = {
2158  .name = "xmpp",
2159  .msg_send = xmpp_send_cb,
2160 };
2161 
2162 /*! \brief Internal function which creates a buddy on a client */
2163 static struct ast_xmpp_buddy *xmpp_client_create_buddy(struct ao2_container *container, const char *id)
2164 {
2165  struct ast_xmpp_buddy *buddy;
2166 
2167  if (!(buddy = ao2_alloc(sizeof(*buddy), xmpp_buddy_destructor))) {
2168  return NULL;
2169  }
2170 
2173  if (!buddy->resources) {
2174  ao2_ref(buddy, -1);
2175  return NULL;
2176  }
2177 
2178  ast_copy_string(buddy->id, id, sizeof(buddy->id));
2179 
2180  /* Assume we need to subscribe to get their presence until proven otherwise */
2181  buddy->subscribe = 1;
2182 
2183  ao2_link(container, buddy);
2184 
2185  return buddy;
2186 }
2187 
2188 /*! \brief Helper function which unsubscribes a user and removes them from the roster */
2189 static int xmpp_client_unsubscribe_user(struct ast_xmpp_client *client, const char *user)
2190 {
2191  iks *iq, *query = NULL, *item = NULL;
2192 
2193  if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, user,
2194  "Goodbye. Your status is no longer required.\n"))) {
2195  return -1;
2196  }
2197 
2198  if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item"))) {
2199  ast_log(LOG_WARNING, "Could not allocate memory for roster removal of '%s' from client '%s'\n",
2200  user, client->name);
2201  goto done;
2202  }
2203 
2204  iks_insert_attrib(iq, "from", client->jid->full);
2205  iks_insert_attrib(iq, "type", "set");
2206  iks_insert_attrib(query, "xmlns", "jabber:iq:roster");
2207  iks_insert_node(iq, query);
2208  iks_insert_attrib(item, "jid", user);
2209  iks_insert_attrib(item, "subscription", "remove");
2210  iks_insert_node(query, item);
2211 
2212  if (ast_xmpp_client_send(client, iq)) {
2213  ast_log(LOG_WARNING, "Could not send roster removal request of '%s' from client '%s'\n",
2214  user, client->name);
2215  }
2216 
2217 done:
2218  iks_delete(item);
2219  iks_delete(query);
2220  iks_delete(iq);
2221 
2222  return 0;
2223 }
2224 
2225 /*! \brief Callback function which subscribes to a user if needed */
2226 static int xmpp_client_subscribe_user(void *obj, void *arg, int flags)
2227 {
2228  struct ast_xmpp_buddy *buddy = obj;
2229  struct ast_xmpp_client *client = arg;
2230 
2231  if (!buddy->subscribe) {
2232  return 0;
2233  }
2234 
2235  if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, buddy->id,
2236  "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"))) {
2237  ast_log(LOG_WARNING, "Could not send subscription for '%s' on client '%s'\n",
2238  buddy->id, client->name);
2239  }
2240 
2241  buddy->subscribe = 0;
2242 
2243  return 0;
2244 }
2245 
2246 /*! \brief Hook function called when roster is received from server */
2247 static int xmpp_roster_hook(void *data, ikspak *pak)
2248 {
2249  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2250  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2251  struct ast_xmpp_client *client = data;
2252  iks *item;
2253 
2254  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2255  return IKS_FILTER_EAT;
2256  }
2257 
2258  for (item = iks_child(pak->query); item; item = iks_next(item)) {
2259  struct ast_xmpp_buddy *buddy;
2260 
2261  if (iks_strcmp(iks_name(item), "item")) {
2262  continue;
2263  }
2264 
2265  if (!(buddy = ao2_find(client->buddies, iks_find_attrib(item, "jid"), OBJ_KEY))) {
2266  if (ast_test_flag(&clientcfg->flags, XMPP_AUTOPRUNE)) {
2267  /* The buddy has not been specified in the configuration file, we no longer
2268  * want them on our buddy list or to receive their presence. */
2269  if (xmpp_client_unsubscribe_user(client, iks_find_attrib(item, "jid"))) {
2270  ast_log(LOG_ERROR, "Could not unsubscribe user '%s' on client '%s'\n",
2271  iks_find_attrib(item, "jid"), client->name);
2272  }
2273  continue;
2274  }
2275 
2276  if (!(buddy = xmpp_client_create_buddy(client->buddies, iks_find_attrib(item, "jid")))) {
2277  ast_log(LOG_ERROR, "Could not allocate buddy '%s' on client '%s'\n", iks_find_attrib(item, "jid"),
2278  client->name);
2279  continue;
2280  }
2281  }
2282 
2283  /* Determine if we need to subscribe to their presence or not */
2284  if (!iks_strcmp(iks_find_attrib(item, "subscription"), "none") ||
2285  !iks_strcmp(iks_find_attrib(item, "subscription"), "from")) {
2286  buddy->subscribe = 1;
2287  } else {
2288  buddy->subscribe = 0;
2289  }
2290 
2291  ao2_ref(buddy, -1);
2292  }
2293 
2294  /* If autoregister is enabled we need to go through every buddy that we need to subscribe to and do so */
2295  if (ast_test_flag(&clientcfg->flags, XMPP_AUTOREGISTER)) {
2296  ao2_callback(client->buddies, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_subscribe_user, client);
2297  }
2298 
2300 
2301  return IKS_FILTER_EAT;
2302 }
2303 
2304 /*! \brief Internal function which changes the presence status of an XMPP client */
2305 static void xmpp_client_set_presence(struct ast_xmpp_client *client, const char *to, const char *from, int level, const char *desc)
2306 {
2307  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2308  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2309  iks *presence = NULL, *cnode = NULL, *priority = NULL;
2310  char priorityS[10];
2311 
2312  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2313  !(presence = iks_make_pres(level, desc)) || !(cnode = iks_new("c")) || !(priority = iks_new("priority"))) {
2314  ast_log(LOG_ERROR, "Unable to allocate stanzas for setting presence status for client '%s'\n", client->name);
2315  goto done;
2316  }
2317 
2318  if (!ast_strlen_zero(to)) {
2319  iks_insert_attrib(presence, "to", to);
2320  }
2321 
2322  if (!ast_strlen_zero(from)) {
2323  iks_insert_attrib(presence, "from", from);
2324  }
2325 
2326  snprintf(priorityS, sizeof(priorityS), "%d", clientcfg->priority);
2327  iks_insert_cdata(priority, priorityS, strlen(priorityS));
2328  iks_insert_node(presence, priority);
2329  iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
2330  iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
2331  iks_insert_attrib(cnode, "ext", "voice-v1 video-v1 camera-v1");
2332  iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
2333  iks_insert_node(presence, cnode);
2334  ast_xmpp_client_send(client, presence);
2335 
2336 done:
2337  iks_delete(cnode);
2338  iks_delete(presence);
2339  iks_delete(priority);
2340 }
2341 
2342 /*! \brief Hook function called when client receives a service discovery get message */
2343 static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak)
2344 {
2345  struct ast_xmpp_client *client = data;
2346  iks *iq, *disco = NULL, *ident = NULL, *google = NULL, *jingle = NULL, *ice = NULL, *rtp = NULL, *audio = NULL, *video = NULL, *query = NULL;
2347 
2348  if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(ident = iks_new("identity")) || !(disco = iks_new("feature")) ||
2349  !(google = iks_new("feature")) || !(jingle = iks_new("feature")) || !(ice = iks_new("feature")) || !(rtp = iks_new("feature")) ||
2350  !(audio = iks_new("feature")) || !(video = iks_new("feature"))) {
2351  ast_log(LOG_ERROR, "Could not allocate memory for responding to service discovery request from '%s' on client '%s'\n",
2352  pak->from->full, client->name);
2353  goto end;
2354  }
2355 
2356  iks_insert_attrib(iq, "from", client->jid->full);
2357 
2358  if (pak->from) {
2359  iks_insert_attrib(iq, "to", pak->from->full);
2360  }
2361 
2362  iks_insert_attrib(iq, "type", "result");
2363  iks_insert_attrib(iq, "id", pak->id);
2364  iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2365  iks_insert_attrib(ident, "category", "client");
2366  iks_insert_attrib(ident, "type", "pc");
2367  iks_insert_attrib(ident, "name", "asterisk");
2368  iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
2369 
2370  iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
2371  iks_insert_attrib(jingle, "var", "urn:xmpp:jingle:1");
2372  iks_insert_attrib(ice, "var", "urn:xmpp:jingle:transports:ice-udp:1");
2373  iks_insert_attrib(rtp, "var", "urn:xmpp:jingle:apps:rtp:1");
2374  iks_insert_attrib(audio, "var", "urn:xmpp:jingle:apps:rtp:audio");
2375  iks_insert_attrib(video, "var", "urn:xmpp:jingle:apps:rtp:video");
2376  iks_insert_node(iq, query);
2377  iks_insert_node(query, ident);
2378  iks_insert_node(query, google);
2379  iks_insert_node(query, disco);
2380  iks_insert_node(query, jingle);
2381  iks_insert_node(query, ice);
2382  iks_insert_node(query, rtp);
2383  iks_insert_node(query, audio);
2384  iks_insert_node(query, video);
2385  ast_xmpp_client_send(client, iq);
2386 
2387 end:
2388  iks_delete(query);
2389  iks_delete(video);
2390  iks_delete(audio);
2391  iks_delete(rtp);
2392  iks_delete(ice);
2393  iks_delete(jingle);
2394  iks_delete(google);
2395  iks_delete(ident);
2396  iks_delete(disco);
2397  iks_delete(iq);
2398 
2399  return IKS_FILTER_EAT;
2400 }
2401 
2402 /*! \brief Hook function called when client receives a service discovery result message */
2403 static int xmpp_client_service_discovery_result_hook(void *data, ikspak *pak)
2404 {
2405  struct ast_xmpp_client *client = data;
2406  struct ast_xmpp_buddy *buddy;
2407  struct ast_xmpp_resource *resource;
2408 
2409  if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
2410  return IKS_FILTER_EAT;
2411  }
2412 
2413  if (!(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, pak->from->resource))) {
2414  ao2_ref(buddy, -1);
2415  return IKS_FILTER_EAT;
2416  }
2417 
2418  ao2_lock(resource);
2419 
2420  if (iks_find_with_attrib(pak->query, "feature", "var", "urn:xmpp:jingle:1")) {
2421  resource->caps.jingle = 1;
2422  }
2423 
2424  ao2_unlock(resource);
2425 
2426  ao2_ref(resource, -1);
2427  ao2_ref(buddy, -1);
2428 
2429  return IKS_FILTER_EAT;
2430 }
2431 
2432 /*! \brief Hook function called when client finishes authenticating with the server */
2433 static int xmpp_connect_hook(void *data, ikspak *pak)
2434 {
2435  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2436  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2437  struct ast_xmpp_client *client = data;
2438  iks *roster;
2439 
2440  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
2441  return -1;
2442  }
2443 
2444  client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
2445 
2446  if (ast_test_flag(&clientcfg->flags, XMPP_DISTRIBUTE_EVENTS)) {
2448  }
2449 
2450  if (!(roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER))) {
2451  ast_log(LOG_ERROR, "Unable to allocate memory for roster request for client '%s'\n", client->name);
2452  return -1;
2453  }
2454 
2455  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);
2456  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);
2457 
2458  iks_insert_attrib(roster, "id", "roster");
2459  ast_xmpp_client_send(client, roster);
2460 
2461  iks_filter_remove_hook(client->filter, xmpp_connect_hook);
2462  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);
2463 
2464  xmpp_client_set_presence(client, NULL, client->jid->full, clientcfg->status, clientcfg->statusmsg);
2466 
2467  return IKS_FILTER_EAT;
2468 }
2469 
2470 /*! \brief Logging hook function */
2471 static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incoming)
2472 {
2473  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2474  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2475  struct ast_xmpp_client *client = data;
2476 
2477  if (!debug && (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) || !ast_test_flag(&clientcfg->flags, XMPP_DEBUG))) {
2478  return;
2479  }
2480 
2481  if (!incoming) {
2482  ast_verbose("\n<--- XMPP sent to '%s' --->\n%s\n<------------->\n", client->name, xmpp);
2483  } else {
2484  ast_verbose("\n<--- XMPP received from '%s' --->\n%s\n<------------->\n", client->name, xmpp);
2485  }
2486 }
2487 
2488 /*! \brief Internal function which sends a raw message */
2489 static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
2490 {
2491  int ret;
2492 
2493  if (client->state == XMPP_STATE_DISCONNECTED) {
2494  /* iks_send_raw will crash without a connection */
2495  return IKS_NET_NOCONN;
2496  }
2497 
2498 #ifdef HAVE_OPENSSL
2499  if (xmpp_is_secure(client)) {
2500  int len = strlen(message);
2501 
2502  ret = SSL_write(client->ssl_session, message, len);
2503  if (ret) {
2504  /* Log the message here, because iksemel's logHook is
2505  unaccessible */
2506  xmpp_log_hook(client, message, len, 0);
2507  return IKS_OK;
2508  }
2509  }
2510 #endif
2511  /* If needed, data will be sent unencrypted, and logHook will
2512  be called inside iks_send_raw */
2513  ret = iks_send_raw(client->parser, message);
2514  if (ret != IKS_OK) {
2515  return ret;
2516  }
2517 
2518  return IKS_OK;
2519 }
2520 
2521 /*! \brief Helper function which sends an XMPP stream header to the server */
2522 static int xmpp_send_stream_header(struct ast_xmpp_client *client, const struct ast_xmpp_client_config *cfg, const char *to)
2523 {
2524  char *namespace = ast_test_flag(&cfg->flags, XMPP_COMPONENT) ? "jabber:component:accept" : "jabber:client";
2525  char msg[91 + strlen(namespace) + 6 + strlen(to) + 16 + 1];
2526 
2527  snprintf(msg, sizeof(msg), "<?xml version='1.0'?>"
2528  "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
2529  "%s' to='%s' version='1.0'>", namespace, to);
2530 
2531  return xmpp_client_send_raw_message(client, msg);
2532 }
2533 
2534 int ast_xmpp_client_send(struct ast_xmpp_client *client, iks *stanza)
2535 {
2536  return xmpp_client_send_raw_message(client, iks_string(iks_stack(stanza), stanza));
2537 }
2538 
2539 /*! \brief Internal function called when we need to request TLS support */
2540 static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2541 {
2542  /* If the client connection is already secure we can jump straight to authenticating */
2543  if (xmpp_is_secure(client)) {
2545  return 0;
2546  }
2547 
2548 #ifndef HAVE_OPENSSL
2549  ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL is not available.\n", client->name);
2550  return -1;
2551 #else
2552  if (iks_send_raw(client->parser, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>") == IKS_NET_TLSFAIL) {
2553  ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be started.\n", client->name);
2554  return -1;
2555  }
2556 
2557  client->stream_flags |= TRY_SECURE;
2558 
2560 
2561  return 0;
2562 #endif
2563 }
2564 
2565 #ifdef HAVE_OPENSSL
2566 static char *openssl_error_string(void)
2567 {
2568  char *buf = NULL, *ret;
2569  size_t len;
2570  BIO *bio = BIO_new(BIO_s_mem());
2571 
2572  ERR_print_errors(bio);
2573  len = BIO_get_mem_data(bio, &buf);
2574  ret = ast_calloc(1, len + 1);
2575  if (ret) {
2576  memcpy(ret, buf, len);
2577  }
2578  BIO_free(bio);
2579  return ret;
2580 }
2581 #endif
2582 
2583 /*! \brief Internal function called when we receive a response to our TLS initiation request */
2584 static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2585 {
2586 #ifdef HAVE_OPENSSL
2587  int sock;
2588  long ssl_opts;
2589  char *err;
2590 #endif
2591 
2592  if (!strcmp(iks_name(node), "success")) {
2593  /* TLS is up and working, we can move on to authenticating now */
2595  return 0;
2596  } else if (!strcmp(iks_name(node), "failure")) {
2597  /* TLS negotiation was a failure, close it on down! */
2598  return -1;
2599  } else if (strcmp(iks_name(node), "proceed")) {
2600  /* Ignore any other responses */
2601  return 0;
2602  }
2603 
2604 #ifndef HAVE_OPENSSL
2605  ast_log(LOG_ERROR, "Somehow we managed to try to start TLS negotiation on client '%s' without OpenSSL support, disconnecting\n", client->name);
2606  return -1;
2607 #else
2608  client->ssl_method = SSLv23_method();
2609  if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
2610  goto failure;
2611  }
2612 
2613  ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
2614  SSL_CTX_set_options(client->ssl_context, ssl_opts);
2615 
2616  if (!(client->ssl_session = SSL_new(client->ssl_context))) {
2617  goto failure;
2618  }
2619 
2620  sock = iks_fd(client->parser);
2621  if (!SSL_set_fd(client->ssl_session, sock)) {
2622  goto failure;
2623  }
2624 
2625  if (SSL_connect(client->ssl_session) <= 0) {
2626  goto failure;
2627  }
2628 
2629  client->stream_flags &= (~TRY_SECURE);
2630  client->stream_flags |= SECURE;
2631 
2632  if (xmpp_send_stream_header(client, cfg, client->jid->server) != IKS_OK) {
2633  ast_log(LOG_ERROR, "TLS connection for client '%s' could not be established, failed to send stream header after negotiation\n",
2634  client->name);
2635  return -1;
2636  }
2637 
2638  ast_debug(1, "TLS connection for client '%s' started with server\n", client->name);
2639 
2641 
2642  return 0;
2643 
2644 failure:
2645  err = openssl_error_string();
2646  ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. "
2647  "OpenSSL initialization failed: %s\n", client->name, err);
2648  ast_free(err);
2649  return -1;
2650 #endif
2651 }
2652 
2653 /*! \brief Internal function called when we need to authenticate using non-SASL */
2654 static int xmpp_client_authenticate_digest(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2655 {
2656  iks *iq = NULL, *query = NULL;
2657  char buf[41], sidpass[100];
2658 
2659  if (!(iq = iks_new("iq")) || !(query = iks_insert(iq, "query"))) {
2660  ast_log(LOG_ERROR, "Stanzas could not be allocated for authentication on client '%s'\n", client->name);
2661  iks_delete(iq);
2662  return -1;
2663  }
2664 
2665  iks_insert_attrib(iq, "type", "set");
2666  iks_insert_cdata(iks_insert(query, "username"), client->jid->user, 0);
2667  iks_insert_cdata(iks_insert(query, "resource"), client->jid->resource, 0);
2668 
2669  iks_insert_attrib(query, "xmlns", "jabber:iq:auth");
2670  snprintf(sidpass, sizeof(sidpass), "%s%s", iks_find_attrib(node, "id"), cfg->password);
2671  ast_sha1_hash(buf, sidpass);
2672  iks_insert_cdata(iks_insert(query, "digest"), buf, 0);
2673 
2674  ast_xmpp_client_lock(client);
2675  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);
2676  iks_insert_attrib(iq, "id", client->mid);
2677  ast_xmpp_increment_mid(client->mid);
2678  ast_xmpp_client_unlock(client);
2679 
2680  iks_insert_attrib(iq, "to", client->jid->server);
2681 
2682  ast_xmpp_client_send(client, iq);
2683 
2684  iks_delete(iq);
2685 
2687 
2688  return 0;
2689 }
2690 
2691 /*! \brief Internal function called when we need to authenticate using SASL */
2692 static int xmpp_client_authenticate_sasl(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2693 {
2694  int features, len = strlen(client->jid->user) + strlen(cfg->password) + 3;
2695  iks *auth;
2696  char combined[len];
2697  char base64[(len + 2) * 4 / 3];
2698 
2699  if (strcmp(iks_name(node), "stream:features")) {
2700  /* Ignore anything beside stream features */
2701  return 0;
2702  }
2703 
2704  features = iks_stream_features(node);
2705 
2706  if ((features & IKS_STREAM_SASL_MD5) && !xmpp_is_secure(client)) {
2707  if (iks_start_sasl(client->parser, IKS_SASL_DIGEST_MD5, (char*)client->jid->user, (char*)cfg->password) != IKS_OK) {
2708  ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL DIGEST-MD5 but could not\n", client->name);
2709  return -1;
2710  }
2711 
2713  return 0;
2714  }
2715 
2716  /* Our only other available option is plain so if they don't support it, bail out now */
2717  if (!(features & IKS_STREAM_SASL_PLAIN)) {
2718  ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL PLAIN but server does not support it\n", client->name);
2719  return -1;
2720  }
2721 
2722  if (!(auth = iks_new("auth"))) {
2723  ast_log(LOG_ERROR, "Could not allocate memory for SASL PLAIN authentication for client '%s'\n", client->name);
2724  return -1;
2725  }
2726 
2727  iks_insert_attrib(auth, "xmlns", IKS_NS_XMPP_SASL);
2728  if (!ast_strlen_zero(cfg->refresh_token)) {
2729  iks_insert_attrib(auth, "mechanism", "X-OAUTH2");
2730  iks_insert_attrib(auth, "auth:service", "oauth2");
2731  iks_insert_attrib(auth, "xmlns:auth", "http://www.google.com/talk/protocol/auth");
2732  } else {
2733  iks_insert_attrib(auth, "mechanism", "PLAIN");
2734  }
2735 
2736  if (strchr(client->jid->user, '/')) {
2737  char *user = ast_strdupa(client->jid->user);
2738 
2739  snprintf(combined, sizeof(combined), "%c%s%c%s", 0, strsep(&user, "/"), 0, cfg->password);
2740  } else {
2741  snprintf(combined, sizeof(combined), "%c%s%c%s", 0, client->jid->user, 0, cfg->password);
2742  }
2743 
2744  ast_base64encode(base64, (const unsigned char *) combined, len - 1, (len + 2) * 4 / 3);
2745  iks_insert_cdata(auth, base64, 0);
2746 
2747  ast_xmpp_client_send(client, auth);
2748 
2749  iks_delete(auth);
2750 
2752 
2753  return 0;
2754 }
2755 
2756 /*! \brief Internal function called when we need to authenticate */
2757 static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2758 {
2759  return ast_test_flag(&cfg->flags, XMPP_USESASL) ? xmpp_client_authenticate_sasl(client, cfg, type, node) : xmpp_client_authenticate_digest(client, cfg, type, node);
2760 }
2761 
2762 /*! \brief Internal function called when we are authenticating */
2763 static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2764 {
2765  int features;
2766 
2767  if (!strcmp(iks_name(node), "success")) {
2768  /* Authentication was a success, yay! */
2769  xmpp_send_stream_header(client, cfg, client->jid->server);
2770 
2771  return 0;
2772  } else if (!strcmp(iks_name(node), "failure")) {
2773  /* Authentication was a bust, disconnect and reconnect later */
2774  return -1;
2775  } else if (strcmp(iks_name(node), "stream:features")) {
2776  /* Ignore any other responses */
2777  return 0;
2778  }
2779 
2780  features = iks_stream_features(node);
2781 
2782  if (features & IKS_STREAM_BIND) {
2783  iks *auth;
2784 
2785  if (!(auth = iks_make_resource_bind(client->jid))) {
2786  ast_log(LOG_ERROR, "Failed to allocate memory for stream bind on client '%s'\n", client->name);
2787  return -1;
2788  }
2789 
2790  ast_xmpp_client_lock(client);
2791  iks_insert_attrib(auth, "id", client->mid);
2792  ast_xmpp_increment_mid(client->mid);
2793  ast_xmpp_client_unlock(client);
2794  ast_xmpp_client_send(client, auth);
2795 
2796  iks_delete(auth);
2797 
2798  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);
2799  }
2800 
2801  if (features & IKS_STREAM_SESSION) {
2802  iks *auth;
2803 
2804  if (!(auth = iks_make_session())) {
2805  ast_log(LOG_ERROR, "Failed to allocate memory for stream session on client '%s'\n", client->name);
2806  return -1;
2807  }
2808 
2809  iks_insert_attrib(auth, "id", "auth");
2810  ast_xmpp_client_lock(client);
2811  ast_xmpp_increment_mid(client->mid);
2812  ast_xmpp_client_unlock(client);
2813  ast_xmpp_client_send(client, auth);
2814 
2815  iks_delete(auth);
2816 
2817  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);
2818  }
2819 
2820  return 0;
2821 }
2822 
2823 /*! \brief Internal function called when we should authenticate as a component */
2824 static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
2825 {
2826  char secret[160], shasum[320], message[344];
2827  ikspak *pak = iks_packet(node);
2828 
2829  snprintf(secret, sizeof(secret), "%s%s", pak->id, cfg->password);
2830  ast_sha1_hash(shasum, secret);
2831  snprintf(message, sizeof(message), "<handshake>%s</handshake>", shasum);
2832 
2833  if (xmpp_client_send_raw_message(client, message) != IKS_OK) {
2834  ast_log(LOG_ERROR, "Unable to send handshake for component '%s'\n", client->name);
2835  return -1;
2836  }
2837 
2839 
2840  return 0;
2841 }
2842 
2843 /*! \brief Hook function called when component receives a service discovery get message */
2844 static int xmpp_component_service_discovery_get_hook(void *data, ikspak *pak)
2845 {
2846  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2847  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2848  struct ast_xmpp_client *client = data;
2849  iks *iq = NULL, *query = NULL, *identity = NULL, *disco = NULL, *reg = NULL, *commands = NULL, *gateway = NULL;
2850  iks *version = NULL, *vcard = NULL, *search = NULL, *item = NULL;
2851  char *node;
2852 
2853  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2854  !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(identity = iks_new("identity")) || !(disco = iks_new("feature")) ||
2855  !(reg = iks_new("feature")) || !(commands = iks_new("feature")) || !(gateway = iks_new("feature")) || !(version = iks_new("feature")) ||
2856  !(vcard = iks_new("feature")) || !(search = iks_new("search")) || !(item = iks_new("item"))) {
2857  ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery get response to '%s' on component '%s'\n",
2858  pak->from->partial, client->name);
2859  goto done;
2860  }
2861 
2862  iks_insert_attrib(iq, "from", clientcfg->user);
2863  iks_insert_attrib(iq, "to", pak->from->full);
2864  iks_insert_attrib(iq, "id", pak->id);
2865  iks_insert_attrib(iq, "type", "result");
2866 
2867  if (!(node = iks_find_attrib(pak->query, "node"))) {
2868  iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2869  iks_insert_attrib(identity, "category", "gateway");
2870  iks_insert_attrib(identity, "type", "pstn");
2871  iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
2872  iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
2873  iks_insert_attrib(reg, "var", "jabber:iq:register");
2874  iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2875  iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
2876  iks_insert_attrib(version, "var", "jabber:iq:version");
2877  iks_insert_attrib(vcard, "var", "vcard-temp");
2878  iks_insert_attrib(search, "var", "jabber:iq:search");
2879 
2880  iks_insert_node(iq, query);
2881  iks_insert_node(query, identity);
2882  iks_insert_node(query, disco);
2883  iks_insert_node(query, reg);
2884  iks_insert_node(query, commands);
2885  iks_insert_node(query, gateway);
2886  iks_insert_node(query, version);
2887  iks_insert_node(query, vcard);
2888  iks_insert_node(query, search);
2889  } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
2890  iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2891  iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2892  iks_insert_attrib(item, "node", "confirmaccount");
2893  iks_insert_attrib(item, "name", "Confirm account");
2894  iks_insert_attrib(item, "jid", clientcfg->user);
2895 
2896  iks_insert_node(iq, query);
2897  iks_insert_node(query, item);
2898  } else if (!strcasecmp(node, "confirmaccount")) {
2899  iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2900  iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2901 
2902  iks_insert_node(iq, query);
2903  iks_insert_node(query, commands);
2904  } else {
2905  ast_debug(3, "Unsupported service discovery info request received with node '%s' on component '%s'\n",
2906  node, client->name);
2907  goto done;
2908  }
2909 
2910  if (ast_xmpp_client_send(client, iq)) {
2911  ast_log(LOG_WARNING, "Could not send response to service discovery request on component '%s'\n",
2912  client->name);
2913  }
2914 
2915 done:
2916  iks_delete(search);
2917  iks_delete(vcard);
2918  iks_delete(version);
2919  iks_delete(gateway);
2920  iks_delete(commands);
2921  iks_delete(reg);
2922  iks_delete(disco);
2923  iks_delete(identity);
2924  iks_delete(query);
2925  iks_delete(iq);
2926 
2927  return IKS_FILTER_EAT;
2928 }
2929 
2930 /*! \brief Hook function called when the component is queried about registration */
2931 static int xmpp_component_register_get_hook(void *data, ikspak *pak)
2932 {
2933  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
2934  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
2935  struct ast_xmpp_client *client = data;
2936  iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL, *instructions = NULL;
2937  struct ast_xmpp_buddy *buddy;
2938  char *node;
2939 
2940  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
2941  !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(error = iks_new("error")) || !(notacceptable = iks_new("not-acceptable")) ||
2942  !(instructions = iks_new("instructions"))) {
2943  ast_log(LOG_ERROR, "Failed to allocate stanzas for register get response to '%s' on component '%s'\n",
2944  pak->from->partial, client->name);
2945  goto done;
2946  }
2947 
2948  iks_insert_attrib(iq, "from", clientcfg->user);
2949  iks_insert_attrib(iq, "to", pak->from->full);
2950  iks_insert_attrib(iq, "id", pak->id);
2951  iks_insert_attrib(iq, "type", "result");
2952  iks_insert_attrib(query, "xmlns", "jabber:iq:register");
2953  iks_insert_node(iq, query);
2954 
2955  if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
2956  iks_insert_attrib(error, "code", "406");
2957  iks_insert_attrib(error, "type", "modify");
2958  iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
2959 
2960  iks_insert_node(iq, error);
2961  iks_insert_node(error, notacceptable);
2962 
2963  ast_log(LOG_ERROR, "Received register attempt from '%s' but buddy is not configured on component '%s'\n",
2964  pak->from->partial, client->name);
2965  } else if (!(node = iks_find_attrib(pak->query, "node"))) {
2966  iks_insert_cdata(instructions, "Welcome to Asterisk - the Open Source PBX.\n", 0);
2967  iks_insert_node(query, instructions);
2968  ao2_ref(buddy, -1);
2969  } else {
2970  ast_log(LOG_WARNING, "Received register get to component '%s' using unsupported node '%s' from '%s'\n",
2971  client->name, node, pak->from->partial);
2972  ao2_ref(buddy, -1);
2973  goto done;
2974  }
2975 
2976  if (ast_xmpp_client_send(client, iq)) {
2977  ast_log(LOG_WARNING, "Could not send response to '%s' for received register get on component '%s'\n",
2978  pak->from->partial, client->name);
2979  }
2980 
2981 done:
2982  iks_delete(instructions);
2983  iks_delete(notacceptable);
2984  iks_delete(error);
2985  iks_delete(query);
2986  iks_delete(iq);
2987 
2988  return IKS_FILTER_EAT;
2989 }
2990 
2991 /*! \brief Hook function called when someone registers to the component */
2992 static int xmpp_component_register_set_hook(void *data, ikspak *pak)
2993 {
2994  struct ast_xmpp_client *client = data;
2995  iks *iq, *presence = NULL, *x = NULL;
2996 
2997  if (!(iq = iks_new("iq")) || !(presence = iks_new("presence")) || !(x = iks_new("x"))) {
2998  ast_log(LOG_ERROR, "Failed to allocate stanzas for register set response to '%s' on component '%s'\n",
2999  pak->from->partial, client->name);
3000  goto done;
3001  }
3002 
3003  iks_insert_attrib(iq, "from", client->jid->full);
3004  iks_insert_attrib(iq, "to", pak->from->full);
3005  iks_insert_attrib(iq, "id", pak->id);
3006  iks_insert_attrib(iq, "type", "result");
3007 
3008  if (ast_xmpp_client_send(client, iq)) {
3009  ast_log(LOG_WARNING, "Could not send response to '%s' for received register set on component '%s'\n",
3010  pak->from->partial, client->name);
3011  goto done;
3012  }
3013 
3014  iks_insert_attrib(presence, "from", client->jid->full);
3015  iks_insert_attrib(presence, "to", pak->from->partial);
3016  ast_xmpp_client_lock(client);
3017  iks_insert_attrib(presence, "id", client->mid);
3018  ast_xmpp_increment_mid(client->mid);
3019  ast_xmpp_client_unlock(client);
3020  iks_insert_attrib(presence, "type", "subscribe");
3021  iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
3022 
3023  iks_insert_node(presence, x);
3024 
3025  if (ast_xmpp_client_send(client, presence)) {
3026  ast_log(LOG_WARNING, "Could not send subscription to '%s' on component '%s'\n",
3027  pak->from->partial, client->name);
3028  }
3029 
3030 done:
3031  iks_delete(x);
3032  iks_delete(presence);
3033  iks_delete(iq);
3034 
3035  return IKS_FILTER_EAT;
3036 }
3037 
3038 /*! \brief Hook function called when we receive a service discovery items request */
3039 static int xmpp_component_service_discovery_items_hook(void *data, ikspak *pak)
3040 {
3041  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3042  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3043  struct ast_xmpp_client *client = data;
3044  iks *iq = NULL, *query = NULL, *item = NULL, *feature = NULL;
3045  char *node;
3046 
3047  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
3048  !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item")) || !(feature = iks_new("feature"))) {
3049  ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery items response to '%s' on component '%s'\n",
3050  pak->from->partial, client->name);
3051  goto done;
3052  }
3053 
3054  iks_insert_attrib(iq, "from", clientcfg->user);
3055  iks_insert_attrib(iq, "to", pak->from->full);
3056  iks_insert_attrib(iq, "id", pak->id);
3057  iks_insert_attrib(iq, "type", "result");
3058  iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
3059  iks_insert_node(iq, query);
3060 
3061  if (!(node = iks_find_attrib(pak->query, "node"))) {
3062  iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
3063  iks_insert_attrib(item, "name", "Asterisk Commands");
3064  iks_insert_attrib(item, "jid", clientcfg->user);
3065 
3066  iks_insert_node(query, item);
3067  } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
3068  iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
3069  } else {
3070  ast_log(LOG_WARNING, "Received service discovery items request to component '%s' using unsupported node '%s' from '%s'\n",
3071  client->name, node, pak->from->partial);
3072  goto done;
3073  }
3074 
3075  if (ast_xmpp_client_send(client, iq)) {
3076  ast_log(LOG_WARNING, "Could not send response to service discovery items request from '%s' on component '%s'\n",
3077  pak->from->partial, client->name);
3078  }
3079 
3080 done:
3081  iks_delete(feature);
3082  iks_delete(item);
3083  iks_delete(query);
3084  iks_delete(iq);
3085 
3086  return IKS_FILTER_EAT;
3087 }
3088 
3089 /*! \brief Internal function called when we authenticated as a component */
3090 static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
3091 {
3092  if (!strcmp(iks_name(node), "stream:features")) {
3093  return 0;
3094  }
3095 
3096  if (strcmp(iks_name(node), "handshake")) {
3097  ast_log(LOG_ERROR, "Failed to authenticate component '%s'\n", client->name);
3098  return -1;
3099  }
3100 
3101  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);
3102 
3103  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);
3104 
3105  /* This uses the client service discovery result hook on purpose, as the code is common between both */
3106  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);
3107 
3108  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);
3109  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);
3110 
3112 
3113  return 0;
3114 }
3115 
3116 /*! \brief Internal function called when a message is received */
3117 static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
3118 {
3119  struct ast_xmpp_message *message;
3120  char *body;
3121  int deleted = 0;
3122 
3123  ast_debug(3, "XMPP client '%s' received a message\n", client->name);
3124 
3125  if (!(body = iks_find_cdata(pak->x, "body"))) {
3126  /* Message contains no body, ignore it. */
3127  return 0;
3128  }
3129 
3130  if (!(message = ast_calloc(1, sizeof(*message)))) {
3131  return -1;
3132  }
3133 
3134  message->arrived = ast_tvnow();
3135 
3136  message->message = ast_strdup(body);
3137 
3138  ast_copy_string(message->id, S_OR(pak->id, ""), sizeof(message->id));
3139  message->from = !ast_strlen_zero(pak->from->full) ? ast_strdup(pak->from->full) : NULL;
3140 
3141  if (ast_test_flag(&cfg->flags, XMPP_SEND_TO_DIALPLAN)) {
3142  struct ast_msg *msg;
3143  struct ast_xmpp_buddy *buddy;
3144 
3145  if ((msg = ast_msg_alloc())) {
3146  int res;
3147 
3148  ast_xmpp_client_lock(client);
3149 
3150  buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY | OBJ_NOLOCK);
3151 
3152  res = ast_msg_set_to(msg, "xmpp:%s", cfg->user);
3153  res |= ast_msg_set_from(msg, "xmpp:%s", message->from);
3154  res |= ast_msg_set_body(msg, "%s", message->message);
3155  res |= ast_msg_set_context(msg, "%s", cfg->context);
3156  res |= ast_msg_set_tech(msg, "%s", "XMPP");
3157  res |= ast_msg_set_endpoint(msg, "%s", client->name);
3158 
3159  if (buddy) {
3160  res |= ast_msg_set_var(msg, "XMPP_BUDDY", buddy->id);
3161  }
3162 
3163  ao2_cleanup(buddy);
3164 
3165  ast_xmpp_client_unlock(client);
3166 
3167  if (res) {
3168  ast_msg_destroy(msg);
3169  } else {
3170  ast_msg_queue(msg);
3171  }
3172  }
3173  }
3174 
3175  /* remove old messages received from this JID
3176  * and insert received message */
3177  deleted = delete_old_messages(client, pak->from->partial);
3178  ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
3179  AST_LIST_LOCK(&client->messages);
3180  AST_LIST_INSERT_HEAD(&client->messages, message, list);
3181  AST_LIST_UNLOCK(&client->messages);
3182 
3183  /* wake up threads waiting for messages */
3184  ast_mutex_lock(&messagelock);
3185  ast_cond_broadcast(&message_received_condition);
3186  ast_mutex_unlock(&messagelock);
3187 
3188  return 0;
3189 }
3190 
3191 /*! \brief Helper function which sends a discovery information request to a user */
3192 static int xmpp_client_send_disco_info_request(struct ast_xmpp_client *client, const char *to, const char *from)
3193 {
3194  iks *iq, *query;
3195  int res;
3196 
3197  if (!(iq = iks_new("iq")) || !(query = iks_new("query"))) {
3198  iks_delete(iq);
3199  return -1;
3200  }
3201 
3202  iks_insert_attrib(iq, "type", "get");
3203  iks_insert_attrib(iq, "to", to);
3204  iks_insert_attrib(iq, "from", from);
3205  ast_xmpp_client_lock(client);
3206  iks_insert_attrib(iq, "id", client->mid);
3207  ast_xmpp_increment_mid(client->mid);
3208  ast_xmpp_client_unlock(client);
3209  iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
3210  iks_insert_node(iq, query);
3211 
3212  res = ast_xmpp_client_send(client, iq);
3213 
3214  iks_delete(query);
3215  iks_delete(iq);
3216 
3217  return res;
3218 }
3219 
3220 /*! \brief Callback function which returns when the resource is available */
3221 static int xmpp_resource_is_available(void *obj, void *arg, int flags)
3222 {
3223  struct ast_xmpp_resource *resource = obj;
3224 
3225  return (resource->status == IKS_SHOW_AVAILABLE) ? CMP_MATCH | CMP_STOP : 0;
3226 }
3227 
3228 /*! \brief Helper function which sends a ping request to a server */
3229 static int xmpp_ping_request(struct ast_xmpp_client *client, const char *to, const char *from)
3230 {
3231  iks *iq, *ping;
3232  int res;
3233 
3234  ast_debug(2, "JABBER: Sending Keep-Alive Ping for client '%s'\n", client->name);
3235 
3236  if (!(iq = iks_new("iq")) || !(ping = iks_new("ping"))) {
3237  iks_delete(iq);
3238  return -1;
3239  }
3240 
3241  iks_insert_attrib(iq, "type", "get");
3242  iks_insert_attrib(iq, "to", to);
3243  iks_insert_attrib(iq, "from", from);
3244 
3245  ast_xmpp_client_lock(client);
3246  iks_insert_attrib(iq, "id", client->mid);
3247  ast_xmpp_increment_mid(client->mid);
3248  ast_xmpp_client_unlock(client);
3249 
3250  iks_insert_attrib(ping, "xmlns", "urn:xmpp:ping");
3251  iks_insert_node(iq, ping);
3252 
3253  res = ast_xmpp_client_send(client, iq);
3254 
3255  iks_delete(ping);
3256  iks_delete(iq);
3257 
3258 
3259  return res;
3260 }
3261 
3262 /*! \brief Internal function called when a presence message is received */
3263 static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
3264 {
3265  struct ast_xmpp_buddy *buddy;
3266  struct ast_xmpp_resource *resource;
3267  char *type = iks_find_attrib(pak->x, "type");
3268  int status = pak->show ? pak->show : STATUS_DISAPPEAR;
3270 
3271  /* If this is a component presence probe request answer immediately with our presence status */
3272  if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) {
3273  xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
3274  }
3275 
3276  /* If no resource is available this is a general buddy presence update, which we will ignore */
3277  if (!pak->from->resource) {
3278  return 0;
3279  }
3280 
3281  if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
3282  /* Only output the message if it is not about us */
3283  if (strcmp(client->jid->partial, pak->from->partial)) {
3284  ast_log(LOG_WARNING, "Received presence information about '%s' despite not having them in roster on client '%s'\n",
3285  pak->from->partial, client->name);
3286  }
3287  return 0;
3288  }
3289 
3290  ao2_lock(buddy->resources);
3291 
3292  if (!(resource = ao2_callback(buddy->resources, OBJ_NOLOCK, xmpp_resource_cmp, pak->from->resource))) {
3293  /* Only create the new resource if it is not going away - in reality this should not happen */
3294  if (status != STATUS_DISAPPEAR) {
3295  if (!(resource = ao2_alloc(sizeof(*resource), xmpp_resource_destructor))) {
3296  ast_log(LOG_ERROR, "Could not allocate resource object for resource '%s' of buddy '%s' on client '%s'\n",
3297  pak->from->resource, buddy->id, client->name);
3298  ao2_unlock(buddy->resources);
3299  ao2_ref(buddy, -1);
3300  return 0;
3301  }
3302 
3303  ast_copy_string(resource->resource, pak->from->resource, sizeof(resource->resource));
3304  }
3305  } else {
3306  /* We unlink the resource in case the priority changes or in case they are going away */
3307  ao2_unlink_flags(buddy->resources, resource, OBJ_NOLOCK);
3308  }
3309 
3310  /* Only update the resource and add it back in if it is not going away */
3311  if (resource && (status != STATUS_DISAPPEAR)) {
3312  char *node, *ver;
3313 
3314  /* Try to get the XMPP spec node, and fall back to Google if not found */
3315  if (!(node = iks_find_attrib(iks_find(pak->x, "c"), "node"))) {
3316  node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
3317  }
3318 
3319  if (!(ver = iks_find_attrib(iks_find(pak->x, "c"), "ver"))) {
3320  ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
3321  }
3322 
3323  if (resource->description) {
3324  ast_free(resource->description);
3325  }
3326 
3327  if ((node && strcmp(resource->caps.node, node)) || (ver && strcmp(resource->caps.version, ver))) {
3328  /* For interoperability reasons, proceed even if the resource fails to provide node or version */
3329  if (node) {
3330  ast_copy_string(resource->caps.node, node, sizeof(resource->caps.node));
3331  }
3332  if (ver) {
3333  ast_copy_string(resource->caps.version, ver, sizeof(resource->caps.version));
3334  }
3335 
3336  /* Google Talk places the capabilities information directly in presence, so see if it is there */
3337  if (iks_find_with_attrib(pak->x, "c", "node", "http://www.google.com/xmpp/client/caps") ||
3338  iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.google.com/xmpp/client/caps") ||
3339  iks_find_with_attrib(pak->x, "c", "node", "http://www.android.com/gtalk/client/caps") ||
3340  iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.android.com/gtalk/client/caps") ||
3341  iks_find_with_attrib(pak->x, "c", "node", "http://mail.google.com/xmpp/client/caps") ||
3342  iks_find_with_attrib(pak->x, "caps:c", "node", "http://mail.google.com/xmpp/client/caps")) {
3343  resource->caps.google = 1;
3344  }
3345 
3346  /* To discover if the buddy supports Jingle we need to query, so do so */
3347  if (xmpp_client_send_disco_info_request(client, pak->from->full, client->jid->full)) {
3348  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);
3349  }
3350  }
3351 
3352  resource->status = status;
3353  resource->description = ast_strdup(iks_find_cdata(pak->x, "status"));
3354  resource->priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
3355 
3356  ao2_link_flags(buddy->resources, resource, OBJ_NOLOCK);
3357 
3358  manager_event(EVENT_FLAG_USER, "JabberStatus",
3359  "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
3360  "\r\nDescription: %s\r\n",
3361  client->name, pak->from->partial, resource->resource, resource->status,
3362  resource->priority, S_OR(resource->description, ""));
3363 
3364  ao2_ref(resource, -1);
3365  } else {
3366  /* This will get hit by presence coming in for an unknown resource, and also when a resource goes away */
3367  if (resource) {
3368  ao2_ref(resource, -1);
3369  }
3370 
3371  manager_event(EVENT_FLAG_USER, "JabberStatus",
3372  "Account: %s\r\nJID: %s\r\nStatus: %u\r\n",
3373  client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
3374  }
3375 
3376  /* Determine if at least one resource is available for device state purposes */
3377  if ((resource = ao2_callback(buddy->resources, OBJ_NOLOCK, xmpp_resource_is_available, NULL))) {
3378  state = AST_DEVICE_NOT_INUSE;
3379  ao2_ref(resource, -1);
3380  }
3381 
3382  ao2_unlock(buddy->resources);
3383 
3384  ao2_ref(buddy, -1);
3385 
3386  ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "XMPP/%s/%s", client->name, pak->from->partial);
3387 
3388  return 0;
3389 }
3390 
3391 /*! \brief Internal function called when a subscription message is received */
3392 static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg,iks *node, ikspak *pak)
3393 {
3394  struct ast_xmpp_buddy *buddy;
3395 
3396  switch (pak->subtype) {
3397  case IKS_TYPE_SUBSCRIBE:
3398  if (ast_test_flag(&cfg->flags, XMPP_AUTOREGISTER)) {
3399  iks *presence, *status = NULL;
3400 
3401  if ((presence = iks_new("presence")) && (status = iks_new("status"))) {
3402  iks_insert_attrib(presence, "type", "subscribed");
3403  iks_insert_attrib(presence, "to", pak->from->full);
3404  iks_insert_attrib(presence, "from", client->jid->full);
3405 
3406  if (pak->id) {
3407  iks_insert_attrib(presence, "id", pak->id);
3408  }
3409 
3410  iks_insert_cdata(status, "Asterisk has approved your subscription", 0);
3411  iks_insert_node(presence, status);
3412 
3413  if (ast_xmpp_client_send(client, presence)) {
3414  ast_log(LOG_ERROR, "Could not send subscription acceptance to '%s' from client '%s'\n",
3415  pak->from->partial, client->name);
3416  }
3417  } else {
3418  ast_log(LOG_ERROR, "Could not allocate presence stanzas for accepting subscription from '%s' to client '%s'\n",
3419  pak->from->partial, client->name);
3420  }
3421 
3422  iks_delete(status);
3423  iks_delete(presence);
3424  }
3425 
3426  if (ast_test_flag(&cfg->flags, XMPP_COMPONENT)) {
3427  xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
3428  }
3429  /* This purposely flows through so we have the subscriber amongst our buddies */
3430  case IKS_TYPE_SUBSCRIBED:
3431  ao2_lock(client->buddies);
3432 
3433  if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY | OBJ_NOLOCK))) {
3434  buddy = xmpp_client_create_buddy(client->buddies, pak->from->partial);
3435  }
3436 
3437  if (!buddy) {
3438  ast_log(LOG_WARNING, "Could not find or create buddy '%s' on client '%s'\n",
3439  pak->from->partial, client->name);
3440  } else {
3441  ao2_ref(buddy, -1);
3442  }
3443 
3444  ao2_unlock(client->buddies);
3445 
3446  break;
3447  default:
3448  break;
3449  }
3450 
3451  return 0;
3452 }
3453 
3454 /*! \brief Action hook for when things occur */
3455 static int xmpp_action_hook(void *data, int type, iks *node)
3456 {
3457  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3458  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3459  struct ast_xmpp_client *client = data;
3460  ikspak *pak;
3461  int i;
3462 
3463  if (!node) {
3464  ast_log(LOG_ERROR, "xmpp_action_hook was called without a packet\n");
3465  return IKS_HOOK;
3466  }
3467 
3468  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
3469  return IKS_HOOK;
3470  }
3471 
3472  /* If the client is disconnecting ignore everything */
3473  if (client->state == XMPP_STATE_DISCONNECTING) {
3474  return IKS_HOOK;
3475  }
3476 
3477  pak = iks_packet(node);
3478 
3479  /* work around iksemel's impossibility to recognize node names
3480  * containing a colon. Set the namespace of the corresponding
3481  * node accordingly. */
3482  if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
3483  char *node_ns = NULL;
3484  char attr[XMPP_MAX_ATTRLEN];
3485  char *node_name = iks_name(iks_child(node));
3486  char *aux = strchr(node_name, ':') + 1;
3487  snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
3488  node_ns = iks_find_attrib(iks_child(node), attr);
3489  if (node_ns) {
3490  pak->ns = node_ns;
3491  pak->query = iks_child(node);
3492  }
3493  }
3494 
3495  /* Process through any state handlers */
3496  for (i = 0; i < ARRAY_LEN(xmpp_state_handlers); i++) {
3497  if ((xmpp_state_handlers[i].state == client->state) && (xmpp_state_handlers[i].component == (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) ? 1 : 0))) {
3498  if (xmpp_state_handlers[i].handler(client, clientcfg, type, node)) {
3499  /* If the handler wants us to stop now, do so */
3500  return IKS_HOOK;
3501  }
3502  break;
3503  }
3504  }
3505 
3506  /* Process through any PAK handlers */
3507  for (i = 0; i < ARRAY_LEN(xmpp_pak_handlers); i++) {
3508  if (xmpp_pak_handlers[i].type == pak->type) {
3509  if (xmpp_pak_handlers[i].handler(client, clientcfg, node, pak)) {
3510  /* If the handler wants us to stop now, do so */
3511  return IKS_HOOK;
3512  }
3513  break;
3514  }
3515  }
3516 
3517  /* Send the packet through the filter in case any filters want to process it */
3518  iks_filter_packet(client->filter, pak);
3519 
3520  iks_delete(node);
3521 
3522  return IKS_OK;
3523 }
3524 
3526 {
3527  if ((client->thread != AST_PTHREADT_NULL) && !pthread_equal(pthread_self(), client->thread)) {
3529  pthread_cancel(client->thread);
3530  pthread_join(client->thread, NULL);
3531  client->thread = AST_PTHREADT_NULL;
3532  }
3533 
3534  if (client->mwi_sub) {
3535  client->mwi_sub = stasis_unsubscribe_and_join(client->mwi_sub);
3536  xmpp_pubsub_unsubscribe(client, "message_waiting");
3537  }
3538 
3539  if (client->device_state_sub) {
3541  xmpp_pubsub_unsubscribe(client, "device_state");
3542  }
3543 
3544 #ifdef HAVE_OPENSSL
3545  if (client->stream_flags & SECURE) {
3546  SSL_shutdown(client->ssl_session);
3547  SSL_CTX_free(client->ssl_context);
3548  SSL_free(client->ssl_session);
3549  }
3550 
3551  client->stream_flags = 0;
3552 #endif
3553 
3554  if (client->parser) {
3555  iks_disconnect(client->parser);
3556  }
3557 
3559 
3560  return 0;
3561 }
3562 
3563 /*! \brief Internal function used to reconnect an XMPP client to its server */
3564 static int xmpp_client_reconnect(struct ast_xmpp_client *client)
3565 {
3566  struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
3567  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3568  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3569  int res = IKS_NET_NOCONN;
3570 
3571  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
3572  return -1;
3573  }
3574 
3576 
3577  client->timeout = 50;
3578  iks_parser_reset(client->parser);
3579 
3580  if (!client->filter && !(client->filter = iks_filter_new())) {
3581  ast_log(LOG_ERROR, "Could not create IKS filter for client connection '%s'\n", client->name);
3582  return -1;
3583  }
3584 
3585  if (!ast_strlen_zero(clientcfg->refresh_token)) {
3586  ast_debug(2, "Obtaining OAuth access token for client '%s'\n", client->name);
3587  if (fetch_access_token(clientcfg)) {
3588  return -1;
3589  }
3590  }
3591 
3592  /* If it's a component connect to user otherwise connect to server */
3593  res = iks_connect_via(client->parser, S_OR(clientcfg->server, client->jid->server), clientcfg->port,
3594  ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) ? clientcfg->user : client->jid->server);
3595 
3596  /* Set socket timeout options */
3597  setsockopt(iks_fd(client->parser), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
3598 
3599  if (res == IKS_NET_NOCONN) {
3600  ast_log(LOG_ERROR, "No XMPP connection available when trying to connect client '%s'\n", client->name);
3601  return -1;
3602  } else if (res == IKS_NET_NODNS) {
3603  ast_log(LOG_ERROR, "No DNS available for XMPP connection when trying to connect client '%s'\n", client->name);
3604  return -1;
3605  }
3606 
3607  /* Depending on the configuration of the client we eiher jump to requesting TLS, or authenticating */
3608  xmpp_client_change_state(client, (ast_test_flag(&clientcfg->flags, XMPP_USETLS) ? XMPP_STATE_REQUEST_TLS : XMPP_STATE_AUTHENTICATE));
3609 
3610  return 0;
3611 }
3612 
3613 /*! \brief Internal function which polls on an XMPP client and receives data */
3614 static int xmpp_io_recv(struct ast_xmpp_client *client, char *buffer, size_t buf_len, int timeout)
3615 {
3616  struct pollfd pfd = { .events = POLLIN };
3617  int len, res;
3618 
3619 #ifdef HAVE_OPENSSL
3620  if (xmpp_is_secure(client)) {
3621  pfd.fd = SSL_get_fd(client->ssl_session);
3622  if (pfd.fd < 0) {
3623  return -1;
3624  }
3625  } else
3626 #endif /* HAVE_OPENSSL */
3627  pfd.fd = iks_fd(client->parser);
3628 
3629  res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
3630  if (res > 0) {
3631 #ifdef HAVE_OPENSSL
3632  if (xmpp_is_secure(client)) {
3633  len = SSL_read(client->ssl_session, buffer, buf_len);
3634  } else
3635 #endif /* HAVE_OPENSSL */
3636  len = recv(pfd.fd, buffer, buf_len, 0);
3637 
3638  if (len > 0) {
3639  return len;
3640  } else if (len <= 0) {
3641  return -1;
3642  }
3643  }
3644  return res;
3645 }
3646 
3647 /*! \brief Internal function which receives data from the XMPP client connection */
3648 static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int timeout)
3649 {
3650  int len, ret, pos = 0, newbufpos = 0;
3651  char buf[NET_IO_BUF_SIZE - 1] = "";
3652  char newbuf[NET_IO_BUF_SIZE - 1] = "";
3653  unsigned char c;
3654 
3655  while (1) {
3656  len = xmpp_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
3657  if (len < 0) return IKS_NET_RWERR;
3658  if (len == 0) return IKS_NET_EXPIRED;
3659  buf[len] = '\0';
3660 
3661  /* our iksemel parser won't work as expected if we feed
3662  it with XML packets that contain multiple whitespace
3663  characters between tags */
3664  while (pos < len) {
3665  c = buf[pos];
3666  /* if we stumble on the ending tag character,
3667  we skip any whitespace that follows it*/
3668  if (c == '>') {
3669  while (isspace(buf[pos+1])) {
3670  pos++;
3671  }
3672  }
3673  newbuf[newbufpos] = c;
3674  newbufpos++;
3675  pos++;
3676  }
3677  pos = 0;
3678  newbufpos = 0;
3679 
3680  /* Log the message here, because iksemel's logHook is
3681  unaccessible */
3682  xmpp_log_hook(client, buf, len, 1);
3683 
3684  if(buf[0] == ' ') {
3685  ast_debug(1, "JABBER: Detected Google Keep Alive. "
3686  "Sending out Ping request for client '%s'\n", client->name);
3687  /* If we just send out the ping here then we will have socket
3688  * read errors because the socket will timeout */
3689  xmpp_ping_request(client, client->jid->server, client->jid->full);
3690  }
3691 
3692  /* let iksemel deal with the string length,
3693  and reset our buffer */
3694  ret = iks_parse(client->parser, newbuf, 0, 0);
3695  memset(newbuf, 0, sizeof(newbuf));
3696 
3697  switch (ret) {
3698  case IKS_NOMEM:
3699  ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
3700  break;
3701  case IKS_BADXML:
3702  ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
3703  break;
3704  case IKS_HOOK:
3705  ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
3706  break;
3707  }
3708  if (ret != IKS_OK) {
3709  return ret;
3710  }
3711  ast_debug(3, "XML parsing successful\n");
3712  }
3713  return IKS_OK;
3714 }
3715 
3716 static void sleep_with_backoff(unsigned int *sleep_time)
3717 {
3718  /* We're OK with our thread dying here */
3719  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
3720 
3721  sleep(*sleep_time);
3722  *sleep_time = MIN(60, *sleep_time * 2);
3723 
3724  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
3725 }
3726 
3727 /*! \brief XMPP client connection thread */
3728 static void *xmpp_client_thread(void *data)
3729 {
3730  struct ast_xmpp_client *client = data;
3731  int res = IKS_NET_RWERR;
3732  unsigned int sleep_time = 1;
3733 
3734  /* We only allow cancellation while sleeping */
3735  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
3736 
3737  do {
3738  if (client->state == XMPP_STATE_DISCONNECTING) {
3739  ast_debug(1, "[%s] Disconnecting\n", client->name);
3740  break;
3741  }
3742 
3743  if (res == IKS_NET_RWERR || client->timeout == 0) {
3744  ast_debug(3, "[%s] Connecting\n", client->name);
3745  if ((res = xmpp_client_reconnect(client)) != IKS_OK) {
3746  sleep_with_backoff(&sleep_time);
3747  res = IKS_NET_RWERR;
3748  }
3749  continue;
3750  }
3751 
3752  res = xmpp_client_receive(client, 1);
3753 
3754  /* Decrease timeout if no data received, and delete
3755  * old messages globally */
3756  if (res == IKS_NET_EXPIRED) {
3757  client->timeout--;
3758  }
3759 
3760  if (res == IKS_HOOK) {
3761  ast_debug(2, "[%s] Got hook event\n", client->name);
3762  } else if (res == IKS_NET_TLSFAIL) {
3763  ast_log(LOG_ERROR, "[%s] TLS failure\n", client->name);
3764  } else if (!client->timeout && client->state == XMPP_STATE_CONNECTED) {
3765  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3766  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3767 
3768  if (cfg && cfg->clients) {
3769  clientcfg = xmpp_config_find(cfg->clients, client->name);
3770  }
3771 
3772  if (clientcfg && ast_test_flag(&clientcfg->flags, XMPP_KEEPALIVE)) {
3773  res = xmpp_ping_request(client, client->jid->server, client->jid->full);
3774  } else {
3775  res = IKS_OK;
3776  }
3777 
3778  if (res == IKS_OK) {
3779  client->timeout = 50;
3780  } else {
3781  ast_log(LOG_WARNING, "[%s] Network timeout\n", client->name);
3782  }
3783  } else if (res == IKS_NET_RWERR) {
3784  ast_log(LOG_WARNING, "[%s] Socket read error\n", client->name);
3786  sleep_with_backoff(&sleep_time);
3787  } else if (res == IKS_NET_NOSOCK) {
3788  ast_log(LOG_WARNING, "[%s] No socket\n", client->name);
3789  } else if (res == IKS_NET_NOCONN) {
3790  ast_log(LOG_WARNING, "[%s] No connection\n", client->name);
3791  } else if (res == IKS_NET_NODNS) {
3792  ast_log(LOG_WARNING, "[%s] No DNS\n", client->name);
3793  } else if (res == IKS_NET_NOTSUPP) {
3794  ast_log(LOG_WARNING, "[%s] Not supported\n", client->name);
3795  } else if (res == IKS_NET_DROPPED) {
3796  ast_log(LOG_WARNING, "[%s] Dropped?\n", client->name);
3797  } else if (res == IKS_NET_UNKNOWN) {
3798  ast_debug(5, "[%s] Unknown\n", client->name);
3799  } else if (res == IKS_OK) {
3800  sleep_time = 1;
3801  }
3802 
3803  } while (1);
3804 
3805  return NULL;
3806 }
3807 
3808 static int xmpp_client_config_merge_buddies(void *obj, void *arg, int flags)
3809 {
3810  struct ast_xmpp_buddy *buddy1 = obj, *buddy2;
3811  struct ao2_container *buddies = arg;
3812 
3813  /* If the buddy does not already exist link it into the client buddies container */
3814  if (!(buddy2 = ao2_find(buddies, buddy1->id, OBJ_KEY))) {
3815  ao2_link(buddies, buddy1);
3816  } else {
3817  ao2_ref(buddy2, -1);
3818  }
3819 
3820  /* All buddies are unlinked from the configuration buddies container, always */
3821  return 1;
3822 }
3823 
3824 static int fetch_access_token(struct ast_xmpp_client_config *cfg)
3825 {
3826  RAII_VAR(char *, cmd, NULL, ast_free);
3827  char cBuf[1024] = "";
3828  const char *url = "https://www.googleapis.com/oauth2/v3/token";
3829  struct ast_json_error error;
3830  RAII_VAR(struct ast_json *, jobj, NULL, ast_json_unref);
3831 
3832  if (ast_asprintf(&cmd,
3833  "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",
3834  url, cfg->oauth_clientid, cfg->oauth_secret, cfg->refresh_token) < 0) {
3835  return -1;
3836  }
3837 
3838  ast_debug(2, "Performing OAuth 2.0 authentication for client '%s' using command: %s\n",
3839  cfg->name, cmd);
3840 
3841  if (ast_func_read(NULL, cmd, cBuf, sizeof(cBuf) - 1)) {
3842  ast_log(LOG_ERROR, "CURL is unavailable. This is required for OAuth 2.0 authentication of XMPP client '%s'. Please ensure it is loaded.\n",
3843  cfg->name);
3844  return -1;
3845  }
3846 
3847  ast_debug(2, "OAuth 2.0 authentication for client '%s' returned: %s\n", cfg->name, cBuf);
3848 
3849  jobj = ast_json_load_string(cBuf, &error);
3850  if (jobj) {
3851  const char *token = ast_json_string_get(ast_json_object_get(jobj, "access_token"));
3852  if (token) {
3853  ast_string_field_set(cfg, password, token);
3854  return 0;
3855  }
3856  }
3857 
3858  ast_log(LOG_ERROR, "An error occurred while performing OAuth 2.0 authentication for client '%s': %s\n", cfg->name, cBuf);
3859 
3860  return -1;
3861 }
3862 
3863 static int xmpp_client_config_post_apply(void *obj, void *arg, int flags)
3864 {
3865  struct ast_xmpp_client_config *cfg = obj;
3866  RAII_VAR(struct xmpp_config *, gcfg, ao2_global_obj_ref(globals), ao2_cleanup);
3867 
3868  /* Merge global options that have not been modified */
3869  ast_copy_flags(&cfg->flags, &gcfg->global->general, ~(cfg->mod_flags.flags) & (XMPP_AUTOPRUNE | XMPP_AUTOREGISTER | XMPP_AUTOACCEPT));
3870 
3871  /* Merge buddies as need be */
3872  ao2_callback(cfg->buddies, OBJ_MULTIPLE | OBJ_UNLINK, xmpp_client_config_merge_buddies, cfg->client->buddies);
3873 
3874  if (cfg->client->reconnect) {
3875  /* Disconnect the existing session since our role is changing, or we are starting up */
3877 
3878  if (!(cfg->client->parser = iks_stream_new(ast_test_flag(&cfg->flags, XMPP_COMPONENT) ? "jabber:component:accept" : "jabber:client", cfg->client,
3879  xmpp_action_hook))) {
3880  ast_log(LOG_ERROR, "Iksemel stream could not be created for client '%s' - client not active\n", cfg->name);
3881  return -1;
3882  }
3883 
3884  iks_set_log_hook(cfg->client->parser, xmpp_log_hook);
3885 
3886  /* Create a JID based on the given user, if no resource is given use the default */
3887  if (!strchr(cfg->user, '/') && !ast_test_flag(&cfg->flags, XMPP_COMPONENT)) {
3888  char resource[strlen(cfg->user) + strlen("/asterisk-xmpp") + 1];
3889 
3890  snprintf(resource, sizeof(resource), "%s/asterisk-xmpp", cfg->user);
3891  cfg->client->jid = iks_id_new(cfg->client->stack, resource);
3892  } else {
3893  cfg->client->jid = iks_id_new(cfg->client->stack, cfg->user);
3894  }
3895 
3896  if (!cfg->client->jid || (ast_strlen_zero(cfg->client->jid->user) && !ast_test_flag(&cfg->flags, XMPP_COMPONENT))) {
3897  ast_log(LOG_ERROR, "Jabber identity '%s' could not be created for client '%s' - client not active\n", cfg->user, cfg->name);
3898  return -1;
3899  }
3900 
3901  ast_pthread_create_background(&cfg->client->thread, NULL, xmpp_client_thread, cfg->client);
3902 
3903  cfg->client->reconnect = 0;
3904  } else if (cfg->client->state == XMPP_STATE_CONNECTED) {
3905  /* If this client is connected update their presence status since it may have changed */
3906  xmpp_client_set_presence(cfg->client, NULL, cfg->client->jid->full, cfg->status, cfg->statusmsg);
3907 
3908  /* Subscribe to the status of any newly added buddies */
3909  if (ast_test_flag(&cfg->flags, XMPP_AUTOREGISTER)) {
3911  }
3912  }
3913 
3914  return 0;
3915 }
3916 
3917 /*!
3918  * \internal
3919  * \brief Send a Jabber Message via call from the Manager
3920  * \param s mansession Manager session
3921  * \param m message Message to send
3922  * \retval 0
3923  */
3924 static int manager_jabber_send(struct mansession *s, const struct message *m)
3925 {
3926  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
3927  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
3928  const char *id = astman_get_header(m, "ActionID");
3929  const char *jabber = astman_get_header(m, "Jabber");
3930  const char *screenname = astman_get_header(m, "ScreenName");
3931  const char *message = astman_get_header(m, "Message");
3932 
3933  if (ast_strlen_zero(jabber)) {
3934  astman_send_error(s, m, "No transport specified");
3935  return 0;
3936  }
3937  if (ast_strlen_zero(screenname)) {
3938  astman_send_error(s, m, "No ScreenName specified");
3939  return 0;
3940  }
3941  if (ast_strlen_zero(message)) {
3942  astman_send_error(s, m, "No Message specified");
3943  return 0;
3944  }
3945 
3946  astman_send_ack(s, m, "Attempting to send Jabber Message");
3947 
3948  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, jabber))) {
3949  astman_send_error(s, m, "Could not find Sender");
3950  return 0;
3951  }
3952 
3953  if (strchr(screenname, '@') && !ast_xmpp_client_send_message(clientcfg->client, screenname, message)) {
3954  astman_append(s, "Response: Success\r\n");
3955  } else {
3956  astman_append(s, "Response: Error\r\n");
3957  }
3958 
3959  if (!ast_strlen_zero(id)) {
3960  astman_append(s, "ActionID: %s\r\n", id);
3961  }
3962 
3963  astman_append(s, "\r\n");
3964 
3965  return 0;
3966 }
3967 
3968 /*!
3969  * \brief Build the a node request
3970  * \param client the configured XMPP client we use to connect to a XMPP server
3971  * \param collection name of the collection for request
3972  * \return iks *
3973  */
3974 static iks* xmpp_pubsub_build_node_request(struct ast_xmpp_client *client, const char *collection)
3975 {
3976  iks *request = xmpp_pubsub_iq_create(client, "get"), *query;
3977 
3978  if (!request) {
3979  return NULL;
3980  }
3981 
3982  query = iks_insert(request, "query");
3983  iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
3984 
3985  if (collection) {
3986  iks_insert_attrib(query, "node", collection);
3987  }
3988 
3989  return request;
3990 }
3991 
3992 /*!
3993  * \brief Receive pubsub item lists
3994  * \param data pointer to ast_xmpp_client structure
3995  * \param pak response from pubsub diso#items query
3996  * \retval IKS_FILTER_EAT
3997  */
3998 static int xmpp_pubsub_receive_node_list(void *data, ikspak* pak)
3999 {
4000  struct ast_xmpp_client *client = data;
4001  iks *item = NULL;
4002 
4003  if (iks_has_children(pak->query)) {
4004  item = iks_first_tag(pak->query);
4005  ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
4006  iks_find_attrib(item, "node"));
4007  while ((item = iks_next_tag(item))) {
4008  ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
4009  }
4010  }
4011 
4012  if (item) {
4013  iks_delete(item);
4014  }
4015 
4016 
4017  return IKS_FILTER_EAT;
4018 }
4019 
4020 /*!
4021 * \brief Request item list from pubsub
4022 * \param client the configured XMPP client we use to connect to a XMPP server
4023 * \param collection name of the collection for request
4024 */
4025 static void xmpp_pubsub_request_nodes(struct ast_xmpp_client *client, const char *collection)
4026 {
4027  iks *request = xmpp_pubsub_build_node_request(client, collection);
4028 
4029  if (!request) {
4030  ast_log(LOG_ERROR, "Could not request pubsub nodes on client '%s' - IQ could not be created\n", client->name);
4031  return;
4032  }
4033 
4034  iks_filter_add_rule(client->filter, xmpp_pubsub_receive_node_list, client, IKS_RULE_TYPE,
4035  IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
4036  IKS_RULE_DONE);
4037  ast_xmpp_client_send(client, request);
4038  iks_delete(request);
4039 
4040 }
4041 
4042 /*!
4043  * \brief Method to expose PubSub node list via CLI.
4044  * \param e pointer to ast_cli_entry structure
4045  * \param cmd
4046  * \param a pointer to ast_cli_args structure
4047  * \return char *
4048  */
4049 static char *xmpp_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
4050  ast_cli_args *a)
4051 {
4052  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
4053  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
4054  const char *name = NULL, *collection = NULL;
4055 
4056  switch (cmd) {
4057  case CLI_INIT:
4058  e->command = "xmpp list nodes";
4059  e->usage =
4060  "Usage: xmpp list nodes <connection> [collection]\n"
4061  " Lists the user's nodes on the respective connection\n"
4062  " ([connection] as configured in xmpp.conf.)\n";
4063  return NULL;
4064  case CLI_GENERATE:
4065  return NULL;
4066  }
4067 
4068  if (a->argc > 5 || a->argc < 4) {
4069  return CLI_SHOWUSAGE;
4070  } else if (a->argc == 4 || a->argc == 5) {
4071  name = a->argv[3];
4072  }
4073 
4074  if (a->argc == 5) {
4075  collection = a->argv[4];
4076  }
4077 
4078  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
4079  ast_cli(a->fd, "Unable to find client '%s'!\n", name);
4080  return CLI_FAILURE;
4081  }
4082 
4083  ast_cli(a->fd, "Listing pubsub nodes.\n");
4084 
4085  xmpp_pubsub_request_nodes(clientcfg->client, collection);
4086 
4087  return CLI_SUCCESS;
4088 }
4089 
4090 /*!
4091  * \brief Delete pubsub item lists
4092  * \param data pointer to ast_xmpp_client structure
4093  * \param pak response from pubsub diso#items query
4094  * \retval IKS_FILTER_EAT
4095  */
4096 static int xmpp_pubsub_delete_node_list(void *data, ikspak* pak)
4097 {
4098  struct ast_xmpp_client *client = data;
4099  iks *item = NULL;
4100 
4101  if (iks_has_children(pak->query)) {
4102  item = iks_first_tag(pak->query);
4103  ast_log(LOG_WARNING, "Connection: %s Node name: %s\n", client->jid->partial,
4104  iks_find_attrib(item, "node"));
4105  while ((item = iks_next_tag(item))) {
4106  xmpp_pubsub_delete_node(client, iks_find_attrib(item, "node"));
4107  }
4108  }
4109 
4110  if (item) {
4111  iks_delete(item);
4112  }
4113 
4114  return IKS_FILTER_EAT;
4115 }
4116 
4117 static void xmpp_pubsub_purge_nodes(struct ast_xmpp_client *client, const char* collection_name)
4118 {
4119  iks *request = xmpp_pubsub_build_node_request(client, collection_name);
4120  ast_xmpp_client_send(client, request);
4121  iks_filter_add_rule(client->filter, xmpp_pubsub_delete_node_list, client, IKS_RULE_TYPE,
4122  IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
4123  IKS_RULE_DONE);
4124  ast_xmpp_client_send(client, request);
4125  iks_delete(request);
4126 }
4127 
4128 /*!
4129  * \brief Method to purge PubSub nodes via CLI.
4130  * \param e pointer to ast_cli_entry structure
4131  * \param cmd
4132  * \param a pointer to ast_cli_args structure
4133  * \return char *
4134  */
4135 static char *xmpp_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
4136  ast_cli_args *a)
4137 {
4138  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
4139  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
4140  const char *name;
4141 
4142  switch (cmd) {
4143  case CLI_INIT:
4144  e->command = "xmpp purge nodes";
4145  e->usage =
4146  "Usage: xmpp purge nodes <connection> <node>\n"
4147  " Purges nodes on PubSub server\n"
4148  " as configured in xmpp.conf.\n";
4149  return NULL;
4150  case CLI_GENERATE:
4151  return NULL;
4152  }
4153 
4154  if (a->argc != 5) {
4155  return CLI_SHOWUSAGE;
4156  }
4157  name = a->argv[3];
4158 
4159  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
4160  ast_cli(a->fd, "Unable to find client '%s'!\n", name);
4161  return CLI_FAILURE;
4162  }
4163 
4164  if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
4165  xmpp_pubsub_purge_nodes(clientcfg->client, a->argv[4]);
4166  } else {
4167  xmpp_pubsub_delete_node(clientcfg->client, a->argv[4]);
4168  }
4169 
4170  return CLI_SUCCESS;
4171 }
4172 
4173 /*!
4174  * \brief Method to expose PubSub node deletion via CLI.
4175  * \param e pointer to ast_cli_entry structure
4176  * \param cmd
4177  * \param a pointer to ast_cli_args structure
4178  * \return char *
4179  */
4180 static char *xmpp_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
4181  ast_cli_args *a)
4182 {
4183  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
4184  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
4185  const char *name;
4186 
4187  switch (cmd) {
4188  case CLI_INIT:
4189  e->command = "xmpp delete node";
4190  e->usage =
4191  "Usage: xmpp delete node <connection> <node>\n"
4192  " Deletes a node on PubSub server\n"
4193  " as configured in xmpp.conf.\n";
4194  return NULL;
4195  case CLI_GENERATE:
4196  return NULL;
4197  }
4198 
4199  if (a->argc != 5) {
4200  return CLI_SHOWUSAGE;
4201  }
4202  name = a->argv[3];
4203 
4204  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
4205  ast_cli(a->fd, "Unable to find client '%s'!\n", name);
4206  return CLI_FAILURE;
4207  }
4208 
4209  xmpp_pubsub_delete_node(clientcfg->client, a->argv[4]);
4210 
4211  return CLI_SUCCESS;
4212 }
4213 
4214 /*!
4215  * \brief Method to expose PubSub collection node creation via CLI.
4216  * \return char *
4217  */
4218 static char *xmpp_cli_create_collection(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4219 {
4220  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
4221  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
4222  const char *name, *collection_name;
4223 
4224  switch (cmd) {
4225  case CLI_INIT:
4226  e->command = "xmpp create collection";
4227  e->usage =
4228  "Usage: xmpp create collection <connection> <collection>\n"
4229  " Creates a PubSub collection node using the account\n"
4230  " as configured in xmpp.conf.\n";
4231  return NULL;
4232  case CLI_GENERATE:
4233  return NULL;
4234  }
4235 
4236  if (a->argc != 5) {
4237  return CLI_SHOWUSAGE;
4238  }
4239  name = a->argv[3];
4240  collection_name = a->argv[4];
4241 
4242  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
4243  ast_cli(a->fd, "Unable to find client '%s'!\n", name);
4244  return CLI_FAILURE;
4245  }
4246 
4247  ast_cli(a->fd, "Creating test PubSub node collection.\n");
4248 
4249  xmpp_pubsub_create_collection(clientcfg->client, collection_name);
4250 
4251  return CLI_SUCCESS;
4252 }
4253 
4254 /*!
4255  * \brief Method to expose PubSub leaf node creation via CLI.
4256  * \return char *
4257  */
4258 static char *xmpp_cli_create_leafnode(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4259 {
4260  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
4261  RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
4262  const char *name, *collection_name, *leaf_name;
4263 
4264  switch (cmd) {
4265  case CLI_INIT:
4266  e->command = "xmpp create leaf";
4267  e->usage =
4268  "Usage: xmpp create leaf <connection> <collection> <leaf>\n"
4269  " Creates a PubSub leaf node using the account\n"
4270  " as configured in xmpp.conf.\n";
4271  return NULL;
4272  case CLI_GENERATE:
4273  return NULL;
4274  }
4275 
4276  if (a->argc != 6) {
4277  return CLI_SHOWUSAGE;
4278  }
4279  name = a->argv[3];
4280  collection_name = a->argv[4];
4281  leaf_name = a->argv[5];
4282 
4283  if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
4284  ast_cli(a->fd, "Unable to find client '%s'!\n", name);
4285  return CLI_FAILURE;
4286  }
4287 
4288  ast_cli(a->fd, "Creating test PubSub node collection.\n");
4289 
4290  xmpp_pubsub_create_leaf(clientcfg->client, collection_name, leaf_name);
4291 
4292  return CLI_SUCCESS;
4293 }
4294 
4295 /*!
4296  * \internal
4297  * \brief Turn on/off console debugging.
4298  * \retval CLI_SUCCESS
4299  */
4300 static char *xmpp_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4301 {
4302  switch (cmd) {
4303  case CLI_INIT:
4304  e->command = "xmpp set debug {on|off}";
4305  e->usage =
4306  "Usage: xmpp set debug {on|off}\n"
4307  " Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
4308  return NULL;
4309  case CLI_GENERATE:
4310  return NULL;
4311  }
4312 
4313  if (a->argc != e->args) {
4314  return CLI_SHOWUSAGE;
4315  }
4316 
4317  if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
4318  debug = 1;
4319  ast_cli(a->fd, "XMPP Debugging Enabled.\n");
4320  return CLI_SUCCESS;
4321  } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
4322  debug = 0;
4323  ast_cli(a->fd, "XMPP Debugging Disabled.\n");
4324  return CLI_SUCCESS;
4325  }
4326  return CLI_SHOWUSAGE; /* defaults to invalid */
4327 }
4328 
4329 /*!
4330  * \internal
4331  * \brief Show client status.
4332  * \retval CLI_SUCCESS
4333  */
4334 static char *xmpp_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4335 {
4336  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
4337  struct ao2_iterator i;
4338  struct ast_xmpp_client_config *clientcfg;
4339 
4340  switch (cmd) {
4341  case CLI_INIT:
4342  e->command = "xmpp show connections";
4343  e->usage =
4344  "Usage: xmpp show connections\n"
4345  " Shows state of client and component connections\n";
4346  return NULL;
4347  case CLI_GENERATE:
4348  return NULL;
4349  }
4350 
4351  if (!cfg || !cfg->clients) {
4352  return NULL;
4353  }
4354 
4355  ast_cli(a->fd, "Jabber Users and their status:\n");
4356 
4357  i = ao2_iterator_init(cfg->clients, 0);
4358  while ((clientcfg = ao2_iterator_next(&i))) {
4359  char *state;
4360 
4361  switch (clientcfg->client->state) {
4363  state = "Disconnecting";
4364  break;
4366  state = "Disconnected";
4367  break;
4368  case XMPP_STATE_CONNECTING:
4369  state = "Connecting";
4370  break;
4372  state = "Waiting to request TLS";
4373  break;
4375  state = "Requested TLS";
4376  break;
4378  state = "Waiting to authenticate";
4379  break;
4381  state = "Authenticating";
4382  break;
4383  case XMPP_STATE_ROSTER:
4384  state = "Retrieving roster";
4385  break;
4386  case XMPP_STATE_CONNECTED:
4387  state = "Connected";
4388  break;
4389  default:
4390  state = "Unknown";
4391  }
4392 
4393  ast_cli(a->fd, " [%s] %s - %s\n", clientcfg->name, clientcfg->user, state);
4394 
4395  ao2_ref(clientcfg, -1);
4396  }
4398 
4399  ast_cli(a->fd, "----\n");
4400  ast_cli(a->fd, " Number of clients: %d\n", ao2_container_count(cfg->clients));
4401 
4402  return CLI_SUCCESS;
4403 }
4404 
4405 /*!
4406  * \internal
4407  * \brief Show buddy lists
4408  * \retval CLI_SUCCESS
4409  */
4410 static char *xmpp_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4411 {
4412  RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
4413  struct ao2_iterator i;
4414  struct ast_xmpp_client_config *clientcfg;
4415 
4416  switch (cmd) {
4417  case CLI_INIT:
4418  e->command = "xmpp show buddies";
4419  e->usage =
4420  "Usage: xmpp show buddies\n"
4421  " Shows buddy lists of our clients\n";
4422  return NULL;
4423  case CLI_GENERATE:
4424  return NULL;
4425  }
4426 
4427  if (!cfg || !cfg->clients) {
4428  return NULL;
4429  }
4430 
4431  ast_cli(a->fd, "XMPP buddy lists\n");
4432 
4433  i = ao2_iterator_init(cfg->clients, 0);
4434  while ((clientcfg = ao2_iterator_next(&i))) {
4435  struct ao2_iterator bud;
4436  struct ast_xmpp_buddy *buddy;
4437 
4438  ast_cli(a->fd, "Client: %s\n", clientcfg->name);
4439 
4440  bud = ao2_iterator_init(clientcfg->client->buddies, 0);
4441  while ((buddy = ao2_iterator_next(&bud))) {
4442  struct ao2_iterator res;
4443  struct ast_xmpp_resource *resource;
4444 
4445  ast_cli(a->fd, "\tBuddy:\t%s\n", buddy->id);
4446 
4447  res = ao2_iterator_init(buddy->resources, 0);
4448  while ((resource = ao2_iterator_next(&res))) {
4449  ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
4450  ast_cli(a->fd, "\t\t\tnode: %s\n", resource->caps.node);
4451  ast_cli(a->fd, "\t\t\tversion: %s\n", resource->caps.version);
4452  ast_cli(a->fd, "\t\t\tGoogle Talk capable: %s\n", resource->caps.google ? "yes" : "no");
4453  ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->caps.jingle ? "yes" : "no");
4454 
4455  ao2_ref(resource, -1);
4456  }
4457  ao2_iterator_destroy(&res);
4458 
4459  ao2_ref(buddy, -1);
4460  }
4461  ao2_iterator_destroy(&bud);
4462 
4463  ao2_ref(clientcfg, -1);
4464  }
4466 
4467  return CLI_SUCCESS;
4468 }
4469 
4470 static struct ast_cli_entry xmpp_cli[] = {
4471  AST_CLI_DEFINE(xmpp_do_set_debug, "Enable/Disable Jabber debug"),
4472  AST_CLI_DEFINE(xmpp_show_clients, "Show state of clients and components"),
4473  AST_CLI_DEFINE(xmpp_show_buddies, "Show buddy lists of our clients"),
4474  AST_CLI_DEFINE(xmpp_cli_create_collection, "Creates a PubSub node collection."),
4475  AST_CLI_DEFINE(xmpp_cli_list_pubsub_nodes, "Lists PubSub nodes"),
4476  AST_CLI_DEFINE(xmpp_cli_create_leafnode, "Creates a PubSub leaf node"),
4477  AST_CLI_DEFINE(xmpp_cli_delete_pubsub_node, "Deletes a PubSub node"),
4478  AST_CLI_DEFINE(xmpp_cli_purge_pubsub_nodes, "Purges PubSub nodes"),
4479 };
4480 
4481 static int unload_module(void)
4482 {
4483  ast_msg_tech_unregister(&msg_tech);
4484  ast_cli_unregister_multiple(xmpp_cli, ARRAY_LEN(xmpp_cli));
4485  ast_unregister_application(app_ajisend);
4486  ast_unregister_application(app_ajisendgroup);
4487  ast_unregister_application(app_ajistatus);
4488  ast_unregister_application(app_ajijoin);
4489  ast_unregister_application(app_ajileave);
4490  ast_manager_unregister("JabberSend");
4491  ast_custom_function_unregister(&jabberstatus_function);
4492  ast_custom_function_unregister(&jabberreceive_function);
4493  aco_info_destroy(&cfg_info);
4494  ao2_global_obj_release(globals);
4495 
4496  ast_cond_destroy(&message_received_condition);
4497  ast_mutex_destroy(&messagelock);
4498 
4499  return 0;
4500 }
4501 
4502 static int global_bitfield_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
4503 {
4504  struct ast_xmpp_global_config *global = obj;
4505 
4506  if (!strcasecmp(var->name, "debug")) {
4507  debug = ast_true(var->value);
4508  } else if (!strcasecmp(var->name, "autoprune")) {
4509  ast_set2_flag(&global->general, ast_true(var->value), XMPP_AUTOPRUNE);
4510  } else if (!strcasecmp(var->name, "autoregister")) {
4511  ast_set2_flag(&global->general, ast_true(var->value), XMPP_AUTOREGISTER);
4512  } else if (!strcasecmp(var->name, "auth_policy")) {
4513  ast_set2_flag(&global->general, !strcasecmp(var->value, "accept") ? 1 : 0, XMPP_AUTOACCEPT);
4514  } else if (!strcasecmp(var->name, "collection_nodes")) {
4515  ast_set2_flag(&global->pubsub, ast_true(var->value), XMPP_XEP0248);
4516  } else if (!strcasecmp(var->name, "pubsub_autocreate")) {
4517  ast_set2_flag(&global->pubsub, ast_true(var->value), XMPP_PUBSUB_AUTOCREATE);
4518  } else {
4519  return -1;
4520  }
4521 
4522  return 0;
4523 }
4524 
4525 static int client_bitfield_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
4526 {
4527  struct ast_xmpp_client_config *cfg = obj;
4528 
4529  if (!strcasecmp(var->name, "debug")) {
4530  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_DEBUG);
4531  } else if (!strcasecmp(var->name, "type")) {
4532  ast_set2_flag(&cfg->flags, !strcasecmp(var->value, "component") ? 1 : 0, XMPP_COMPONENT);
4533  } else if (!strcasecmp(var->name, "distribute_events")) {
4534  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_DISTRIBUTE_EVENTS);
4535  } else if (!strcasecmp(var->name, "usetls")) {
4536  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_USETLS);
4537  } else if (!strcasecmp(var->name, "usesasl")) {
4538  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_USESASL);
4539  } else if (!strcasecmp(var->name, "forceoldssl")) {
4540  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_FORCESSL);
4541  } else if (!strcasecmp(var->name, "keepalive")) {
4542  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_KEEPALIVE);
4543  } else if (!strcasecmp(var->name, "autoprune")) {
4544  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_AUTOPRUNE);
4545  ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOPRUNE);
4546  } else if (!strcasecmp(var->name, "autoregister")) {
4547  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_AUTOREGISTER);
4548  ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOREGISTER);
4549  } else if (!strcasecmp(var->name, "auth_policy")) {
4550  ast_set2_flag(&cfg->flags, !strcasecmp(var->value, "accept") ? 1 : 0, XMPP_AUTOACCEPT);
4551  ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOACCEPT);
4552  } else if (!strcasecmp(var->name, "sendtodialplan")) {
4553  ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_SEND_TO_DIALPLAN);
4554  } else {
4555  return -1;
4556  }
4557 
4558  return 0;
4559 }
4560 
4561 static int client_status_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
4562 {
4563  struct ast_xmpp_client_config *cfg = obj;
4564 
4565  if (!strcasecmp(var->value, "unavailable")) {
4566  cfg->status = IKS_SHOW_UNAVAILABLE;
4567  } else if (!strcasecmp(var->value, "available") || !strcasecmp(var->value, "online")) {
4568  cfg->status = IKS_SHOW_AVAILABLE;
4569  } else if (!strcasecmp(var->value, "chat") || !strcasecmp(var->value, "chatty")) {
4570  cfg->status = IKS_SHOW_CHAT;
4571  } else if (!strcasecmp(var->value, "away")) {
4572  cfg->status = IKS_SHOW_AWAY;
4573  } else if (!strcasecmp(var->value, "xa") || !strcasecmp(var->value, "xaway")) {
4574  cfg->status = IKS_SHOW_XA;
4575  } else if (!strcasecmp(var->value, "dnd")) {
4576  cfg->status = IKS_SHOW_DND;
4577  } else if (!strcasecmp(var->value, "invisible")) {
4578 #ifdef IKS_SHOW_INVISIBLE
4579  cfg->status = IKS_SHOW_INVISIBLE;
4580 #else
4581  cfg->status = IKS_SHOW_DND;
4582 #endif
4583  } else {
4584  return -1;
4585  }
4586 
4587  return 0;
4588 }
4589 
4590 static int client_buddy_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
4591 {
4592  struct ast_xmpp_client_config *cfg = obj;
4593  struct ast_xmpp_buddy *buddy;
4594 
4595  if ((buddy = ao2_find(cfg->buddies, var->value, OBJ_KEY))) {
4596  ao2_ref(buddy, -1);
4597  return -1;
4598  }
4599 
4600  if (!(buddy = xmpp_client_create_buddy(cfg->buddies, var->value))) {
4601  return -1;
4602  }
4603 
4604  ao2_ref(buddy, -1);
4605 
4606  return 0;
4607 }
4608 
4609 /*!
4610  * \brief Load the module
4611  *
4612  * Module loading including tests for configuration or dependencies.
4613  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
4614  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
4615  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
4616  * configuration file or other non-critical problem return
4617  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
4618  */
4619 static int load_module(void)
4620 {
4621  if (aco_info_init(&cfg_info)) {
4622  return AST_MODULE_LOAD_DECLINE;
4623  }
4624 
4625  aco_option_register_custom(&cfg_info, "debug", ACO_EXACT, global_options, "no", global_bitfield_handler, 0);
4626  aco_option_register_custom(&cfg_info, "autoprune", ACO_EXACT, global_options, "no", global_bitfield_handler, 0);
4627  aco_option_register_custom(&cfg_info, "autoregister", ACO_EXACT, global_options, "yes", global_bitfield_handler, 0);
4628  aco_option_register_custom(&cfg_info, "collection_nodes", ACO_EXACT, global_options, "no", global_bitfield_handler, 0);
4629  aco_option_register_custom(&cfg_info, "pubsub_autocreate", ACO_EXACT, global_options, "no", global_bitfield_handler, 0);
4630  aco_option_register_custom(&cfg_info, "auth_policy", ACO_EXACT, global_options, "accept", global_bitfield_handler, 0);
4631 
4632  aco_option_register(&cfg_info, "username", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, user));
4633  aco_option_register(&cfg_info, "secret", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, password));
4634  aco_option_register(&cfg_info, "refresh_token", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, refresh_token));
4635  aco_option_register(&cfg_info, "oauth_clientid", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, oauth_clientid));
4636  aco_option_register(&cfg_info, "oauth_secret", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, oauth_secret));
4637  aco_option_register(&cfg_info, "serverhost", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, server));
4638  aco_option_register(&cfg_info, "statusmessage", ACO_EXACT, client_options, "Online and Available", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, statusmsg));
4639  aco_option_register(&cfg_info, "pubsub_node", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, pubsubnode));
4640  aco_option_register(&cfg_info, "context", ACO_EXACT, client_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, context));
4641  aco_option_register(&cfg_info, "priority", ACO_EXACT, client_options, "1", OPT_UINT_T, 0, FLDSET(struct ast_xmpp_client_config, priority));
4642  aco_option_register(&cfg_info, "port", ACO_EXACT, client_options, "5222", OPT_UINT_T, 0, FLDSET(struct ast_xmpp_client_config, port));
4643  aco_option_register(&cfg_info, "timeout", ACO_EXACT, client_options, "5", OPT_UINT_T, 0, FLDSET(struct ast_xmpp_client_config, message_timeout));
4644 
4645  /* Global options that can be overridden per client must not specify a default */
4646  aco_option_register_custom(&cfg_info, "autoprune", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
4647  aco_option_register_custom(&cfg_info, "autoregister", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
4648  aco_option_register_custom(&cfg_info, "auth_policy", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
4649 
4650  aco_option_register_custom(&cfg_info, "debug", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
4651  aco_option_register_custom(&cfg_info, "type", ACO_EXACT, client_options, "client", client_bitfield_handler, 0);
4652  aco_option_register_custom(&cfg_info, "distribute_events", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
4653  aco_option_register_custom(&cfg_info, "usetls", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
4654  aco_option_register_custom(&cfg_info, "usesasl", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
4655  aco_option_register_custom(&cfg_info, "forceoldssl", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
4656  aco_option_register_custom(&cfg_info, "keepalive", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
4657  aco_option_register_custom(&cfg_info, "sendtodialplan", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
4658  aco_option_register_custom(&cfg_info, "status", ACO_EXACT, client_options, "available", client_status_handler, 0);
4659  aco_option_register_custom(&cfg_info, "buddy", ACO_EXACT, client_options, NULL, client_buddy_handler, 0);
4660 
4661  if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
4662  aco_info_destroy(&cfg_info);
4663  return AST_MODULE_LOAD_DECLINE;
4664  }
4665 
4666  ast_manager_register_xml("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send);
4667 
4668  ast_register_application_xml(app_ajisend, xmpp_send_exec);
4672 
4673  ast_cli_register_multiple(xmpp_cli, ARRAY_LEN(xmpp_cli));
4674  ast_custom_function_register(&jabberstatus_function);
4675  ast_custom_function_register(&jabberreceive_function);
4676  ast_msg_tech_register(&msg_tech);
4677 
4678  ast_mutex_init(&messagelock);
4679  ast_cond_init(&message_received_condition, NULL);
4680 
4682  ast_log(LOG_WARNING, "Entity ID is not set. The distributing device state or MWI will not work.\n");
4683  }
4684 
4685  return AST_MODULE_LOAD_SUCCESS;
4686 }
4687 
4688 static int reload(void)
4689 {
4690  if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
4691  return AST_MODULE_LOAD_DECLINE;
4692  }
4693 
4694  return 0;
4695 }
4696 
4697 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk XMPP Interface",
4698  .support_level = AST_MODULE_SUPPORT_CORE,
4699  .load = load_module,
4700  .unload = unload_module,
4701  .reload = reload,
4702  .load_pri = AST_MODPRI_CHANNEL_DEPEND,
4703 );
static struct ast_xmpp_buddy * xmpp_client_create_buddy(struct ao2_container *container, const char *id)
Internal function which creates a buddy on a client.
Definition: res_xmpp.c:2163
const char * name
Definition: pbx.h:119
int ast_xmpp_chatroom_leave(struct ast_xmpp_client *client, const char *room, const char *nickname)
Leave an XMPP multi-user chatroom.
Definition: res_xmpp.c:1020
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
Main Channel structure associated with a channel.
static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak)
Hook function called when client receives a service discovery get message.
Definition: res_xmpp.c:2343
Definition: test_heap.c:38
struct ast_xmpp_message::@293 list
int ast_xmpp_chatroom_send(struct ast_xmpp_client *client, const char *nickname, const char *address, const char *message)
Send a message to an XMPP multi-user chatroom.
Definition: res_xmpp.c:1015
ast_device_state
Device States.
Definition: devicestate.h:52
static int xmpp_resource_hash(const void *obj, const int flags)
Hashing function for XMPP resource.
Definition: res_xmpp.c:845
int ast_msg_set_tech(struct ast_msg *msg, const char *fmt,...)
Set the technology associated with this message.
Definition: main/message.c:523
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
static int xmpp_client_authenticate_sasl(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we need to authenticate using SASL.
Definition: res_xmpp.c:2692
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
Asterisk main include file. File version handling, generic pbx functions.
static void xmpp_pubsub_create_collection(struct ast_xmpp_client *client, const char *collection_name)
Create a PubSub collection node.
Definition: res_xmpp.c:1244
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
static char * xmpp_cli_create_collection(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to expose PubSub collection node creation via CLI.
Definition: res_xmpp.c:4218
static void * ast_xmpp_client_config_alloc(const char *cat)
Allocator function for configuration.
Definition: res_xmpp.c:677
XMPP Client Configuration.
Definition: res_xmpp.c:450
int ast_msg_set_context(struct ast_msg *msg, const char *fmt,...)
Set the dialplan context for this message.
Definition: main/message.c:501
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition: utils.c:2839
static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int timeout)
Internal function which receives data from the XMPP client connection.
Definition: res_xmpp.c:3648
static int xmpp_client_unsubscribe_user(struct ast_xmpp_client *client, const char *user)
Helper function which unsubscribes a user and removes them from the roster.
Definition: res_xmpp.c:2189
int ast_msg_set_body(struct ast_msg *msg, const char *fmt,...)
Set the 'body' text of a message (in UTF-8)
Definition: main/message.c:490
struct ast_endpoint * ast_endpoint_create(const char *tech, const char *resource)
Create an endpoint struct.
static char * xmpp_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to expose PubSub node deletion via CLI.
Definition: res_xmpp.c:4180
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define OBJ_KEY
Definition: astobj2.h:1151
static int xmpp_client_service_discovery_result_hook(void *data, ikspak *pak)
Hook function called when client receives a service discovery result message.
Definition: res_xmpp.c:2403
static int xmpp_pubsub_delete_node_list(void *data, ikspak *pak)
Delete pubsub item lists.
Definition: res_xmpp.c:4096
static int xmpp_leave_exec(struct ast_channel *chan, const char *data)
Application to leave a chat room.
Definition: res_xmpp.c:1777
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
static int xmpp_component_service_discovery_items_hook(void *data, ikspak *pak)
Hook function called when we receive a service discovery items request.
Definition: res_xmpp.c:3039
descriptor for a cli entry.
Definition: cli.h:171
int ast_xmpp_chatroom_invite(struct ast_xmpp_client *client, const char *user, const char *room, const char *message)
Invite a user to an XMPP multi-user chatroom.
Definition: res_xmpp.c:943
static void * xmpp_config_find(struct ao2_container *tmp_container, const char *category)
Find function for configuration.
Definition: res_xmpp.c:657
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
static void xmpp_pubsub_mwi_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
Callback function for MWI events.
Definition: res_xmpp.c:1335
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:73
static int debug
Global debug status.
Definition: res_xmpp.c:441
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1693
struct ast_msg * ast_msg_alloc(void)
Allocate a message.
Definition: main/message.c:432
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define RESOURCE_BUCKETS
Number of buckets for resources (per buddy)
Definition: res_xmpp.c:432
enum ast_device_state state
Definition: devicestate.h:248
static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we are authenticating.
Definition: res_xmpp.c:2763
int stasis_subscription_is_subscribed(const struct stasis_subscription *sub)
Returns whether a subscription is currently subscribed.
Definition: stasis.c:1150
void ast_xmpp_increment_mid(char *mid)
Helper function which increments the message identifier.
Definition: res_xmpp.c:1025
static void * xmpp_client_thread(void *data)
XMPP client connection thread.
Definition: res_xmpp.c:3728
static char * xmpp_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to purge PubSub nodes via CLI.
Definition: res_xmpp.c:4135
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
int ast_xmpp_chatroom_join(struct ast_xmpp_client *client, const char *room, const char *nickname)
Join an XMPP multi-user chatroom.
Definition: res_xmpp.c:1010
Structure for variables, used for configurations and for channel variables.
const ast_string_field password
Definition: res_xmpp.c:462
static void xmpp_pubsub_request_nodes(struct ast_xmpp_client *client, const char *collection)
Request item list from pubsub.
Definition: res_xmpp.c:4025
char id[XMPP_MAX_JIDLEN]
Definition: xmpp.h:113
static struct ast_xmpp_client * xmpp_client_alloc(const char *name)
Allocator function for ast_xmpp_client.
Definition: res_xmpp.c:610
const char *const name
Name of this message technology.
Definition: message.h:61
static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we need to request TLS support.
Definition: res_xmpp.c:2540
struct ast_flags flags
Definition: res_xmpp.c:466
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1077
void ast_xmpp_client_lock(struct ast_xmpp_client *client)
Lock an XMPP client connection.
Definition: res_xmpp.c:899
#define XMPP_MAX_ATTRLEN
Maximum size of an attribute.
Definition: xmpp.h:68
static int xmpp_client_send_disco_info_request(struct ast_xmpp_client *client, const char *to, const char *from)
Helper function which sends a discovery information request to a user.
Definition: res_xmpp.c:3192
const ast_string_field pubsubnode
Definition: res_xmpp.c:462
int ast_msg_tech_register(const struct ast_msg_tech *tech)
Register a message technology.
static void xmpp_resource_destructor(void *obj)
Destructor callback function for XMPP resource.
Definition: res_xmpp.c:835
char resource[XMPP_MAX_RESJIDLEN]
Definition: xmpp.h:93
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
unsigned int reconnect
Definition: xmpp.h:142
enum ast_devstate_cache cachable
Definition: devicestate.h:250
static char * xmpp_cli_create_leafnode(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to expose PubSub leaf node creation via CLI.
Definition: res_xmpp.c:4258
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
void ast_endpoint_set_state(struct ast_endpoint *endpoint, enum ast_endpoint_state state)
Updates the state of the given endpoint.
static int xmpp_roster_hook(void *data, ikspak *pak)
Hook function called when roster is received from server.
Definition: res_xmpp.c:2247
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
Definition: json.c:567
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3421
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
static int xmpp_buddy_cmp(void *obj, void *arg, int flags)
Comparator function for XMPP buddy.
Definition: res_xmpp.c:587
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
Defined handlers for XMPP client states.
Definition: res_xmpp.c:489
struct ao2_container * stasis_cache_dump(struct stasis_cache *cache, struct stasis_message_type *type)
Dump cached items to a subscription for the ast_eid_default entity.
Definition: stasis_cache.c:736
Out-of-call text message support.
struct stasis_subscription * device_state_sub
Definition: xmpp.h:146
The representation of a single configuration file to be processed.
static int xmpp_component_register_get_hook(void *data, ikspak *pak)
Hook function called when the component is queried about registration.
Definition: res_xmpp.c:2931
static void xmpp_pubsub_devstate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
Callback function for device state events.
Definition: res_xmpp.c:1362
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
Initialize collections for event distribution.
Definition: res_xmpp.c:1583
enum aco_type_t type
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
const char * ast_msg_get_body(const struct ast_msg *msg)
Get the body of a message.
Definition: main/message.c:545
struct ast_xmpp_client * ast_xmpp_client_find(const char *name)
Find an XMPP client connection using a given name.
Definition: res_xmpp.c:881
An Entity ID is essentially a MAC address, brief and unique.
Definition: utils.h:813
JSON parsing error information.
Definition: json.h:887
static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *node)
Subscribe to a PubSub node.
Definition: res_xmpp.c:1410
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_msg_set_to(struct ast_msg *msg, const char *fmt,...)
Set the 'to' URI of a message.
Definition: main/message.c:468
int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
Compare two EIDs.
Definition: utils.c:3094
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
int args
This gets set in ast_cli_register()
Definition: cli.h:185
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
static void xmpp_client_set_presence(struct ast_xmpp_client *client, const char *to, const char *from, int level, const char *desc)
Internal function which changes the presence status of an XMPP client.
Definition: res_xmpp.c:2305
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
Callback for handling PubSub events.
Definition: res_xmpp.c:1457
#define BUDDY_BUCKETS
Number of buckets for buddies (per client)
Definition: res_xmpp.c:429
struct ast_flags pubsub
Definition: res_xmpp.c:446
struct stasis_subscription * mwi_sub
Definition: xmpp.h:144
char node[200]
Definition: xmpp.h:85
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
char * from
Definition: xmpp.h:102
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
enum ast_device_state ast_devstate_val(const char *val)
Convert device state from text to integer value.
Definition: devicestate.c:260
#define XMPP_MAX_RESJIDLEN
Maximum size of a resource JID.
Definition: xmpp.h:65
Asterisk JSON abstraction layer.
static int xmpp_component_register_set_hook(void *data, ikspak *pak)
Hook function called when someone registers to the component.
Definition: res_xmpp.c:2992
static int xmpp_client_authenticate_digest(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we need to authenticate using non-SASL.
Definition: res_xmpp.c:2654
XMPP Client Connection.
Definition: xmpp.h:119
XMPP Interface.
Type for default option handler for unsigned integers.
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:246
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define STATUS_DISAPPEAR
Status for a disappearing buddy.
Definition: res_xmpp.c:438
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
unsigned int google
Definition: xmpp.h:88
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
static int xmpp_client_reconnect(struct ast_xmpp_client *client)
Internal function used to reconnect an XMPP client to its server.
Definition: res_xmpp.c:3564
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1785
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3738
static void ast_xmpp_client_config_destructor(void *obj)
Destructor function for configuration.
Definition: res_xmpp.c:529
int ast_str_to_eid(struct ast_eid *eid, const char *s)
Convert a string into an EID.
Definition: utils.c:3077
static void * xmpp_config_alloc(void)
Allocator for XMPP configuration.
Definition: res_xmpp.c:724
const ast_string_field user
Definition: res_xmpp.c:462
const ast_string_field statusmsg
Definition: res_xmpp.c:462
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ao2_container * container
Definition: res_fax.c:501
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
Set a variable on the message going to the dialplan.
Definition: main/message.c:629
struct ao2_container * buddies
Definition: res_xmpp.c:470
int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
Disconnect an XMPP client connection.
Definition: res_xmpp.c:3525
static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
Internal function called when a presence message is received.
Definition: res_xmpp.c:3263
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
static int xmpp_is_secure(struct ast_xmpp_client *client)
Helper function which returns whether an XMPP client connection is secure or not. ...
Definition: res_xmpp.c:872
struct timeval arrived
Definition: xmpp.h:105
int ast_publish_mwi_state_full(const char *mailbox, const char *context, int new_msgs, int old_msgs, const char *channel_id, struct ast_eid *eid)
Publish a MWI state update via stasis with all parameters.
Definition: mwi.c:393
Their was an error and no changes were applied.
void ast_sha1_hash(char *output, const char *input)
Produces SHA1 hash based on input string.
Definition: utils.c:266
static int xmpp_resource_immediate(void *obj, void *arg, int flags)
Internal astobj2 callback function which returns the first resource, which is the highest priority on...
Definition: res_xmpp.c:1622
static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
Internal function which sends a raw message.
Definition: res_xmpp.c:2489
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
Definition: devicestate.c:255
int ast_msg_queue(struct ast_msg *msg)
Queue a message for routing through the dialplan.
Definition: main/message.c:972
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
static iks * xmpp_pubsub_build_node_request(struct ast_xmpp_client *client, const char *collection)
Build the a node request.
Definition: res_xmpp.c:3974
const ast_string_field name
Definition: res_xmpp.c:462
unsigned int subscribe
Definition: xmpp.h:115
XMPP Resource.
Definition: xmpp.h:92
Configuration option-handling.
int ast_publish_device_state_full(const char *device, enum ast_device_state state, enum ast_devstate_cache cachable, struct ast_eid *eid)
Publish a device state update with EID.
Definition: devicestate.c:709
int new_msgs
Definition: mwi.h:459
char * message
Definition: xmpp.h:103
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
struct stasis_cache * ast_device_state_cache(void)
Backend cache for ast_device_state_topic_cached()
Definition: devicestate.c:673
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: utils.c:2199
XMPP Message.
Definition: xmpp.h:101
static void xmpp_pubsub_create_affiliations(struct ast_xmpp_client *client, const char *node)
Add Owner affiliations for pubsub node.
Definition: res_xmpp.c:1161
int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
Encode data in base64.
Definition: utils.c:406
static int load_module(void)
Load the module.
Definition: res_xmpp.c:4619
Defined handlers for different PAK types.
Definition: res_xmpp.c:507
static iks * xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, const char *node, const char *event_type, unsigned int cachable)
Build the skeleton of a publish.
Definition: res_xmpp.c:1077
static int xmpp_pubsub_receive_node_list(void *data, ikspak *pak)
Receive pubsub item lists.
Definition: res_xmpp.c:3998
int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
Unregister a message technology.
static int xmpp_buddy_hash(const void *obj, const int flags)
Hashing function for XMPP buddy.
Definition: res_xmpp.c:578
static void xmpp_message_destroy(struct ast_xmpp_message *message)
Destroy function for XMPP messages.
Definition: res_xmpp.c:538
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
static void xmpp_config_destructor(void *obj)
Destructor for XMPP configuration.
Definition: res_xmpp.c:708
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
static int xmpp_ping_request(struct ast_xmpp_client *client, const char *to, const char *from)
Helper function which sends a ping request to a server.
Definition: res_xmpp.c:3229
struct ast_xmpp_client * client
Definition: res_xmpp.c:469
unsigned int jingle
Definition: xmpp.h:87
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
static int xmpp_config_cmp(void *obj, void *arg, int flags)
Comparator function for configuration.
Definition: res_xmpp.c:716
static int xmpp_send_stream_header(struct ast_xmpp_client *client, const struct ast_xmpp_client_config *cfg, const char *to)
Helper function which sends an XMPP stream header to the server.
Definition: res_xmpp.c:2522
static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char *mailbox, const char *oldmsgs, const char *newmsgs)
Publish MWI to a PubSub node.
Definition: res_xmpp.c:1269
char version[50]
Definition: xmpp.h:86
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
struct stasis_message_type * ast_mwi_state_type(void)
Get the Stasis Message Bus API message type for MWI messages.
A message technology.
Definition: message.h:52
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:971
const ast_string_field context
Definition: res_xmpp.c:462
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:668
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
static void xmpp_pubsub_create_node(struct ast_xmpp_client *client, const char *node_type, const char *name, const char *collection_name)
Create a pubsub node.
Definition: res_xmpp.c:1198
struct ast_eid eid
Definition: mwi.h:463
static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incoming)
Logging hook function.
Definition: res_xmpp.c:2471
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
char * command
Definition: cli.h:186
static int xmpp_sendgroup_exec(struct ast_channel *chan, const char *data)
Application to send a message to a groupchat.
Definition: res_xmpp.c:1879
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
XMPP Buddy.
Definition: xmpp.h:112
struct ast_endpoint * endpoint
Definition: xmpp.h:148
static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we receive a response to our TLS initiation request.
Definition: res_xmpp.c:2584
static int xmpp_io_recv(struct ast_xmpp_client *client, char *buffer, size_t buf_len, int timeout)
Internal function which polls on an XMPP client and receives data.
Definition: res_xmpp.c:3614
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1134
static char * xmpp_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to expose PubSub node list via CLI.
Definition: res_xmpp.c:4049
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct aco_type global_option
An aco_type structure to link the "general" category to the skel_global_config type.
Definition: app_skel.c:241
struct ao2_container * resources
Definition: xmpp.h:114
static int xmpp_action_hook(void *data, int type, iks *node)
Action hook for when things occur.
Definition: res_xmpp.c:3455
struct ast_flags general
Definition: res_xmpp.c:445
static int xmpp_client_subscribe_user(void *obj, void *arg, int flags)
Callback function which subscribes to a user if needed.
Definition: res_xmpp.c:2226
structure to hold users read from users.conf
static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, const char *device, const char *device_state, unsigned int cachable)
Publish device state to a PubSub node.
Definition: res_xmpp.c:1300
Structure used to handle boolean flags.
Definition: utils.h:199
const ast_string_field oauth_secret
Definition: res_xmpp.c:462
const ast_string_field name
Definition: xmpp.h:123
const ast_string_field uniqueid
Definition: mwi.h:458
static int xmpp_resource_cmp(void *obj, void *arg, int flags)
Comparator function for XMPP resource.
Definition: res_xmpp.c:853
int ast_msg_set_from(struct ast_msg *msg, const char *fmt,...)
Set the 'from' URI of a message.
Definition: main/message.c:479
const char * usage
Definition: cli.h:177
static void xmpp_client_destructor(void *obj)
Destructor callback function for XMPP client.
Definition: res_xmpp.c:551
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:93
static void xmpp_pubsub_unsubscribe(struct ast_xmpp_client *client, const char *node)
Unsubscribe from a PubSub node.
Definition: res_xmpp.c:1385
static void xmpp_buddy_destructor(void *obj)
Destructor callback function for XMPP buddy.
Definition: res_xmpp.c:862
static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
Internal function called when a subscription message is received.
Definition: res_xmpp.c:3392
int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt,...)
Set the technology's endpoint associated with this message.
Definition: main/message.c:534
const ast_string_field oauth_clientid
Definition: res_xmpp.c:462
static void xmpp_pubsub_create_leaf(struct ast_xmpp_client *client, const char *collection_name, const char *leaf_name)
Create a PubSub leaf node.
Definition: res_xmpp.c:1256
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Standard Command Line Interface.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
int old_msgs
Definition: mwi.h:460
Type information about a category-level configurable object.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235
const char * filename
enum ikshowtype status
Definition: res_xmpp.c:468
static int xmpp_join_exec(struct ast_channel *chan, const char *data)
Application to join a chat room.
Definition: res_xmpp.c:1718
char mid[6]
Definition: xmpp.h:125
Asterisk MWI API.
char id[25]
Definition: xmpp.h:104
static void xmpp_pubsub_delete_node(struct ast_xmpp_client *client, const char *node_name)
Delete a PubSub node.
Definition: res_xmpp.c:1222
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1023
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition: astobj2.h:1600
Abstract JSON element (object, array, string, int, ...).
Type for default option handler for stringfields.
static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
Internal function called when a message is received.
Definition: res_xmpp.c:3117
void ast_xmpp_client_unlock(struct ast_xmpp_client *client)
Unlock an XMPP client connection.
Definition: res_xmpp.c:904
The structure that contains device state.
Definition: devicestate.h:238
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
int ast_eid_is_empty(const struct ast_eid *eid)
Check if EID is empty.
Definition: utils.c:3099
struct ast_xmpp_global_config * global
Definition: res_xmpp.c:474
Generic container type.
A message.
Definition: main/message.c:247
const ast_string_field refresh_token
Definition: res_xmpp.c:462
static int xmpp_client_send_message(struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
Internal function used to send a message to a user or chatroom.
Definition: res_xmpp.c:910
static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we need to authenticate.
Definition: res_xmpp.c:2757
int priority
Definition: xmpp.h:96
struct stasis_topic * ast_mwi_topic_all(void)
Get the Stasis Message Bus API topic for MWI messages.
Definition: mwi.c:89
struct ast_xmpp_capabilities caps
Definition: xmpp.h:97
struct ast_msg * ast_msg_destroy(struct ast_msg *msg)
Destroy an ast_msg.
Definition: main/message.c:462
static int xmpp_component_service_discovery_get_hook(void *data, ikspak *pak)
Hook function called when component receives a service discovery get message.
Definition: res_xmpp.c:2844
const ast_string_field server
Definition: res_xmpp.c:462
The structure that contains MWI state.
Definition: mwi.h:455
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
void ast_endpoint_shutdown(struct ast_endpoint *endpoint)
Shutsdown an ast_endpoint.
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
Definition: astobj2.h:847
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:253
static void * xmpp_client_find_or_create(const char *category)
Look up existing client or create a new one.
Definition: res_xmpp.c:663
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
void ast_xmpp_client_unref(struct ast_xmpp_client *client)
Release XMPP client connection reference.
Definition: res_xmpp.c:894
XMPP Global Configuration.
Definition: res_xmpp.c:444
static void xmpp_client_change_state(struct ast_xmpp_client *client, int state)
Internal function which changes the XMPP client state.
Definition: res_xmpp.c:596
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
#define CONFIG_INFO_STANDARD(name, arr, alloc,...)
Declare an aco_info struct with default module and preload values.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we authenticated as a component.
Definition: res_xmpp.c:3090
static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we should authenticate as a component.
Definition: res_xmpp.c:2824
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
struct ast_flags mod_flags
Definition: res_xmpp.c:467
static iks * xmpp_pubsub_iq_create(struct ast_xmpp_client *client, const char *type)
Create an IQ packet.
Definition: res_xmpp.c:1045
char * description
Definition: xmpp.h:95
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
int ast_xmpp_client_send(struct ast_xmpp_client *client, iks *stanza)
Send an XML stanza out using an established XMPP client connection.
Definition: res_xmpp.c:2534
struct ao2_container * clients
Definition: res_xmpp.c:475
Structure for mutex and tracking information.
Definition: lock.h:135
static int xmpp_resource_is_available(void *obj, void *arg, int flags)
Callback function which returns when the resource is available.
Definition: res_xmpp.c:3221
int ast_xmpp_client_send_message(struct ast_xmpp_client *client, const char *user, const char *message)
Send a message to a given user using an established XMPP client connection.
Definition: res_xmpp.c:938
#define AST_APP_ARG(name)
Define an application argument.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
static int xmpp_connect_hook(void *data, ikspak *pak)
Hook function called when client finishes authenticating with the server.
Definition: res_xmpp.c:2433