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