00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00037
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <iksemel.h>
00041
00042 #include "asterisk/channel.h"
00043 #include "asterisk/jabber.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/config.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/options.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/md5.h"
00054 #include "asterisk/acl.h"
00055 #include "asterisk/utils.h"
00056 #include "asterisk/module.h"
00057 #include "asterisk/astobj.h"
00058 #include "asterisk/astdb.h"
00059 #include "asterisk/manager.h"
00060
00061 #define JABBER_CONFIG "jabber.conf"
00062
00063 #ifndef FALSE
00064 #define FALSE 0
00065 #endif
00066
00067 #ifndef TRUE
00068 #define TRUE 1
00069 #endif
00070
00071
00072 static int aji_highest_bit(int number);
00073 static void aji_buddy_destroy(struct aji_buddy *obj);
00074 static void aji_client_destroy(struct aji_client *obj);
00075 static int aji_send_exec(struct ast_channel *chan, void *data);
00076 static int aji_status_exec(struct ast_channel *chan, void *data);
00077 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
00078 static int aji_act_hook(void *data, int type, iks *node);
00079 static void aji_handle_iq(struct aji_client *client, iks *node);
00080 static void aji_handle_message(struct aji_client *client, ikspak *pak);
00081 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
00082 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
00083 static void *aji_recv_loop(void *data);
00084 static int aji_component_initialize(struct aji_client *client);
00085 static int aji_client_initialize(struct aji_client *client);
00086 static int aji_client_connect(void *data, ikspak *pak);
00087 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
00088 static int aji_do_debug(int fd, int argc, char *argv[]);
00089 static int aji_do_reload(int fd, int argc, char *argv[]);
00090 static int aji_no_debug(int fd, int argc, char *argv[]);
00091 static int aji_test(int fd, int argc, char *argv[]);
00092 static int aji_show_clients(int fd, int argc, char *argv[]);
00093 static int aji_create_client(char *label, struct ast_variable *var, int debug);
00094 static int aji_create_buddy(char *label, struct aji_client *client);
00095 static int aji_reload(void);
00096 static int aji_load_config(void);
00097 static void aji_pruneregister(struct aji_client *client);
00098 static int aji_filter_roster(void *data, ikspak *pak);
00099 static int aji_get_roster(struct aji_client *client);
00100 static int aji_client_info_handler(void *data, ikspak *pak);
00101 static int aji_dinfo_handler(void *data, ikspak *pak);
00102 static int aji_ditems_handler(void *data, ikspak *pak);
00103 static int aji_register_query_handler(void *data, ikspak *pak);
00104 static int aji_register_approve_handler(void *data, ikspak *pak);
00105 static int aji_reconnect(struct aji_client *client);
00106 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
00107
00108
00109
00110
00111
00112
00113
00114 static char debug_usage[] =
00115 "Usage: jabber debug\n"
00116 " Enables dumping of Jabber packets for debugging purposes.\n";
00117
00118 static char no_debug_usage[] =
00119 "Usage: jabber debug off\n"
00120 " Disables dumping of Jabber packets for debugging purposes.\n";
00121
00122 static char reload_usage[] =
00123 "Usage: jabber reload\n"
00124 " Enables reloading of Jabber module.\n";
00125
00126 static char test_usage[] =
00127 "Usage: jabber test [client]\n"
00128 " Sends test message for debugging purposes. A specific client\n"
00129 " as configured in jabber.conf can be optionally specified.\n";
00130
00131 static struct ast_cli_entry aji_cli[] = {
00132 { { "jabber", "debug", NULL},
00133 aji_do_debug, "Enable Jabber debugging",
00134 debug_usage },
00135
00136 { { "jabber", "reload", NULL},
00137 aji_do_reload, "Reload Jabber configuration",
00138 reload_usage },
00139
00140 { { "jabber", "show", "connected", NULL},
00141 aji_show_clients, "Show state of clients and components",
00142 debug_usage },
00143
00144 { { "jabber", "debug", "off", NULL},
00145 aji_no_debug, "Disable Jabber debug",
00146 no_debug_usage },
00147
00148 { { "jabber", "test", NULL},
00149 aji_test, "Shows roster, but is generally used for mog's debugging.",
00150 test_usage },
00151 };
00152
00153 static char *app_ajisend = "JabberSend";
00154
00155 static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
00156
00157 static char *ajisend_descrip =
00158 "JabberSend(Jabber,ScreenName,Message)\n"
00159 " Jabber - Client or transport Asterisk uses to connect to Jabber\n"
00160 " ScreenName - User Name to message.\n"
00161 " Message - Message to be sent to the buddy\n";
00162
00163 static char *app_ajistatus = "JabberStatus";
00164
00165 static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
00166
00167 static char *ajistatus_descrip =
00168 "JabberStatus(Jabber,ScreenName,Variable)\n"
00169 " Jabber - Client or transport Asterisk uses to connect to Jabber\n"
00170 " ScreenName - User Name to retrieve status from.\n"
00171 " Variable - Variable to store presence in will be 1-6.\n"
00172 " In order, Online, Chatty, Away, XAway, DND, Offline\n"
00173 " If not in roster variable will = 7\n";
00174
00175 struct aji_client_container clients;
00176 struct aji_capabilities *capabilities = NULL;
00177
00178
00179 static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
00180 static int tls_initialized = FALSE;
00181
00182
00183
00184
00185
00186
00187 static void aji_client_destroy(struct aji_client *obj)
00188 {
00189 struct aji_message *tmp;
00190 ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
00191 ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00192 iks_filter_delete(obj->f);
00193 iks_parser_delete(obj->p);
00194 iks_stack_delete(obj->stack);
00195 AST_LIST_LOCK(&obj->messages);
00196 while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00197 if (tmp->from)
00198 free(tmp->from);
00199 if (tmp->message)
00200 free(tmp->message);
00201 }
00202 AST_LIST_HEAD_DESTROY(&obj->messages);
00203 free(obj);
00204 }
00205
00206
00207
00208
00209
00210
00211 static void aji_buddy_destroy(struct aji_buddy *obj)
00212 {
00213 struct aji_resource *tmp;
00214
00215 while ((tmp = obj->resources)) {
00216 obj->resources = obj->resources->next;
00217 free(tmp->description);
00218 free(tmp);
00219 }
00220
00221 free(obj);
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
00234 {
00235 struct aji_capabilities *list = NULL;
00236 struct aji_version *res = NULL;
00237
00238 list = capabilities;
00239
00240 if(!node)
00241 node = pak->from->full;
00242 if(!version)
00243 version = "none supplied.";
00244 while(list) {
00245 if(!strcasecmp(list->node, node)) {
00246 res = list->versions;
00247 while(res) {
00248 if(!strcasecmp(res->version, version))
00249 return res;
00250 res = res->next;
00251 }
00252
00253
00254 if(!res) {
00255 res = (struct aji_version *)malloc(sizeof(struct aji_version));
00256 if(!res) {
00257 ast_log(LOG_ERROR, "Out of memory!\n");
00258 return NULL;
00259 }
00260 res->jingle = 0;
00261 res->parent = list;
00262 ast_copy_string(res->version, version, sizeof(res->version));
00263 res->next = list->versions;
00264 list->versions = res;
00265 return res;
00266 }
00267 }
00268 list = list->next;
00269 }
00270
00271 if(!list) {
00272 list = (struct aji_capabilities *)malloc(sizeof(struct aji_capabilities));
00273 if(!list) {
00274 ast_log(LOG_ERROR, "Out of memory!\n");
00275 return NULL;
00276 }
00277 res = (struct aji_version *)malloc(sizeof(struct aji_version));
00278 if(!res) {
00279 ast_log(LOG_ERROR, "Out of memory!\n");
00280 return NULL;
00281 }
00282 ast_copy_string(list->node, node, sizeof(list->node));
00283 ast_copy_string(res->version, version, sizeof(res->version));
00284 res->jingle = 0;
00285 res->parent = list;
00286 res->next = NULL;
00287 list->versions = res;
00288 list->next = capabilities;
00289 capabilities = list;
00290 }
00291 return res;
00292 }
00293
00294 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
00295 {
00296 struct aji_resource *res = NULL;
00297 if (!buddy || !name)
00298 return res;
00299 res = buddy->resources;
00300 while (res) {
00301 if (!strcasecmp(res->resource, name)) {
00302 break;
00303 }
00304 res = res->next;
00305 }
00306 return res;
00307 }
00308
00309 static int gtalk_yuck(iks *node)
00310 {
00311 if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00312 return 1;
00313 return 0;
00314 }
00315
00316
00317
00318
00319
00320
00321 static int aji_highest_bit(int number)
00322 {
00323 int x = sizeof(number) * 8 - 1;
00324 if (!number)
00325 return 0;
00326 for (; x > 0; x--) {
00327 if (number & (1 << x))
00328 break;
00329 }
00330 return (1 << x);
00331 }
00332
00333 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
00334 {
00335 iks *x, *y;
00336 x = iks_new("iq");
00337 iks_insert_attrib(x, "type", "set");
00338 y = iks_insert(x, "query");
00339 iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00340 iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00341 iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00342 if (sid) {
00343 char buf[41];
00344 char sidpass[100];
00345 snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00346 ast_sha1_hash(buf, sidpass);
00347 iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00348 } else {
00349 iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00350 }
00351 return x;
00352 }
00353
00354
00355
00356
00357
00358
00359
00360 static int aji_status_exec(struct ast_channel *chan, void *data)
00361 {
00362 struct aji_client *client = NULL;
00363 struct aji_buddy *buddy = NULL;
00364 struct aji_resource *r = NULL;
00365 char *s = NULL, *sender = NULL, *jid = NULL, *screenname = NULL, *resource = NULL, *variable = NULL;
00366 int stat = 7;
00367 char status[2];
00368
00369 if (!data) {
00370 ast_log(LOG_ERROR, "This application requires arguments.\n");
00371 return 0;
00372 }
00373 s = ast_strdupa(data);
00374 if (s) {
00375 sender = strsep(&s, "|");
00376 if (sender && (sender[0] != '\0')) {
00377 jid = strsep(&s, "|");
00378 if (jid && (jid[0] != '\0')) {
00379 variable = s;
00380 } else {
00381 ast_log(LOG_ERROR, "Bad arguments\n");
00382 return -1;
00383 }
00384 }
00385 }
00386
00387 if(!strchr(jid, '/')) {
00388 resource = NULL;
00389 } else {
00390 screenname = strsep(&jid, "/");
00391 resource = jid;
00392 }
00393 client = ast_aji_get_client(sender);
00394 if (!client) {
00395 ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00396 return -1;
00397 }
00398 if(!&client->buddies) {
00399 ast_log(LOG_WARNING, "No buddies for connection : %s\n", sender);
00400 return -1;
00401 }
00402 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, resource ? screenname: jid);
00403 if (!buddy) {
00404 ast_log(LOG_WARNING, "Could not find buddy in list : %s\n", resource ? screenname : jid);
00405 return -1;
00406 }
00407 r = aji_find_resource(buddy, resource);
00408 if(!r && buddy->resources)
00409 r = buddy->resources;
00410 if(!r)
00411 ast_log(LOG_NOTICE, "Resource %s of buddy %s not found \n", resource, screenname);
00412 else
00413 stat = r->status;
00414 sprintf(status, "%d", stat);
00415 pbx_builtin_setvar_helper(chan, variable, status);
00416 return 0;
00417 }
00418
00419
00420
00421
00422
00423
00424 static int aji_send_exec(struct ast_channel *chan, void *data)
00425 {
00426 struct aji_client *client = NULL;
00427
00428 char *s = NULL, *sender = NULL, *recipient = NULL, *message = NULL;
00429
00430 if (!data) {
00431 ast_log(LOG_ERROR, "This application requires arguments.\n");
00432 return 0;
00433 }
00434 s = ast_strdupa(data);
00435 if (s) {
00436 sender = strsep(&s, "|");
00437 if (sender && (sender[0] != '\0')) {
00438 recipient = strsep(&s, "|");
00439 if (recipient && (recipient[0] != '\0')) {
00440 message = s;
00441 } else {
00442 ast_log(LOG_ERROR, "Bad arguments: %s\n", (char *) data);
00443 return -1;
00444 }
00445 }
00446 }
00447 if (!(client = ast_aji_get_client(sender))) {
00448 ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00449 return -1;
00450 }
00451 if (strchr(recipient, '@') && message)
00452 ast_aji_send(client, recipient, message);
00453 return 0;
00454 }
00455
00456
00457
00458
00459
00460 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
00461 {
00462 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00463 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00464
00465 if (client->debug) {
00466 if (is_incoming)
00467 ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00468 else {
00469 if( strlen(xmpp) == 1) {
00470 if(option_debug > 2 && xmpp[0] == ' ')
00471 ast_verbose("\nJABBER: Keep alive packet\n");
00472 } else
00473 ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00474 }
00475
00476 }
00477 ASTOBJ_UNREF(client, aji_client_destroy);
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487 static int aji_act_hook(void *data, int type, iks *node)
00488 {
00489 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00490 ikspak *pak = NULL;
00491 iks *auth = NULL;
00492
00493 if(!node) {
00494 ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n");
00495 ASTOBJ_UNREF(client, aji_client_destroy);
00496 return IKS_HOOK;
00497 }
00498
00499 if (client->state == AJI_DISCONNECTING) {
00500 ASTOBJ_UNREF(client, aji_client_destroy);
00501 return IKS_HOOK;
00502 }
00503
00504 pak = iks_packet(node);
00505
00506 if (!client->component) {
00507 switch (type) {
00508 case IKS_NODE_START:
00509 if (client->usetls && !iks_is_secure(client->p)) {
00510 if (iks_has_tls()) {
00511 iks_start_tls(client->p);
00512 tls_initialized = TRUE;
00513 } else
00514 ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
00515 break;
00516 }
00517 if (!client->usesasl) {
00518 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);
00519 auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00520 if (auth) {
00521 iks_insert_attrib(auth, "id", client->mid);
00522 iks_insert_attrib(auth, "to", client->jid->server);
00523 ast_aji_increment_mid(client->mid);
00524 iks_send(client->p, auth);
00525 iks_delete(auth);
00526 } else
00527 ast_log(LOG_ERROR, "Out of memory.\n");
00528 }
00529 break;
00530
00531 case IKS_NODE_NORMAL:
00532 {
00533 int features = 0;
00534 if (!strcmp("stream:features", iks_name(node))) {
00535 features = iks_stream_features(node);
00536 if (client->usesasl) {
00537 if (client->usetls && !iks_is_secure(client->p))
00538 break;
00539 if (client->authorized) {
00540 if (features & IKS_STREAM_BIND) {
00541 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);
00542 auth = iks_make_resource_bind(client->jid);
00543 if (auth) {
00544 iks_insert_attrib(auth, "id", client->mid);
00545 ast_aji_increment_mid(client->mid);
00546 iks_send(client->p, auth);
00547 iks_delete(auth);
00548 } else {
00549 ast_log(LOG_ERROR, "Out of memory.\n");
00550 break;
00551 }
00552 }
00553 if (features & IKS_STREAM_SESSION) {
00554 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);
00555 auth = iks_make_session();
00556 if (auth) {
00557 iks_insert_attrib(auth, "id", "auth");
00558 ast_aji_increment_mid(client->mid);
00559 iks_send(client->p, auth);
00560 iks_delete(auth);
00561 } else {
00562 ast_log(LOG_ERROR, "Out of memory.\n");
00563 }
00564 }
00565 } else {
00566 if (!client->jid->user) {
00567 ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00568 break;
00569 }
00570 features = aji_highest_bit(features);
00571 if (features == IKS_STREAM_SASL_MD5)
00572 iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, client->jid->user, client->password);
00573 else {
00574 if (features == IKS_STREAM_SASL_PLAIN) {
00575 iks *x = NULL;
00576 x = iks_new("auth");
00577 if (x) {
00578 int len = strlen(client->jid->user) + strlen(client->password) + 3;
00579
00580 char *s = ast_malloc(80 + len);
00581 char *base64 = ast_malloc(80 + len * 2);
00582 iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00583 iks_insert_attrib(x, "mechanism", "PLAIN");
00584 sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
00585 ast_base64encode(base64, (const unsigned char *) s, len, len * 2);
00586 iks_insert_cdata(x, base64, 0);
00587 iks_send(client->p, x);
00588 iks_delete(x);
00589 if (base64)
00590 free(base64);
00591 if (s)
00592 free(s);
00593 } else {
00594 ast_log(LOG_ERROR, "Out of memory.\n");
00595 }
00596 }
00597 }
00598 }
00599 }
00600 } else if (!strcmp("failure", iks_name(node))) {
00601 ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00602 } else if (!strcmp("success", iks_name(node))) {
00603 client->authorized = 1;
00604 iks_send_header(client->p, client->jid->server);
00605 }
00606 break;
00607 }
00608 case IKS_NODE_ERROR:
00609 ast_log(LOG_ERROR, "JABBER: Node Error\n");
00610 ASTOBJ_UNREF(client, aji_client_destroy);
00611 return IKS_HOOK;
00612 break;
00613 case IKS_NODE_STOP:
00614 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00615 ASTOBJ_UNREF(client, aji_client_destroy);
00616 return IKS_HOOK;
00617 break;
00618 }
00619 } else if (client->state != AJI_CONNECTED && client->component) {
00620 switch (type) {
00621 case IKS_NODE_START:
00622 if (client->state == AJI_DISCONNECTED) {
00623 char secret[160], shasum[320], *handshake;
00624
00625 sprintf(secret, "%s%s", pak->id, client->password);
00626 ast_sha1_hash(shasum, secret);
00627 handshake = NULL;
00628 asprintf(&handshake, "<handshake>%s</handshake>", shasum);
00629 if (handshake) {
00630 iks_send_raw(client->p, handshake);
00631 free(handshake);
00632 handshake = NULL;
00633 }
00634 client->state = AJI_CONNECTING;
00635 if(iks_recv(client->p,1) == 2)
00636 client->state = AJI_CONNECTED;
00637 else
00638 ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
00639 break;
00640 }
00641 break;
00642
00643 case IKS_NODE_NORMAL:
00644 break;
00645
00646 case IKS_NODE_ERROR:
00647 ast_log(LOG_ERROR, "JABBER: Node Error\n");
00648 ASTOBJ_UNREF(client, aji_client_destroy);
00649 return IKS_HOOK;
00650
00651 case IKS_NODE_STOP:
00652 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00653 ASTOBJ_UNREF(client, aji_client_destroy);
00654 return IKS_HOOK;
00655 }
00656 }
00657
00658 switch (pak->type) {
00659 case IKS_PAK_NONE:
00660 if (option_debug)
00661 ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
00662 break;
00663 case IKS_PAK_MESSAGE:
00664 aji_handle_message(client, pak);
00665 if (option_debug)
00666 ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
00667 break;
00668 case IKS_PAK_PRESENCE:
00669 aji_handle_presence(client, pak);
00670 if (option_debug)
00671 ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
00672 break;
00673 case IKS_PAK_S10N:
00674 aji_handle_subscribe(client, pak);
00675 if (option_debug)
00676 ast_log(LOG_DEBUG, "JABBER: I Dont know S10N subscribe!!\n");
00677 break;
00678 case IKS_PAK_IQ:
00679 if (option_debug)
00680 ast_log(LOG_DEBUG, "JABBER: I Dont have an IQ!!!\n");
00681 aji_handle_iq(client, node);
00682 break;
00683 default:
00684 if (option_debug)
00685 ast_log(LOG_DEBUG, "JABBER: I Dont know %i\n", pak->type);
00686 break;
00687 }
00688
00689 iks_filter_packet(client->f, pak);
00690
00691 if (node)
00692 iks_delete(node);
00693
00694 ASTOBJ_UNREF(client, aji_client_destroy);
00695 return IKS_OK;
00696 }
00697
00698 static int aji_register_approve_handler(void *data, ikspak *pak)
00699 {
00700 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00701 iks *iq = NULL, *presence = NULL, *x = NULL;
00702
00703 iq = iks_new("iq");
00704 presence = iks_new("presence");
00705 x = iks_new("x");
00706 if (client && iq && presence && x) {
00707 if (!iks_find(pak->query, "remove")) {
00708 iks_insert_attrib(iq, "from", client->jid->full);
00709 iks_insert_attrib(iq, "to", pak->from->full);
00710 iks_insert_attrib(iq, "id", pak->id);
00711 iks_insert_attrib(iq, "type", "result");
00712 iks_send(client->p, iq);
00713
00714 iks_insert_attrib(presence, "from", client->jid->full);
00715 iks_insert_attrib(presence, "to", pak->from->partial);
00716 iks_insert_attrib(presence, "id", client->mid);
00717 ast_aji_increment_mid(client->mid);
00718 iks_insert_attrib(presence, "type", "subscribe");
00719 iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
00720 iks_insert_node(presence, x);
00721 iks_send(client->p, presence);
00722 }
00723 } else {
00724 ast_log(LOG_ERROR, "Out of memory.\n");
00725 }
00726
00727 if (iq)
00728 iks_delete(iq);
00729 if(presence)
00730 iks_delete(presence);
00731 if (x)
00732 iks_delete(x);
00733 ASTOBJ_UNREF(client, aji_client_destroy);
00734 return IKS_FILTER_EAT;
00735 }
00736
00737 static int aji_register_query_handler(void *data, ikspak *pak)
00738 {
00739 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00740 struct aji_buddy *buddy = NULL;
00741 char *node = NULL;
00742
00743 client = (struct aji_client *) data;
00744
00745 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00746 if (!buddy) {
00747 iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
00748 ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
00749 iq = iks_new("iq");
00750 query = iks_new("query");
00751 error = iks_new("error");
00752 notacceptable = iks_new("not-acceptable");
00753 if(iq && query && error && notacceptable) {
00754 iks_insert_attrib(iq, "type", "error");
00755 iks_insert_attrib(iq, "from", client->user);
00756 iks_insert_attrib(iq, "to", pak->from->full);
00757 iks_insert_attrib(iq, "id", pak->id);
00758 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00759 iks_insert_attrib(error, "code" , "406");
00760 iks_insert_attrib(error, "type", "modify");
00761 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
00762 iks_insert_node(iq, query);
00763 iks_insert_node(iq, error);
00764 iks_insert_node(error, notacceptable);
00765 iks_send(client->p, iq);
00766 } else {
00767 ast_log(LOG_ERROR, "Out of memory.\n");
00768 }
00769 if (iq)
00770 iks_delete(iq);
00771 if (query)
00772 iks_delete(query);
00773 if (error)
00774 iks_delete(error);
00775 if (notacceptable)
00776 iks_delete(notacceptable);
00777 } else if (!(node = iks_find_attrib(pak->query, "node"))) {
00778 iks *iq = NULL, *query = NULL, *instructions = NULL;
00779 char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
00780 iq = iks_new("iq");
00781 query = iks_new("query");
00782 instructions = iks_new("instructions");
00783 if (iq && query && instructions && client) {
00784 iks_insert_attrib(iq, "from", client->user);
00785 iks_insert_attrib(iq, "to", pak->from->full);
00786 iks_insert_attrib(iq, "id", pak->id);
00787 iks_insert_attrib(iq, "type", "result");
00788 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00789 iks_insert_cdata(instructions, explain, 0);
00790 iks_insert_node(iq, query);
00791 iks_insert_node(query, instructions);
00792 iks_send(client->p, iq);
00793 } else {
00794 ast_log(LOG_ERROR, "Out of memory.\n");
00795 }
00796 if (iq)
00797 iks_delete(iq);
00798 if (query)
00799 iks_delete(query);
00800 if (instructions)
00801 iks_delete(instructions);
00802 }
00803 ASTOBJ_UNREF(client, aji_client_destroy);
00804 return IKS_FILTER_EAT;
00805 }
00806
00807 static int aji_ditems_handler(void *data, ikspak *pak)
00808 {
00809 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00810 char *node = NULL;
00811
00812 if (!(node = iks_find_attrib(pak->query, "node"))) {
00813 iks *iq = NULL, *query = NULL, *item = NULL;
00814 iq = iks_new("iq");
00815 query = iks_new("query");
00816 item = iks_new("item");
00817
00818 if (iq && query && item) {
00819 iks_insert_attrib(iq, "from", client->user);
00820 iks_insert_attrib(iq, "to", pak->from->full);
00821 iks_insert_attrib(iq, "id", pak->id);
00822 iks_insert_attrib(iq, "type", "result");
00823 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00824 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
00825 iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
00826 iks_insert_attrib(item, "jid", client->user);
00827
00828 iks_insert_node(iq, query);
00829 iks_insert_node(query, item);
00830 iks_send(client->p, iq);
00831 } else {
00832 ast_log(LOG_ERROR, "Out of memory.\n");
00833 }
00834 if (iq)
00835 iks_delete(iq);
00836 if (query)
00837 iks_delete(query);
00838 if (item)
00839 iks_delete(item);
00840
00841 } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
00842 iks *iq, *query, *confirm;
00843 iq = iks_new("iq");
00844 query = iks_new("query");
00845 confirm = iks_new("item");
00846 if (iq && query && confirm && client) {
00847 iks_insert_attrib(iq, "from", client->user);
00848 iks_insert_attrib(iq, "to", pak->from->full);
00849 iks_insert_attrib(iq, "id", pak->id);
00850 iks_insert_attrib(iq, "type", "result");
00851 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00852 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
00853 iks_insert_attrib(confirm, "node", "confirmaccount");
00854 iks_insert_attrib(confirm, "name", "Confirm AIM account");
00855 iks_insert_attrib(confirm, "jid", "blog.astjab.org");
00856
00857 iks_insert_node(iq, query);
00858 iks_insert_node(query, confirm);
00859 iks_send(client->p, iq);
00860 } else {
00861 ast_log(LOG_ERROR, "Out of memory.\n");
00862 }
00863 if (iq)
00864 iks_delete(iq);
00865 if (query)
00866 iks_delete(query);
00867 if (confirm)
00868 iks_delete(confirm);
00869
00870 } else if (!strcasecmp(node, "confirmaccount")) {
00871 iks *iq = NULL, *query = NULL, *feature = NULL;
00872
00873 iq = iks_new("iq");
00874 query = iks_new("query");
00875 feature = iks_new("feature");
00876
00877 if (iq && query && feature && client) {
00878 iks_insert_attrib(iq, "from", client->user);
00879 iks_insert_attrib(iq, "to", pak->from->full);
00880 iks_insert_attrib(iq, "id", pak->id);
00881 iks_insert_attrib(iq, "type", "result");
00882 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00883 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
00884 iks_insert_node(iq, query);
00885 iks_insert_node(query, feature);
00886 iks_send(client->p, iq);
00887 } else {
00888 ast_log(LOG_ERROR, "Out of memory.\n");
00889 }
00890 if (iq)
00891 iks_delete(iq);
00892 if (query)
00893 iks_delete(query);
00894 if (feature)
00895 iks_delete(feature);
00896 }
00897
00898 ASTOBJ_UNREF(client, aji_client_destroy);
00899 return IKS_FILTER_EAT;
00900
00901 }
00902
00903 static int aji_client_info_handler(void *data, ikspak *pak)
00904 {
00905 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00906 struct aji_resource *resource = NULL;
00907 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00908
00909 resource = aji_find_resource(buddy, pak->from->resource);
00910 if (pak->subtype == IKS_TYPE_RESULT) {
00911 if (!resource) {
00912 ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00913 ASTOBJ_UNREF(client, aji_client_destroy);
00914 return IKS_FILTER_EAT;
00915 }
00916 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00917 resource->cap->jingle = 1;
00918 } else
00919 resource->cap->jingle = 0;
00920 } else if (pak->subtype == IKS_TYPE_GET) {
00921 iks *iq, *disco, *ident, *google, *query;
00922 iq = iks_new("iq");
00923 query = iks_new("query");
00924 ident = iks_new("identity");
00925 disco = iks_new("feature");
00926 google = iks_new("feature");
00927 if (iq && ident && disco && google) {
00928 iks_insert_attrib(iq, "from", client->jid->full);
00929 iks_insert_attrib(iq, "to", pak->from->full);
00930 iks_insert_attrib(iq, "type", "result");
00931 iks_insert_attrib(iq, "id", pak->id);
00932 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
00933 iks_insert_attrib(ident, "category", "client");
00934 iks_insert_attrib(ident, "type", "pc");
00935 iks_insert_attrib(ident, "name", "asterisk");
00936 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
00937 iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
00938 iks_insert_node(iq, query);
00939 iks_insert_node(query, ident);
00940 iks_insert_node(query, google);
00941 iks_insert_node(query, disco);
00942 iks_send(client->p, iq);
00943 } else
00944 ast_log(LOG_ERROR, "Out of Memory.\n");
00945 if (iq)
00946 iks_delete(iq);
00947 if (query)
00948 iks_delete(query);
00949 if (ident)
00950 iks_delete(ident);
00951 if (google)
00952 iks_delete(google);
00953 if (disco)
00954 iks_delete(disco);
00955 } else if (pak->subtype == IKS_TYPE_ERROR) {
00956 ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
00957 }
00958 ASTOBJ_UNREF(client, aji_client_destroy);
00959 return IKS_FILTER_EAT;
00960 }
00961
00962 static int aji_dinfo_handler(void *data, ikspak *pak)
00963 {
00964 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00965 char *node = NULL;
00966 struct aji_resource *resource = NULL;
00967 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00968
00969 resource = aji_find_resource(buddy, pak->from->resource);
00970 if (pak->subtype == IKS_TYPE_ERROR) {
00971 ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
00972 return IKS_FILTER_EAT;
00973 }
00974 if (pak->subtype == IKS_TYPE_RESULT) {
00975 if (!resource) {
00976 ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00977 ASTOBJ_UNREF(client, aji_client_destroy);
00978 return IKS_FILTER_EAT;
00979 }
00980 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00981 resource->cap->jingle = 1;
00982 } else
00983 resource->cap->jingle = 0;
00984 } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
00985 iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
00986
00987 iq = iks_new("iq");
00988 query = iks_new("query");
00989 identity = iks_new("identity");
00990 disco = iks_new("feature");
00991 reg = iks_new("feature");
00992 commands = iks_new("feature");
00993 gateway = iks_new("feature");
00994 version = iks_new("feature");
00995 vcard = iks_new("feature");
00996 search = iks_new("feature");
00997
00998 if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
00999 iks_insert_attrib(iq, "from", client->user);
01000 iks_insert_attrib(iq, "to", pak->from->full);
01001 iks_insert_attrib(iq, "id", pak->id);
01002 iks_insert_attrib(iq, "type", "result");
01003 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01004 iks_insert_attrib(identity, "category", "gateway");
01005 iks_insert_attrib(identity, "type", "pstn");
01006 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01007 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01008 iks_insert_attrib(reg, "var", "jabber:iq:register");
01009 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01010 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01011 iks_insert_attrib(version, "var", "jabber:iq:version");
01012 iks_insert_attrib(vcard, "var", "vcard-temp");
01013 iks_insert_attrib(search, "var", "jabber:iq:search");
01014
01015 iks_insert_node(iq, query);
01016 iks_insert_node(query, identity);
01017 iks_insert_node(query, disco);
01018 iks_insert_node(query, reg);
01019 iks_insert_node(query, commands);
01020 iks_insert_node(query, gateway);
01021 iks_insert_node(query, version);
01022 iks_insert_node(query, vcard);
01023 iks_insert_node(query, search);
01024 iks_send(client->p, iq);
01025 } else {
01026 ast_log(LOG_ERROR, "Out of memory.\n");
01027 }
01028
01029 if (iq)
01030 iks_delete(iq);
01031 if (query)
01032 iks_delete(query);
01033 if (identity)
01034 iks_delete(identity);
01035 if (disco)
01036 iks_delete(disco);
01037 if (reg)
01038 iks_delete(reg);
01039 if (commands)
01040 iks_delete(commands);
01041 if (gateway)
01042 iks_delete(gateway);
01043 if (version)
01044 iks_delete(version);
01045 if (vcard)
01046 iks_delete(vcard);
01047 if (search)
01048 iks_delete(search);
01049
01050 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01051 iks *iq, *query, *confirm;
01052 iq = iks_new("iq");
01053 query = iks_new("query");
01054 confirm = iks_new("item");
01055
01056 if (iq && query && confirm && client) {
01057 iks_insert_attrib(iq, "from", client->user);
01058 iks_insert_attrib(iq, "to", pak->from->full);
01059 iks_insert_attrib(iq, "id", pak->id);
01060 iks_insert_attrib(iq, "type", "result");
01061 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01062 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01063 iks_insert_attrib(confirm, "node", "confirmaccount");
01064 iks_insert_attrib(confirm, "name", "Confirm AIM account");
01065 iks_insert_attrib(confirm, "jid", client->user);
01066 iks_insert_node(iq, query);
01067 iks_insert_node(query, confirm);
01068 iks_send(client->p, iq);
01069 } else {
01070 ast_log(LOG_ERROR, "Out of memory.\n");
01071 }
01072 if (iq)
01073 iks_delete(iq);
01074 if (query)
01075 iks_delete(query);
01076 if (confirm)
01077 iks_delete(confirm);
01078
01079 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01080 iks *iq, *query, *feature;
01081
01082 iq = iks_new("iq");
01083 query = iks_new("query");
01084 feature = iks_new("feature");
01085
01086 if (iq && query && feature && client) {
01087 iks_insert_attrib(iq, "from", client->user);
01088 iks_insert_attrib(iq, "to", pak->from->full);
01089 iks_insert_attrib(iq, "id", pak->id);
01090 iks_insert_attrib(iq, "type", "result");
01091 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01092 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01093 iks_insert_node(iq, query);
01094 iks_insert_node(query, feature);
01095 iks_send(client->p, iq);
01096 } else {
01097 ast_log(LOG_ERROR, "Out of memory.\n");
01098 }
01099 if (iq)
01100 iks_delete(iq);
01101 if (query)
01102 iks_delete(query);
01103 if (feature)
01104 iks_delete(feature);
01105 }
01106
01107 ASTOBJ_UNREF(client, aji_client_destroy);
01108 return IKS_FILTER_EAT;
01109 }
01110
01111
01112
01113
01114
01115
01116 static void aji_handle_iq(struct aji_client *client, iks *node)
01117 {
01118
01119 }
01120
01121
01122
01123
01124
01125
01126 static void aji_handle_message(struct aji_client *client, ikspak *pak)
01127 {
01128 struct aji_message *insert, *tmp;
01129 int flag = 0;
01130
01131 if (!(insert = ast_calloc(1, sizeof(struct aji_message))))
01132 return;
01133 time(&insert->arrived);
01134 if (iks_find_cdata(pak->x, "body"))
01135 insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01136 if(pak->id)
01137 ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01138 if (pak->from)
01139 insert->from = ast_strdup(pak->from->full);
01140 AST_LIST_LOCK(&client->messages);
01141 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01142 if (flag) {
01143 AST_LIST_REMOVE_CURRENT(&client->messages, list);
01144 if (tmp->from)
01145 free(tmp->from);
01146 if (tmp->message)
01147 free(tmp->message);
01148 } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01149 flag = 1;
01150 AST_LIST_REMOVE_CURRENT(&client->messages, list);
01151 if (tmp->from)
01152 free(tmp->from);
01153 if (tmp->message)
01154 free(tmp->message);
01155 }
01156 }
01157 AST_LIST_TRAVERSE_SAFE_END;
01158 AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01159 AST_LIST_UNLOCK(&client->messages);
01160 }
01161
01162 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
01163 {
01164 int status, priority;
01165 struct aji_buddy *buddy;
01166 struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01167 char *ver, *node, *descrip, *type;
01168
01169 if(client->state != AJI_CONNECTED)
01170 aji_create_buddy(pak->from->partial, client);
01171
01172 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01173 if (!buddy) {
01174 ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01175 return;
01176 }
01177 type = iks_find_attrib(pak->x, "type");
01178 if(client->component && type &&!strcasecmp("probe", type)) {
01179 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01180 ast_verbose("what i was looking for \n");
01181 }
01182 ASTOBJ_WRLOCK(buddy);
01183 status = (pak->show) ? pak->show : 6;
01184 priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01185 tmp = buddy->resources;
01186 descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01187
01188 while (tmp) {
01189 if (!strcasecmp(tmp->resource, pak->from->resource)) {
01190 tmp->status = status;
01191 if (tmp->description) free(tmp->description);
01192 tmp->description = descrip;
01193 found = tmp;
01194 if (status == 6) {
01195 if (last && found->next) {
01196 last->next = found->next;
01197 } else if (!last) {
01198 if (found->next)
01199 buddy->resources = found->next;
01200 else
01201 buddy->resources = NULL;
01202 } else if (!found->next) {
01203 if (last)
01204 last->next = NULL;
01205 else
01206 buddy->resources = NULL;
01207 }
01208 free(found);
01209 found = NULL;
01210 break;
01211 }
01212
01213 if (tmp->priority != priority) {
01214 found->priority = priority;
01215 if (!last && !found->next)
01216
01217
01218 break;
01219
01220
01221 if (last)
01222 last->next = found->next;
01223 else
01224 buddy->resources = found->next;
01225
01226 last = NULL;
01227 tmp = buddy->resources;
01228 if (!buddy->resources)
01229 buddy->resources = found;
01230
01231 while (tmp) {
01232
01233
01234 if (found->priority > tmp->priority) {
01235 if (last)
01236
01237 last->next = found;
01238 found->next = tmp;
01239 if (!last)
01240
01241 buddy->resources = found;
01242 break;
01243 }
01244 if (!tmp->next) {
01245
01246 tmp->next = found;
01247 found->next = NULL;
01248 break;
01249 }
01250 last = tmp;
01251 tmp = tmp->next;
01252 }
01253 }
01254 break;
01255 }
01256 last = tmp;
01257 tmp = tmp->next;
01258 }
01259
01260
01261 if (!found && status != 6) {
01262 found = (struct aji_resource *) malloc(sizeof(struct aji_resource));
01263 memset(found, 0, sizeof(struct aji_resource));
01264
01265 if (!found) {
01266 ast_log(LOG_ERROR, "Out of memory!\n");
01267 return;
01268 }
01269 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01270 found->status = status;
01271 found->description = descrip;
01272 found->priority = priority;
01273 found->next = NULL;
01274 last = NULL;
01275 tmp = buddy->resources;
01276 while (tmp) {
01277 if (found->priority > tmp->priority) {
01278 if (last)
01279 last->next = found;
01280 found->next = tmp;
01281 if (!last)
01282 buddy->resources = found;
01283 break;
01284 }
01285 if (!tmp->next) {
01286 tmp->next = found;
01287 break;
01288 }
01289 last = tmp;
01290 tmp = tmp->next;
01291 }
01292 if (!tmp)
01293 buddy->resources = found;
01294 }
01295
01296
01297
01298 if (!found && !pak->from->resource && buddy->resources) {
01299 found = buddy->resources;
01300 }
01301
01302 ASTOBJ_UNLOCK(buddy);
01303 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01304
01305 node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01306 ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01307
01308
01309 if (!node && !ver) {
01310 node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01311 ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01312 }
01313
01314 if(status !=6 && !found->cap) {
01315 found->cap = aji_find_version(node, ver, pak);
01316 if(gtalk_yuck(pak->x))
01317 found->cap->jingle = 1;
01318 if(found->cap->jingle && option_debug > 4)
01319 ast_log(LOG_DEBUG,"Special case for google till they support discover.\n");
01320 else {
01321 iks *iq, *query;
01322 iq = iks_new("iq");
01323 query = iks_new("query");
01324 if(query && iq) {
01325 iks_insert_attrib(iq, "type", "get");
01326 iks_insert_attrib(iq, "to", pak->from->full);
01327 iks_insert_attrib(iq,"from",iks_find_attrib(pak->x,"to"));
01328 iks_insert_attrib(iq, "id", client->mid);
01329 ast_aji_increment_mid(client->mid);
01330 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01331 iks_insert_node(iq, query);
01332 iks_send(client->p, iq);
01333
01334 } else
01335 ast_log(LOG_ERROR, "Out of memory.\n");
01336 if(query)
01337 iks_delete(query);
01338 if(iq)
01339 iks_delete(iq);
01340 }
01341 }
01342 if (option_verbose > 4) {
01343 switch (pak->subtype) {
01344 case IKS_TYPE_AVAILABLE:
01345 ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am available ^_* %i\n", pak->subtype);
01346 break;
01347 case IKS_TYPE_UNAVAILABLE:
01348 ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01349 break;
01350 default:
01351 ast_verbose(VERBOSE_PREFIX_3 "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01352 }
01353 switch (pak->show) {
01354 case IKS_SHOW_UNAVAILABLE:
01355 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01356 break;
01357 case IKS_SHOW_AVAILABLE:
01358 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is available\n");
01359 break;
01360 case IKS_SHOW_CHAT:
01361 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01362 break;
01363 case IKS_SHOW_AWAY:
01364 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is away\n");
01365 break;
01366 case IKS_SHOW_XA:
01367 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01368 break;
01369 case IKS_SHOW_DND:
01370 ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01371 break;
01372 default:
01373 ast_verbose(VERBOSE_PREFIX_3 "JABBER: Kinky! how did that happen %i\n", pak->show);
01374 }
01375 }
01376 }
01377
01378
01379
01380
01381
01382
01383 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
01384 {
01385 if(pak->subtype == IKS_TYPE_SUBSCRIBE) {
01386 iks *presence = NULL, *status = NULL;
01387 presence = iks_new("presence");
01388 status = iks_new("status");
01389 if(presence && status) {
01390 iks_insert_attrib(presence, "type", "subscribed");
01391 iks_insert_attrib(presence, "to", pak->from->full);
01392 iks_insert_attrib(presence, "from", client->jid->full);
01393 if(pak->id)
01394 iks_insert_attrib(presence, "id", pak->id);
01395 iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01396 iks_insert_node(presence, status);
01397 iks_send(client->p, presence);
01398 } else
01399 ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01400 if(presence)
01401 iks_delete(presence);
01402 if(status)
01403 iks_delete(status);
01404 if(client->component)
01405 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01406 }
01407 if (option_verbose > 4) {
01408 switch (pak->subtype) {
01409 case IKS_TYPE_SUBSCRIBE:
01410 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01411 break;
01412 case IKS_TYPE_SUBSCRIBED:
01413 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01414 break;
01415 case IKS_TYPE_UNSUBSCRIBE:
01416 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01417 break;
01418 case IKS_TYPE_UNSUBSCRIBED:
01419 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01420 break;
01421 default:
01422 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01423 break;
01424 }
01425 }
01426 }
01427
01428
01429
01430
01431
01432
01433 int ast_aji_send(struct aji_client *client, const char *address, const char *message)
01434 {
01435 int res = 0;
01436 iks *message_packet = NULL;
01437 if (client->state == AJI_CONNECTED) {
01438 message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01439 if (message_packet) {
01440 iks_insert_attrib(message_packet, "from", client->jid->full);
01441 res = iks_send(client->p, message_packet);
01442 } else {
01443 ast_log(LOG_ERROR, "Out of memory.\n");
01444 }
01445 if (message_packet)
01446 iks_delete(message_packet);
01447 } else
01448 ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01449 return 1;
01450 }
01451
01452
01453
01454
01455
01456
01457 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
01458 {
01459 int res = 0;
01460 iks *iq = NULL;
01461 iq = iks_new("iq");
01462 if (iq && client) {
01463 iks_insert_attrib(iq, "type", "get");
01464 iks_insert_attrib(iq, "to", server);
01465 iks_insert_attrib(iq, "id", client->mid);
01466 ast_aji_increment_mid(client->mid);
01467 iks_send(client->p, iq);
01468 } else
01469 ast_log(LOG_ERROR, "Out of memory.\n");
01470 return res;
01471 }
01472
01473
01474
01475
01476
01477
01478 int ast_aji_join_chat(struct aji_client *client, char *room)
01479 {
01480 int res = 0;
01481 iks *presence = NULL, *priority = NULL;
01482 presence = iks_new("presence");
01483 priority = iks_new("priority");
01484 if (presence && priority && client) {
01485 iks_insert_cdata(priority, "0", 1);
01486 iks_insert_attrib(presence, "to", room);
01487 iks_insert_node(presence, priority);
01488 res = iks_send(client->p, presence);
01489 iks_insert_cdata(priority, "5", 1);
01490 iks_insert_attrib(presence, "to", room);
01491 res = iks_send(client->p, presence);
01492 } else
01493 ast_log(LOG_ERROR, "Out of memory.\n");
01494 if (presence)
01495 iks_delete(presence);
01496 if (priority)
01497 iks_delete(priority);
01498 return res;
01499 }
01500
01501
01502
01503
01504
01505
01506 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
01507 {
01508 int res = 0;
01509 iks *invite, *body, *namespace;
01510
01511 invite = iks_new("message");
01512 body = iks_new("body");
01513 namespace = iks_new("x");
01514 if (client && invite && body && namespace) {
01515 iks_insert_attrib(invite, "to", user);
01516 iks_insert_attrib(invite, "id", client->mid);
01517 ast_aji_increment_mid(client->mid);
01518 iks_insert_cdata(body, message, 0);
01519 iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01520 iks_insert_attrib(namespace, "jid", room);
01521 iks_insert_node(invite, body);
01522 iks_insert_node(invite, namespace);
01523 res = iks_send(client->p, invite);
01524 } else
01525 ast_log(LOG_ERROR, "Out of memory.\n");
01526 if (body)
01527 iks_delete(body);
01528 if (namespace)
01529 iks_delete(namespace);
01530 if (invite)
01531 iks_delete(invite);
01532 return res;
01533 }
01534
01535
01536
01537
01538
01539
01540
01541 static void *aji_recv_loop(void *data)
01542 {
01543 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01544 int res = IKS_HOOK;
01545 do {
01546 if (res != IKS_OK) {
01547 while(res != IKS_OK) {
01548 if(option_verbose > 3)
01549 ast_verbose("JABBER: reconnecting.\n");
01550 res = aji_reconnect(client);
01551 sleep(4);
01552 }
01553 }
01554
01555 res = iks_recv(client->p, 1);
01556
01557 if (client->state == AJI_DISCONNECTING) {
01558 if (option_debug > 1)
01559 ast_log(LOG_DEBUG, "Ending our Jabber client's thread due to a disconnect\n");
01560 pthread_exit(NULL);
01561 }
01562 client->timeout--;
01563 if (res == IKS_HOOK)
01564 ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
01565 else if (res == IKS_NET_TLSFAIL)
01566 ast_log(LOG_WARNING, "JABBER: Failure in TLS.\n");
01567 else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
01568 res = iks_send_raw(client->p, " ");
01569 if(res == IKS_OK)
01570 client->timeout = 50;
01571 else
01572 ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
01573 } else if (res == IKS_NET_RWERR)
01574 ast_log(LOG_WARNING, "JABBER: socket read error\n");
01575 } while (client);
01576 ASTOBJ_UNREF(client, aji_client_destroy);
01577 return 0;
01578 }
01579
01580
01581
01582
01583
01584
01585 void ast_aji_increment_mid(char *mid)
01586 {
01587 int i = 0;
01588
01589 for (i = strlen(mid) - 1; i >= 0; i--) {
01590 if (mid[i] != 'z') {
01591 mid[i] = mid[i] + 1;
01592 i = 0;
01593 } else
01594 mid[i] = 'a';
01595 }
01596 }
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692 static void aji_pruneregister(struct aji_client *client)
01693 {
01694 int res = 0;
01695 iks *removeiq = iks_new("iq");
01696 iks *removequery = iks_new("query");
01697 iks *removeitem = iks_new("item");
01698 iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
01699
01700 if (client && removeiq && removequery && removeitem && send) {
01701 iks_insert_node(removeiq, removequery);
01702 iks_insert_node(removequery, removeitem);
01703 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01704 ASTOBJ_RDLOCK(iterator);
01705
01706
01707 if (ast_test_flag(iterator, AJI_AUTOPRUNE)) {
01708 res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
01709 "GoodBye your status is no longer needed by Asterisk the Open Source PBX"
01710 " so I am no longer subscribing to your presence.\n"));
01711 res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
01712 "GoodBye you are no longer in the asterisk config file so I am removing"
01713 " your access to my presence.\n"));
01714 iks_insert_attrib(removeiq, "from", client->jid->full);
01715 iks_insert_attrib(removeiq, "type", "set");
01716 iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
01717 iks_insert_attrib(removeitem, "jid", iterator->name);
01718 iks_insert_attrib(removeitem, "subscription", "remove");
01719 res = iks_send(client->p, removeiq);
01720 } else if (ast_test_flag(iterator, AJI_AUTOREGISTER)) {
01721 res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
01722 "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
01723 ast_clear_flag(iterator, AJI_AUTOREGISTER);
01724 }
01725 ASTOBJ_UNLOCK(iterator);
01726 });
01727 } else
01728 ast_log(LOG_ERROR, "Out of memory.\n");
01729 if (removeiq)
01730 iks_delete(removeiq);
01731 if (removequery)
01732 iks_delete(removequery);
01733 if (removeitem)
01734 iks_delete(removeitem);
01735 if (send)
01736 iks_delete(send);
01737 ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
01738 }
01739
01740
01741
01742
01743
01744
01745 static int aji_filter_roster(void *data, ikspak *pak)
01746 {
01747 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01748 int flag = 0;
01749 iks *x = NULL;
01750 struct aji_buddy *buddy;
01751
01752 client->state = AJI_CONNECTED;
01753 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01754 ASTOBJ_RDLOCK(iterator);
01755 x = iks_child(pak->query);
01756 flag = 0;
01757 while (x) {
01758 if (!iks_strcmp(iks_name(x), "item")) {
01759 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
01760 flag = 1;
01761 ast_clear_flag(iterator, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
01762 }
01763 }
01764 x = iks_next(x);
01765 }
01766 if (!flag)
01767 ast_copy_flags(iterator, client, AJI_AUTOREGISTER);
01768 if (x)
01769 iks_delete(x);
01770 ASTOBJ_UNLOCK(iterator);
01771 });
01772
01773 x = iks_child(pak->query);
01774 while (x) {
01775 flag = 0;
01776 if (iks_strcmp(iks_name(x), "item") == 0) {
01777 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01778 ASTOBJ_RDLOCK(iterator);
01779 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
01780 flag = 1;
01781 ASTOBJ_UNLOCK(iterator);
01782 });
01783
01784 if (!flag) {
01785 buddy = (struct aji_buddy *) malloc(sizeof(struct aji_buddy));
01786 if (!buddy) {
01787 ast_log(LOG_WARNING, "Out of memory\n");
01788 return 0;
01789 }
01790 memset(buddy, 0, sizeof(struct aji_buddy));
01791 ASTOBJ_INIT(buddy);
01792 ASTOBJ_WRLOCK(buddy);
01793 ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
01794 ast_clear_flag(buddy, AST_FLAGS_ALL);
01795 if(ast_test_flag(client, AJI_AUTOPRUNE)) {
01796 ast_set_flag(buddy, AJI_AUTOPRUNE);
01797 buddy->objflags |= ASTOBJ_FLAG_MARKED;
01798 } else
01799 ast_set_flag(buddy, AJI_AUTOREGISTER);
01800 ASTOBJ_UNLOCK(buddy);
01801 if (buddy) {
01802 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
01803 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01804 }
01805 }
01806 }
01807 x = iks_next(x);
01808 }
01809 if (x)
01810 iks_delete(x);
01811 aji_pruneregister(client);
01812
01813 ASTOBJ_UNREF(client, aji_client_destroy);
01814 return IKS_FILTER_EAT;
01815 }
01816
01817 static int aji_reconnect(struct aji_client *client)
01818 {
01819 int res = 0;
01820
01821 if (client->state)
01822 client->state = AJI_DISCONNECTED;
01823 client->timeout=50;
01824 if (client->p)
01825 iks_parser_reset(client->p);
01826 if (client->authorized)
01827 client->authorized = 0;
01828
01829 if(client->component)
01830 res = aji_component_initialize(client);
01831 else
01832 res = aji_client_initialize(client);
01833
01834 return res;
01835 }
01836
01837 static int aji_get_roster(struct aji_client *client)
01838 {
01839 iks *roster = NULL;
01840 roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
01841 if(roster) {
01842 iks_insert_attrib(roster, "id", "roster");
01843 aji_set_presence(client, NULL, client->jid->full, 1, client->statusmessage);
01844 iks_send(client->p, roster);
01845 }
01846 if (roster)
01847 iks_delete(roster);
01848 return 1;
01849 }
01850
01851
01852
01853
01854
01855
01856 static int aji_client_connect(void *data, ikspak *pak)
01857 {
01858 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01859 int res = 0;
01860
01861 if (client) {
01862 if (client->state == AJI_DISCONNECTED) {
01863 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);
01864 client->state = AJI_CONNECTING;
01865 client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
01866 iks_filter_remove_hook(client->f, aji_client_connect);
01867 if(!client->component)
01868 aji_get_roster(client);
01869 }
01870 } else
01871 ast_log(LOG_ERROR, "Out of memory.\n");
01872
01873 ASTOBJ_UNREF(client, aji_client_destroy);
01874 return res;
01875 }
01876
01877
01878
01879
01880
01881
01882 static int aji_client_initialize(struct aji_client *client)
01883 {
01884 int connected = 0;
01885
01886 connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->jid->server);
01887
01888 if (connected == IKS_NET_NOCONN) {
01889 ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01890 return IKS_HOOK;
01891 } else if (connected == IKS_NET_NODNS) {
01892 ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01893 return IKS_HOOK;
01894 } else
01895 iks_recv(client->p, 30);
01896 return IKS_OK;
01897 }
01898
01899
01900
01901
01902
01903
01904 static int aji_component_initialize(struct aji_client *client)
01905 {
01906 int connected = 1;
01907
01908 connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->user);
01909 if (connected == IKS_NET_NOCONN) {
01910 ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01911 return IKS_HOOK;
01912 } else if (connected == IKS_NET_NODNS) {
01913 ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01914 return IKS_HOOK;
01915 } else if (!connected)
01916 iks_recv(client->p, 30);
01917 return IKS_OK;
01918 }
01919
01920
01921
01922
01923
01924
01925 int ast_aji_disconnect(struct aji_client *client)
01926 {
01927 if (client) {
01928 if (option_verbose > 3)
01929 ast_verbose(VERBOSE_PREFIX_3 "JABBER: Disconnecting\n");
01930 iks_disconnect(client->p);
01931 iks_parser_delete(client->p);
01932 ASTOBJ_UNREF(client, aji_client_destroy);
01933 }
01934
01935 return 1;
01936 }
01937
01938
01939
01940
01941
01942
01943 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
01944 {
01945 int res = 0;
01946 iks *presence = iks_make_pres(level, desc);
01947 iks *cnode = iks_new("c");
01948 iks *priority = iks_new("priority");
01949
01950 iks_insert_cdata(priority, "0", 1);
01951 if (presence && cnode && client) {
01952 if(to)
01953 iks_insert_attrib(presence, "to", to);
01954 if(from)
01955 iks_insert_attrib(presence, "from", from);
01956 iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
01957 iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
01958 iks_insert_attrib(cnode, "ext", "voice-v1");
01959 iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
01960 iks_insert_node(presence, cnode);
01961 res = iks_send(client->p, presence);
01962 } else
01963 ast_log(LOG_ERROR, "Out of memory.\n");
01964 if (cnode)
01965 iks_delete(cnode);
01966 if (presence)
01967 iks_delete(presence);
01968 }
01969
01970
01971
01972
01973
01974
01975 static int aji_do_debug(int fd, int argc, char *argv[])
01976 {
01977 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
01978 ASTOBJ_RDLOCK(iterator);
01979 iterator->debug = 1;
01980 ASTOBJ_UNLOCK(iterator);
01981 });
01982 ast_cli(fd, "Jabber Debugging Enabled.\n");
01983 return RESULT_SUCCESS;
01984 }
01985
01986
01987
01988
01989
01990
01991 static int aji_do_reload(int fd, int argc, char *argv[])
01992 {
01993 aji_reload();
01994 ast_cli(fd, "Jabber Reloaded.\n");
01995 return RESULT_SUCCESS;
01996 }
01997
01998
01999
02000
02001
02002
02003 static int aji_no_debug(int fd, int argc, char *argv[])
02004 {
02005 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02006 ASTOBJ_RDLOCK(iterator);
02007 iterator->debug = 0;
02008 ASTOBJ_UNLOCK(iterator);
02009 });
02010 ast_cli(fd, "Jabber Debugging Disabled.\n");
02011 return RESULT_SUCCESS;
02012 }
02013
02014
02015
02016
02017
02018
02019 static int aji_show_clients(int fd, int argc, char *argv[])
02020 {
02021 char *status;
02022 int count = 0;
02023 ast_cli(fd, "Jabber Users and their status:\n");
02024 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02025 ASTOBJ_RDLOCK(iterator);
02026 count++;
02027 switch (iterator->state) {
02028 case AJI_DISCONNECTED:
02029 status = "Disconnected";
02030 break;
02031 case AJI_CONNECTING:
02032 status = "Connecting";
02033 break;
02034 case AJI_CONNECTED:
02035 status = "Connected";
02036 break;
02037 default:
02038 status = "Unknown";
02039 }
02040 ast_cli(fd, " User: %s - %s\n", iterator->user, status);
02041 ASTOBJ_UNLOCK(iterator);
02042 });
02043 ast_cli(fd, "----\n");
02044 ast_cli(fd, " Number of users: %d\n", count);
02045 return RESULT_SUCCESS;
02046 }
02047
02048
02049
02050
02051
02052
02053 static int aji_test(int fd, int argc, char *argv[])
02054 {
02055 struct aji_client *client;
02056 struct aji_resource *resource;
02057 const char *name = "asterisk";
02058 struct aji_message *tmp;
02059
02060 if (argc > 3)
02061 return RESULT_SHOWUSAGE;
02062 else if (argc == 3)
02063 name = argv[2];
02064
02065 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02066 ast_cli(fd, "Unable to find client '%s'!\n", name);
02067 return RESULT_FAILURE;
02068 }
02069
02070
02071 ast_aji_send(client, "mogorman@astjab.org", "blahblah");
02072 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02073 ASTOBJ_RDLOCK(iterator);
02074 ast_verbose("User: %s\n", iterator->name);
02075 for (resource = iterator->resources; resource; resource = resource->next) {
02076 ast_verbose("Resource: %s\n", resource->resource);
02077 if(resource->cap) {
02078 ast_verbose(" client: %s\n", resource->cap->parent->node);
02079 ast_verbose(" version: %s\n", resource->cap->version);
02080 ast_verbose(" Jingle Capable: %d\n", resource->cap->jingle);
02081 }
02082 ast_verbose(" Priority: %d\n", resource->priority);
02083 ast_verbose(" Status: %d\n", resource->status);
02084 ast_verbose(" Message: %s\n", S_OR(resource->description,""));
02085 }
02086 ASTOBJ_UNLOCK(iterator);
02087 });
02088 ast_verbose("\nOooh a working message stack!\n");
02089 AST_LIST_LOCK(&client->messages);
02090 AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02091 ast_verbose(" Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02092 }
02093 AST_LIST_UNLOCK(&client->messages);
02094 ASTOBJ_UNREF(client, aji_client_destroy);
02095
02096 return RESULT_SUCCESS;
02097 }
02098
02099
02100
02101
02102
02103
02104 static int aji_create_client(char *label, struct ast_variable *var, int debug)
02105 {
02106 char *resource;
02107 struct aji_client *client = NULL;
02108 int flag = 0;
02109
02110 client = ASTOBJ_CONTAINER_FIND(&clients,label);
02111 if (!client) {
02112 flag = 1;
02113 client = (struct aji_client *) malloc(sizeof(struct aji_client));
02114 if (!client) {
02115 ast_log(LOG_ERROR, "Out of memory!\n");
02116 return 0;
02117 }
02118 memset(client, 0, sizeof(struct aji_client));
02119 ASTOBJ_INIT(client);
02120 ASTOBJ_WRLOCK(client);
02121 ASTOBJ_CONTAINER_INIT(&client->buddies);
02122 } else {
02123 ASTOBJ_WRLOCK(client);
02124 ASTOBJ_UNMARK(client);
02125 }
02126 ASTOBJ_CONTAINER_MARKALL(&client->buddies);
02127 ast_copy_string(client->name, label, sizeof(client->name));
02128 ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
02129
02130
02131 client->debug = debug;
02132 ast_copy_flags(client, &globalflags, AST_FLAGS_ALL);
02133 client->port = 5222;
02134 client->usetls = 1;
02135 client->usesasl = 1;
02136 client->forcessl = 0;
02137 client->keepalive = 1;
02138 client->timeout = 50;
02139 client->message_timeout = 100;
02140 AST_LIST_HEAD_INIT(&client->messages);
02141 client->component = 0;
02142 ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
02143
02144 if (flag) {
02145 client->authorized = 0;
02146 client->state = AJI_DISCONNECTED;
02147 }
02148 while (var) {
02149 if (!strcasecmp(var->name, "username"))
02150 ast_copy_string(client->user, var->value, sizeof(client->user));
02151 else if (!strcasecmp(var->name, "serverhost"))
02152 ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
02153 else if (!strcasecmp(var->name, "secret"))
02154 ast_copy_string(client->password, var->value, sizeof(client->password));
02155 else if (!strcasecmp(var->name, "statusmessage"))
02156 ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
02157 else if (!strcasecmp(var->name, "port"))
02158 client->port = atoi(var->value);
02159 else if (!strcasecmp(var->name, "timeout"))
02160 client->message_timeout = atoi(var->value);
02161 else if (!strcasecmp(var->name, "debug"))
02162 client->debug = (ast_false(var->value)) ? 0 : 1;
02163 else if (!strcasecmp(var->name, "type")) {
02164 if (!strcasecmp(var->value, "component"))
02165 client->component = 1;
02166 } else if (!strcasecmp(var->name, "usetls")) {
02167 client->usetls = (ast_false(var->value)) ? 0 : 1;
02168 } else if (!strcasecmp(var->name, "usesasl")) {
02169 client->usesasl = (ast_false(var->value)) ? 0 : 1;
02170 } else if (!strcasecmp(var->name, "forceoldssl"))
02171 client->forcessl = (ast_false(var->value)) ? 0 : 1;
02172 else if (!strcasecmp(var->name, "keepalive"))
02173 client->keepalive = (ast_false(var->value)) ? 0 : 1;
02174 else if (!strcasecmp(var->name, "autoprune"))
02175 ast_set2_flag(client, ast_true(var->value), AJI_AUTOPRUNE);
02176 else if (!strcasecmp(var->name, "autoregister"))
02177 ast_set2_flag(client, ast_true(var->value), AJI_AUTOREGISTER);
02178 else if (!strcasecmp(var->name, "buddy"))
02179 aji_create_buddy(var->value, client);
02180
02181
02182
02183
02184 var = var->next;
02185 }
02186 if (!flag) {
02187 ASTOBJ_UNLOCK(client);
02188 ASTOBJ_UNREF(client, aji_client_destroy);
02189 return 1;
02190 }
02191 client->p = iks_stream_new(((client->component) ? "jabber:component:accept" : "jabber:client"), client, aji_act_hook);
02192 if (!client->p) {
02193 ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
02194 return 0;
02195 }
02196 client->stack = iks_stack_new(8192, 8192);
02197 if (!client->stack) {
02198 ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
02199 return 0;
02200 }
02201 client->f = iks_filter_new();
02202 if (!client->f) {
02203 ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
02204 return 0;
02205 }
02206 if (!strchr(client->user, '/') && !client->component) {
02207 resource = NULL;
02208 asprintf(&resource, "%s/asterisk", client->user);
02209 if (resource) {
02210 client->jid = iks_id_new(client->stack, resource);
02211 free(resource);
02212 }
02213 } else
02214 client->jid = iks_id_new(client->stack, client->user);
02215 if (client->component) {
02216 iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02217 iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
02218 iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
02219 iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
02220 } else {
02221 iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02222 }
02223 if (!strchr(client->user, '/') && !client->component) {
02224 resource = NULL;
02225 asprintf(&resource, "%s/asterisk", client->user);
02226 if (resource) {
02227 client->jid = iks_id_new(client->stack, resource);
02228 free(resource);
02229 }
02230 } else
02231 client->jid = iks_id_new(client->stack, client->user);
02232 iks_set_log_hook(client->p, aji_log_hook);
02233 ASTOBJ_UNLOCK(client);
02234 ASTOBJ_CONTAINER_LINK(&clients,client);
02235 return 1;
02236 }
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282
02283
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295 static int aji_create_buddy(char *label, struct aji_client *client)
02296 {
02297 struct aji_buddy *buddy = NULL;
02298 int flag = 0;
02299 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02300 if (!buddy) {
02301 flag = 1;
02302 buddy = malloc(sizeof(struct aji_buddy));
02303 if(!buddy) {
02304 ast_log(LOG_WARNING, "Out of memory\n");
02305 return 0;
02306 }
02307 memset(buddy, 0, sizeof(struct aji_buddy));
02308 ASTOBJ_INIT(buddy);
02309 }
02310 ASTOBJ_WRLOCK(buddy);
02311 ast_copy_string(buddy->name, label, sizeof(buddy->name));
02312 ASTOBJ_UNLOCK(buddy);
02313 if(flag)
02314 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02315 else {
02316 ASTOBJ_UNMARK(buddy);
02317 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02318 }
02319 return 1;
02320 }
02321
02322
02323
02324
02325
02326
02327 static int aji_load_config(void)
02328 {
02329 char *cat = NULL;
02330 int debug = 1;
02331 struct ast_config *cfg = NULL;
02332 struct ast_variable *var = NULL;
02333
02334 cfg = ast_config_load(JABBER_CONFIG);
02335 if (!cfg) {
02336 ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
02337 return 0;
02338 }
02339
02340 cat = ast_category_browse(cfg, NULL);
02341 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02342 if (!strcasecmp(var->name, "debug"))
02343 debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
02344 else if (!strcasecmp(var->name, "autoprune"))
02345 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
02346 else if (!strcasecmp(var->name, "autoregister"))
02347 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
02348 }
02349
02350 while (cat) {
02351 if (strcasecmp(cat, "general")) {
02352 var = ast_variable_browse(cfg, cat);
02353 aji_create_client(cat, var, debug);
02354 }
02355 cat = ast_category_browse(cfg, cat);
02356 }
02357 return 1;
02358 }
02359
02360
02361
02362
02363
02364
02365 struct aji_client *ast_aji_get_client(const char *name)
02366 {
02367 struct aji_client *client = NULL;
02368
02369 client = ASTOBJ_CONTAINER_FIND(&clients, name);
02370 if (!client && !strchr(name, '@'))
02371 client = ASTOBJ_CONTAINER_FIND_FULL(&clients, name, user,,, strcasecmp);
02372 return client;
02373 }
02374
02375 struct aji_client_container *ast_aji_get_clients(void)
02376 {
02377 return &clients;
02378 }
02379
02380 static char mandescr_jabber_send[] =
02381 "Description: Sends a message to a Jabber Client.\n"
02382 "Variables: \n"
02383 " Jabber: Client or transport Asterisk uses to connect to JABBER.\n"
02384 " ScreenName: User Name to message.\n"
02385 " Message: Message to be sent to the buddy\n";
02386
02387
02388 static int manager_jabber_send(struct mansession *s, const struct message *m)
02389 {
02390 struct aji_client *client = NULL;
02391 const char *id = astman_get_header(m,"ActionID");
02392 const char *jabber = astman_get_header(m,"Jabber");
02393 const char *screenname = astman_get_header(m,"ScreenName");
02394 const char *message = astman_get_header(m,"Message");
02395
02396 if (ast_strlen_zero(jabber)) {
02397 astman_send_error(s, m, "No transport specified");
02398 return 0;
02399 }
02400 if (ast_strlen_zero(screenname)) {
02401 astman_send_error(s, m, "No ScreenName specified");
02402 return 0;
02403 }
02404 if (ast_strlen_zero(message)) {
02405 astman_send_error(s, m, "No Message specified");
02406 return 0;
02407 }
02408
02409 astman_send_ack(s, m, "Attempting to send Jabber Message");
02410 client = ast_aji_get_client(jabber);
02411 if (!client) {
02412 astman_send_error(s, m, "Could not find Sender");
02413 return 0;
02414 }
02415 if (strchr(screenname, '@') && message){
02416 ast_aji_send(client, screenname, message);
02417 if (!ast_strlen_zero(id))
02418 astman_append(s, "ActionID: %s\r\n",id);
02419 astman_append(s, "Response: Success\r\n");
02420 return 0;
02421 }
02422 if (!ast_strlen_zero(id))
02423 astman_append(s, "ActionID: %s\r\n",id);
02424 astman_append(s, "Response: Failure\r\n");
02425 return 0;
02426 }
02427
02428
02429 static int aji_reload()
02430 {
02431 ASTOBJ_CONTAINER_MARKALL(&clients);
02432 if (!aji_load_config()) {
02433 ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
02434 return 0;
02435 }
02436 ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
02437 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02438 ASTOBJ_RDLOCK(iterator);
02439 if(iterator->state == AJI_DISCONNECTED) {
02440 if (!iterator->thread)
02441 ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
02442 } else if (iterator->state == AJI_CONNECTING)
02443 aji_get_roster(iterator);
02444 ASTOBJ_UNLOCK(iterator);
02445 });
02446
02447 return 1;
02448 }
02449
02450 static int unload_module(void)
02451 {
02452
02453
02454
02455
02456
02457
02458 if (tls_initialized) {
02459 ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
02460 return 1;
02461 }
02462
02463 ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02464 ast_unregister_application(app_ajisend);
02465 ast_unregister_application(app_ajistatus);
02466 ast_manager_unregister("JabberSend");
02467
02468 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02469 ASTOBJ_RDLOCK(iterator);
02470 if (option_debug > 2)
02471 ast_log(LOG_DEBUG, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
02472 iterator->state = AJI_DISCONNECTING;
02473 ast_aji_disconnect(iterator);
02474 pthread_join(iterator->thread, NULL);
02475 ASTOBJ_UNLOCK(iterator);
02476 });
02477
02478 ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
02479 ASTOBJ_CONTAINER_DESTROY(&clients);
02480 return 0;
02481 }
02482
02483 static int load_module(void)
02484 {
02485 ASTOBJ_CONTAINER_INIT(&clients);
02486 if(!aji_reload())
02487 return AST_MODULE_LOAD_DECLINE;
02488 ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
02489 "Sends a message to a Jabber Client", mandescr_jabber_send);
02490 ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
02491 ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
02492 ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02493
02494 return 0;
02495 }
02496
02497 static int reload(void)
02498 {
02499 aji_reload();
02500 return 0;
02501 }
02502
02503 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "AJI - Asterisk Jabber Interface",
02504 .load = load_module,
02505 .unload = unload_module,
02506 .reload = reload,
02507 );