Argh, mixed declarations and code.
[asterisk/asterisk.git] / res / res_jabber.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2010, Digium, Inc.
5  *
6  * Matt O'Gorman <mogorman@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  * \brief A resource for interfacing Asterisk directly as a client
21  * or a component to a XMPP/Jabber compliant server.
22  *
23  * References:
24  * - http://www.xmpp.org - The XMPP standards foundation
25  *
26  * \extref Iksemel http://code.google.com/p/iksemel/
27  *
28  * \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
29  * \todo Dialplan applications need RETURN variable, like JABBERSENDSTATUS
30  *
31  */
32
33 /*** MODULEINFO
34         <depend>iksemel</depend>
35         <use>openssl</use>
36  ***/
37
38 #include "asterisk.h"
39
40 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
41
42 #include <ctype.h>
43 #include <iksemel.h>
44
45 #include "asterisk/channel.h"
46 #include "asterisk/jabber.h"
47 #include "asterisk/file.h"
48 #include "asterisk/config.h"
49 #include "asterisk/callerid.h"
50 #include "asterisk/lock.h"
51 #include "asterisk/cli.h"
52 #include "asterisk/app.h"
53 #include "asterisk/pbx.h"
54 #include "asterisk/md5.h"
55 #include "asterisk/acl.h"
56 #include "asterisk/utils.h"
57 #include "asterisk/module.h"
58 #include "asterisk/astobj.h"
59 #include "asterisk/astdb.h"
60 #include "asterisk/manager.h"
61 #include "asterisk/event.h"
62 #include "asterisk/devicestate.h"
63
64 /*** DOCUMENTATION
65         <application name="JabberSend" language="en_US">
66                 <synopsis>
67                         Sends an XMPP message to a buddy.
68                 </synopsis>
69                 <syntax>
70                         <parameter name="account" required="true">
71                                 <para>The local named account to listen on (specified in
72                                 jabber.conf)</para>
73                         </parameter>
74                         <parameter name="jid" required="true">
75                                 <para>Jabber ID of the buddy to send the message to. It can be a
76                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
77                         </parameter>
78                         <parameter name="message" required="true">
79                                 <para>The message to send.</para>
80                         </parameter>
81                 </syntax>
82                 <description>
83                         <para>Sends the content of <replaceable>message</replaceable> as text message
84                         from the given <replaceable>account</replaceable> to the buddy identified by
85                         <replaceable>jid</replaceable></para>
86                         <para>Example: JabberSend(asterisk,bob@domain.com,Hello world) sends "Hello world"
87                         to <replaceable>bob@domain.com</replaceable> as an XMPP message from the account
88                         <replaceable>asterisk</replaceable>, configured in jabber.conf.</para>
89                 </description>
90                 <see-also>
91                         <ref type="function">JABBER_STATUS</ref>
92                         <ref type="function">JABBER_RECEIVE</ref>
93                 </see-also>
94         </application>
95         <function name="JABBER_RECEIVE" language="en_US">
96                 <synopsis>
97                         Reads XMPP messages.
98                 </synopsis>
99                 <syntax>
100                         <parameter name="account" required="true">
101                                 <para>The local named account to listen on (specified in
102                                 jabber.conf)</para>
103                         </parameter>
104                         <parameter name="jid" required="true">
105                                 <para>Jabber ID of the buddy to receive message from. It can be a
106                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
107                         </parameter>
108                         <parameter name="timeout">
109                                 <para>In seconds, defaults to <literal>20</literal>.</para>
110                         </parameter>
111                 </syntax>
112                 <description>
113                         <para>Receives a text message on the given <replaceable>account</replaceable>
114                         from the buddy identified by <replaceable>jid</replaceable> and returns the contents.</para>
115                         <para>Example: ${JABBER_RECEIVE(asterisk,bob@domain.com)} returns an XMPP message
116                         sent from <replaceable>bob@domain.com</replaceable> (or nothing in case of a time out), to
117                         the <replaceable>asterisk</replaceable> XMPP account configured in jabber.conf.</para>
118                 </description>
119                 <see-also>
120                         <ref type="function">JABBER_STATUS</ref>
121                         <ref type="application">JabberSend</ref>
122                 </see-also>
123         </function>
124         <function name="JABBER_STATUS" language="en_US">
125                 <synopsis>
126                         Retrieves a buddy's status.
127                 </synopsis>
128                 <syntax>
129                         <parameter name="account" required="true">
130                                 <para>The local named account to listen on (specified in
131                                 jabber.conf)</para>
132                         </parameter>
133                         <parameter name="jid" required="true">
134                                 <para>Jabber ID of the buddy to receive message from. It can be a
135                                 bare JID (username@domain) or a full JID (username@domain/resource).</para>
136                         </parameter>
137                 </syntax>
138                 <description>
139                         <para>Retrieves the numeric status associated with the buddy identified
140                         by <replaceable>jid</replaceable>.
141                         If the buddy does not exist in the buddylist, returns 7.</para>
142                         <para>Status will be 1-7.</para>
143                         <para>1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline</para>
144                         <para>If not in roster variable will be set to 7.</para>
145                         <para>Example: ${JABBER_STATUS(asterisk,bob@domain.com)} returns 1 if
146                         <replaceable>bob@domain.com</replaceable> is online. <replaceable>asterisk</replaceable> is
147                         the associated XMPP account configured in jabber.conf.</para>
148                 </description>
149                 <see-also>
150                         <ref type="function">JABBER_RECEIVE</ref>
151                         <ref type="application">JabberSend</ref>
152                 </see-also>
153         </function>
154         <application name="JabberSendGroup" language="en_US">
155                 <synopsis>
156                         Send a Jabber Message to a specified chat room
157                 </synopsis>
158                 <syntax>
159                         <parameter name="Jabber" required="true">
160                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
161                         </parameter>
162                         <parameter name="RoomJID" required="true">
163                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
164                         </parameter>
165                         <parameter name="Message" required="true">
166                                 <para>Message to be sent to the chat room.</para>
167                         </parameter>
168                         <parameter name="Nickname" required="false">
169                                 <para>The nickname Asterisk uses in the chat room.</para>
170                         </parameter>
171                 </syntax>
172                 <description>
173                         <para>Allows user to send a message to a chat room via XMPP.</para>
174                         <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>
175                 </description>
176         </application>
177         <application name="JabberJoin" language="en_US">
178                 <synopsis>
179                         Join a chat room
180                 </synopsis>
181                 <syntax>
182                         <parameter name="Jabber" required="true">
183                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
184                         </parameter>
185                         <parameter name="RoomJID" required="true">
186                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
187                         </parameter>
188                         <parameter name="Nickname" required="false">
189                                 <para>The nickname Asterisk will use in the chat room.</para>
190                                 <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>
191                         </parameter>
192                 </syntax>
193                 <description>
194                         <para>Allows Asterisk to join a chat room.</para>
195                 </description>
196         </application>
197         <application name="JabberLeave" language="en_US">
198                 <synopsis>
199                         Leave a chat room
200                 </synopsis>
201                 <syntax>
202                         <parameter name="Jabber" required="true">
203                                 <para>Client or transport Asterisk uses to connect to Jabber.</para>
204                         </parameter>
205                         <parameter name="RoomJID" required="true">
206                                 <para>XMPP/Jabber JID (Name) of chat room.</para>
207                         </parameter>
208                         <parameter name="Nickname" required="false">
209                                 <para>The nickname Asterisk uses in the chat room.</para>
210                         </parameter>
211                 </syntax>
212                 <description>
213                         <para>Allows Asterisk to leave a chat room.</para>
214                 </description>
215         </application>
216         <application name="JabberStatus" language="en_US">
217                 <synopsis>
218                         Retrieve the status of a jabber list member
219                 </synopsis>
220                 <syntax>
221                         <parameter name="Jabber" required="true">
222                                 <para>Client or transport Asterisk users to connect to Jabber.</para>
223                         </parameter>
224                         <parameter name="JID" required="true">
225                                 <para>XMPP/Jabber JID (Name) of recipient.</para>
226                         </parameter>
227                         <parameter name="Variable" required="true">
228                                 <para>Variable to store the status of requested user.</para>
229                         </parameter>
230                 </syntax>
231                 <description>
232                         <para>This application is deprecated. Please use the JABBER_STATUS() function instead.</para>
233                         <para>Retrieves the numeric status associated with the specified buddy <replaceable>JID</replaceable>.
234                         The return value in the <replaceable>Variable</replaceable>will be one of the following.</para>
235                         <enumlist>
236                                 <enum name="1">
237                                         <para>Online.</para>
238                                 </enum>
239                                 <enum name="2">
240                                         <para>Chatty.</para>
241                                 </enum>
242                                 <enum name="3">
243                                         <para>Away.</para>
244                                 </enum>
245                                 <enum name="4">
246                                         <para>Extended Away.</para>
247                                 </enum>
248                                 <enum name="5">
249                                         <para>Do Not Disturb.</para>
250                                 </enum>
251                                 <enum name="6">
252                                         <para>Offline.</para>
253                                 </enum>
254                                 <enum name="7">
255                                         <para>Not In Roster.</para>
256                                 </enum>
257                         </enumlist>
258                 </description>
259         </application>
260         <manager name="JabberSend" language="en_US">
261                 <synopsis>
262                         Sends a message to a Jabber Client.
263                 </synopsis>
264                 <syntax>
265                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
266                         <parameter name="Jabber" required="true">
267                                 <para>Client or transport Asterisk uses to connect to JABBER.</para>
268                         </parameter>
269                         <parameter name="JID" required="true">
270                                 <para>XMPP/Jabber JID (Name) of recipient.</para>
271                         </parameter>
272                         <parameter name="Message" required="true">
273                                 <para>Message to be sent to the buddy.</para>
274                         </parameter>
275                 </syntax>
276                 <description>
277                         <para>Sends a message to a Jabber Client.</para>
278                 </description>
279         </manager>
280  ***/
281
282 /*!\todo This should really be renamed to xmpp.conf. For backwards compatibility, we
283  * need to read both files */
284 #define JABBER_CONFIG "jabber.conf"
285
286 /*-- Forward declarations */
287 static void aji_message_destroy(struct aji_message *obj);
288 static void aji_buddy_destroy(struct aji_buddy *obj);
289 static void aji_client_destroy(struct aji_client *obj);
290 static int aji_is_secure(struct aji_client *client);
291 #ifdef HAVE_OPENSSL
292 static int aji_start_tls(struct aji_client *client);
293 static int aji_tls_handshake(struct aji_client *client);
294 #endif
295 static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout);
296 static int aji_recv(struct aji_client *client, int timeout);
297 static int aji_send_header(struct aji_client *client, const char *to);
298 static int aji_send_raw(struct aji_client *client, const char *xmlstr);
299 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
300 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass);
301 static int aji_act_hook(void *data, int type, iks *node);
302 static void aji_handle_iq(struct aji_client *client, iks *node);
303 static void aji_handle_message(struct aji_client *client, ikspak *pak);
304 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
305 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
306 static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message);
307 static void *aji_recv_loop(void *data);
308 static int aji_initialize(struct aji_client *client);
309 static int aji_client_connect(void *data, ikspak *pak);
310 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
311 static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc);
312 static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
313 static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
314 static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
315 static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
316 static char *aji_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
317 static int aji_create_client(char *label, struct ast_variable *var, int debug);
318 static int aji_create_buddy(char *label, struct aji_client *client);
319 static int aji_reload(int reload);
320 static int aji_load_config(int reload);
321 static void aji_pruneregister(struct aji_client *client);
322 static int aji_filter_roster(void *data, ikspak *pak);
323 static int aji_get_roster(struct aji_client *client);
324 static int aji_client_info_handler(void *data, ikspak *pak);
325 static int aji_dinfo_handler(void *data, ikspak *pak);
326 static int aji_ditems_handler(void *data, ikspak *pak);
327 static int aji_register_query_handler(void *data, ikspak *pak);
328 static int aji_register_approve_handler(void *data, ikspak *pak);
329 static int aji_reconnect(struct aji_client *client);
330 static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd,
331         struct ast_cli_args *a);
332 static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd,
333         struct ast_cli_args *a);
334 static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
335         ast_cli_args *a);
336 static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
337                 ast_cli_args *a);
338 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
339 static int aji_receive_node_list(void *data, ikspak* pak);
340 static void aji_init_event_distribution(struct aji_client *client);
341 static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type,
342         const char *name, const char *collection_name);
343 static iks* aji_build_node_config(iks *pubsub, const char *node_type,
344         const char *collection_name);
345 static void aji_create_pubsub_collection(struct aji_client *client,
346         const char *collection_name);
347 static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name,
348    const char *leaf_name);
349 static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd,
350         struct ast_cli_args *a);
351 static void aji_create_affiliations(struct aji_client *client, const char *node);
352 static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type);
353 static void aji_publish_device_state(struct aji_client *client, const char * device,
354         const char *device_state);
355 static int aji_handle_pubsub_error(void *data, ikspak *pak);
356 static int aji_handle_pubsub_event(void *data, ikspak *pak);
357 static void aji_pubsub_subscribe(struct aji_client *client, const char *node);
358 static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name);
359 static iks* aji_build_node_request(struct aji_client *client, const char *collection);
360 static int aji_delete_node_list(void *data, ikspak* pak);
361 static void aji_pubsub_purge_nodes(struct aji_client *client,
362         const char* collection_name);
363 static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
364         const char *context, const char *oldmsgs, const char *newmsgs);
365 static void aji_devstate_cb(const struct ast_event *ast_event, void *data);
366 static void aji_mwi_cb(const struct ast_event *ast_event, void *data);
367 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
368         const char *event_type);
369 /* No transports in this version */
370 /*
371 static int aji_create_transport(char *label, struct aji_client *client);
372 static int aji_register_transport(void *data, ikspak *pak);
373 static int aji_register_transport2(void *data, ikspak *pak);
374 */
375
376 static struct ast_cli_entry aji_cli[] = {
377         AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug"),
378         AST_CLI_DEFINE(aji_do_reload, "Reload Jabber configuration"),
379         AST_CLI_DEFINE(aji_show_clients, "Show state of clients and components"),
380         AST_CLI_DEFINE(aji_show_buddies, "Show buddy lists of our clients"),
381         AST_CLI_DEFINE(aji_test, "Shows roster, but is generally used for mog's debugging."),
382         AST_CLI_DEFINE(aji_cli_create_collection, "Creates a PubSub node collection."),
383         AST_CLI_DEFINE(aji_cli_list_pubsub_nodes, "Lists PubSub nodes"),
384         AST_CLI_DEFINE(aji_cli_create_leafnode, "Creates a PubSub leaf node"),
385         AST_CLI_DEFINE(aji_cli_delete_pubsub_node, "Deletes a PubSub node"),
386         AST_CLI_DEFINE(aji_cli_purge_pubsub_nodes, "Purges PubSub nodes"),
387 };
388
389 static char *app_ajisend = "JabberSend";
390 static char *app_ajisendgroup = "JabberSendGroup";
391 static char *app_ajistatus = "JabberStatus";
392 static char *app_ajijoin = "JabberJoin";
393 static char *app_ajileave = "JabberLeave";
394
395 static struct aji_client_container clients;
396 static struct aji_capabilities *capabilities = NULL;
397 static struct ast_event_sub *mwi_sub = NULL;
398 static struct ast_event_sub *device_state_sub = NULL;
399 static ast_cond_t message_received_condition;
400 static ast_mutex_t messagelock;
401
402 /*! \brief Global flags, initialized to default values */
403 static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT };
404
405 /*! \brief PubSub flags, initialized to default values */
406 static struct ast_flags pubsubflags = { AJI_AUTOREGISTER };
407 /*!
408  * \internal
409  * \brief Deletes the aji_client data structure.
410  * \param obj aji_client The structure we will delete.
411  * \return void.
412  */
413 static void aji_client_destroy(struct aji_client *obj)
414 {
415         struct aji_message *tmp;
416         ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
417         ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
418         iks_filter_delete(obj->f);
419         iks_parser_delete(obj->p);
420         iks_stack_delete(obj->stack);
421         AST_LIST_LOCK(&obj->messages);
422         while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
423                 aji_message_destroy(tmp);
424         }
425         AST_LIST_HEAD_DESTROY(&obj->messages);
426         ast_free(obj);
427 }
428
429 /*!
430  * \internal
431  * \brief Deletes the aji_buddy data structure.
432  * \param obj aji_buddy The structure we will delete.
433  * \return void.
434  */
435 static void aji_buddy_destroy(struct aji_buddy *obj)
436 {
437         struct aji_resource *tmp;
438
439         while ((tmp = obj->resources)) {
440                 obj->resources = obj->resources->next;
441                 ast_free(tmp->description);
442                 ast_free(tmp);
443         }
444
445         ast_free(obj);
446 }
447
448 /*!
449  * \internal
450  * \brief Deletes the aji_message data structure.
451  * \param obj aji_message The structure we will delete.
452  * \return void.
453  */
454 static void aji_message_destroy(struct aji_message *obj)
455 {
456         if (obj->from) {
457                 ast_free(obj->from);
458         }
459         if (obj->message) {
460                 ast_free(obj->message);
461         }
462         ast_free(obj);
463 }
464
465 /*!
466  * \internal
467  * \brief Find version in XML stream and populate our capabilities list
468  * \param node the node attribute in the caps element we'll look for or add to
469  * our list
470  * \param version the version attribute in the caps element we'll look for or
471  * add to our list
472  * \param pak struct The XML stanza we're processing
473  * \return a pointer to the added or found aji_version structure
474  */
475 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
476 {
477         struct aji_capabilities *list = NULL;
478         struct aji_version *res = NULL;
479
480         list = capabilities;
481
482         if (!node) {
483                 node = pak->from->full;
484         }
485         if (!version) {
486                 version = "none supplied.";
487         }
488         while (list) {
489                 if (!strcasecmp(list->node, node)) {
490                         res = list->versions;
491                         while(res) {
492                                 if (!strcasecmp(res->version, version)) {
493                                         return res;
494                                 }
495                                 res = res->next;
496                         }
497                         /* Specified version not found. Let's add it to
498                            this node in our capabilities list */
499                         if (!res) {
500                                 res = ast_malloc(sizeof(*res));
501                                 if (!res) {
502                                         ast_log(LOG_ERROR, "Out of memory!\n");
503                                         return NULL;
504                                 }
505                                 res->jingle = 0;
506                                 res->parent = list;
507                                 ast_copy_string(res->version, version, sizeof(res->version));
508                                 res->next = list->versions;
509                                 list->versions = res;
510                                 return res;
511                         }
512                 }
513                 list = list->next;
514         }
515         /* Specified node not found. Let's add it our capabilities list */
516         if (!list) {
517                 list = ast_malloc(sizeof(*list));
518                 if (!list) {
519                         ast_log(LOG_ERROR, "Out of memory!\n");
520                         return NULL;
521                 }
522                 res = ast_malloc(sizeof(*res));
523                 if (!res) {
524                         ast_log(LOG_ERROR, "Out of memory!\n");
525                         ast_free(list);
526                         return NULL;
527                 }
528                 ast_copy_string(list->node, node, sizeof(list->node));
529                 ast_copy_string(res->version, version, sizeof(res->version));
530                 res->jingle = 0;
531                 res->parent = list;
532                 res->next = NULL;
533                 list->versions = res;
534                 list->next = capabilities;
535                 capabilities = list;
536         }
537         return res;
538 }
539
540 /*!
541  * \internal
542  * \brief Find the aji_resource we want
543  * \param buddy aji_buddy A buddy
544  * \param name
545  * \return aji_resource object
546 */
547 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
548 {
549         struct aji_resource *res = NULL;
550         if (!buddy || !name) {
551                 return res;
552         }
553         res = buddy->resources;
554         while (res) {
555                 if (!strcasecmp(res->resource, name)) {
556                         break;
557                 }
558                 res = res->next;
559         }
560         return res;
561 }
562
563 /*!
564  * \internal
565  * \brief Jabber GTalk function
566  * \param node iks
567  * \return 1 on success, 0 on failure.
568 */
569 static int gtalk_yuck(iks *node)
570 {
571         if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
572                 return 1;
573         }
574         return 0;
575 }
576
577 /*!
578  * \internal
579  * \brief Setup the authentication struct
580  * \param id iksid 
581  * \param pass password
582  * \param sid
583  * \return x iks
584 */
585 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
586 {
587         iks *x, *y;
588         x = iks_new("iq");
589         iks_insert_attrib(x, "type", "set");
590         y = iks_insert(x, "query");
591         iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
592         iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
593         iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
594         if (sid) {
595                 char buf[41];
596                 char sidpass[100];
597                 snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
598                 ast_sha1_hash(buf, sidpass);
599                 iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
600         } else {
601                 iks_insert_cdata(iks_insert(y, "password"), pass, 0);
602         }
603         return x;
604 }
605
606 /*!
607  * \internal
608  * \brief Dial plan function status(). puts the status of watched user 
609  * into a channel variable.
610  * \param chan ast_channel
611  * \param data
612  * \retval 0 success
613  * \retval -1 error
614  */
615 static int aji_status_exec(struct ast_channel *chan, const char *data)
616 {
617         struct aji_client *client = NULL;
618         struct aji_buddy *buddy = NULL;
619         struct aji_resource *r = NULL;
620         char *s = NULL;
621         int stat = 7;
622         char status[2];
623         static int deprecation_warning = 0;
624         AST_DECLARE_APP_ARGS(args,
625                 AST_APP_ARG(sender);
626                 AST_APP_ARG(jid);
627                 AST_APP_ARG(variable);
628         );
629         AST_DECLARE_APP_ARGS(jid,
630                 AST_APP_ARG(screenname);
631                 AST_APP_ARG(resource);
632         );
633
634         if (deprecation_warning++ % 10 == 0) {
635                 ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
636         }
637
638         if (!data) {
639                 ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
640                 return 0;
641         }
642         s = ast_strdupa(data);
643         AST_STANDARD_APP_ARGS(args, s);
644
645         if (args.argc != 3) {
646                 ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
647                 return -1;
648         }
649
650         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
651         if (jid.argc < 1 || jid.argc > 2) {
652                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
653                 return -1;
654         }
655
656         if (!(client = ast_aji_get_client(args.sender))) {
657                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
658                 return -1;
659         }
660         buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
661         if (!buddy) {
662                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
663                 return -1;
664         }
665         r = aji_find_resource(buddy, jid.resource);
666         if (!r && buddy->resources) {
667                 r = buddy->resources;
668         }
669         if (!r) {
670                 ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
671         } else {
672                 stat = r->status;
673         }
674         snprintf(status, sizeof(status), "%d", stat);
675         pbx_builtin_setvar_helper(chan, args.variable, status);
676         return 0;
677 }
678
679 /*!
680  * \internal
681  * \brief Dial plan funtcion to retrieve the status of a buddy.
682  * \param channel The associated ast_channel, if there is one
683  * \param data The account, buddy JID, and optional timeout
684  * timeout.
685  * \retval 0 success
686  * \retval -1 failure
687  */
688 static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
689 {
690         struct aji_client *client = NULL;
691         struct aji_buddy *buddy = NULL;
692         struct aji_resource *r = NULL;
693         int stat = 7;
694         AST_DECLARE_APP_ARGS(args,
695                 AST_APP_ARG(sender);
696                 AST_APP_ARG(jid);
697         );
698         AST_DECLARE_APP_ARGS(jid,
699                 AST_APP_ARG(screenname);
700                 AST_APP_ARG(resource);
701         );
702
703         if (!data) {
704                 ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
705                 return 0;
706         }
707         AST_STANDARD_APP_ARGS(args, data);
708
709         if (args.argc != 2) {
710                 ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
711                 return -1;
712         }
713
714         AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
715         if (jid.argc < 1 || jid.argc > 2) {
716                 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
717                 return -1;
718         }
719
720         if (!(client = ast_aji_get_client(args.sender))) {
721                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
722                 return -1;
723         }
724         buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
725         if (!buddy) {
726                 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
727                 return -1;
728         }
729         r = aji_find_resource(buddy, jid.resource);
730         if (!r && buddy->resources) {
731                 r = buddy->resources;
732         }
733         if (!r) {
734                 ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
735         } else {
736                 stat = r->status;
737         }
738         snprintf(buf, buflen, "%d", stat);
739         return 0;
740 }
741
742 static struct ast_custom_function jabberstatus_function = {
743         .name = "JABBER_STATUS",
744         .read = acf_jabberstatus_read,
745 };
746
747 /*!
748  * \internal
749  * \brief Dial plan function to receive a message.
750  * \param channel The associated ast_channel, if there is one
751  * \param data The account, JID, and optional timeout
752  * timeout.
753  * \retval 0 success
754  * \retval -1 failure
755  */
756 static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
757 {
758         char *aux = NULL, *parse = NULL;
759         int timeout;
760         int jidlen, resourcelen;
761         struct timeval start;
762         long diff = 0;
763         struct aji_client *client = NULL;
764         int found = 0;
765         struct aji_message *tmp = NULL;
766         AST_DECLARE_APP_ARGS(args,
767                         AST_APP_ARG(account);
768                         AST_APP_ARG(jid);
769                         AST_APP_ARG(timeout);
770                         );
771         AST_DECLARE_APP_ARGS(jid,
772                         AST_APP_ARG(screenname);
773                         AST_APP_ARG(resource);
774         );
775
776         if (ast_strlen_zero(data)) {
777                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
778                 return -1;
779         }
780
781         parse = ast_strdupa(data);
782         AST_STANDARD_APP_ARGS(args, parse);
783
784         if (args.argc < 2 || args.argc > 3) {
785                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
786                 return -1;
787         }
788
789         client = ast_aji_get_client(args.account);
790         if (!client) {
791                 ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
792                 return -1;
793         }
794
795         parse = ast_strdupa(args.jid);
796         AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
797         if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) {
798                 ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
799                 ASTOBJ_UNREF(client, aji_client_destroy);
800                 return -1;
801         }
802
803         if (ast_strlen_zero(args.timeout)) {
804                 timeout = 20;
805         } else {
806                 sscanf(args.timeout, "%d", &timeout);
807                 if (timeout <= 0) {
808                         ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
809                         ASTOBJ_UNREF(client, aji_client_destroy);
810                         return -1;
811                 }
812         }
813
814         jidlen = strlen(jid.screenname);
815         resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
816
817         ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
818
819         start = ast_tvnow();
820
821         if (ast_autoservice_start(chan) < 0) {
822                 ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", chan->name);
823                 return -1;
824         }
825
826         /* search the messages list, grab the first message that matches with
827          * the from JID we're expecting, and remove it from the messages list */
828         while (diff < timeout) {
829                 struct timespec ts = { 0, };
830                 struct timeval wait;
831                 int res;
832
833                 wait = ast_tvadd(start, ast_tv(timeout, 0));
834                 ts.tv_sec = wait.tv_sec;
835                 ts.tv_nsec = wait.tv_usec * 1000;
836
837                 /* wait up to timeout seconds for an incoming message */
838                 ast_mutex_lock(&messagelock);
839                 res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
840                 ast_mutex_unlock(&messagelock);
841                 if (res == ETIMEDOUT) {
842                         ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
843                         break;
844                 }
845
846                 AST_LIST_LOCK(&client->messages);
847                 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
848                         if (jid.argc == 1) {
849                                 /* no resource provided, compare bare JIDs */
850                                 if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
851                                         continue;
852                                 }
853                         } else {
854                                 /* resource appended, compare bare JIDs and resources */
855                                 char *resource = strchr(tmp->from, '/');
856                                 if (!resource || strlen(resource) == 0) {
857                                         ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", tmp->from);
858                                         if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
859                                                 continue;
860                                         }
861                                 } else {
862                                         resource ++;
863                                         if (strncasecmp(jid.screenname, tmp->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
864                                                 continue;
865                                         }
866                                 }
867                         }
868                         /* check if the message is not too old */
869                         if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
870                                 ast_debug(3, "Found old message from %s, deleting it\n", tmp->from);
871                                 AST_LIST_REMOVE_CURRENT(list);
872                                 aji_message_destroy(tmp);
873                                 continue;
874                         }
875                         found = 1;
876                         aux = ast_strdupa(tmp->message);
877                         AST_LIST_REMOVE_CURRENT(list);
878                         aji_message_destroy(tmp);
879                         break;
880                 }
881                 AST_LIST_TRAVERSE_SAFE_END;
882                 AST_LIST_UNLOCK(&client->messages);
883                 if (found) {
884                         break;
885                 }
886
887                 /* check timeout */
888                 diff = ast_tvdiff_ms(ast_tvnow(), start);
889         }
890
891         ASTOBJ_UNREF(client, aji_client_destroy);
892         if (ast_autoservice_stop(chan) < 0) {
893                 ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", chan->name);
894         }
895
896         /* return if we timed out */
897         if (!found) {
898                 ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
899                 return -1;
900         }
901         ast_copy_string(buf, aux, buflen);
902
903         return 0;
904 }
905
906 static struct ast_custom_function jabberreceive_function = {
907         .name = "JABBER_RECEIVE",
908         .read = acf_jabberreceive_read,
909 };
910
911 /*!
912  * \internal
913  * \brief Delete old messages from a given JID
914  * Messages stored during more than client->message_timeout are deleted
915  * \param client Asterisk's XMPP client
916  * \param from the JID we received messages from
917  * \retval the number of deleted messages
918  * \retval -1 failure
919  */
920 static int delete_old_messages(struct aji_client *client, char *from)
921 {
922         int deleted = 0;
923         int isold = 0;
924         struct aji_message *tmp = NULL;
925         if (!client) {
926                 ast_log(LOG_ERROR, "Cannot find our XMPP client\n");
927                 return -1;
928         }
929
930         /* remove old messages */
931         AST_LIST_LOCK(&client->messages);
932         if (AST_LIST_EMPTY(&client->messages)) {
933                 AST_LIST_UNLOCK(&client->messages);
934                 return 0;
935         }
936
937         AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
938                 if (isold) {
939                         if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
940                                 AST_LIST_REMOVE_CURRENT(list);
941                                 aji_message_destroy(tmp);
942                                 deleted ++;
943                         }
944                 } else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
945                         isold = 1;
946                         if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
947                                 AST_LIST_REMOVE_CURRENT(list);
948                                 aji_message_destroy(tmp);
949                                 deleted ++;
950                         }
951                 }
952         }
953         AST_LIST_TRAVERSE_SAFE_END;
954         AST_LIST_UNLOCK(&client->messages);
955
956         return deleted;
957 }
958
959 /*!
960  * \internal
961  * \brief Delete old messages
962  * Messages stored during more than client->message_timeout are deleted
963  * \param client Asterisk's XMPP client
964  * \retval the number of deleted messages
965  * \retval -1 failure
966  */
967 static int delete_old_messages_all(struct aji_client *client)
968 {
969         return delete_old_messages(client, NULL);
970 }
971
972 /*!
973 * \brief Application to join a chat room
974 * \param chan ast_channel
975 * \param data  Data is sender|jid|nickname.
976 * \retval 0 success
977 * \retval -1 error
978 */
979 static int aji_join_exec(struct ast_channel *chan, const char *data)
980 {
981         struct aji_client *client = NULL;
982         char *s;
983         char nick[AJI_MAX_RESJIDLEN];
984
985         AST_DECLARE_APP_ARGS(args,
986                 AST_APP_ARG(sender);
987                 AST_APP_ARG(jid);
988                 AST_APP_ARG(nick);
989         );
990
991         if (!data) {
992                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
993                 return -1;
994         }
995         s = ast_strdupa(data);
996
997         AST_STANDARD_APP_ARGS(args, s);
998         if (args.argc < 2 || args.argc > 3) {
999                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1000                 return -1;
1001         }
1002
1003         if (!(client = ast_aji_get_client(args.sender))) {
1004                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1005                 return -1;
1006         }
1007
1008         if (strchr(args.jid, '/')) {
1009                 ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
1010                 ASTOBJ_UNREF(client, aji_client_destroy);
1011                 return -1;
1012         }
1013
1014         if (!ast_strlen_zero(args.nick)) {
1015                 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
1016         } else {
1017                 if (client->component) {
1018                         sprintf(nick, "asterisk");
1019                 } else {
1020                         snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
1021                 }
1022         }
1023
1024         if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
1025                 ast_aji_join_chat(client, args.jid, nick);
1026         } else {
1027                 ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
1028         }
1029
1030         ASTOBJ_UNREF(client, aji_client_destroy);
1031         return 0;
1032 }
1033
1034 /*!
1035 * \brief Application to leave a chat room
1036 * \param chan ast_channel
1037 * \param data  Data is sender|jid|nickname.
1038 * \retval 0 success
1039 * \retval -1 error
1040 */
1041 static int aji_leave_exec(struct ast_channel *chan, const char *data)
1042 {
1043         struct aji_client *client = NULL;
1044         char *s;
1045         char nick[AJI_MAX_RESJIDLEN];
1046         AST_DECLARE_APP_ARGS(args,
1047                 AST_APP_ARG(sender);
1048                 AST_APP_ARG(jid);
1049                 AST_APP_ARG(nick);
1050         );
1051
1052         if (!data) {
1053                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1054                 return -1;
1055         }
1056         s = ast_strdupa(data);
1057
1058         AST_STANDARD_APP_ARGS(args, s);
1059         if (args.argc < 2 || args.argc > 3) {
1060                 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1061                 return -1;
1062         }
1063
1064         if (!(client = ast_aji_get_client(args.sender))) {
1065                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1066                 return -1;
1067         }
1068
1069         if (strchr(args.jid, '/')) {
1070                 ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
1071                 ASTOBJ_UNREF(client, aji_client_destroy);
1072                 return -1;
1073         }
1074         if (!ast_strlen_zero(args.nick)) {
1075                 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
1076         } else {
1077                 if (client->component) {
1078                         sprintf(nick, "asterisk");
1079                 } else {
1080                         snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
1081                 }
1082         }
1083
1084         if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
1085                 ast_aji_leave_chat(client, args.jid, nick);
1086         }
1087         ASTOBJ_UNREF(client, aji_client_destroy);
1088         return 0;
1089 }
1090
1091 /*!
1092  * \internal
1093  * \brief Dial plan function to send a message.
1094  * \param chan ast_channel
1095  * \param data  Data is account,jid,message.
1096  * \retval 0 success
1097  * \retval -1 failure
1098  */
1099 static int aji_send_exec(struct ast_channel *chan, const char *data)
1100 {
1101         struct aji_client *client = NULL;
1102         char *s;
1103         AST_DECLARE_APP_ARGS(args,
1104                 AST_APP_ARG(sender);
1105                 AST_APP_ARG(recipient);
1106                 AST_APP_ARG(message);
1107         );
1108
1109         if (!data) {
1110                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1111                 return -1;
1112         }
1113         s = ast_strdupa(data);
1114
1115         AST_STANDARD_APP_ARGS(args, s);
1116         if (args.argc < 3) {
1117                 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
1118                 return -1;
1119         }
1120
1121         if (!(client = ast_aji_get_client(args.sender))) {
1122                 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
1123                 return -1;
1124         }
1125         if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
1126                 ast_aji_send_chat(client, args.recipient, args.message);
1127         }
1128         return 0;
1129 }
1130
1131 /*!
1132 * \brief Application to send a message to a groupchat.
1133 * \param chan ast_channel
1134 * \param data  Data is sender|groupchat|message.
1135 * \retval 0 success
1136 * \retval -1 error
1137 */
1138 static int aji_sendgroup_exec(struct ast_channel *chan, const char *data)
1139 {
1140         struct aji_client *client = NULL;
1141         char *s;
1142         char nick[AJI_MAX_RESJIDLEN];
1143         int res = 0;
1144         AST_DECLARE_APP_ARGS(args,
1145                 AST_APP_ARG(sender);
1146                 AST_APP_ARG(groupchat);
1147                 AST_APP_ARG(message);
1148                 AST_APP_ARG(nick);
1149         );
1150
1151         if (!data) {
1152                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1153                 return -1;
1154         }
1155         s = ast_strdupa(data);
1156
1157         AST_STANDARD_APP_ARGS(args, s);
1158         if (args.argc < 3 || args.argc > 4) {
1159                 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1160                 return -1;
1161         }
1162
1163         if (!(client = ast_aji_get_client(args.sender))) {
1164                 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
1165                 return -1;
1166         }
1167
1168         if (ast_strlen_zero(args.nick) || args.argc == 3) {
1169                 if (client->component) {
1170                         sprintf(nick, "asterisk");
1171                 } else {
1172                         snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
1173                 }
1174         } else {
1175                 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
1176         }
1177
1178         if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) {
1179                 res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
1180         }
1181
1182         ASTOBJ_UNREF(client, aji_client_destroy);
1183         if (res != IKS_OK) {
1184                 return -1;
1185         }
1186         return 0;
1187 }
1188
1189 /*!
1190  * \internal
1191  * \brief Tests whether the connection is secured or not
1192  * \return 0 if the connection is not secured
1193  */
1194 static int aji_is_secure(struct aji_client *client)
1195 {
1196 #ifdef HAVE_OPENSSL
1197         return client->stream_flags & SECURE;
1198 #else
1199         return 0;
1200 #endif
1201 }
1202
1203 #ifdef HAVE_OPENSSL
1204 /*!
1205  * \internal
1206  * \brief Starts the TLS procedure
1207  * \param client the configured XMPP client we use to connect to a XMPP server
1208  * \return IKS_OK on success, an error code if sending failed, IKS_NET_TLSFAIL
1209  * if OpenSSL is not installed
1210  */
1211 static int aji_start_tls(struct aji_client *client)
1212 {
1213         int ret;
1214
1215         /* This is sent not encrypted */
1216         if ((ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"))) {
1217                 return ret;
1218         }
1219
1220         client->stream_flags |= TRY_SECURE;
1221         return IKS_OK;
1222 }
1223
1224 /*!
1225  * \internal
1226  * \brief TLS handshake, OpenSSL initialization
1227  * \param client the configured XMPP client we use to connect to a XMPP server
1228  * \return IKS_OK on success, IKS_NET_TLSFAIL on failure
1229  */
1230 static int aji_tls_handshake(struct aji_client *client)
1231 {
1232         int ret;
1233         int sock;
1234
1235         ast_debug(1, "Starting TLS handshake\n");
1236
1237         /* Choose an SSL/TLS protocol version, create SSL_CTX */
1238         client->ssl_method = SSLv3_method();
1239         if (!(client->ssl_context = SSL_CTX_new(client->ssl_method))) {
1240                 return IKS_NET_TLSFAIL;
1241         }
1242
1243         /* Create new SSL session */
1244         if (!(client->ssl_session = SSL_new(client->ssl_context))) {
1245                 return IKS_NET_TLSFAIL;
1246         }
1247
1248         /* Enforce TLS on our XMPP connection */
1249         sock = iks_fd(client->p);
1250         if (!(ret = SSL_set_fd(client->ssl_session, sock))) {
1251                 return IKS_NET_TLSFAIL;
1252         }
1253
1254         /* Perform SSL handshake */
1255         if (!(ret = SSL_connect(client->ssl_session))) {
1256                 return IKS_NET_TLSFAIL;
1257         }
1258
1259         client->stream_flags &= (~TRY_SECURE);
1260         client->stream_flags |= SECURE;
1261
1262         /* Sent over the established TLS connection */
1263         if ((ret = aji_send_header(client, client->jid->server)) != IKS_OK) {
1264                 return IKS_NET_TLSFAIL;
1265         }
1266
1267         ast_debug(1, "TLS started with server\n");
1268
1269         return IKS_OK;
1270 }
1271 #endif /* HAVE_OPENSSL */
1272
1273 /*!
1274  * \internal
1275  * \brief Secured or unsecured IO socket receiving function
1276  * \param client the configured XMPP client we use to connect to a XMPP server
1277  * \param buffer the reception buffer
1278  * \param buf_len the size of the buffer
1279  * \param timeout the select timer
1280  * \retval the number of read bytes
1281  * \retval 0 timeout expiration
1282  * \retval -1 error
1283  */
1284 static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
1285 {
1286         int sock;
1287         fd_set fds;
1288         struct timeval tv, *tvptr = NULL;
1289         int len, res;
1290
1291 #ifdef HAVE_OPENSSL
1292         if (aji_is_secure(client)) {
1293                 sock = SSL_get_fd(client->ssl_session);
1294                 if (sock < 0) {
1295                         return -1;
1296                 }
1297         } else
1298 #endif /* HAVE_OPENSSL */
1299                 sock = iks_fd(client->p);
1300
1301         memset(&tv, 0, sizeof(struct timeval));
1302         FD_ZERO(&fds);
1303         FD_SET(sock, &fds);
1304         tv.tv_sec = timeout;
1305
1306         /* NULL value for tvptr makes ast_select wait indefinitely */
1307         tvptr = (timeout != -1) ? &tv : NULL;
1308
1309         /* ast_select emulates linux behaviour in terms of timeout handling */
1310         res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
1311         if (res > 0) {
1312 #ifdef HAVE_OPENSSL
1313                 if (aji_is_secure(client)) {
1314                         len = SSL_read(client->ssl_session, buffer, buf_len);
1315                 } else
1316 #endif /* HAVE_OPENSSL */
1317                         len = recv(sock, buffer, buf_len, 0);
1318
1319                 if (len > 0) {
1320                         return len;
1321                 } else if (len <= 0) {
1322                         return -1;
1323                 }
1324         }
1325         return res;
1326 }
1327
1328 /*!
1329  * \internal
1330  * \brief Tries to receive data from the Jabber server
1331  * \param client the configured XMPP client we use to connect to a XMPP server
1332  * \param timeout the timeout value
1333  * This function receives (encrypted or unencrypted) data from the XMPP server,
1334  * and passes it to the parser.
1335  * \retval IKS_OK success
1336  * \retval IKS_NET_RWERR IO error
1337  * \retval IKS_NET_NOCONN no connection available
1338  * \retval IKS_NET_EXPIRED timeout expiration
1339  */
1340 static int aji_recv (struct aji_client *client, int timeout)
1341 {
1342         int len, ret;
1343         char buf[NET_IO_BUF_SIZE - 1];
1344         char newbuf[NET_IO_BUF_SIZE - 1];
1345         int pos = 0;
1346         int newbufpos = 0;
1347         unsigned char c;
1348
1349         memset(buf, 0, sizeof(buf));
1350         memset(newbuf, 0, sizeof(newbuf));
1351
1352         while (1) {
1353                 len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
1354                 if (len < 0) return IKS_NET_RWERR;
1355                 if (len == 0) return IKS_NET_EXPIRED;
1356                 buf[len] = '\0';
1357
1358                 /* our iksemel parser won't work as expected if we feed
1359                    it with XML packets that contain multiple whitespace
1360                    characters between tags */
1361                 while (pos < len) {
1362                         c = buf[pos];
1363                         /* if we stumble on the ending tag character,
1364                            we skip any whitespace that follows it*/
1365                         if (c == '>') {
1366                                 while (isspace(buf[pos+1])) {
1367                                         pos++;
1368                                 }
1369                         }
1370                         newbuf[newbufpos] = c;
1371                         newbufpos ++;
1372                         pos++;
1373                 }
1374                 pos = 0;
1375                 newbufpos = 0;
1376
1377                 /* Log the message here, because iksemel's logHook is
1378                    unaccessible */
1379                 aji_log_hook(client, buf, len, 1);
1380
1381                 /* let iksemel deal with the string length,
1382                    and reset our buffer */
1383                 ret = iks_parse(client->p, newbuf, 0, 0);
1384                 memset(newbuf, 0, sizeof(newbuf));
1385
1386                 switch (ret) {
1387                 case IKS_NOMEM:
1388                         ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
1389                         break;
1390                 case IKS_BADXML:
1391                         ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
1392                         break;
1393                 case IKS_HOOK:
1394                         ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
1395                         break;
1396                 }
1397                 if (ret != IKS_OK) {
1398                         return ret;
1399                 }
1400                 ast_debug(3, "XML parsing successful\n");
1401         }
1402         return IKS_OK;
1403 }
1404
1405 /*!
1406  * \internal
1407  * \brief Sends XMPP header to the server
1408  * \param client the configured XMPP client we use to connect to a XMPP server
1409  * \param to the target XMPP server
1410  * \return IKS_OK on success, any other value on failure
1411  */
1412 static int aji_send_header(struct aji_client *client, const char *to)
1413 {
1414         char *msg;
1415         int len, err;
1416
1417         len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
1418         msg = iks_malloc(len);
1419         if (!msg)
1420                 return IKS_NOMEM;
1421         sprintf(msg, "<?xml version='1.0'?>"
1422                 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
1423                 "%s' to='%s' version='1.0'>", client->name_space, to);
1424         err = aji_send_raw(client, msg);
1425         iks_free(msg);
1426         if (err != IKS_OK)
1427                 return err;
1428
1429         return IKS_OK;
1430 }
1431
1432 /*!
1433  * \brief Wraps raw sending
1434  * \param client the configured XMPP client we use to connect to a XMPP server
1435  * \param x the XMPP packet to send
1436  * \return IKS_OK on success, any other value on failure
1437  */
1438 int ast_aji_send(struct aji_client *client, iks *x)
1439 {
1440         return aji_send_raw(client, iks_string(iks_stack(x), x));
1441 }
1442
1443 /*!
1444  * \internal
1445  * \brief Sends an XML string over an XMPP connection
1446  * \param client the configured XMPP client we use to connect to a XMPP server
1447  * \param xmlstr the XML string to send
1448  * The XML data is sent whether the connection is secured or not. In the
1449  * latter case, we just call iks_send_raw().
1450  * \return IKS_OK on success, any other value on failure
1451  */
1452 static int aji_send_raw(struct aji_client *client, const char *xmlstr)
1453 {
1454         int ret;
1455 #ifdef HAVE_OPENSSL
1456         int len = strlen(xmlstr);
1457
1458         if (aji_is_secure(client)) {
1459                 ret = SSL_write(client->ssl_session, xmlstr, len);
1460                 if (ret) {
1461                         /* Log the message here, because iksemel's logHook is
1462                            unaccessible */
1463                         aji_log_hook(client, xmlstr, len, 0);
1464                         return IKS_OK;
1465                 }
1466         }
1467 #endif
1468         /* If needed, data will be sent unencrypted, and logHook will
1469            be called inside iks_send_raw */
1470         ret = iks_send_raw(client->p, xmlstr);
1471         if (ret != IKS_OK) {
1472                 return ret;
1473         }
1474
1475         return IKS_OK;
1476 }
1477
1478 /*!
1479  * \internal
1480  * \brief the debug loop.
1481  * \param data void
1482  * \param xmpp xml data as string
1483  * \param size size of string
1484  * \param is_incoming direction of packet 1 for inbound 0 for outbound.
1485  */
1486 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
1487 {
1488         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1489
1490         if (!ast_strlen_zero(xmpp)) {
1491                 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
1492         }
1493
1494         if (client->debug) {
1495                 if (is_incoming) {
1496                         ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
1497                 } else {
1498                         if (strlen(xmpp) == 1) {
1499                                 if (option_debug > 2  && xmpp[0] == ' ') {
1500                                         ast_verbose("\nJABBER: Keep alive packet\n");
1501                                 }
1502                         } else {
1503                                 ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
1504                         }
1505                 }
1506
1507         }
1508         ASTOBJ_UNREF(client, aji_client_destroy);
1509 }
1510
1511 /*!
1512  * \internal
1513  * \brief A wrapper function for iks_start_sasl
1514  * \param client the configured XMPP client we use to connect to a XMPP server
1515  * \param type the SASL authentication type. Supported types are PLAIN and MD5
1516  * \param username
1517  * \param pass password.
1518  *
1519  * \return IKS_OK on success, IKSNET_NOTSUPP on failure.
1520  */
1521 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass)
1522 {
1523         iks *x = NULL;
1524         int len;
1525         char *s;
1526         char *base64;
1527
1528         /* trigger SASL DIGEST-MD5 only over an unsecured connection.
1529            iks_start_sasl is an iksemel API function and relies on GnuTLS,
1530            whereas we use OpenSSL */
1531         if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
1532                 return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); 
1533         if (!(type & IKS_STREAM_SASL_PLAIN)) {
1534                 ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
1535                 return IKS_NET_NOTSUPP;
1536         }
1537
1538         x = iks_new("auth"); 
1539         if (!x) {
1540                 ast_log(LOG_ERROR, "Out of memory.\n");
1541                 return IKS_NET_NOTSUPP;
1542         }
1543
1544         iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
1545         len = strlen(username) + strlen(pass) + 3;
1546         s = alloca(len);
1547         base64 = alloca((len + 2) * 4 / 3);
1548         iks_insert_attrib(x, "mechanism", "PLAIN");
1549         snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
1550
1551         /* exclude the NULL training byte from the base64 encoding operation
1552            as some XMPP servers will refuse it.
1553            The format for authentication is [authzid]\0authcid\0password
1554            not [authzid]\0authcid\0password\0 */
1555         ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
1556         iks_insert_cdata(x, base64, 0);
1557         ast_aji_send(client, x);
1558         iks_delete(x);
1559
1560         return IKS_OK;
1561 }
1562
1563 /*!
1564  * \internal
1565  * \brief The action hook parses the inbound packets, constantly running.
1566  * \param data aji client structure 
1567  * \param type type of packet 
1568  * \param node the actual packet.
1569  * \return IKS_OK or IKS_HOOK .
1570  */
1571 static int aji_act_hook(void *data, int type, iks *node)
1572 {
1573         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1574         ikspak *pak = NULL;
1575         iks *auth = NULL;
1576         int features = 0;
1577
1578         if (!node) {
1579                 ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
1580                 ASTOBJ_UNREF(client, aji_client_destroy);
1581                 return IKS_HOOK;
1582         }
1583
1584         if (client->state == AJI_DISCONNECTING) {
1585                 ASTOBJ_UNREF(client, aji_client_destroy);
1586                 return IKS_HOOK;
1587         }
1588
1589         pak = iks_packet(node);
1590
1591         if (!client->component) { /*client */
1592                 switch (type) {
1593                 case IKS_NODE_START:
1594                         if (client->usetls && !aji_is_secure(client)) {
1595 #ifndef HAVE_OPENSSL
1596                                 ast_log(LOG_ERROR, "OpenSSL not installed. You need to install OpenSSL on this system, or disable the TLS option in your configuration file\n");
1597                                 ASTOBJ_UNREF(client, aji_client_destroy);
1598                                 return IKS_HOOK;
1599 #else
1600                                 if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
1601                                         ast_log(LOG_ERROR, "Could not start TLS\n");
1602                                         ASTOBJ_UNREF(client, aji_client_destroy);
1603                                         return IKS_HOOK;                
1604                                 }
1605 #endif
1606                                 break;
1607                         }
1608                         if (!client->usesasl) {
1609                                 iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
1610                                 auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
1611                                 if (auth) {
1612                                         iks_insert_attrib(auth, "id", client->mid);
1613                                         iks_insert_attrib(auth, "to", client->jid->server);
1614                                         ast_aji_increment_mid(client->mid);
1615                                         ast_aji_send(client, auth);
1616                                         iks_delete(auth);
1617                                 } else {
1618                                         ast_log(LOG_ERROR, "Out of memory.\n");
1619                                 }
1620                         }
1621                         break;
1622
1623                 case IKS_NODE_NORMAL:
1624 #ifdef HAVE_OPENSSL
1625                         if (client->stream_flags & TRY_SECURE) {
1626                                 if (!strcmp("proceed", iks_name(node))) {
1627                                         return aji_tls_handshake(client);
1628                                 }
1629                         }
1630 #endif
1631                         if (!strcmp("stream:features", iks_name(node))) {
1632                                 features = iks_stream_features(node);
1633                                 if (client->usesasl) {
1634                                         if (client->usetls && !aji_is_secure(client)) {
1635                                                 break;
1636                                         }
1637                                         if (client->authorized) {
1638                                                 if (features & IKS_STREAM_BIND) {
1639                                                         iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
1640                                                         auth = iks_make_resource_bind(client->jid);
1641                                                         if (auth) {
1642                                                                 iks_insert_attrib(auth, "id", client->mid);
1643                                                                 ast_aji_increment_mid(client->mid);
1644                                                                 ast_aji_send(client, auth);
1645                                                                 iks_delete(auth);
1646                                                         } else {
1647                                                                 ast_log(LOG_ERROR, "Out of memory.\n");
1648                                                                 break;
1649                                                         }
1650                                                 }
1651                                                 if (features & IKS_STREAM_SESSION) {
1652                                                         iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
1653                                                         auth = iks_make_session();
1654                                                         if (auth) {
1655                                                                 iks_insert_attrib(auth, "id", "auth");
1656                                                                 ast_aji_increment_mid(client->mid);
1657                                                                 ast_aji_send(client, auth);
1658                                                                 iks_delete(auth);
1659                                                         } else {
1660                                                                 ast_log(LOG_ERROR, "Out of memory.\n");
1661                                                         }
1662                                                 }
1663                                         } else {
1664                                                 int ret;
1665                                                 if (!client->jid->user) {
1666                                                         ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
1667                                                         break;
1668                                                 }
1669
1670                                                 ret = aji_start_sasl(client, features, client->jid->user, client->password);
1671                                                 if (ret != IKS_OK) {
1672                                                         ASTOBJ_UNREF(client, aji_client_destroy);
1673                                                         return IKS_HOOK;
1674                                                 }
1675                                                 break;
1676                                         }
1677                                 }
1678                         } else if (!strcmp("failure", iks_name(node))) {
1679                                 ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
1680                         } else if (!strcmp("success", iks_name(node))) {
1681                                 client->authorized = 1;
1682                                 aji_send_header(client, client->jid->server);
1683                         }
1684                         break;
1685                 case IKS_NODE_ERROR:
1686                         ast_log(LOG_ERROR, "JABBER: Node Error\n");
1687                         ASTOBJ_UNREF(client, aji_client_destroy);
1688                         return IKS_HOOK;
1689                         break;
1690                 case IKS_NODE_STOP:
1691                         ast_log(LOG_WARNING, "JABBER: Disconnected\n");
1692                         ASTOBJ_UNREF(client, aji_client_destroy);
1693                         return IKS_HOOK;
1694                         break;
1695                 }
1696         } else if (client->state != AJI_CONNECTED && client->component) {
1697                 switch (type) {
1698                 case IKS_NODE_START:
1699                         if (client->state == AJI_DISCONNECTED) {
1700                                 char secret[160], shasum[320], *handshake;
1701
1702                                 sprintf(secret, "%s%s", pak->id, client->password);
1703                                 ast_sha1_hash(shasum, secret);
1704                                 handshake = NULL;
1705                                 if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
1706                                         aji_send_raw(client, handshake);
1707                                         ast_free(handshake);
1708                                         handshake = NULL;
1709                                 }
1710                                 client->state = AJI_CONNECTING;
1711                                 if (aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
1712                                         client->state = AJI_CONNECTED;
1713                                 else
1714                                         ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
1715                                 break;
1716                         }
1717                         break;
1718
1719                 case IKS_NODE_NORMAL:
1720                         break;
1721
1722                 case IKS_NODE_ERROR:
1723                         ast_log(LOG_ERROR, "JABBER: Node Error\n");
1724                         ASTOBJ_UNREF(client, aji_client_destroy);
1725                         return IKS_HOOK;
1726
1727                 case IKS_NODE_STOP:
1728                         ast_log(LOG_WARNING, "JABBER: Disconnected\n");
1729                         ASTOBJ_UNREF(client, aji_client_destroy);
1730                         return IKS_HOOK;
1731                 }
1732         }
1733
1734         switch (pak->type) {
1735         case IKS_PAK_NONE:
1736                 ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
1737                 break;
1738         case IKS_PAK_MESSAGE:
1739                 aji_handle_message(client, pak);
1740                 ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
1741                 break;
1742         case IKS_PAK_PRESENCE:
1743                 aji_handle_presence(client, pak);
1744                 ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
1745                 break;
1746         case IKS_PAK_S10N:
1747                 aji_handle_subscribe(client, pak);
1748                 ast_debug(1, "JABBER: Handling paktype S10N\n");
1749                 break;
1750         case IKS_PAK_IQ:
1751                 ast_debug(1, "JABBER: Handling paktype IQ\n");
1752                 aji_handle_iq(client, node);
1753                 break;
1754         default:
1755                 ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
1756                 break;
1757         }
1758
1759         iks_filter_packet(client->f, pak);
1760
1761         if (node)
1762                 iks_delete(node);
1763
1764         ASTOBJ_UNREF(client, aji_client_destroy);
1765         return IKS_OK;
1766 }
1767 /*!
1768  * \internal
1769  * \brief Unknown
1770  * \param data void
1771  * \param pak ikspak
1772  * \return IKS_FILTER_EAT.
1773 */
1774 static int aji_register_approve_handler(void *data, ikspak *pak)
1775 {
1776         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1777         iks *iq = NULL, *presence = NULL, *x = NULL;
1778
1779         iq = iks_new("iq");
1780         presence = iks_new("presence");
1781         x = iks_new("x");
1782         if (client && iq && presence && x) {
1783                 if (!iks_find(pak->query, "remove")) {
1784                         iks_insert_attrib(iq, "from", client->jid->full);
1785                         iks_insert_attrib(iq, "to", pak->from->full);
1786                         iks_insert_attrib(iq, "id", pak->id);
1787                         iks_insert_attrib(iq, "type", "result");
1788                         ast_aji_send(client, iq);
1789
1790                         iks_insert_attrib(presence, "from", client->jid->full);
1791                         iks_insert_attrib(presence, "to", pak->from->partial);
1792                         iks_insert_attrib(presence, "id", client->mid);
1793                         ast_aji_increment_mid(client->mid);
1794                         iks_insert_attrib(presence, "type", "subscribe");
1795                         iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
1796                         iks_insert_node(presence, x);
1797                         ast_aji_send(client, presence);
1798                 }
1799         } else {
1800                 ast_log(LOG_ERROR, "Out of memory.\n");
1801         }
1802
1803         iks_delete(iq);
1804         iks_delete(presence);
1805         iks_delete(x);
1806
1807         ASTOBJ_UNREF(client, aji_client_destroy);
1808         return IKS_FILTER_EAT;
1809 }
1810 /*!
1811  * \internal
1812  * \brief register handler for incoming querys (IQ's)
1813  * \param data incoming aji_client request
1814  * \param pak ikspak
1815  * \return IKS_FILTER_EAT.
1816 */
1817 static int aji_register_query_handler(void *data, ikspak *pak)
1818 {
1819         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1820         struct aji_buddy *buddy = NULL;
1821         char *node = NULL;
1822         iks *iq = NULL, *query = NULL;
1823
1824         client = (struct aji_client *) data;
1825
1826         buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
1827         if (!buddy) {
1828                 iks  *error = NULL, *notacceptable = NULL;
1829
1830                 ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
1831                 iq = iks_new("iq");
1832                 query = iks_new("query");
1833                 error = iks_new("error");
1834                 notacceptable = iks_new("not-acceptable");
1835                 if (iq && query && error && notacceptable) {
1836                         iks_insert_attrib(iq, "type", "error");
1837                         iks_insert_attrib(iq, "from", client->user);
1838                         iks_insert_attrib(iq, "to", pak->from->full);
1839                         iks_insert_attrib(iq, "id", pak->id);
1840                         iks_insert_attrib(query, "xmlns", "jabber:iq:register");
1841                         iks_insert_attrib(error, "code" , "406");
1842                         iks_insert_attrib(error, "type", "modify");
1843                         iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
1844                         iks_insert_node(iq, query);
1845                         iks_insert_node(iq, error);
1846                         iks_insert_node(error, notacceptable);
1847                         ast_aji_send(client, iq);
1848                 } else {
1849                         ast_log(LOG_ERROR, "Out of memory.\n");
1850                 }
1851
1852                 iks_delete(error);
1853                 iks_delete(notacceptable);
1854         } else if (!(node = iks_find_attrib(pak->query, "node"))) {
1855                 iks *instructions = NULL;
1856                 char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
1857                 iq = iks_new("iq");
1858                 query = iks_new("query");
1859                 instructions = iks_new("instructions");
1860                 if (iq && query && instructions && client) {
1861                         iks_insert_attrib(iq, "from", client->user);
1862                         iks_insert_attrib(iq, "to", pak->from->full);
1863                         iks_insert_attrib(iq, "id", pak->id);
1864                         iks_insert_attrib(iq, "type", "result");
1865                         iks_insert_attrib(query, "xmlns", "jabber:iq:register");
1866                         iks_insert_cdata(instructions, explain, 0);
1867                         iks_insert_node(iq, query);
1868                         iks_insert_node(query, instructions);
1869                         ast_aji_send(client, iq);
1870                 } else {
1871                         ast_log(LOG_ERROR, "Out of memory.\n");
1872                 }
1873
1874                 iks_delete(instructions);
1875         }
1876         iks_delete(iq);
1877         iks_delete(query);
1878         ASTOBJ_UNREF(client, aji_client_destroy);
1879         return IKS_FILTER_EAT;
1880 }
1881
1882 /*!
1883  * \internal
1884  * \brief Handles stuff
1885  * \param data void
1886  * \param pak ikspak
1887  * \return IKS_FILTER_EAT.
1888 */
1889 static int aji_ditems_handler(void *data, ikspak *pak)
1890 {
1891         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1892         char *node = NULL;
1893
1894         if (!(node = iks_find_attrib(pak->query, "node"))) {
1895                 iks *iq = NULL, *query = NULL, *item = NULL;
1896                 iq = iks_new("iq");
1897                 query = iks_new("query");
1898                 item = iks_new("item");
1899
1900                 if (iq && query && item) {
1901                         iks_insert_attrib(iq, "from", client->user);
1902                         iks_insert_attrib(iq, "to", pak->from->full);
1903                         iks_insert_attrib(iq, "id", pak->id);
1904                         iks_insert_attrib(iq, "type", "result");
1905                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
1906                         iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
1907                         iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
1908                         iks_insert_attrib(item, "jid", client->user);
1909
1910                         iks_insert_node(iq, query);
1911                         iks_insert_node(query, item);
1912                         ast_aji_send(client, iq);
1913                 } else {
1914                         ast_log(LOG_ERROR, "Out of memory.\n");
1915                 }
1916
1917                 iks_delete(iq);
1918                 iks_delete(query);
1919                 iks_delete(item);
1920
1921         } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
1922                 iks *iq, *query, *confirm;
1923                 iq = iks_new("iq");
1924                 query = iks_new("query");
1925                 confirm = iks_new("item");
1926                 if (iq && query && confirm && client) {
1927                         iks_insert_attrib(iq, "from", client->user);
1928                         iks_insert_attrib(iq, "to", pak->from->full);
1929                         iks_insert_attrib(iq, "id", pak->id);
1930                         iks_insert_attrib(iq, "type", "result");
1931                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
1932                         iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
1933                         iks_insert_attrib(confirm, "node", "confirmaccount");
1934                         iks_insert_attrib(confirm, "name", "Confirm AIM account");
1935                         iks_insert_attrib(confirm, "jid", "blog.astjab.org");
1936
1937                         iks_insert_node(iq, query);
1938                         iks_insert_node(query, confirm);
1939                         ast_aji_send(client, iq);
1940                 } else {
1941                         ast_log(LOG_ERROR, "Out of memory.\n");
1942                 }
1943
1944                 iks_delete(iq);
1945                 iks_delete(query);
1946                 iks_delete(confirm);
1947
1948         } else if (!strcasecmp(node, "confirmaccount")) {
1949                 iks *iq = NULL, *query = NULL, *feature = NULL;
1950
1951                 iq = iks_new("iq");
1952                 query = iks_new("query");
1953                 feature = iks_new("feature");
1954
1955                 if (iq && query && feature && client) {
1956                         iks_insert_attrib(iq, "from", client->user);
1957                         iks_insert_attrib(iq, "to", pak->from->full);
1958                         iks_insert_attrib(iq, "id", pak->id);
1959                         iks_insert_attrib(iq, "type", "result");
1960                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
1961                         iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
1962                         iks_insert_node(iq, query);
1963                         iks_insert_node(query, feature);
1964                         ast_aji_send(client, iq);
1965                 } else {
1966                         ast_log(LOG_ERROR, "Out of memory.\n");
1967                 }
1968
1969                 iks_delete(iq);
1970                 iks_delete(query);
1971                 iks_delete(feature);
1972         }
1973
1974         ASTOBJ_UNREF(client, aji_client_destroy);
1975         return IKS_FILTER_EAT;
1976
1977 }
1978
1979 /*!
1980  * \internal
1981  * \brief Handle add extra info
1982  * \param data void
1983  * \param pak ikspak
1984  * \return IKS_FILTER_EAT
1985 */
1986 static int aji_client_info_handler(void *data, ikspak *pak)
1987 {
1988         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
1989         struct aji_resource *resource = NULL;
1990         struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
1991
1992         resource = aji_find_resource(buddy, pak->from->resource);
1993         if (pak->subtype == IKS_TYPE_RESULT) {
1994                 if (!resource) {
1995                         ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
1996                         ASTOBJ_UNREF(client, aji_client_destroy);
1997                         return IKS_FILTER_EAT;
1998                 }
1999                 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
2000                         resource->cap->jingle = 1;
2001                 } else {
2002                         resource->cap->jingle = 0;
2003                 }
2004         } else if (pak->subtype == IKS_TYPE_GET) {
2005                 iks *iq, *disco, *ident, *google, *query;
2006                 iq = iks_new("iq");
2007                 query = iks_new("query");
2008                 ident = iks_new("identity");
2009                 disco = iks_new("feature");
2010                 google = iks_new("feature");
2011                 if (iq && ident && disco && google) {
2012                         iks_insert_attrib(iq, "from", client->jid->full);
2013                         iks_insert_attrib(iq, "to", pak->from->full);
2014                         iks_insert_attrib(iq, "type", "result");
2015                         iks_insert_attrib(iq, "id", pak->id);
2016                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2017                         iks_insert_attrib(ident, "category", "client");
2018                         iks_insert_attrib(ident, "type", "pc");
2019                         iks_insert_attrib(ident, "name", "asterisk");
2020                         iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
2021                         iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
2022                         iks_insert_node(iq, query);
2023                         iks_insert_node(query, ident);
2024                         iks_insert_node(query, google);
2025                         iks_insert_node(query, disco);
2026                         ast_aji_send(client, iq);
2027                 } else {
2028                         ast_log(LOG_ERROR, "Out of Memory.\n");
2029                 }
2030
2031                 iks_delete(iq);
2032                 iks_delete(query);
2033                 iks_delete(ident);
2034                 iks_delete(google);
2035                 iks_delete(disco);
2036         } else if (pak->subtype == IKS_TYPE_ERROR) {
2037                 ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
2038         }
2039         ASTOBJ_UNREF(client, aji_client_destroy);
2040         return IKS_FILTER_EAT;
2041 }
2042
2043 /*!
2044  * \internal
2045  * \brief Handler of the return info packet
2046  * \param data aji_client
2047  * \param pak ikspak
2048  * \return IKS_FILTER_EAT
2049 */
2050 static int aji_dinfo_handler(void *data, ikspak *pak)
2051 {
2052         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2053         char *node = NULL;
2054         struct aji_resource *resource = NULL;
2055         struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
2056
2057         resource = aji_find_resource(buddy, pak->from->resource);
2058         if (pak->subtype == IKS_TYPE_ERROR) {
2059                 ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
2060                 return IKS_FILTER_EAT;
2061         }
2062         if (pak->subtype == IKS_TYPE_RESULT) {
2063                 if (!resource) {
2064                         ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
2065                         ASTOBJ_UNREF(client, aji_client_destroy);
2066                         return IKS_FILTER_EAT;
2067                 }
2068                 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
2069                         resource->cap->jingle = 1;
2070                 } else {
2071                         resource->cap->jingle = 0;
2072                 }
2073         } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
2074                 iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
2075
2076                 iq = iks_new("iq");
2077                 query = iks_new("query");
2078                 identity = iks_new("identity");
2079                 disco = iks_new("feature");
2080                 reg = iks_new("feature");
2081                 commands = iks_new("feature");
2082                 gateway = iks_new("feature");
2083                 version = iks_new("feature");
2084                 vcard = iks_new("feature");
2085                 search = iks_new("feature");
2086                 if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
2087                         iks_insert_attrib(iq, "from", client->user);
2088                         iks_insert_attrib(iq, "to", pak->from->full);
2089                         iks_insert_attrib(iq, "id", pak->id);
2090                         iks_insert_attrib(iq, "type", "result");
2091                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2092                         iks_insert_attrib(identity, "category", "gateway");
2093                         iks_insert_attrib(identity, "type", "pstn");
2094                         iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
2095                         iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
2096                         iks_insert_attrib(reg, "var", "jabber:iq:register");
2097                         iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
2098                         iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
2099                         iks_insert_attrib(version, "var", "jabber:iq:version");
2100                         iks_insert_attrib(vcard, "var", "vcard-temp");
2101                         iks_insert_attrib(search, "var", "jabber:iq:search");
2102
2103                         iks_insert_node(iq, query);
2104                         iks_insert_node(query, identity);
2105                         iks_insert_node(query, disco);
2106                         iks_insert_node(query, reg);
2107                         iks_insert_node(query, commands);
2108                         iks_insert_node(query, gateway);
2109                         iks_insert_node(query, version);
2110                         iks_insert_node(query, vcard);
2111                         iks_insert_node(query, search);
2112                         ast_aji_send(client, iq);
2113                 } else {
2114                         ast_log(LOG_ERROR, "Out of memory.\n");
2115                 }
2116
2117                 iks_delete(iq);
2118                 iks_delete(query);
2119                 iks_delete(identity);
2120                 iks_delete(disco);
2121                 iks_delete(reg);
2122                 iks_delete(commands);
2123                 iks_delete(gateway);
2124                 iks_delete(version);
2125                 iks_delete(vcard);
2126                 iks_delete(search);
2127         } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
2128                 iks *iq, *query, *confirm;
2129                 iq = iks_new("iq");
2130                 query = iks_new("query");
2131                 confirm = iks_new("item");
2132
2133                 if (iq && query && confirm && client) {
2134                         iks_insert_attrib(iq, "from", client->user);
2135                         iks_insert_attrib(iq, "to", pak->from->full);
2136                         iks_insert_attrib(iq, "id", pak->id);
2137                         iks_insert_attrib(iq, "type", "result");
2138                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
2139                         iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
2140                         iks_insert_attrib(confirm, "node", "confirmaccount");
2141                         iks_insert_attrib(confirm, "name", "Confirm AIM account");
2142                         iks_insert_attrib(confirm, "jid", client->user);
2143                         iks_insert_node(iq, query);
2144                         iks_insert_node(query, confirm);
2145                         ast_aji_send(client, iq);
2146                 } else {
2147                         ast_log(LOG_ERROR, "Out of memory.\n");
2148                 }
2149
2150                 iks_delete(iq);
2151                 iks_delete(query);
2152                 iks_delete(confirm);
2153
2154         } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
2155                 iks *iq, *query, *feature;
2156
2157                 iq = iks_new("iq");
2158                 query = iks_new("query");
2159                 feature = iks_new("feature");
2160
2161                 if (iq && query && feature && client) {
2162                         iks_insert_attrib(iq, "from", client->user);
2163                         iks_insert_attrib(iq, "to", pak->from->full);
2164                         iks_insert_attrib(iq, "id", pak->id);
2165                         iks_insert_attrib(iq, "type", "result");
2166                         iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2167                         iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
2168                         iks_insert_node(iq, query);
2169                         iks_insert_node(query, feature);
2170                         ast_aji_send(client, iq);
2171                 } else {
2172                         ast_log(LOG_ERROR, "Out of memory.\n");
2173                 }
2174
2175                 iks_delete(iq);
2176                 iks_delete(query);
2177                 iks_delete(feature);
2178         }
2179
2180         ASTOBJ_UNREF(client, aji_client_destroy);
2181         return IKS_FILTER_EAT;
2182 }
2183
2184 /*!
2185  * \internal
2186  * \brief Handles \verbatim <iq> \endverbatim stanzas.
2187  * \param client the configured XMPP client we use to connect to a XMPP server
2188  * \param node iks
2189  * \return void.
2190  */
2191 static void aji_handle_iq(struct aji_client *client, iks *node)
2192 {
2193         /*Nothing to see here */
2194 }
2195
2196 /*!
2197  * \internal
2198  * \brief Handles \verbatim <message>\endverbatim stanzas.
2199  * Adds the incoming message to the client's message list.
2200  * \param client the configured XMPP client we use to connect to a XMPP server
2201  * \param pak ikspak the node
2202  */
2203 static void aji_handle_message(struct aji_client *client, ikspak *pak)
2204 {
2205         struct aji_message *insert;
2206         int deleted = 0;
2207
2208         ast_debug(3, "client %s received a message\n", client->name);
2209
2210         if (!(insert = ast_calloc(1, sizeof(*insert)))) {
2211                 return;
2212         }
2213
2214         insert->arrived = ast_tvnow();
2215
2216         /* wake up threads waiting for messages */
2217         ast_mutex_lock(&messagelock);
2218         ast_cond_broadcast(&message_received_condition);
2219         ast_mutex_unlock(&messagelock);
2220
2221         if (iks_find_cdata(pak->x, "body")) {
2222                 insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
2223         }
2224         if (pak->id) {
2225                 ast_copy_string(insert->id, pak->id, sizeof(insert->id));
2226         }
2227         if (pak->from){
2228                 /* insert will furtherly be added to message list */
2229                 insert->from = ast_strdup(pak->from->full);
2230                 if (!insert->from) {
2231                         ast_log(LOG_ERROR, "Memory allocation failure\n");
2232                         return;
2233                 }
2234                 ast_debug(3, "message comes from %s\n", insert->from);
2235         }
2236
2237         /* remove old messages received from this JID
2238          * and insert received message */
2239         deleted = delete_old_messages(client, pak->from->partial);
2240         ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
2241         AST_LIST_LOCK(&client->messages);
2242         AST_LIST_INSERT_HEAD(&client->messages, insert, list);
2243         AST_LIST_UNLOCK(&client->messages);
2244 }
2245
2246 /*!
2247  * \internal
2248  * \brief handles \verbatim <presence>\endverbatim stanzas.
2249  * \param client the configured XMPP client we use to connect to a XMPP server
2250  * \param pak ikspak
2251  */
2252 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
2253 {
2254         int status, priority;
2255         struct aji_buddy *buddy;
2256         struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
2257         char *ver, *node, *descrip, *type;
2258
2259         if (client->state != AJI_CONNECTED)
2260                 aji_create_buddy(pak->from->partial, client);
2261
2262         buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
2263         if (!buddy && pak->from->partial) {
2264                 /* allow our jid to be used to log in with another resource */
2265                 if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
2266                         aji_create_buddy(pak->from->partial, client);
2267                 else
2268                         ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
2269                 return;
2270         }
2271         type = iks_find_attrib(pak->x, "type");
2272         if (client->component && type &&!strcasecmp("probe", type)) {
2273                 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
2274                 ast_verbose("what i was looking for \n");
2275         }
2276         ASTOBJ_WRLOCK(buddy);
2277         status = (pak->show) ? pak->show : 6;
2278         priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
2279         tmp = buddy->resources;
2280         descrip = ast_strdup(iks_find_cdata(pak->x, "status"));
2281
2282         while (tmp && pak->from->resource) {
2283                 if (!strcasecmp(tmp->resource, pak->from->resource)) {
2284                         tmp->status = status;
2285                         if (tmp->description) {
2286                                 ast_free(tmp->description);
2287                         }
2288                         tmp->description = descrip;
2289                         found = tmp;
2290                         if (status == 6) {      /* Sign off Destroy resource */
2291                                 if (last && found->next) {
2292                                         last->next = found->next;
2293                                 } else if (!last) {
2294                                         if (found->next) {
2295                                                 buddy->resources = found->next;
2296                                         } else {
2297                                                 buddy->resources = NULL;
2298                                         }
2299                                 } else if (!found->next) {
2300                                         if (last) {
2301                                                 last->next = NULL;
2302                                         } else {
2303                                                 buddy->resources = NULL;
2304                                         }
2305                                 }
2306                                 ast_free(found);
2307                                 found = NULL;
2308                                 break;
2309                         }
2310                         /* resource list is sorted by descending priority */
2311                         if (tmp->priority != priority) {
2312                                 found->priority = priority;
2313                                 if (!last && !found->next) {
2314                                         /* resource was found to be unique,
2315                                            leave loop */
2316                                         break;
2317                                 }
2318                                 /* search for resource in our list
2319                                    and take it out for the moment */
2320                                 if (last) {
2321                                         last->next = found->next;
2322                                 } else {
2323                                         buddy->resources = found->next;
2324                                 }
2325
2326                                 last = NULL;
2327                                 tmp = buddy->resources;
2328                                 if (!buddy->resources) {
2329                                         buddy->resources = found;
2330                                 }
2331                                 /* priority processing */
2332                                 while (tmp) {
2333                                         /* insert resource back according to
2334                                            its priority value */
2335                                         if (found->priority > tmp->priority) {
2336                                                 if (last) {
2337                                                         /* insert within list */
2338                                                         last->next = found;
2339                                                 }
2340                                                 found->next = tmp;
2341                                                 if (!last) {
2342                                                         /* insert on top */
2343                                                         buddy->resources = found;
2344                                                 }
2345                                                 break;
2346                                         }
2347                                         if (!tmp->next) {
2348                                                 /* insert at the end of the list */
2349                                                 tmp->next = found;
2350                                                 found->next = NULL;
2351                                                 break;
2352                                         }
2353                                         last = tmp;
2354                                         tmp = tmp->next;
2355                                 }
2356                         }
2357                         break;
2358                 }
2359                 last = tmp;
2360                 tmp = tmp->next;
2361         }
2362
2363         /* resource not found in our list, create it */
2364         if (!found && status != 6 && pak->from->resource) {
2365                 found = ast_calloc(1, sizeof(*found));
2366
2367                 if (!found) {
2368                         ast_log(LOG_ERROR, "Out of memory!\n");
2369                         return;
2370                 }
2371                 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
2372                 found->status = status;
2373                 found->description = descrip;
2374                 found->priority = priority;
2375                 found->next = NULL;
2376                 last = NULL;
2377                 tmp = buddy->resources;
2378                 while (tmp) {
2379                         if (found->priority > tmp->priority) {
2380                                 if (last) {
2381                                         last->next = found;
2382                                 }
2383                                 found->next = tmp;
2384                                 if (!last) {
2385                                         buddy->resources = found;
2386                                 }
2387                                 break;
2388                         }
2389                         if (!tmp->next) {
2390                                 tmp->next = found;
2391                                 break;
2392                         }
2393                         last = tmp;
2394                         tmp = tmp->next;
2395                 }
2396                 if (!tmp) {
2397                         buddy->resources = found;
2398                 }
2399         }
2400
2401         ASTOBJ_UNLOCK(buddy);
2402         ASTOBJ_UNREF(buddy, aji_buddy_destroy);
2403
2404         node = iks_find_attrib(iks_find(pak->x, "c"), "node");
2405         ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
2406
2407         /* handle gmail client's special caps:c tag */
2408         if (!node && !ver) {
2409                 node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
2410                 ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
2411         }
2412
2413         /* retrieve capabilites of the new resource */
2414         if (status != 6 && found && !found->cap) {
2415                 found->cap = aji_find_version(node, ver, pak);
2416                 if (gtalk_yuck(pak->x)) { /* gtalk should do discover */
2417                         found->cap->jingle = 1;
2418                 }
2419                 if (found->cap->jingle && option_debug > 4) {
2420                         ast_debug(1, "Special case for google till they support discover.\n");
2421                 } else {
2422                         iks *iq, *query;
2423                         iq = iks_new("iq");
2424                         query = iks_new("query");
2425                         if (query && iq) {
2426                                 iks_insert_attrib(iq, "type", "get");
2427                                 iks_insert_attrib(iq, "to", pak->from->full);
2428                                 iks_insert_attrib(iq, "from", client->jid->full);
2429                                 iks_insert_attrib(iq, "id", client->mid);
2430                                 ast_aji_increment_mid(client->mid);
2431                                 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2432                                 iks_insert_node(iq, query);
2433                                 ast_aji_send(client, iq);
2434                         } else {
2435                                 ast_log(LOG_ERROR, "Out of memory.\n");
2436                         }
2437                         iks_delete(query);
2438                         iks_delete(iq);
2439                 }
2440         }
2441         switch (pak->subtype) {
2442         case IKS_TYPE_AVAILABLE:
2443                 ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
2444                 break;
2445         case IKS_TYPE_UNAVAILABLE:
2446                 ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
2447                 break;
2448         default:
2449                 ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
2450         }
2451         switch (pak->show) {
2452         case IKS_SHOW_UNAVAILABLE:
2453                 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
2454                 break;
2455         case IKS_SHOW_AVAILABLE:
2456                 ast_debug(3, "JABBER: type is available\n");
2457                 break;
2458         case IKS_SHOW_CHAT:
2459                 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
2460                 break;
2461         case IKS_SHOW_AWAY:
2462                 ast_debug(3, "JABBER: type is away\n");
2463                 break;
2464         case IKS_SHOW_XA:
2465                 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
2466                 break;
2467         case IKS_SHOW_DND:
2468                 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
2469                 break;
2470         default:
2471                 ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
2472         }
2473
2474         if (found) {
2475                 manager_event(EVENT_FLAG_USER, "JabberStatus",
2476                         "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
2477                         "\r\nDescription: %s\r\n",
2478                         client->name, pak->from->partial, found->resource, found->status,
2479                         found->priority, found->description);
2480         } else {
2481                 manager_event(EVENT_FLAG_USER, "JabberStatus",
2482                         "Account: %s\r\nJID: %s\r\nStatus: %d\r\n",
2483                         client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
2484         }
2485 }
2486
2487 /*!
2488  * \internal
2489  * \brief handles subscription requests.
2490  * \param client the configured XMPP client we use to connect to a XMPP server
2491  * \param pak ikspak iksemel packet.
2492  * \return void.
2493  */
2494 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
2495 {
2496         iks *presence = NULL, *status = NULL;
2497         struct aji_buddy* buddy = NULL;
2498
2499         switch (pak->subtype) {
2500         case IKS_TYPE_SUBSCRIBE:
2501                 if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
2502                         presence = iks_new("presence");
2503                         status = iks_new("status");
2504                         if (presence && status) {
2505                                 iks_insert_attrib(presence, "type", "subscribed");
2506                                 iks_insert_attrib(presence, "to", pak->from->full);
2507                                 iks_insert_attrib(presence, "from", client->jid->full);
2508                                 if (pak->id)
2509                                         iks_insert_attrib(presence, "id", pak->id);
2510                                 iks_insert_cdata(status, "Asterisk has approved subscription", 0);
2511                                 iks_insert_node(presence, status);
2512                                 ast_aji_send(client, presence);
2513                         } else {
2514                                 ast_log(LOG_ERROR, "Unable to allocate nodes\n");
2515                         }
2516
2517                         iks_delete(presence);
2518                         iks_delete(status);
2519                 }
2520
2521                 if (client->component)
2522                         aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
2523         case IKS_TYPE_SUBSCRIBED:
2524                 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
2525                 if (!buddy && pak->from->partial) {
2526                         aji_create_buddy(pak->from->partial, client);
2527                 }
2528         default:
2529                 if (option_verbose > 4) {
2530                         ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
2531                 }
2532         }
2533 }
2534
2535 /*!
2536  * \brief sends messages.
2537  * \param client the configured XMPP client we use to connect to a XMPP server
2538  * \param address
2539  * \param message
2540  * \retval IKS_OK success
2541  * \retval -1 failure
2542  */
2543 int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message)
2544 {
2545         return aji_send_raw_chat(client, 0, NULL, address, message);
2546 }
2547
2548 /*!
2549 * \brief sends message to a groupchat
2550 * Prior to sending messages to a groupchat, one must be connected to it.
2551 * \param client the configured XMPP client we use to connect to a XMPP server
2552 * \param nick the nickname we use in the chatroom
2553 * \param address the user the messages must be sent to
2554 * \param message the message to send
2555 * \return IKS_OK on success, any other value on failure
2556 */
2557 int ast_aji_send_groupchat(struct aji_client *client, const char *nick, const char *address, const char *message) {
2558         return aji_send_raw_chat(client, 1, nick, address, message);
2559 }
2560
2561 /*!
2562 * \brief sends messages.
2563 * \param client the configured XMPP client we use to connect to a XMPP server
2564 * \param groupchat 
2565 * \param nick the nickname we use in chatrooms
2566 * \param address
2567 * \param message
2568 * \return IKS_OK on success, any other value on failure
2569 */
2570 static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message)
2571 {
2572         int res = 0;
2573         iks *message_packet = NULL;
2574         char from[AJI_MAX_JIDLEN];
2575         /* the nickname is used only in component mode */
2576         if (nick && client->component) {
2577                 snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
2578         } else {
2579                 snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
2580         }
2581
2582         if (client->state != AJI_CONNECTED) {
2583                 ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
2584                 return -1;
2585         }
2586
2587         message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
2588         if (!message_packet) {
2589                 ast_log(LOG_ERROR, "Out of memory.\n");
2590                 return -1;
2591         }
2592         iks_insert_attrib(message_packet, "from", from);
2593         res = ast_aji_send(client, message_packet);
2594         iks_delete(message_packet);
2595
2596         return res;
2597 }
2598
2599 /*!
2600  * \brief create a chatroom.
2601  * \param client the configured XMPP client we use to connect to a XMPP server
2602  * \param room name of room
2603  * \param server name of server
2604  * \param topic topic for the room.
2605  * \return 0.
2606  */
2607 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
2608 {
2609         int res = 0;
2610         iks *iq = NULL;
2611         iq = iks_new("iq");
2612
2613         if (iq && client) {
2614                 iks_insert_attrib(iq, "type", "get");
2615                 iks_insert_attrib(iq, "to", server);
2616                 iks_insert_attrib(iq, "id", client->mid);
2617                 ast_aji_increment_mid(client->mid);
2618                 ast_aji_send(client, iq);
2619         } else {
2620                 ast_log(LOG_ERROR, "Out of memory.\n");
2621         }
2622
2623         iks_delete(iq);
2624
2625         return res;
2626 }
2627
2628 /*!
2629  * \brief join a chatroom.
2630  * \param client the configured XMPP client we use to connect to a XMPP server
2631  * \param room room to join
2632  * \param nick the nickname to use in this room
2633  * \return IKS_OK on success, any other value on failure.
2634  */
2635 int ast_aji_join_chat(struct aji_client *client, char *room, char *nick)
2636 {
2637         return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
2638 }
2639
2640 /*!
2641  * \brief leave a chatroom.
2642  * \param client the configured XMPP client we use to connect to a XMPP server
2643  * \param room room to leave
2644  * \param nick the nickname used in this room
2645  * \return IKS_OK on success, any other value on failure.
2646  */
2647 int ast_aji_leave_chat(struct aji_client *client, char *room, char *nick)
2648 {
2649         return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
2650 }
2651 /*!
2652  * \brief invite to a chatroom.
2653  * \param client the configured XMPP client we use to connect to a XMPP server
2654  * \param user
2655  * \param room
2656  * \param message
2657  * \return res.
2658  */
2659 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
2660 {
2661         int res = 0;
2662         iks *invite, *body, *namespace;
2663
2664         invite = iks_new("message");
2665         body = iks_new("body");
2666         namespace = iks_new("x");
2667         if (client && invite && body && namespace) {
2668                 iks_insert_attrib(invite, "to", user);
2669                 iks_insert_attrib(invite, "id", client->mid);
2670                 ast_aji_increment_mid(client->mid);
2671                 iks_insert_cdata(body, message, 0);
2672                 iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
2673                 iks_insert_attrib(namespace, "jid", room);
2674                 iks_insert_node(invite, body);
2675                 iks_insert_node(invite, namespace);
2676                 res = ast_aji_send(client, invite);
2677         } else {
2678                 ast_log(LOG_ERROR, "Out of memory.\n");
2679         }
2680
2681         iks_delete(body);
2682         iks_delete(namespace);
2683         iks_delete(invite);
2684
2685         return res;
2686 }
2687
2688 /*!
2689  * \internal
2690  * \brief receive message loop.
2691  * \param data void
2692  * \return void.
2693  */
2694 static void *aji_recv_loop(void *data)
2695 {
2696         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2697         int res = IKS_HOOK;
2698
2699         while (res != IKS_OK) {
2700                 ast_debug(3, "JABBER: Connecting.\n");
2701                 res = aji_reconnect(client);
2702                 sleep(4);
2703         }
2704
2705         do {
2706                 if (res == IKS_NET_RWERR || client->timeout == 0) {
2707                         while (res != IKS_OK) {
2708                                 ast_debug(3, "JABBER: reconnecting.\n");
2709                                 res = aji_reconnect(client);
2710                                 sleep(4);
2711                         }
2712                 }
2713
2714                 res = aji_recv(client, 1);
2715
2716                 if (client->state == AJI_DISCONNECTING) {
2717                         ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
2718                         pthread_exit(NULL);
2719                 }
2720
2721                 /* Decrease timeout if no data received, and delete
2722                  * old messages globally */
2723                 if (res == IKS_NET_EXPIRED) {
2724                         client->timeout--;
2725                         delete_old_messages_all(client);
2726                 }
2727                 if (res == IKS_HOOK) {
2728                         ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
2729                 } else if (res == IKS_NET_TLSFAIL) {
2730                         ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
2731                 } else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
2732                         res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
2733                         if (res == IKS_OK) {
2734                                 client->timeout = 50;
2735                         } else {
2736                                 ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
2737                         }
2738                 } else if (res == IKS_NET_RWERR) {
2739                         ast_log(LOG_WARNING, "JABBER: socket read error\n");
2740                 }
2741         } while (client);
2742         ASTOBJ_UNREF(client, aji_client_destroy);
2743         return 0;
2744 }
2745
2746 /*!
2747  * \brief increments the mid field for messages and other events.
2748  * \param mid char.
2749  * \return void.
2750  */
2751 void ast_aji_increment_mid(char *mid)
2752 {
2753         int i = 0;
2754
2755         for (i = strlen(mid) - 1; i >= 0; i--) {
2756                 if (mid[i] != 'z') {
2757                         mid[i] = mid[i] + 1;
2758                         i = 0;
2759                 } else
2760                         mid[i] = 'a';
2761         }
2762 }
2763
2764 #if 0
2765 /*!
2766  * \brief attempts to register to a transport.
2767  * \param aji_client struct, and xml packet.
2768  * \return IKS_FILTER_EAT.
2769  */
2770 /*allows for registering to transport , was too sketch and is out for now. */
2771 static int aji_register_transport(void *data, ikspak *pak)
2772 {
2773         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2774         int res = 0;
2775         struct aji_buddy *buddy = NULL;
2776         iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
2777
2778         if (client && send) {
2779                 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
2780                         ASTOBJ_RDLOCK(iterator); 
2781                         if (iterator->btype == AJI_TRANS) {
2782                                   buddy = iterator;
2783                         }
2784                         ASTOBJ_UNLOCK(iterator);
2785                 });
2786                 iks_filter_remove_hook(client->f, aji_register_transport);
2787                 iks_filter_add_rule(client->f, aji_register_transport2, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, IKS_NS_REGISTER, IKS_RULE_DONE);
2788                 iks_insert_attrib(send, "to", buddy->host);
2789                 iks_insert_attrib(send, "id", client->mid);
2790                 ast_aji_increment_mid(client->mid);
2791                 iks_insert_attrib(send, "from", client->user);
2792                 res = ast_aji_send(client, send);
2793         } else 
2794                 ast_log(LOG_ERROR, "Out of memory.\n");
2795
2796         if (send)
2797                 iks_delete(send);
2798         ASTOBJ_UNREF(client, aji_client_destroy);
2799         return IKS_FILTER_EAT;
2800
2801 }
2802 /*!
2803  * \brief attempts to register to a transport step 2.
2804  * \param aji_client struct, and xml packet.
2805  * \return IKS_FILTER_EAT.
2806  */
2807 /* more of the same blob of code, too wonky for now*/
2808 static int aji_register_transport2(void *data, ikspak *pak)
2809 {
2810         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2811         int res = 0;
2812         struct aji_buddy *buddy = NULL;
2813
2814         iks *regiq = iks_new("iq");
2815         iks *regquery = iks_new("query");
2816         iks *reguser = iks_new("username");
2817         iks *regpass = iks_new("password");
2818
2819         if (client && regquery && reguser && regpass && regiq) {
2820                 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
2821                         ASTOBJ_RDLOCK(iterator);
2822                         if (iterator->btype == AJI_TRANS)
2823                                 buddy = iterator; ASTOBJ_UNLOCK(iterator);
2824                 });
2825                 iks_filter_remove_hook(client->f, aji_register_transport2);
2826                 iks_insert_attrib(regiq, "to", buddy->host);
2827                 iks_insert_attrib(regiq, "type", "set");
2828                 iks_insert_attrib(regiq, "id", client->mid);
2829                 ast_aji_increment_mid(client->mid);
2830                 iks_insert_attrib(regiq, "from", client->user);
2831                 iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
2832                 iks_insert_cdata(reguser, buddy->user, 0);
2833                 iks_insert_cdata(regpass, buddy->pass, 0);
2834                 iks_insert_node(regiq, regquery);
2835                 iks_insert_node(regquery, reguser);
2836                 iks_insert_node(regquery, regpass);
2837                 res = ast_aji_send(client, regiq);
2838         } else
2839                 ast_log(LOG_ERROR, "Out of memory.\n");
2840         if (regiq)
2841                 iks_delete(regiq);
2842         if (regquery)
2843                 iks_delete(regquery);
2844         if (reguser)
2845                 iks_delete(reguser);
2846         if (regpass)
2847                 iks_delete(regpass);
2848         ASTOBJ_UNREF(client, aji_client_destroy);
2849         return IKS_FILTER_EAT;
2850 }
2851 #endif
2852
2853 /*!
2854  * \internal
2855  * \brief goes through roster and prunes users not needed in list, or adds them accordingly.
2856  * \param client the configured XMPP client we use to connect to a XMPP server
2857  * \return void.
2858  * \note The messages here should be configurable.
2859  */
2860 static void aji_pruneregister(struct aji_client *client)
2861 {
2862         int res = 0;
2863         iks *removeiq = iks_new("iq");
2864         iks *removequery = iks_new("query");
2865         iks *removeitem = iks_new("item");
2866         iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
2867         if (!client || !removeiq || !removequery || !removeitem || !send) {
2868                 ast_log(LOG_ERROR, "Out of memory.\n");
2869                 goto safeout;
2870         }
2871
2872         iks_insert_node(removeiq, removequery);
2873         iks_insert_node(removequery, removeitem);
2874         ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
2875                 ASTOBJ_RDLOCK(iterator);
2876                 /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
2877                  * be called at the same time */
2878                 if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
2879                         res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
2880                                                                  "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
2881                                                                  " so I am no longer subscribing to your presence.\n"));
2882                         res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
2883                                                                  "GoodBye.  You are no longer in the Asterisk config file so I am removing"
2884                                                                  " your access to my presence.\n"));
2885                         iks_insert_attrib(removeiq, "from", client->jid->full);
2886                         iks_insert_attrib(removeiq, "type", "set");
2887                         iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
2888                         iks_insert_attrib(removeitem, "jid", iterator->name);
2889                         iks_insert_attrib(removeitem, "subscription", "remove");
2890                         res = ast_aji_send(client, removeiq);
2891                 } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
2892                         res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
2893                                                                  "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
2894                         ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
2895                 }
2896                 ASTOBJ_UNLOCK(iterator);
2897         });
2898
2899  safeout:
2900         iks_delete(removeiq);
2901         iks_delete(removequery);
2902         iks_delete(removeitem);
2903         iks_delete(send);
2904
2905         ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
2906 }
2907
2908 /*!
2909  * \internal
2910  * \brief filters the roster packet we get back from server.
2911  * \param data void
2912  * \param pak ikspak iksemel packet.
2913  * \return IKS_FILTER_EAT.
2914  */
2915 static int aji_filter_roster(void *data, ikspak *pak)
2916 {
2917         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
2918         int flag = 0;
2919         iks *x = NULL;
2920         struct aji_buddy *buddy;
2921
2922         client->state = AJI_CONNECTED;
2923         ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
2924                 ASTOBJ_RDLOCK(iterator);
2925                 x = iks_child(pak->query);
2926                 flag = 0;
2927                 while (x) {
2928                         if (!iks_strcmp(iks_name(x), "item")) {
2929                                 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
2930                                         flag = 1;
2931                                         ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
2932                                 }
2933                         }
2934                         x = iks_next(x);
2935                 }
2936                 if (!flag) {
2937                         ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
2938                 }
2939                 iks_delete(x);
2940
2941                 ASTOBJ_UNLOCK(iterator);
2942         });
2943
2944         x = iks_child(pak->query);
2945         while (x) {
2946                 flag = 0;
2947                 if (iks_strcmp(iks_name(x), "item") == 0) {
2948                         ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
2949                                 ASTOBJ_RDLOCK(iterator);
2950                                 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
2951                                         flag = 1;
2952                                 ASTOBJ_UNLOCK(iterator);
2953                         });
2954
2955                         if (flag) {
2956                                 /* found buddy, don't create a new one */
2957                                 x = iks_next(x);
2958                                 continue;
2959                         }
2960
2961                         buddy = ast_calloc(1, sizeof(*buddy));
2962                         if (!buddy) {
2963                                 ast_log(LOG_WARNING, "Out of memory\n");
2964                                 return 0;
2965                         }
2966                         ASTOBJ_INIT(buddy);
2967                         ASTOBJ_WRLOCK(buddy);
2968                         ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
2969                         ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
2970                         if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
2971                                 ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
2972                                 ASTOBJ_MARK(buddy);
2973                         } else if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
2974                                 /* subscribe to buddy's presence only
2975                                    if we really need to */
2976                                 ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
2977                         }
2978                         ASTOBJ_UNLOCK(buddy);
2979                         if (buddy) {
2980                                 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
2981                                 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
2982                         }
2983                 }
2984                 x = iks_next(x);
2985         }
2986
2987         iks_delete(x);
2988         aji_pruneregister(client);
2989
2990         ASTOBJ_UNREF(client, aji_client_destroy);
2991         return IKS_FILTER_EAT;
2992 }
2993
2994 /*!
2995  * \internal
2996  * \brief reconnect to jabber server
2997  * \param client the configured XMPP client we use to connect to a XMPP server
2998  * \return res.
2999 */
3000 static int aji_reconnect(struct aji_client *client)
3001 {
3002         int res = 0;
3003
3004         if (client->state) {
3005                 client->state = AJI_DISCONNECTED;
3006         }
3007         client->timeout = 50;
3008         if (client->p) {
3009                 iks_parser_reset(client->p);
3010         }
3011         if (client->authorized) {
3012                 client->authorized = 0;
3013         }
3014
3015         res = aji_initialize(client);
3016
3017         return res;
3018 }
3019
3020 /*!
3021  * \internal
3022  * \brief Get the roster of jabber users
3023  * \param client the configured XMPP client we use to connect to a XMPP server
3024  * \return 1.
3025 */
3026 static int aji_get_roster(struct aji_client *client)
3027 {
3028         iks *roster = NULL;
3029         roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
3030
3031         if (roster) {
3032                 iks_insert_attrib(roster, "id", "roster");
3033                 aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
3034                 ast_aji_send(client, roster);
3035         }
3036
3037         iks_delete(roster);
3038
3039         return 1;
3040 }
3041
3042 /*!
3043  * \internal
3044  * \brief connects as a client to jabber server.
3045  * \param data void
3046  * \param pak ikspak iksemel packet
3047  * \return res.
3048  */
3049 static int aji_client_connect(void *data, ikspak *pak)
3050 {
3051         struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
3052         int res = 0;
3053
3054         if (client) {
3055                 if (client->state == AJI_DISCONNECTED) {
3056                         iks_filter_add_rule(client->f, aji_filter_roster, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
3057                         client->state = AJI_CONNECTING;
3058                         client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
3059                         iks_filter_remove_hook(client->f, aji_client_connect);
3060                         if (!client->component) { /*client*/
3061                                 aji_get_roster(client);
3062                                 if (client->distribute_events) {
3063                                         aji_init_event_distribution(client);
3064                                 }
3065                         }
3066                 }
3067         } else {
3068                 ast_log(LOG_ERROR, "Out of memory.\n");
3069         }
3070
3071         ASTOBJ_UNREF(client, aji_client_destroy);
3072         return res;
3073 }
3074
3075 /*!
3076  * \internal
3077  * \brief prepares client for connect.
3078  * \param client the configured XMPP client we use to connect to a XMPP server
3079  * \return 1.