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: 89088 $")
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 ast_free(list);
00281 return NULL;
00282 }
00283 ast_copy_string(list->node, node, sizeof(list->node));
00284 ast_copy_string(res->version, version, sizeof(res->version));
00285 res->jingle = 0;
00286 res->parent = list;
00287 res->next = NULL;
00288 list->versions = res;
00289 list->next = capabilities;
00290 capabilities = list;
00291 }
00292 return res;
00293 }
00294
00295 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
00296 {
00297 struct aji_resource *res = NULL;
00298 if (!buddy || !name)
00299 return res;
00300 res = buddy->resources;
00301 while (res) {
00302 if (!strcasecmp(res->resource, name)) {
00303 break;
00304 }
00305 res = res->next;
00306 }
00307 return res;
00308 }
00309
00310 static int gtalk_yuck(iks *node)
00311 {
00312 if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00313 return 1;
00314 return 0;
00315 }
00316
00317
00318
00319
00320
00321
00322 static int aji_highest_bit(int number)
00323 {
00324 int x = sizeof(number) * 8 - 1;
00325 if (!number)
00326 return 0;
00327 for (; x > 0; x--) {
00328 if (number & (1 << x))
00329 break;
00330 }
00331 return (1 << x);
00332 }
00333
00334 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
00335 {
00336 iks *x, *y;
00337 x = iks_new("iq");
00338 iks_insert_attrib(x, "type", "set");
00339 y = iks_insert(x, "query");
00340 iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00341 iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00342 iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00343 if (sid) {
00344 char buf[41];
00345 char sidpass[100];
00346 snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00347 ast_sha1_hash(buf, sidpass);
00348 iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00349 } else {
00350 iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00351 }
00352 return x;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361 static int aji_status_exec(struct ast_channel *chan, void *data)
00362 {
00363 struct aji_client *client = NULL;
00364 struct aji_buddy *buddy = NULL;
00365 struct aji_resource *r = NULL;
00366 char *s = NULL, *sender = NULL, *jid = NULL, *screenname = NULL, *resource = NULL, *variable = NULL;
00367 int stat = 7;
00368 char status[2];
00369
00370 if (!data) {
00371 ast_log(LOG_ERROR, "This application requires arguments.\n");
00372 return 0;
00373 }
00374 s = ast_strdupa(data);
00375 if (s) {
00376 sender = strsep(&s, "|");
00377 if (sender && (sender[0] != '\0')) {
00378 jid = strsep(&s, "|");
00379 if (jid && (jid[0] != '\0')) {
00380 variable = s;
00381 } else {
00382 ast_log(LOG_ERROR, "Bad arguments\n");
00383 return -1;
00384 }
00385 }
00386 }
00387
00388 if(!strchr(jid, '/')) {
00389 resource = NULL;
00390 } else {
00391 screenname = strsep(&jid, "/");
00392 resource = jid;
00393 }
00394 client = ast_aji_get_client(sender);
00395 if (!client) {
00396 ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00397 return -1;
00398 }
00399 if(!&client->buddies) {
00400 ast_log(LOG_WARNING, "No buddies for connection : %s\n", sender);
00401 return -1;
00402 }
00403 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, resource ? screenname: jid);
00404 if (!buddy) {
00405 ast_log(LOG_WARNING, "Could not find buddy in list : %s\n", resource ? screenname : jid);
00406 return -1;
00407 }
00408 r = aji_find_resource(buddy, resource);
00409 if(!r && buddy->resources)
00410 r = buddy->resources;
00411 if(!r)
00412 ast_log(LOG_NOTICE, "Resource %s of buddy %s not found \n", resource, screenname);
00413 else
00414 stat = r->status;
00415 sprintf(status, "%d", stat);
00416 pbx_builtin_setvar_helper(chan, variable, status);
00417 return 0;
00418 }
00419
00420
00421
00422
00423
00424
00425 static int aji_send_exec(struct ast_channel *chan, void *data)
00426 {
00427 struct aji_client *client = NULL;
00428
00429 char *s = NULL, *sender = NULL, *recipient = NULL, *message = NULL;
00430
00431 if (!data) {
00432 ast_log(LOG_ERROR, "This application requires arguments.\n");
00433 return 0;
00434 }
00435 s = ast_strdupa(data);
00436 if (s) {
00437 sender = strsep(&s, "|");
00438 if (sender && (sender[0] != '\0')) {
00439 recipient = strsep(&s, "|");
00440 if (recipient && (recipient[0] != '\0')) {
00441 message = s;
00442 } else {
00443 ast_log(LOG_ERROR, "Bad arguments: %s\n", (char *) data);
00444 return -1;
00445 }
00446 }
00447 }
00448 if (!(client = ast_aji_get_client(sender))) {
00449 ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00450 return -1;
00451 }
00452 if (strchr(recipient, '@') && message)
00453 ast_aji_send(client, recipient, message);
00454 return 0;
00455 }
00456
00457
00458
00459
00460
00461 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
00462 {
00463 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00464 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00465
00466 if (client->debug) {
00467 if (is_incoming)
00468 ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00469 else {
00470 if( strlen(xmpp) == 1) {
00471 if(option_debug > 2 && xmpp[0] == ' ')
00472 ast_verbose("\nJABBER: Keep alive packet\n");
00473 } else
00474 ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00475 }
00476
00477 }
00478 ASTOBJ_UNREF(client, aji_client_destroy);
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488 static int aji_act_hook(void *data, int type, iks *node)
00489 {
00490 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00491 ikspak *pak = NULL;
00492 iks *auth = NULL;
00493
00494 if(!node) {
00495 ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n");
00496 ASTOBJ_UNREF(client, aji_client_destroy);
00497 return IKS_HOOK;
00498 }
00499
00500 if (client->state == AJI_DISCONNECTING) {
00501 ASTOBJ_UNREF(client, aji_client_destroy);
00502 return IKS_HOOK;
00503 }
00504
00505 pak = iks_packet(node);
00506
00507 if (!client->component) {
00508 switch (type) {
00509 case IKS_NODE_START:
00510 if (client->usetls && !iks_is_secure(client->p)) {
00511 if (iks_has_tls()) {
00512 iks_start_tls(client->p);
00513 tls_initialized = TRUE;
00514 } else
00515 ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
00516 break;
00517 }
00518 if (!client->usesasl) {
00519 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);
00520 auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00521 if (auth) {
00522 iks_insert_attrib(auth, "id", client->mid);
00523 iks_insert_attrib(auth, "to", client->jid->server);
00524 ast_aji_increment_mid(client->mid);
00525 iks_send(client->p, auth);
00526 iks_delete(auth);
00527 } else
00528 ast_log(LOG_ERROR, "Out of memory.\n");
00529 }
00530 break;
00531
00532 case IKS_NODE_NORMAL:
00533 {
00534 int features = 0;
00535 if (!strcmp("stream:features", iks_name(node))) {
00536 features = iks_stream_features(node);
00537 if (client->usesasl) {
00538 if (client->usetls && !iks_is_secure(client->p))
00539 break;
00540 if (client->authorized) {
00541 if (features & IKS_STREAM_BIND) {
00542 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);
00543 auth = iks_make_resource_bind(client->jid);
00544 if (auth) {
00545 iks_insert_attrib(auth, "id", client->mid);
00546 ast_aji_increment_mid(client->mid);
00547 iks_send(client->p, auth);
00548 iks_delete(auth);
00549 } else {
00550 ast_log(LOG_ERROR, "Out of memory.\n");
00551 break;
00552 }
00553 }
00554 if (features & IKS_STREAM_SESSION) {
00555 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);
00556 auth = iks_make_session();
00557 if (auth) {
00558 iks_insert_attrib(auth, "id", "auth");
00559 ast_aji_increment_mid(client->mid);
00560 iks_send(client->p, auth);
00561 iks_delete(auth);
00562 } else {
00563 ast_log(LOG_ERROR, "Out of memory.\n");
00564 }
00565 }
00566 } else {
00567 if (!client->jid->user) {
00568 ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00569 break;
00570 }
00571 features = aji_highest_bit(features);
00572 if (features == IKS_STREAM_SASL_MD5)
00573 iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, client->jid->user, client->password);
00574 else {
00575 if (features == IKS_STREAM_SASL_PLAIN) {
00576 iks *x = NULL;
00577 x = iks_new("auth");
00578 if (x) {
00579 int len = strlen(client->jid->user) + strlen(client->password) + 3;
00580
00581 char *s = ast_malloc(80 + len);
00582 char *base64 = ast_malloc(80 + len * 2);
00583 iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00584 iks_insert_attrib(x, "mechanism", "PLAIN");
00585 sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
00586 ast_base64encode(base64, (const unsigned char *) s, len, len * 2);
00587 iks_insert_cdata(x, base64, 0);
00588 iks_send(client->p, x);
00589 iks_delete(x);
00590 if (base64)
00591 free(base64);
00592 if (s)
00593 free(s);
00594 } else {
00595 ast_log(LOG_ERROR, "Out of memory.\n");
00596 }
00597 }
00598 }
00599 }
00600 }
00601 } else if (!strcmp("failure", iks_name(node))) {
00602 ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00603 } else if (!strcmp("success", iks_name(node))) {
00604 client->authorized = 1;
00605 iks_send_header(client->p, client->jid->server);
00606 }
00607 break;
00608 }
00609 case IKS_NODE_ERROR:
00610 ast_log(LOG_ERROR, "JABBER: Node Error\n");
00611 ASTOBJ_UNREF(client, aji_client_destroy);
00612 return IKS_HOOK;
00613 break;
00614 case IKS_NODE_STOP:
00615 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00616 ASTOBJ_UNREF(client, aji_client_destroy);
00617 return IKS_HOOK;
00618 break;
00619 }
00620 } else if (client->state != AJI_CONNECTED && client->component) {
00621 switch (type) {
00622 case IKS_NODE_START:
00623 if (client->state == AJI_DISCONNECTED) {
00624 char secret[160], shasum[320], *handshake;
00625
00626 sprintf(secret, "%s%s", pak->id, client->password);
00627 ast_sha1_hash(shasum, secret);
00628 handshake = NULL;
00629 asprintf(&handshake, "<handshake>%s</handshake>", shasum);
00630 if (handshake) {
00631 iks_send_raw(client->p, handshake);
00632 free(handshake);
00633 handshake = NULL;
00634 }
00635 client->state = AJI_CONNECTING;
00636 if(iks_recv(client->p,1) == 2)
00637 client->state = AJI_CONNECTED;
00638 else
00639 ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
00640 break;
00641 }
00642 break;
00643
00644 case IKS_NODE_NORMAL:
00645 break;
00646
00647 case IKS_NODE_ERROR:
00648 ast_log(LOG_ERROR, "JABBER: Node Error\n");
00649 ASTOBJ_UNREF(client, aji_client_destroy);
00650 return IKS_HOOK;
00651
00652 case IKS_NODE_STOP:
00653 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00654 ASTOBJ_UNREF(client, aji_client_destroy);
00655 return IKS_HOOK;
00656 }
00657 }
00658
00659 switch (pak->type) {
00660 case IKS_PAK_NONE:
00661 if (option_debug)
00662 ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
00663 break;
00664 case IKS_PAK_MESSAGE:
00665 aji_handle_message(client, pak);
00666 if (option_debug)
00667 ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
00668 break;
00669 case IKS_PAK_PRESENCE:
00670 aji_handle_presence(client, pak);
00671 if (option_debug)
00672 ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
00673 break;
00674 case IKS_PAK_S10N:
00675 aji_handle_subscribe(client, pak);
00676 if (option_debug)
00677 ast_log(LOG_DEBUG, "JABBER: I Dont know S10N subscribe!!\n");
00678 break;
00679 case IKS_PAK_IQ:
00680 if (option_debug)
00681 ast_log(LOG_DEBUG, "JABBER: I Dont have an IQ!!!\n");
00682 aji_handle_iq(client, node);
00683 break;
00684 default:
00685 if (option_debug)
00686 ast_log(LOG_DEBUG, "JABBER: I Dont know %i\n", pak->type);
00687 break;
00688 }
00689
00690 iks_filter_packet(client->f, pak);
00691
00692 if (node)
00693 iks_delete(node);
00694
00695 ASTOBJ_UNREF(client, aji_client_destroy);
00696 return IKS_OK;
00697 }
00698
00699 static int aji_register_approve_handler(void *data, ikspak *pak)
00700 {
00701 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00702 iks *iq = NULL, *presence = NULL, *x = NULL;
00703
00704 iq = iks_new("iq");
00705 presence = iks_new("presence");
00706 x = iks_new("x");
00707 if (client && iq && presence && x) {
00708 if (!iks_find(pak->query, "remove")) {
00709 iks_insert_attrib(iq, "from", client->jid->full);
00710 iks_insert_attrib(iq, "to", pak->from->full);
00711 iks_insert_attrib(iq, "id", pak->id);
00712 iks_insert_attrib(iq, "type", "result");
00713 iks_send(client->p, iq);
00714
00715 iks_insert_attrib(presence, "from", client->jid->full);
00716 iks_insert_attrib(presence, "to", pak->from->partial);
00717 iks_insert_attrib(presence, "id", client->mid);
00718 ast_aji_increment_mid(client->mid);
00719 iks_insert_attrib(presence, "type", "subscribe");
00720 iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
00721 iks_insert_node(presence, x);
00722 iks_send(client->p, presence);
00723 }
00724 } else {
00725 ast_log(LOG_ERROR, "Out of memory.\n");
00726 }
00727
00728 if (iq)
00729 iks_delete(iq);
00730 if(presence)
00731 iks_delete(presence);
00732 if (x)
00733 iks_delete(x);
00734 ASTOBJ_UNREF(client, aji_client_destroy);
00735 return IKS_FILTER_EAT;
00736 }
00737
00738 static int aji_register_query_handler(void *data, ikspak *pak)
00739 {
00740 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00741 struct aji_buddy *buddy = NULL;
00742 char *node = NULL;
00743
00744 client = (struct aji_client *) data;
00745
00746 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00747 if (!buddy) {
00748 iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
00749 ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
00750 iq = iks_new("iq");
00751 query = iks_new("query");
00752 error = iks_new("error");
00753 notacceptable = iks_new("not-acceptable");
00754 if(iq && query && error && notacceptable) {
00755 iks_insert_attrib(iq, "type", "error");
00756 iks_insert_attrib(iq, "from", client->user);
00757 iks_insert_attrib(iq, "to", pak->from->full);
00758 iks_insert_attrib(iq, "id", pak->id);
00759 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00760 iks_insert_attrib(error, "code" , "406");
00761 iks_insert_attrib(error, "type", "modify");
00762 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
00763 iks_insert_node(iq, query);
00764 iks_insert_node(iq, error);
00765 iks_insert_node(error, notacceptable);
00766 iks_send(client->p, iq);
00767 } else {
00768 ast_log(LOG_ERROR, "Out of memory.\n");
00769 }
00770 if (iq)
00771 iks_delete(iq);
00772 if (query)
00773 iks_delete(query);
00774 if (error)
00775 iks_delete(error);
00776 if (notacceptable)
00777 iks_delete(notacceptable);
00778 } else if (!(node = iks_find_attrib(pak->query, "node"))) {
00779 iks *iq = NULL, *query = NULL, *instructions = NULL;
00780 char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
00781 iq = iks_new("iq");
00782 query = iks_new("query");
00783 instructions = iks_new("instructions");
00784 if (iq && query && instructions && client) {
00785 iks_insert_attrib(iq, "from", client->user);
00786 iks_insert_attrib(iq, "to", pak->from->full);
00787 iks_insert_attrib(iq, "id", pak->id);
00788 iks_insert_attrib(iq, "type", "result");
00789 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00790 iks_insert_cdata(instructions, explain, 0);
00791 iks_insert_node(iq, query);
00792 iks_insert_node(query, instructions);
00793 iks_send(client->p, iq);
00794 } else {
00795 ast_log(LOG_ERROR, "Out of memory.\n");
00796 }
00797 if (iq)
00798 iks_delete(iq);
00799 if (query)
00800 iks_delete(query);
00801 if (instructions)
00802 iks_delete(instructions);
00803 }
00804 ASTOBJ_UNREF(client, aji_client_destroy);
00805 return IKS_FILTER_EAT;
00806 }
00807
00808 static int aji_ditems_handler(void *data, ikspak *pak)
00809 {
00810 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00811 char *node = NULL;
00812
00813 if (!(node = iks_find_attrib(pak->query, "node"))) {
00814 iks *iq = NULL, *query = NULL, *item = NULL;
00815 iq = iks_new("iq");
00816 query = iks_new("query");
00817 item = iks_new("item");
00818
00819 if (iq && query && item) {
00820 iks_insert_attrib(iq, "from", client->user);
00821 iks_insert_attrib(iq, "to", pak->from->full);
00822 iks_insert_attrib(iq, "id", pak->id);
00823 iks_insert_attrib(iq, "type", "result");
00824 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00825 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
00826 iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
00827 iks_insert_attrib(item, "jid", client->user);
00828
00829 iks_insert_node(iq, query);
00830 iks_insert_node(query, item);
00831 iks_send(client->p, iq);
00832 } else {
00833 ast_log(LOG_ERROR, "Out of memory.\n");
00834 }
00835 if (iq)
00836 iks_delete(iq);
00837 if (query)
00838 iks_delete(query);
00839 if (item)
00840 iks_delete(item);
00841
00842 } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
00843 iks *iq, *query, *confirm;
00844 iq = iks_new("iq");
00845 query = iks_new("query");
00846 confirm = iks_new("item");
00847 if (iq && query && confirm && client) {
00848 iks_insert_attrib(iq, "from", client->user);
00849 iks_insert_attrib(iq, "to", pak->from->full);
00850 iks_insert_attrib(iq, "id", pak->id);
00851 iks_insert_attrib(iq, "type", "result");
00852 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00853 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
00854 iks_insert_attrib(confirm, "node", "confirmaccount");
00855 iks_insert_attrib(confirm, "name", "Confirm AIM account");
00856 iks_insert_attrib(confirm, "jid", "blog.astjab.org");
00857
00858 iks_insert_node(iq, query);
00859 iks_insert_node(query, confirm);
00860 iks_send(client->p, iq);
00861 } else {
00862 ast_log(LOG_ERROR, "Out of memory.\n");
00863 }
00864 if (iq)
00865 iks_delete(iq);
00866 if (query)
00867 iks_delete(query);
00868 if (confirm)
00869 iks_delete(confirm);
00870
00871 } else if (!strcasecmp(node, "confirmaccount")) {
00872 iks *iq = NULL, *query = NULL, *feature = NULL;
00873
00874 iq = iks_new("iq");
00875 query = iks_new("query");
00876 feature = iks_new("feature");
00877
00878 if (iq && query && feature && client) {
00879 iks_insert_attrib(iq, "from", client->user);
00880 iks_insert_attrib(iq, "to", pak->from->full);
00881 iks_insert_attrib(iq, "id", pak->id);
00882 iks_insert_attrib(iq, "type", "result");
00883 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00884 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
00885 iks_insert_node(iq, query);
00886 iks_insert_node(query, feature);
00887 iks_send(client->p, iq);
00888 } else {
00889 ast_log(LOG_ERROR, "Out of memory.\n");
00890 }
00891 if (iq)
00892 iks_delete(iq);
00893 if (query)
00894 iks_delete(query);
00895 if (feature)
00896 iks_delete(feature);
00897 }
00898
00899 ASTOBJ_UNREF(client, aji_client_destroy);
00900 return IKS_FILTER_EAT;
00901
00902 }
00903
00904 static int aji_client_info_handler(void *data, ikspak *pak)
00905 {
00906 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00907 struct aji_resource *resource = NULL;
00908 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00909
00910 resource = aji_find_resource(buddy, pak->from->resource);
00911 if (pak->subtype == IKS_TYPE_RESULT) {
00912 if (!resource) {
00913 ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00914 ASTOBJ_UNREF(client, aji_client_destroy);
00915 return IKS_FILTER_EAT;
00916 }
00917 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00918 resource->cap->jingle = 1;
00919 } else
00920 resource->cap->jingle = 0;
00921 } else if (pak->subtype == IKS_TYPE_GET) {
00922 iks *iq, *disco, *ident, *google, *query;
00923 iq = iks_new("iq");
00924 query = iks_new("query");
00925 ident = iks_new("identity");
00926 disco = iks_new("feature");
00927 google = iks_new("feature");
00928 if (iq && ident && disco && google) {
00929 iks_insert_attrib(iq, "from", client->jid->full);
00930 iks_insert_attrib(iq, "to", pak->from->full);
00931 iks_insert_attrib(iq, "type", "result");
00932 iks_insert_attrib(iq, "id", pak->id);
00933 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
00934 iks_insert_attrib(ident, "category", "client");
00935 iks_insert_attrib(ident, "type", "pc");
00936 iks_insert_attrib(ident, "name", "asterisk");
00937 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
00938 iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
00939 iks_insert_node(iq, query);
00940 iks_insert_node(query, ident);
00941 iks_insert_node(query, google);
00942 iks_insert_node(query, disco);
00943 iks_send(client->p, iq);
00944 } else
00945 ast_log(LOG_ERROR, "Out of Memory.\n");
00946 if (iq)
00947 iks_delete(iq);
00948 if (query)
00949 iks_delete(query);
00950 if (ident)
00951 iks_delete(ident);
00952 if (google)
00953 iks_delete(google);
00954 if (disco)
00955 iks_delete(disco);
00956 } else if (pak->subtype == IKS_TYPE_ERROR) {
00957 ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
00958 }
00959 ASTOBJ_UNREF(client, aji_client_destroy);
00960 return IKS_FILTER_EAT;
00961 }
00962
00963 static int aji_dinfo_handler(void *data, ikspak *pak)
00964 {
00965 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00966 char *node = NULL;
00967 struct aji_resource *resource = NULL;
00968 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00969
00970 resource = aji_find_resource(buddy, pak->from->resource);
00971 if (pak->subtype == IKS_TYPE_ERROR) {
00972 ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
00973 return IKS_FILTER_EAT;
00974 }
00975 if (pak->subtype == IKS_TYPE_RESULT) {
00976 if (!resource) {
00977 ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00978 ASTOBJ_UNREF(client, aji_client_destroy);
00979 return IKS_FILTER_EAT;
00980 }
00981 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00982 resource->cap->jingle = 1;
00983 } else
00984 resource->cap->jingle = 0;
00985 } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
00986 iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
00987
00988 iq = iks_new("iq");
00989 query = iks_new("query");
00990 identity = iks_new("identity");
00991 disco = iks_new("feature");
00992 reg = iks_new("feature");
00993 commands = iks_new("feature");
00994 gateway = iks_new("feature");
00995 version = iks_new("feature");
00996 vcard = iks_new("feature");
00997 search = iks_new("feature");
00998
00999 if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01000 iks_insert_attrib(iq, "from", client->user);
01001 iks_insert_attrib(iq, "to", pak->from->full);
01002 iks_insert_attrib(iq, "id", pak->id);
01003 iks_insert_attrib(iq, "type", "result");
01004 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01005 iks_insert_attrib(identity, "category", "gateway");
01006 iks_insert_attrib(identity, "type", "pstn");
01007 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01008 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01009 iks_insert_attrib(reg, "var", "jabber:iq:register");
01010 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01011 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01012 iks_insert_attrib(version, "var", "jabber:iq:version");
01013 iks_insert_attrib(vcard, "var", "vcard-temp");
01014 iks_insert_attrib(search, "var", "jabber:iq:search");
01015
01016 iks_insert_node(iq, query);
01017 iks_insert_node(query, identity);
01018 iks_insert_node(query, disco);
01019 iks_insert_node(query, reg);
01020 iks_insert_node(query, commands);
01021 iks_insert_node(query, gateway);
01022 iks_insert_node(query, version);
01023 iks_insert_node(query, vcard);
01024 iks_insert_node(query, search);
01025 iks_send(client->p, iq);
01026 } else {
01027 ast_log(LOG_ERROR, "Out of memory.\n");
01028 }
01029
01030 if (iq)
01031 iks_delete(iq);
01032 if (query)
01033 iks_delete(query);
01034 if (identity)
01035 iks_delete(identity);
01036 if (disco)
01037 iks_delete(disco);
01038 if (reg)
01039 iks_delete(reg);
01040 if (commands)
01041 iks_delete(commands);
01042 if (gateway)
01043 iks_delete(gateway);
01044 if (version)
01045 iks_delete(version);
01046 if (vcard)
01047 iks_delete(vcard);
01048 if (search)
01049 iks_delete(search);
01050
01051 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01052 iks *iq, *query, *confirm;
01053 iq = iks_new("iq");
01054 query = iks_new("query");
01055 confirm = iks_new("item");
01056
01057 if (iq && query && confirm && client) {
01058 iks_insert_attrib(iq, "from", client->user);
01059 iks_insert_attrib(iq, "to", pak->from->full);
01060 iks_insert_attrib(iq, "id", pak->id);
01061 iks_insert_attrib(iq, "type", "result");
01062 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01063 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01064 iks_insert_attrib(confirm, "node", "confirmaccount");
01065 iks_insert_attrib(confirm, "name", "Confirm AIM account");
01066 iks_insert_attrib(confirm, "jid", client->user);
01067 iks_insert_node(iq, query);
01068 iks_insert_node(query, confirm);
01069 iks_send(client->p, iq);
01070 } else {
01071 ast_log(LOG_ERROR, "Out of memory.\n");
01072 }
01073 if (iq)
01074 iks_delete(iq);
01075 if (query)
01076 iks_delete(query);
01077 if (confirm)
01078 iks_delete(confirm);
01079
01080 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01081 iks *iq, *query, *feature;
01082
01083 iq = iks_new("iq");
01084 query = iks_new("query");
01085 feature = iks_new("feature");
01086
01087 if (iq && query && feature && client) {
01088 iks_insert_attrib(iq, "from", client->user);
01089 iks_insert_attrib(iq, "to", pak->from->full);
01090 iks_insert_attrib(iq, "id", pak->id);
01091 iks_insert_attrib(iq, "type", "result");
01092 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01093 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01094 iks_insert_node(iq, query);
01095 iks_insert_node(query, feature);
01096 iks_send(client->p, iq);
01097 } else {
01098 ast_log(LOG_ERROR, "Out of memory.\n");
01099 }
01100 if (iq)
01101 iks_delete(iq);
01102 if (query)
01103 iks_delete(query);
01104 if (feature)
01105 iks_delete(feature);
01106 }
01107
01108 ASTOBJ_UNREF(client, aji_client_destroy);
01109 return IKS_FILTER_EAT;
01110 }
01111
01112
01113
01114
01115
01116
01117 static void aji_handle_iq(struct aji_client *client, iks *node)
01118 {
01119
01120 }
01121
01122
01123
01124
01125
01126
01127 static void aji_handle_message(struct aji_client *client, ikspak *pak)
01128 {
01129 struct aji_message *insert, *tmp;
01130 int flag = 0;
01131
01132 if (!(insert = ast_calloc(1, sizeof(struct aji_message))))
01133 return;
01134 time(&insert->arrived);
01135 if (iks_find_cdata(pak->x, "body"))
01136 insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01137 if(pak->id)
01138 ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01139 if (pak->from)
01140 insert->from = ast_strdup(pak->from->full);
01141 AST_LIST_LOCK(&client->messages);
01142 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01143 if (flag) {
01144 AST_LIST_REMOVE_CURRENT(&client->messages, list);
01145 if (tmp->from)
01146 free(tmp->from);
01147 if (tmp->message)
01148 free(tmp->message);
01149 } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01150 flag = 1;
01151 AST_LIST_REMOVE_CURRENT(&client->messages, list);
01152 if (tmp->from)
01153 free(tmp->from);
01154 if (tmp->message)
01155 free(tmp->message);
01156 }
01157 }
01158 AST_LIST_TRAVERSE_SAFE_END;
01159 AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01160 AST_LIST_UNLOCK(&client->messages);
01161 }
01162
01163 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
01164 {
01165 int status, priority;
01166 struct aji_buddy *buddy;
01167 struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01168 char *ver, *node, *descrip, *type;
01169
01170 if(client->state != AJI_CONNECTED)
01171 aji_create_buddy(pak->from->partial, client);
01172
01173 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01174 if (!buddy && pak->from->partial) {
01175
01176 if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01177 aji_create_buddy(pak->from->partial, client);
01178 else
01179 ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01180 return;
01181 }
01182 type = iks_find_attrib(pak->x, "type");
01183 if(client->component && type &&!strcasecmp("probe", type)) {
01184 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01185 ast_verbose("what i was looking for \n");
01186 }
01187 ASTOBJ_WRLOCK(buddy);
01188 status = (pak->show) ? pak->show : 6;
01189 priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01190 tmp = buddy->resources;
01191 descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01192
01193 while (tmp && pak->from->resource) {
01194 if (!strcasecmp(tmp->resource, pak->from->resource)) {
01195 tmp->status = status;
01196 if (tmp->description) free(tmp->description);
01197 tmp->description = descrip;
01198 found = tmp;
01199 if (status == 6) {
01200 if (last && found->next) {
01201 last->next = found->next;
01202 } else if (!last) {
01203 if (found->next)
01204 buddy->resources = found->next;
01205 else
01206 buddy->resources = NULL;
01207 } else if (!found->next) {
01208 if (last)
01209 last->next = NULL;
01210 else
01211 buddy->resources = NULL;
01212 }
01213 free(found);
01214 found = NULL;
01215 break;
01216 }
01217
01218 if (tmp->priority != priority) {
01219 found->priority = priority;
01220 if (!last && !found->next)
01221
01222
01223 break;
01224
01225
01226 if (last)
01227 last->next = found->next;
01228 else
01229 buddy->resources = found->next;
01230
01231 last = NULL;
01232 tmp = buddy->resources;
01233 if (!buddy->resources)
01234 buddy->resources = found;
01235
01236 while (tmp) {
01237
01238
01239 if (found->priority > tmp->priority) {
01240 if (last)
01241
01242 last->next = found;
01243 found->next = tmp;
01244 if (!last)
01245
01246 buddy->resources = found;
01247 break;
01248 }
01249 if (!tmp->next) {
01250
01251 tmp->next = found;
01252 found->next = NULL;
01253 break;
01254 }
01255 last = tmp;
01256 tmp = tmp->next;
01257 }
01258 }
01259 break;
01260 }
01261 last = tmp;
01262 tmp = tmp->next;
01263 }
01264
01265
01266 if (!found && status != 6 && pak->from->resource) {
01267 found = (struct aji_resource *) malloc(sizeof(struct aji_resource));
01268 memset(found, 0, sizeof(struct aji_resource));
01269
01270 if (!found) {
01271 ast_log(LOG_ERROR, "Out of memory!\n");
01272 return;
01273 }
01274 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01275 found->status = status;
01276 found->description = descrip;
01277 found->priority = priority;
01278 found->next = NULL;
01279 last = NULL;
01280 tmp = buddy->resources;
01281 while (tmp) {
01282 if (found->priority > tmp->priority) {
01283 if (last)
01284 last->next = found;
01285 found->next = tmp;
01286 if (!last)
01287 buddy->resources = found;
01288 break;
01289 }
01290 if (!tmp->next) {
01291 tmp->next = found;
01292 break;
01293 }
01294 last = tmp;
01295 tmp = tmp->next;
01296 }
01297 if (!tmp)
01298 buddy->resources = found;
01299 }
01300
01301 ASTOBJ_UNLOCK(buddy);
01302 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01303
01304 node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01305 ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01306
01307
01308 if (!node && !ver) {
01309 node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01310 ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01311 }
01312
01313
01314 if(status !=6 && found && !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", client->jid->full);
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 ast_config_destroy(cfg);
02358 return 1;
02359 }
02360
02361
02362
02363
02364
02365
02366 struct aji_client *ast_aji_get_client(const char *name)
02367 {
02368 struct aji_client *client = NULL;
02369
02370 client = ASTOBJ_CONTAINER_FIND(&clients, name);
02371 if (!client && !strchr(name, '@'))
02372 client = ASTOBJ_CONTAINER_FIND_FULL(&clients, name, user,,, strcasecmp);
02373 return client;
02374 }
02375
02376 struct aji_client_container *ast_aji_get_clients(void)
02377 {
02378 return &clients;
02379 }
02380
02381 static char mandescr_jabber_send[] =
02382 "Description: Sends a message to a Jabber Client.\n"
02383 "Variables: \n"
02384 " Jabber: Client or transport Asterisk uses to connect to JABBER.\n"
02385 " ScreenName: User Name to message.\n"
02386 " Message: Message to be sent to the buddy\n";
02387
02388
02389 static int manager_jabber_send(struct mansession *s, const struct message *m)
02390 {
02391 struct aji_client *client = NULL;
02392 const char *id = astman_get_header(m,"ActionID");
02393 const char *jabber = astman_get_header(m,"Jabber");
02394 const char *screenname = astman_get_header(m,"ScreenName");
02395 const char *message = astman_get_header(m,"Message");
02396
02397 if (ast_strlen_zero(jabber)) {
02398 astman_send_error(s, m, "No transport specified");
02399 return 0;
02400 }
02401 if (ast_strlen_zero(screenname)) {
02402 astman_send_error(s, m, "No ScreenName specified");
02403 return 0;
02404 }
02405 if (ast_strlen_zero(message)) {
02406 astman_send_error(s, m, "No Message specified");
02407 return 0;
02408 }
02409
02410 astman_send_ack(s, m, "Attempting to send Jabber Message");
02411 client = ast_aji_get_client(jabber);
02412 if (!client) {
02413 astman_send_error(s, m, "Could not find Sender");
02414 return 0;
02415 }
02416 if (strchr(screenname, '@') && message){
02417 ast_aji_send(client, screenname, message);
02418 if (!ast_strlen_zero(id))
02419 astman_append(s, "ActionID: %s\r\n",id);
02420 astman_append(s, "Response: Success\r\n");
02421 return 0;
02422 }
02423 if (!ast_strlen_zero(id))
02424 astman_append(s, "ActionID: %s\r\n",id);
02425 astman_append(s, "Response: Failure\r\n");
02426 return 0;
02427 }
02428
02429
02430 static int aji_reload()
02431 {
02432 ASTOBJ_CONTAINER_MARKALL(&clients);
02433 if (!aji_load_config()) {
02434 ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
02435 return 0;
02436 }
02437 ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
02438 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02439 ASTOBJ_RDLOCK(iterator);
02440 if(iterator->state == AJI_DISCONNECTED) {
02441 if (!iterator->thread)
02442 ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
02443 } else if (iterator->state == AJI_CONNECTING)
02444 aji_get_roster(iterator);
02445 ASTOBJ_UNLOCK(iterator);
02446 });
02447
02448 return 1;
02449 }
02450
02451 static int unload_module(void)
02452 {
02453
02454
02455
02456
02457
02458
02459 if (tls_initialized) {
02460 ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
02461 return 1;
02462 }
02463
02464 ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02465 ast_unregister_application(app_ajisend);
02466 ast_unregister_application(app_ajistatus);
02467 ast_manager_unregister("JabberSend");
02468
02469 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02470 ASTOBJ_RDLOCK(iterator);
02471 if (option_debug > 2)
02472 ast_log(LOG_DEBUG, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
02473 iterator->state = AJI_DISCONNECTING;
02474 ast_aji_disconnect(iterator);
02475 pthread_join(iterator->thread, NULL);
02476 ASTOBJ_UNLOCK(iterator);
02477 });
02478
02479 ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
02480 ASTOBJ_CONTAINER_DESTROY(&clients);
02481 return 0;
02482 }
02483
02484 static int load_module(void)
02485 {
02486 ASTOBJ_CONTAINER_INIT(&clients);
02487 if(!aji_reload())
02488 return AST_MODULE_LOAD_DECLINE;
02489 ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
02490 "Sends a message to a Jabber Client", mandescr_jabber_send);
02491 ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
02492 ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
02493 ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02494
02495 return 0;
02496 }
02497
02498 static int reload(void)
02499 {
02500 aji_reload();
02501 return 0;
02502 }
02503
02504 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "AJI - Asterisk Jabber Interface",
02505 .load = load_module,
02506 .unload = unload_module,
02507 .reload = reload,
02508 );