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
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "asterisk.h"
00044
00045 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 372795 $")
00046
00047 #include <sys/socket.h>
00048 #include <fcntl.h>
00049 #include <netdb.h>
00050 #include <netinet/in.h>
00051 #include <arpa/inet.h>
00052 #include <sys/signal.h>
00053 #include <iksemel.h>
00054 #include <pthread.h>
00055 #include <ctype.h>
00056
00057 #include "asterisk/lock.h"
00058 #include "asterisk/channel.h"
00059 #include "asterisk/config.h"
00060 #include "asterisk/module.h"
00061 #include "asterisk/pbx.h"
00062 #include "asterisk/sched.h"
00063 #include "asterisk/io.h"
00064 #include "asterisk/rtp_engine.h"
00065 #include "asterisk/stun.h"
00066 #include "asterisk/acl.h"
00067 #include "asterisk/callerid.h"
00068 #include "asterisk/file.h"
00069 #include "asterisk/cli.h"
00070 #include "asterisk/app.h"
00071 #include "asterisk/musiconhold.h"
00072 #include "asterisk/manager.h"
00073 #include "asterisk/stringfields.h"
00074 #include "asterisk/utils.h"
00075 #include "asterisk/causes.h"
00076 #include "asterisk/astobj.h"
00077 #include "asterisk/abstract_jb.h"
00078 #include "asterisk/jabber.h"
00079 #include "asterisk/jingle.h"
00080 #include "asterisk/features.h"
00081
00082 #define GOOGLE_CONFIG "gtalk.conf"
00083
00084
00085 static struct ast_jb_conf default_jbconf =
00086 {
00087 .flags = 0,
00088 .max_size = -1,
00089 .resync_threshold = -1,
00090 .impl = "",
00091 .target_extra = -1,
00092 };
00093 static struct ast_jb_conf global_jbconf;
00094
00095 enum gtalk_protocol {
00096 AJI_PROTOCOL_UDP = 1,
00097 AJI_PROTOCOL_SSLTCP = 2,
00098 };
00099
00100 enum gtalk_connect_type {
00101 AJI_CONNECT_STUN = 1,
00102 AJI_CONNECT_LOCAL = 2,
00103 AJI_CONNECT_RELAY = 3,
00104 };
00105
00106 struct gtalk_pvt {
00107 ast_mutex_t lock;
00108 time_t laststun;
00109 struct gtalk *parent;
00110 char sid[100];
00111 char us[AJI_MAX_JIDLEN];
00112 char them[AJI_MAX_JIDLEN];
00113 char ring[10];
00114 iksrule *ringrule;
00115 int initiator;
00116 int alreadygone;
00117 struct ast_codec_pref prefs;
00118 struct gtalk_candidate *theircandidates;
00119 struct gtalk_candidate *ourcandidates;
00120 char cid_num[80];
00121 char cid_name[80];
00122 char exten[80];
00123 struct ast_channel *owner;
00124 struct ast_rtp_instance *rtp;
00125 struct ast_rtp_instance *vrtp;
00126 struct ast_format_cap *cap;
00127 struct ast_format_cap *jointcap;
00128 struct ast_format_cap *peercap;
00129 struct gtalk_pvt *next;
00130 };
00131
00132 struct gtalk_candidate {
00133 char name[100];
00134 enum gtalk_protocol protocol;
00135 double preference;
00136 char username[100];
00137 char password[100];
00138 enum gtalk_connect_type type;
00139 char network[6];
00140 int generation;
00141 char ip[16];
00142 int port;
00143 int receipt;
00144 struct gtalk_candidate *next;
00145 };
00146
00147 struct gtalk {
00148 ASTOBJ_COMPONENTS(struct gtalk);
00149 struct aji_client *connection;
00150 struct aji_buddy *buddy;
00151 struct gtalk_pvt *p;
00152 struct ast_codec_pref prefs;
00153 int amaflags;
00154 char user[AJI_MAX_JIDLEN];
00155 char context[AST_MAX_CONTEXT];
00156 char parkinglot[AST_MAX_CONTEXT];
00157 char accountcode[AST_MAX_ACCOUNT_CODE];
00158 struct ast_format_cap *cap;
00159 ast_group_t callgroup;
00160 ast_group_t pickupgroup;
00161 int callingpres;
00162 int allowguest;
00163 char language[MAX_LANGUAGE];
00164 char musicclass[MAX_MUSICCLASS];
00165 };
00166
00167 struct gtalk_container {
00168 ASTOBJ_CONTAINER_COMPONENTS(struct gtalk);
00169 };
00170
00171 static const char desc[] = "Gtalk Channel";
00172 static const char DEFAULT_CONTEXT[] = "default";
00173 static const int DEFAULT_ALLOWGUEST = 1;
00174
00175 static struct ast_format_cap *global_capability;
00176
00177 AST_MUTEX_DEFINE_STATIC(gtalklock);
00178
00179
00180 static struct ast_channel *gtalk_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
00181
00182 static int gtalk_sendtext(struct ast_channel *ast, const char *text);
00183 static int gtalk_digit_begin(struct ast_channel *ast, char digit);
00184 static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00185 static int gtalk_call(struct ast_channel *ast, const char *dest, int timeout);
00186 static int gtalk_hangup(struct ast_channel *ast);
00187 static int gtalk_answer(struct ast_channel *ast);
00188 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action);
00189 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p);
00190 static int gtalk_newcall(struct gtalk *client, ikspak *pak);
00191 static struct ast_frame *gtalk_read(struct ast_channel *ast);
00192 static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);
00193 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00194 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00195 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00196 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
00197 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p);
00198
00199 static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00200 static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00201 static int gtalk_update_externip(void);
00202 static int gtalk_parser(void *data, ikspak *pak);
00203 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to);
00204
00205
00206 static struct ast_channel_tech gtalk_tech = {
00207 .type = "Gtalk",
00208 .description = "Gtalk Channel Driver",
00209 .requester = gtalk_request,
00210 .send_text = gtalk_sendtext,
00211 .send_digit_begin = gtalk_digit_begin,
00212 .send_digit_end = gtalk_digit_end,
00213
00214
00215
00216
00217 .call = gtalk_call,
00218 .hangup = gtalk_hangup,
00219 .answer = gtalk_answer,
00220 .read = gtalk_read,
00221 .write = gtalk_write,
00222 .exception = gtalk_read,
00223 .indicate = gtalk_indicate,
00224 .fixup = gtalk_fixup,
00225 .send_html = gtalk_sendhtml,
00226 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
00227 };
00228
00229 static struct sockaddr_in bindaddr = { 0, };
00230
00231 static struct ast_sched_context *sched;
00232 static struct io_context *io;
00233 static struct in_addr __ourip;
00234
00235 static struct ast_cli_entry gtalk_cli[] = {
00236
00237 AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
00238 AST_CLI_DEFINE(gtalk_show_settings, "Show GoogleTalk global settings"),
00239 };
00240
00241 static char externip[16];
00242 static char global_context[AST_MAX_CONTEXT];
00243 static char global_parkinglot[AST_MAX_CONTEXT];
00244 static int global_allowguest;
00245 static struct sockaddr_in stunaddr;
00246 static int global_stunaddr;
00247
00248 static struct gtalk_container gtalk_list;
00249
00250 static void gtalk_member_destroy(struct gtalk *obj)
00251 {
00252 obj->cap = ast_format_cap_destroy(obj->cap);
00253 if (obj->connection) {
00254 ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
00255 }
00256 if (obj->buddy) {
00257 ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
00258 }
00259 ast_free(obj);
00260 }
00261
00262
00263
00264 static struct gtalk *find_gtalk(char *name, char *connection)
00265 {
00266 struct gtalk *gtalk = NULL;
00267 char *domain = NULL , *s = NULL;
00268
00269 if (strchr(connection, '@')) {
00270 s = ast_strdupa(connection);
00271 domain = strsep(&s, "@");
00272 ast_verbose("OOOOH domain = %s\n", domain);
00273 }
00274 gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name);
00275 if (!gtalk && strchr(name, '@'))
00276 gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp);
00277
00278 if (!gtalk) {
00279
00280 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
00281 ASTOBJ_RDLOCK(iterator);
00282 if (!strcasecmp(iterator->name, "guest")) {
00283 gtalk = iterator;
00284 }
00285 ASTOBJ_UNLOCK(iterator);
00286
00287 if (gtalk)
00288 break;
00289 });
00290
00291 }
00292 return gtalk;
00293 }
00294
00295
00296 static int add_codec_to_answer(const struct gtalk_pvt *p, struct ast_format *codec, iks *dcodecs)
00297 {
00298 int res = 0;
00299 const char *format = ast_getformatname(codec);
00300
00301 if (!strcasecmp("ulaw", format)) {
00302 iks *payload_eg711u, *payload_pcmu;
00303 payload_pcmu = iks_new("payload-type");
00304 payload_eg711u = iks_new("payload-type");
00305
00306 if(!payload_eg711u || !payload_pcmu) {
00307 iks_delete(payload_pcmu);
00308 iks_delete(payload_eg711u);
00309 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00310 return -1;
00311 }
00312 iks_insert_attrib(payload_pcmu, "id", "0");
00313 iks_insert_attrib(payload_pcmu, "name", "PCMU");
00314 iks_insert_attrib(payload_pcmu, "clockrate","8000");
00315 iks_insert_attrib(payload_pcmu, "bitrate","64000");
00316 iks_insert_attrib(payload_eg711u, "id", "100");
00317 iks_insert_attrib(payload_eg711u, "name", "EG711U");
00318 iks_insert_attrib(payload_eg711u, "clockrate","8000");
00319 iks_insert_attrib(payload_eg711u, "bitrate","64000");
00320 iks_insert_node(dcodecs, payload_pcmu);
00321 iks_insert_node(dcodecs, payload_eg711u);
00322 res ++;
00323 }
00324 if (!strcasecmp("alaw", format)) {
00325 iks *payload_eg711a, *payload_pcma;
00326 payload_pcma = iks_new("payload-type");
00327 payload_eg711a = iks_new("payload-type");
00328 if(!payload_eg711a || !payload_pcma) {
00329 iks_delete(payload_eg711a);
00330 iks_delete(payload_pcma);
00331 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00332 return -1;
00333 }
00334 iks_insert_attrib(payload_pcma, "id", "8");
00335 iks_insert_attrib(payload_pcma, "name", "PCMA");
00336 iks_insert_attrib(payload_pcma, "clockrate","8000");
00337 iks_insert_attrib(payload_pcma, "bitrate","64000");
00338 payload_eg711a = iks_new("payload-type");
00339 iks_insert_attrib(payload_eg711a, "id", "101");
00340 iks_insert_attrib(payload_eg711a, "name", "EG711A");
00341 iks_insert_attrib(payload_eg711a, "clockrate","8000");
00342 iks_insert_attrib(payload_eg711a, "bitrate","64000");
00343 iks_insert_node(dcodecs, payload_pcma);
00344 iks_insert_node(dcodecs, payload_eg711a);
00345 res ++;
00346 }
00347 if (!strcasecmp("ilbc", format)) {
00348 iks *payload_ilbc = iks_new("payload-type");
00349 if(!payload_ilbc) {
00350 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00351 return -1;
00352 }
00353 iks_insert_attrib(payload_ilbc, "id", "97");
00354 iks_insert_attrib(payload_ilbc, "name", "iLBC");
00355 iks_insert_attrib(payload_ilbc, "clockrate","8000");
00356 iks_insert_attrib(payload_ilbc, "bitrate","13300");
00357 iks_insert_node(dcodecs, payload_ilbc);
00358 res ++;
00359 }
00360 if (!strcasecmp("g723", format)) {
00361 iks *payload_g723 = iks_new("payload-type");
00362 if(!payload_g723) {
00363 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00364 return -1;
00365 }
00366 iks_insert_attrib(payload_g723, "id", "4");
00367 iks_insert_attrib(payload_g723, "name", "G723");
00368 iks_insert_attrib(payload_g723, "clockrate","8000");
00369 iks_insert_attrib(payload_g723, "bitrate","6300");
00370 iks_insert_node(dcodecs, payload_g723);
00371 res ++;
00372 }
00373 if (!strcasecmp("speex", format)) {
00374 iks *payload_speex = iks_new("payload-type");
00375 if(!payload_speex) {
00376 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00377 return -1;
00378 }
00379 iks_insert_attrib(payload_speex, "id", "110");
00380 iks_insert_attrib(payload_speex, "name", "speex");
00381 iks_insert_attrib(payload_speex, "clockrate","8000");
00382 iks_insert_attrib(payload_speex, "bitrate","11000");
00383 iks_insert_node(dcodecs, payload_speex);
00384 res++;
00385 }
00386 if (!strcasecmp("gsm", format)) {
00387 iks *payload_gsm = iks_new("payload-type");
00388 if(!payload_gsm) {
00389 ast_log(LOG_WARNING,"Failed to allocate iks node\n");
00390 return -1;
00391 }
00392 iks_insert_attrib(payload_gsm, "id", "103");
00393 iks_insert_attrib(payload_gsm, "name", "gsm");
00394 iks_insert_node(dcodecs, payload_gsm);
00395 res++;
00396 }
00397
00398 return res;
00399 }
00400
00401 static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
00402 {
00403 struct gtalk *client = p->parent;
00404 iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
00405 int x;
00406 struct ast_format_cap *alreadysent;
00407 int codecs_num = 0;
00408 char *lowerto = NULL;
00409 struct ast_format tmpfmt;
00410
00411 iq = iks_new("iq");
00412 gtalk = iks_new("session");
00413 dcodecs = iks_new("description");
00414 transport = iks_new("transport");
00415 payload_telephone = iks_new("payload-type");
00416 if (!(iq && gtalk && dcodecs && transport && payload_telephone)) {
00417 iks_delete(iq);
00418 iks_delete(gtalk);
00419 iks_delete(dcodecs);
00420 iks_delete(transport);
00421 iks_delete(payload_telephone);
00422
00423 ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
00424 return 0;
00425 }
00426 iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS);
00427 iks_insert_attrib(dcodecs, "xml:lang", "en");
00428
00429 if (!(alreadysent = ast_format_cap_alloc_nolock())) {
00430 return 0;
00431 }
00432 for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
00433 if (!(ast_codec_pref_index(&client->prefs, x, &tmpfmt))) {
00434 break;
00435 }
00436 if (!(ast_format_cap_iscompatible(client->cap, &tmpfmt))) {
00437 continue;
00438 }
00439 if (ast_format_cap_iscompatible(alreadysent, &tmpfmt)) {
00440 continue;
00441 }
00442 codecs_num = add_codec_to_answer(p, &tmpfmt, dcodecs);
00443 ast_format_cap_add(alreadysent, &tmpfmt);
00444 }
00445 alreadysent = ast_format_cap_destroy(alreadysent);
00446
00447 if (codecs_num) {
00448
00449 iks_insert_attrib(payload_telephone, "id", "101");
00450 iks_insert_attrib(payload_telephone, "name", "telephone-event");
00451 iks_insert_attrib(payload_telephone, "clockrate", "8000");
00452 }
00453 iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS);
00454
00455 iks_insert_attrib(iq, "type", "set");
00456 iks_insert_attrib(iq, "to", to);
00457 iks_insert_attrib(iq, "from", from);
00458 iks_insert_attrib(iq, "id", client->connection->mid);
00459 ast_aji_increment_mid(client->connection->mid);
00460
00461 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00462 iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
00463
00464
00465 if (!initiator) {
00466 char c;
00467 char *t = lowerto = ast_strdupa(to);
00468 while (((c = *t) != '/') && (*t++ = tolower(c)));
00469 }
00470 iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto);
00471 iks_insert_attrib(gtalk, "id", sid);
00472 iks_insert_node(iq, gtalk);
00473 iks_insert_node(gtalk, dcodecs);
00474 iks_insert_node(dcodecs, payload_telephone);
00475
00476 ast_aji_send(client->connection, iq);
00477
00478 iks_delete(payload_telephone);
00479 iks_delete(transport);
00480 iks_delete(dcodecs);
00481 iks_delete(gtalk);
00482 iks_delete(iq);
00483 return 1;
00484 }
00485
00486 static int gtalk_ringing_ack(void *data, ikspak *pak)
00487 {
00488 struct gtalk_pvt *p = data;
00489 struct ast_channel *owner;
00490
00491 ast_mutex_lock(&p->lock);
00492
00493 if (p->ringrule) {
00494 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00495 }
00496 p->ringrule = NULL;
00497
00498
00499 if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
00500 char *name = NULL;
00501 char *redirect = NULL;
00502 iks *traversenodes = NULL;
00503 traversenodes = pak->query;
00504 while (traversenodes) {
00505 if (!(name = iks_name(traversenodes))) {
00506 break;
00507 }
00508 if (!strcasecmp(name, "error") &&
00509 ((redirect = iks_find_cdata(traversenodes, "redirect")) ||
00510 (redirect = iks_find_cdata(traversenodes, "sta:redirect"))) &&
00511 (redirect = strstr(redirect, "xmpp:"))) {
00512 redirect += 5;
00513 ast_debug(1, "redirect %s\n", redirect);
00514 ast_copy_string(p->them, redirect, sizeof(p->them));
00515
00516 gtalk_invite(p, p->them, p->us, p->sid, 1);
00517 break;
00518 }
00519 traversenodes = iks_next_tag(traversenodes);
00520 }
00521 }
00522 gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
00523 owner = p->owner;
00524 ast_mutex_unlock(&p->lock);
00525
00526 if (owner) {
00527 ast_queue_control(owner, AST_CONTROL_RINGING);
00528 }
00529
00530 return IKS_FILTER_EAT;
00531 }
00532
00533 static int gtalk_answer(struct ast_channel *ast)
00534 {
00535 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
00536 int res = 0;
00537
00538 ast_debug(1, "Answer!\n");
00539 ast_mutex_lock(&p->lock);
00540 gtalk_invite(p, p->them, p->us,p->sid, 0);
00541 manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
00542 ast_channel_name(ast), "GTALK", p->sid);
00543 ast_mutex_unlock(&p->lock);
00544 return res;
00545 }
00546
00547 static enum ast_rtp_glue_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
00548 {
00549 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
00550 enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
00551
00552 if (!p)
00553 return res;
00554
00555 ast_mutex_lock(&p->lock);
00556 if (p->rtp){
00557 ao2_ref(p->rtp, +1);
00558 *instance = p->rtp;
00559 res = AST_RTP_GLUE_RESULT_LOCAL;
00560 }
00561 ast_mutex_unlock(&p->lock);
00562
00563 return res;
00564 }
00565
00566 static void gtalk_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
00567 {
00568 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
00569 ast_mutex_lock(&p->lock);
00570 ast_format_cap_copy(result, p->peercap);
00571 ast_mutex_unlock(&p->lock);
00572 }
00573
00574 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *cap, int nat_active)
00575 {
00576 struct gtalk_pvt *p;
00577
00578 p = ast_channel_tech_pvt(chan);
00579 if (!p)
00580 return -1;
00581 ast_mutex_lock(&p->lock);
00582
00583
00584
00585
00586
00587
00588
00589
00590 ast_mutex_unlock(&p->lock);
00591 return 0;
00592 }
00593
00594 static struct ast_rtp_glue gtalk_rtp_glue = {
00595 .type = "Gtalk",
00596 .get_rtp_info = gtalk_get_rtp_peer,
00597 .get_codec = gtalk_get_codec,
00598 .update_peer = gtalk_set_rtp_peer,
00599 };
00600
00601 static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
00602 {
00603 iks *response = NULL, *error = NULL, *reason = NULL;
00604 int res = -1;
00605
00606 response = iks_new("iq");
00607 if (response) {
00608 iks_insert_attrib(response, "type", "result");
00609 iks_insert_attrib(response, "from", from);
00610 iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
00611 iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
00612 if (reasonstr) {
00613 error = iks_new("error");
00614 if (error) {
00615 iks_insert_attrib(error, "type", "cancel");
00616 reason = iks_new(reasonstr);
00617 if (reason)
00618 iks_insert_node(error, reason);
00619 iks_insert_node(response, error);
00620 }
00621 }
00622 ast_aji_send(client->connection, response);
00623 res = 0;
00624 }
00625
00626 iks_delete(reason);
00627 iks_delete(error);
00628 iks_delete(response);
00629
00630 return res;
00631 }
00632
00633 static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
00634 {
00635 struct gtalk_pvt *tmp = NULL;
00636 char *from;
00637 iks *codec;
00638 char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
00639 int peernoncodeccapability;
00640
00641 ast_debug(1, "The client is %s\n", client->name);
00642
00643
00644 for (tmp = client->p; tmp; tmp = tmp->next) {
00645 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00646 break;
00647 } else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
00648 break;
00649 }
00650 }
00651
00652 if (!tmp) {
00653 ast_log(LOG_WARNING, "Could not find session in iq\n");
00654 return -1;
00655 }
00656
00657
00658 codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
00659 while (codec) {
00660 char *codec_id = iks_find_attrib(codec, "id");
00661 char *codec_name = iks_find_attrib(codec, "name");
00662 if (!codec_id || !codec_name) {
00663 codec = iks_next_tag(codec);
00664 continue;
00665 }
00666
00667 ast_rtp_codecs_payloads_set_m_type(
00668 ast_rtp_instance_get_codecs(tmp->rtp),
00669 tmp->rtp,
00670 atoi(codec_id));
00671 ast_rtp_codecs_payloads_set_rtpmap_type(
00672 ast_rtp_instance_get_codecs(tmp->rtp),
00673 tmp->rtp,
00674 atoi(codec_id),
00675 "audio",
00676 codec_name,
00677 0);
00678 codec = iks_next_tag(codec);
00679 }
00680
00681
00682 ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), tmp->peercap, &peernoncodeccapability);
00683
00684
00685
00686 ast_format_cap_joint_copy(tmp->cap, tmp->peercap, tmp->jointcap);
00687 if (ast_format_cap_is_empty(tmp->jointcap)) {
00688 ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->cap),
00689 ast_getformatname_multiple(s2, BUFSIZ, tmp->peercap),
00690 ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcap));
00691
00692 ast_queue_hangup(tmp->owner);
00693
00694 return -1;
00695
00696 }
00697
00698 from = iks_find_attrib(pak->x, "to");
00699 if (!from) {
00700 from = client->connection->jid->full;
00701 }
00702
00703 if (tmp->owner) {
00704 ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00705 }
00706 gtalk_update_stun(tmp->parent, tmp);
00707 gtalk_response(client, from, pak, NULL, NULL);
00708 return 1;
00709 }
00710
00711 static int gtalk_is_accepted(struct gtalk *client, ikspak *pak)
00712 {
00713 struct gtalk_pvt *tmp;
00714 char *from;
00715
00716 ast_debug(1, "The client is %s\n", client->name);
00717
00718 for (tmp = client->p; tmp; tmp = tmp->next) {
00719 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00720 break;
00721 }
00722 }
00723
00724 from = iks_find_attrib(pak->x, "to");
00725 if (!from) {
00726 from = client->connection->jid->full;
00727 }
00728
00729 if (tmp) {
00730 gtalk_update_stun(tmp->parent, tmp);
00731 } else {
00732 ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n");
00733 }
00734
00735
00736 gtalk_response(client, from, pak, NULL, NULL);
00737 return 1;
00738 }
00739
00740 static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
00741 {
00742 struct gtalk_pvt *tmp;
00743 iks *dtmfnode = NULL, *dtmfchild = NULL;
00744 char *dtmf;
00745 char *from;
00746
00747 for (tmp = client->p; tmp; tmp = tmp->next) {
00748 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
00749 break;
00750 }
00751 from = iks_find_attrib(pak->x, "to");
00752 if (!from) {
00753 from = client->connection->jid->full;
00754 }
00755
00756 if (tmp) {
00757 if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00758 gtalk_response(client, from, pak,
00759 "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00760 "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00761 return -1;
00762 }
00763 if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00764 if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00765 if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00766 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00767 f.subclass.integer = dtmf[0];
00768 ast_queue_frame(tmp->owner, &f);
00769 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00770 } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00771 struct ast_frame f = {AST_FRAME_DTMF_END, };
00772 f.subclass.integer = dtmf[0];
00773 ast_queue_frame(tmp->owner, &f);
00774 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00775 } else if(iks_find_attrib(pak->x, "dtmf")) {
00776 struct ast_frame f = {AST_FRAME_DTMF, };
00777 f.subclass.integer = dtmf[0];
00778 ast_queue_frame(tmp->owner, &f);
00779 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00780 }
00781 }
00782 } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
00783 if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
00784 if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
00785 if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
00786 struct ast_frame f = {AST_FRAME_DTMF_END, };
00787 f.subclass.integer = dtmf[0];
00788 ast_queue_frame(tmp->owner, &f);
00789 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00790 } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
00791 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00792 f.subclass.integer = dtmf[0];
00793 ast_queue_frame(tmp->owner, &f);
00794 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00795 }
00796 }
00797 }
00798 }
00799 gtalk_response(client, from, pak, NULL, NULL);
00800 return 1;
00801 } else {
00802 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00803 }
00804
00805 gtalk_response(client, from, pak, NULL, NULL);
00806 return 1;
00807 }
00808
00809 static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
00810 {
00811 struct gtalk_pvt *tmp;
00812 char *from;
00813
00814 ast_debug(1, "The client is %s\n", client->name);
00815
00816 for (tmp = client->p; tmp; tmp = tmp->next) {
00817 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
00818 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
00819 break;
00820 }
00821 }
00822 from = iks_find_attrib(pak->x, "to");
00823 if (!from) {
00824 from = client->connection->jid->full;
00825 }
00826
00827 if (tmp) {
00828 tmp->alreadygone = 1;
00829 if (tmp->owner) {
00830 ast_queue_hangup(tmp->owner);
00831 }
00832 } else {
00833 ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n");
00834 }
00835 gtalk_response(client, from, pak, NULL, NULL);
00836 return 1;
00837 }
00838
00839 static int gtalk_get_local_ip(struct ast_sockaddr *ourip)
00840 {
00841 struct ast_sockaddr root;
00842 struct ast_sockaddr bindaddr_tmp;
00843 struct ast_sockaddr *addrs;
00844
00845
00846 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
00847 if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
00848 ast_sockaddr_copy(ourip, &bindaddr_tmp);
00849 return 0;
00850 }
00851
00852
00853
00854 if (ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET) > 0) {
00855 ast_sockaddr_copy(&root, &addrs[0]);
00856 ast_free(addrs);
00857 if (!ast_ouraddrfor(&root, ourip)) {
00858 return 0;
00859 }
00860 }
00861
00862
00863 return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
00864 }
00865
00866 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
00867 {
00868 struct gtalk_candidate *tmp;
00869 struct aji_client *c = client->connection;
00870 struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
00871 struct sockaddr_in sin = { 0, };
00872 struct ast_sockaddr sin_tmp;
00873 struct ast_sockaddr us;
00874 iks *iq, *gtalk, *candidate, *transport;
00875 char user[17], pass[17], preference[5], port[7];
00876 char *lowerfrom = NULL;
00877
00878 iq = iks_new("iq");
00879 gtalk = iks_new("session");
00880 candidate = iks_new("candidate");
00881 transport = iks_new("transport");
00882 if (!iq || !gtalk || !candidate || !transport) {
00883 ast_log(LOG_ERROR, "Memory allocation error\n");
00884 goto safeout;
00885 }
00886 ours1 = ast_calloc(1, sizeof(*ours1));
00887 ours2 = ast_calloc(1, sizeof(*ours2));
00888 if (!ours1 || !ours2)
00889 goto safeout;
00890
00891 iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
00892 iks_insert_node(iq, gtalk);
00893 iks_insert_node(gtalk,candidate);
00894 iks_insert_node(gtalk,transport);
00895
00896 for (; p; p = p->next) {
00897 if (!strcasecmp(p->sid, sid))
00898 break;
00899 }
00900
00901 if (!p) {
00902 ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
00903 goto safeout;
00904 }
00905
00906 ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
00907 ast_sockaddr_to_sin(&sin_tmp, &sin);
00908
00909 gtalk_get_local_ip(&us);
00910
00911 if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) {
00912 ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.\n");
00913 }
00914
00915
00916 ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
00917 ours1->port = ntohs(sin.sin_port);
00918 ours1->preference = 1;
00919 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00920 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00921 ast_copy_string(ours1->username, user, sizeof(ours1->username));
00922 ast_copy_string(ours1->password, pass, sizeof(ours1->password));
00923 ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us),
00924 sizeof(ours1->ip));
00925 ours1->protocol = AJI_PROTOCOL_UDP;
00926 ours1->type = AJI_CONNECT_LOCAL;
00927 ours1->generation = 0;
00928 p->ourcandidates = ours1;
00929
00930
00931
00932
00933 gtalk_update_externip();
00934 if (!ast_strlen_zero(externip)) {
00935 ast_copy_string(ours2->username, user, sizeof(ours2->username));
00936 ast_copy_string(ours2->password, pass, sizeof(ours2->password));
00937 ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
00938 ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
00939 ours2->port = ntohs(sin.sin_port);
00940 ours2->preference = 0.9;
00941 ours2->protocol = AJI_PROTOCOL_UDP;
00942 ours2->type = AJI_CONNECT_STUN;
00943 ours2->generation = 0;
00944 ours1->next = ours2;
00945 ours2 = NULL;
00946 }
00947 ours1 = NULL;
00948
00949 for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
00950 snprintf(port, sizeof(port), "%d", tmp->port);
00951 snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
00952 iks_insert_attrib(iq, "from", to);
00953 iks_insert_attrib(iq, "to", from);
00954 iks_insert_attrib(iq, "type", "set");
00955 iks_insert_attrib(iq, "id", c->mid);
00956 ast_aji_increment_mid(c->mid);
00957 iks_insert_attrib(gtalk, "type", "candidates");
00958 iks_insert_attrib(gtalk, "id", sid);
00959
00960
00961 if (!p->initiator) {
00962 char cur;
00963 char *t = lowerfrom = ast_strdupa(from);
00964 while (((cur = *t) != '/') && (*t++ = tolower(cur)));
00965 }
00966 iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
00967 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00968 iks_insert_attrib(candidate, "name", tmp->name);
00969 iks_insert_attrib(candidate, "address", tmp->ip);
00970 iks_insert_attrib(candidate, "port", port);
00971 iks_insert_attrib(candidate, "username", tmp->username);
00972 iks_insert_attrib(candidate, "password", tmp->password);
00973 iks_insert_attrib(candidate, "preference", preference);
00974 if (tmp->protocol == AJI_PROTOCOL_UDP)
00975 iks_insert_attrib(candidate, "protocol", "udp");
00976 if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
00977 iks_insert_attrib(candidate, "protocol", "ssltcp");
00978 if (tmp->type == AJI_CONNECT_STUN)
00979 iks_insert_attrib(candidate, "type", "stun");
00980 if (tmp->type == AJI_CONNECT_LOCAL)
00981 iks_insert_attrib(candidate, "type", "local");
00982 if (tmp->type == AJI_CONNECT_RELAY)
00983 iks_insert_attrib(candidate, "type", "relay");
00984 iks_insert_attrib(candidate, "network", "0");
00985 iks_insert_attrib(candidate, "generation", "0");
00986 ast_aji_send(c, iq);
00987 }
00988 p->laststun = 0;
00989
00990 safeout:
00991 if (ours1)
00992 ast_free(ours1);
00993 if (ours2)
00994 ast_free(ours2);
00995 iks_delete(iq);
00996 iks_delete(gtalk);
00997 iks_delete(candidate);
00998 iks_delete(transport);
00999
01000 return 1;
01001 }
01002
01003 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
01004 {
01005 struct gtalk_pvt *tmp = NULL;
01006 struct aji_resource *resources = NULL;
01007 struct aji_buddy *buddy = NULL;
01008 char idroster[200] = "";
01009 char *data, *exten = NULL;
01010 struct ast_sockaddr bindaddr_tmp;
01011
01012 ast_debug(1, "The client is %s for alloc\n", client->name);
01013 if (!sid && !strchr(them, '/')) {
01014 if (!strcasecmp(client->name, "guest")) {
01015 buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
01016 if (buddy) {
01017 resources = buddy->resources;
01018 }
01019 } else if (client->buddy) {
01020 resources = client->buddy->resources;
01021 }
01022
01023 while (resources) {
01024 if (resources->cap->jingle) {
01025 break;
01026 }
01027 resources = resources->next;
01028 }
01029 if (resources) {
01030 snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
01031 } else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
01032 snprintf(idroster, sizeof(idroster), "%s", them);
01033 } else {
01034 ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
01035 if (buddy) {
01036 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01037 }
01038 return NULL;
01039 }
01040 if (buddy) {
01041 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01042 }
01043 }
01044 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
01045 return NULL;
01046 }
01047 tmp->cap = ast_format_cap_alloc_nolock();
01048 tmp->jointcap = ast_format_cap_alloc_nolock();
01049 tmp->peercap = ast_format_cap_alloc_nolock();
01050 if (!tmp->jointcap || !tmp->peercap || !tmp->cap) {
01051 tmp->cap = ast_format_cap_destroy(tmp->cap);
01052 tmp->jointcap = ast_format_cap_destroy(tmp->jointcap);
01053 tmp->peercap = ast_format_cap_destroy(tmp->peercap);
01054 ast_free(tmp);
01055 return NULL;
01056 }
01057
01058 memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
01059
01060 if (sid) {
01061 ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
01062 ast_copy_string(tmp->them, them, sizeof(tmp->them));
01063 ast_copy_string(tmp->us, us, sizeof(tmp->us));
01064 } else {
01065 snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
01066 ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
01067 ast_copy_string(tmp->us, us, sizeof(tmp->us));
01068 tmp->initiator = 1;
01069 }
01070
01071 bindaddr.sin_family = AF_INET;
01072 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
01073 if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
01074 ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
01075 ast_free(tmp);
01076 return NULL;
01077 }
01078 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
01079 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1);
01080 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1);
01081 ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833);
01082 ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
01083
01084
01085 if (!(ast_format_cap_is_empty(client->cap))) {
01086 ast_format_cap_copy(tmp->cap, client->cap);
01087 } else if (!(ast_format_cap_is_empty(global_capability))) {
01088 ast_format_cap_copy(tmp->cap, global_capability);
01089 }
01090
01091 tmp->parent = client;
01092 if (!tmp->rtp) {
01093 ast_log(LOG_WARNING, "Out of RTP sessions?\n");
01094 ast_free(tmp);
01095 return NULL;
01096 }
01097
01098
01099 ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
01100
01101 if(strchr(tmp->us, '/')) {
01102 data = ast_strdupa(tmp->us);
01103 exten = strsep(&data, "/");
01104 } else {
01105 exten = tmp->us;
01106 }
01107 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
01108 ast_mutex_init(&tmp->lock);
01109 ast_mutex_lock(>alklock);
01110 tmp->next = client->p;
01111 client->p = tmp;
01112 ast_mutex_unlock(>alklock);
01113 return tmp;
01114 }
01115
01116
01117 static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title, const char *linkedid)
01118 {
01119 struct ast_channel *tmp;
01120 const char *n2;
01121 struct ast_format_cap *what;
01122 struct ast_format tmpfmt;
01123
01124 if (title)
01125 n2 = title;
01126 else
01127 n2 = i->us;
01128 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff);
01129 if (!tmp) {
01130 ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
01131 return NULL;
01132 }
01133 ast_channel_tech_set(tmp, >alk_tech);
01134
01135
01136
01137 if (!(ast_format_cap_is_empty(i->jointcap))) {
01138 what = i->jointcap;
01139 } else if (i->cap) {
01140 what = i->cap;
01141 } else {
01142 what = global_capability;
01143 }
01144
01145
01146 if (i->rtp) {
01147 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
01148 }
01149
01150 ast_codec_choose(&i->prefs, what, 1, &tmpfmt);
01151 ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
01152
01153 ast_format_cap_iter_start(i->jointcap);
01154 while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) {
01155 if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) {
01156 ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
01157 }
01158 }
01159 ast_format_cap_iter_end(i->jointcap);
01160
01161 if (i->rtp) {
01162 ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
01163 ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
01164 }
01165 if (i->vrtp) {
01166 ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
01167 ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
01168 }
01169 if (state == AST_STATE_RING)
01170 ast_channel_rings_set(tmp, 1);
01171 ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
01172
01173 ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
01174 ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
01175 ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
01176 ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
01177 ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
01178 ast_channel_tech_pvt_set(tmp, i);
01179
01180 ast_channel_callgroup_set(tmp, client->callgroup);
01181 ast_channel_pickupgroup_set(tmp, client->pickupgroup);
01182 ast_channel_caller(tmp)->id.name.presentation = client->callingpres;
01183 ast_channel_caller(tmp)->id.number.presentation = client->callingpres;
01184 if (!ast_strlen_zero(client->accountcode))
01185 ast_channel_accountcode_set(tmp, client->accountcode);
01186 if (client->amaflags)
01187 ast_channel_amaflags_set(tmp, client->amaflags);
01188 if (!ast_strlen_zero(client->language))
01189 ast_channel_language_set(tmp, client->language);
01190 if (!ast_strlen_zero(client->musicclass))
01191 ast_channel_musicclass_set(tmp, client->musicclass);
01192 if (!ast_strlen_zero(client->parkinglot))
01193 ast_channel_parkinglot_set(tmp, client->parkinglot);
01194 i->owner = tmp;
01195 ast_module_ref(ast_module_info->self);
01196 ast_channel_context_set(tmp, client->context);
01197 ast_channel_exten_set(tmp, i->exten);
01198
01199 if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
01200 ast_channel_dialed(tmp)->number.str = ast_strdup(i->exten);
01201 }
01202 ast_channel_priority_set(tmp, 1);
01203 if (i->rtp)
01204 ast_jb_configure(tmp, &global_jbconf);
01205 if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
01206 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
01207 ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION);
01208 ast_hangup(tmp);
01209 tmp = NULL;
01210 } else {
01211 manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
01212 "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
01213 i->owner ? ast_channel_name(i->owner) : "", "Gtalk", i->sid);
01214 }
01215 return tmp;
01216 }
01217
01218 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
01219 {
01220 iks *request, *session = NULL;
01221 int res = -1;
01222 char *lowerthem = NULL;
01223
01224 request = iks_new("iq");
01225 if (request) {
01226 iks_insert_attrib(request, "type", "set");
01227 iks_insert_attrib(request, "from", p->us);
01228 iks_insert_attrib(request, "to", p->them);
01229 iks_insert_attrib(request, "id", client->connection->mid);
01230 ast_aji_increment_mid(client->connection->mid);
01231 session = iks_new("session");
01232 if (session) {
01233 iks_insert_attrib(session, "type", action);
01234 iks_insert_attrib(session, "id", p->sid);
01235
01236
01237 if (!p->initiator) {
01238 char c;
01239 char *t = lowerthem = ast_strdupa(p->them);
01240 while (((c = *t) != '/') && (*t++ = tolower(c)));
01241 }
01242 iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
01243 iks_insert_attrib(session, "xmlns", GOOGLE_NS);
01244 iks_insert_node(request, session);
01245 ast_aji_send(client->connection, request);
01246 res = 0;
01247 }
01248 }
01249
01250 iks_delete(session);
01251 iks_delete(request);
01252
01253 return res;
01254 }
01255
01256 static void gtalk_free_candidates(struct gtalk_candidate *candidate)
01257 {
01258 struct gtalk_candidate *last;
01259 while (candidate) {
01260 last = candidate;
01261 candidate = candidate->next;
01262 ast_free(last);
01263 }
01264 }
01265
01266 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
01267 {
01268 struct gtalk_pvt *cur, *prev = NULL;
01269 cur = client->p;
01270 while (cur) {
01271 if (cur == p) {
01272 if (prev)
01273 prev->next = p->next;
01274 else
01275 client->p = p->next;
01276 break;
01277 }
01278 prev = cur;
01279 cur = cur->next;
01280 }
01281 if (p->ringrule)
01282 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01283 if (p->owner)
01284 ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01285 if (p->rtp)
01286 ast_rtp_instance_destroy(p->rtp);
01287 if (p->vrtp)
01288 ast_rtp_instance_destroy(p->vrtp);
01289 gtalk_free_candidates(p->theircandidates);
01290 p->cap = ast_format_cap_destroy(p->cap);
01291 p->jointcap = ast_format_cap_destroy(p->jointcap);
01292 p->peercap = ast_format_cap_destroy(p->peercap);
01293 ast_free(p);
01294 }
01295
01296
01297 static int gtalk_newcall(struct gtalk *client, ikspak *pak)
01298 {
01299 struct gtalk_pvt *p, *tmp = client->p;
01300 struct ast_channel *chan;
01301 int res;
01302 iks *codec;
01303 char *from = NULL;
01304 char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
01305 int peernoncodeccapability;
01306 char *sid;
01307
01308
01309 from = iks_find_attrib(pak->x,"to");
01310 if (!from) {
01311 from = client->connection->jid->full;
01312 }
01313
01314 while (tmp) {
01315 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01316 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01317 ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01318 gtalk_response(client, from, pak, "out-of-order", NULL);
01319 return -1;
01320 }
01321 tmp = tmp->next;
01322 }
01323
01324 if (!strcasecmp(client->name, "guest")){
01325
01326
01327 if (client->connection) {
01328 ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
01329 }
01330 client->connection = ast_aji_get_client(from);
01331 if (!client->connection) {
01332 ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
01333 return -1;
01334 }
01335 }
01336
01337 if (!(sid = iks_find_attrib(pak->query, "id"))) {
01338 ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n");
01339 return -1;
01340 }
01341
01342 p = gtalk_alloc(client, from, pak->from->full, sid);
01343 if (!p) {
01344 ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01345 return -1;
01346 }
01347
01348 chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
01349 if (!chan) {
01350 gtalk_free_pvt(client, p);
01351 return -1;
01352 }
01353
01354 ast_mutex_lock(&p->lock);
01355 ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01356 ast_copy_string(p->sid, sid, sizeof(p->sid));
01357
01358
01359 codec = iks_first_tag(iks_first_tag(pak->query));
01360
01361 while (codec) {
01362 char *codec_id = iks_find_attrib(codec, "id");
01363 char *codec_name = iks_find_attrib(codec, "name");
01364 if (!codec_id || !codec_name) {
01365 codec = iks_next_tag(codec);
01366 continue;
01367 }
01368 if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
01369 ast_rtp_codecs_payloads_set_m_type(
01370 ast_rtp_instance_get_codecs(p->vrtp),
01371 p->vrtp,
01372 atoi(codec_id));
01373 ast_rtp_codecs_payloads_set_rtpmap_type(
01374 ast_rtp_instance_get_codecs(p->vrtp),
01375 p->vrtp,
01376 atoi(codec_id),
01377 "video",
01378 codec_name,
01379 0);
01380 } else {
01381 ast_rtp_codecs_payloads_set_m_type(
01382 ast_rtp_instance_get_codecs(p->rtp),
01383 p->rtp,
01384 atoi(codec_id));
01385 ast_rtp_codecs_payloads_set_rtpmap_type(
01386 ast_rtp_instance_get_codecs(p->rtp),
01387 p->rtp,
01388 atoi(codec_id),
01389 "audio",
01390 codec_name,
01391 0);
01392 }
01393 codec = iks_next_tag(codec);
01394 }
01395
01396
01397 ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), p->peercap, &peernoncodeccapability);
01398 ast_format_cap_joint_copy(p->cap, p->peercap, p->jointcap);
01399 ast_mutex_unlock(&p->lock);
01400
01401 ast_setstate(chan, AST_STATE_RING);
01402 if (ast_format_cap_is_empty(p->jointcap)) {
01403 ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->cap),
01404 ast_getformatname_multiple(s2, BUFSIZ, p->peercap),
01405 ast_getformatname_multiple(s3, BUFSIZ, p->jointcap));
01406
01407 gtalk_action(client, p, "reject");
01408 p->alreadygone = 1;
01409 gtalk_hangup(chan);
01410 ast_channel_release(chan);
01411 return -1;
01412 }
01413
01414 res = ast_pbx_start(chan);
01415
01416 switch (res) {
01417 case AST_PBX_FAILED:
01418 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01419 gtalk_response(client, from, pak, "service-unavailable", NULL);
01420 break;
01421 case AST_PBX_CALL_LIMIT:
01422 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01423 gtalk_response(client, from, pak, "service-unavailable", NULL);
01424 break;
01425 case AST_PBX_SUCCESS:
01426 gtalk_response(client, from, pak, NULL, NULL);
01427 gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01428
01429 break;
01430 }
01431
01432 return 1;
01433 }
01434
01435 static int gtalk_update_externip(void)
01436 {
01437 int sock;
01438 char *newaddr;
01439 struct sockaddr_in answer = { 0, };
01440 struct sockaddr_in *dst;
01441 struct ast_sockaddr tmp_dst;
01442
01443 if (!stunaddr.sin_addr.s_addr) {
01444 return -1;
01445 }
01446 dst = &stunaddr;
01447
01448 sock = socket(AF_INET, SOCK_DGRAM, 0);
01449 if (sock < 0) {
01450 ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
01451 return -1;
01452 }
01453
01454 ast_sockaddr_from_sin(&tmp_dst, dst);
01455 if (ast_connect(sock, &tmp_dst) != 0) {
01456 ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst));
01457 close(sock);
01458 return -1;
01459 }
01460
01461 if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) {
01462 close(sock);
01463 return -1;
01464 }
01465
01466 newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
01467 memcpy(externip, newaddr, sizeof(externip));
01468
01469 close(sock);
01470 return 0;
01471
01472 }
01473
01474 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
01475 {
01476 struct gtalk_candidate *tmp;
01477 struct hostent *hp;
01478 struct ast_hostent ahp;
01479 struct sockaddr_in sin = { 0, };
01480 struct sockaddr_in aux = { 0, };
01481 struct ast_sockaddr sin_tmp;
01482 struct ast_sockaddr aux_tmp;
01483
01484 if (time(NULL) == p->laststun)
01485 return 0;
01486
01487 tmp = p->theircandidates;
01488 p->laststun = time(NULL);
01489 while (tmp) {
01490 char username[256];
01491
01492
01493 if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) {
01494 ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip);
01495 tmp = tmp->next;
01496 continue;
01497 }
01498 sin.sin_family = AF_INET;
01499 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01500 sin.sin_port = htons(tmp->port);
01501 snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
01502
01503
01504 ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp);
01505 ast_sockaddr_to_sin(&aux_tmp, &aux);
01506
01507
01508
01509
01510 if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
01511 ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
01512 } else {
01513 ast_sockaddr_from_sin(&sin_tmp, &sin);
01514 ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
01515 }
01516 if (aux.sin_addr.s_addr) {
01517 ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
01518 ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
01519 }
01520
01521 tmp = tmp->next;
01522 }
01523 return 1;
01524 }
01525
01526 static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
01527 {
01528 struct gtalk_pvt *p = NULL, *tmp = NULL;
01529 struct aji_client *c = client->connection;
01530 struct gtalk_candidate *newcandidate = NULL;
01531 iks *traversenodes = NULL, *receipt = NULL;
01532 char *from;
01533
01534 from = iks_find_attrib(pak->x,"to");
01535 if (!from) {
01536 from = c->jid->full;
01537 }
01538
01539 for (tmp = client->p; tmp; tmp = tmp->next) {
01540 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01541 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01542 p = tmp;
01543 break;
01544 }
01545 }
01546
01547 if (!p) {
01548 return -1;
01549 }
01550 traversenodes = pak->query;
01551 while(traversenodes) {
01552 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
01553 traversenodes = iks_first_tag(traversenodes);
01554 continue;
01555 }
01556 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
01557 traversenodes = iks_child(traversenodes);
01558 continue;
01559 }
01560 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
01561 newcandidate = ast_calloc(1, sizeof(*newcandidate));
01562 if (!newcandidate)
01563 return 0;
01564 ast_copy_string(newcandidate->name,
01565 S_OR(iks_find_attrib(traversenodes, "name"), ""),
01566 sizeof(newcandidate->name));
01567 ast_copy_string(newcandidate->ip,
01568 S_OR(iks_find_attrib(traversenodes, "address"), ""),
01569 sizeof(newcandidate->ip));
01570 newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01571 ast_copy_string(newcandidate->username,
01572 S_OR(iks_find_attrib(traversenodes, "username"), ""),
01573 sizeof(newcandidate->username));
01574 ast_copy_string(newcandidate->password,
01575 S_OR(iks_find_attrib(traversenodes, "password"), ""),
01576 sizeof(newcandidate->password));
01577 newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01578 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp"))
01579 newcandidate->protocol = AJI_PROTOCOL_UDP;
01580 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp"))
01581 newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01582
01583 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun"))
01584 newcandidate->type = AJI_CONNECT_STUN;
01585 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local"))
01586 newcandidate->type = AJI_CONNECT_LOCAL;
01587 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay"))
01588 newcandidate->type = AJI_CONNECT_RELAY;
01589 ast_copy_string(newcandidate->network,
01590 S_OR(iks_find_attrib(traversenodes, "network"), ""),
01591 sizeof(newcandidate->network));
01592 newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0"));
01593 newcandidate->next = NULL;
01594
01595 newcandidate->next = p->theircandidates;
01596 p->theircandidates = newcandidate;
01597 p->laststun = 0;
01598 gtalk_update_stun(p->parent, p);
01599 newcandidate = NULL;
01600 }
01601 traversenodes = iks_next_tag(traversenodes);
01602 }
01603
01604 receipt = iks_new("iq");
01605 iks_insert_attrib(receipt, "type", "result");
01606 iks_insert_attrib(receipt, "from", from);
01607 iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
01608 iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
01609 ast_aji_send(c, receipt);
01610
01611 iks_delete(receipt);
01612
01613 return 1;
01614 }
01615
01616 static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
01617 {
01618 struct ast_frame *f;
01619
01620 if (!p->rtp) {
01621 return &ast_null_frame;
01622 }
01623 f = ast_rtp_instance_read(p->rtp, 0);
01624 gtalk_update_stun(p->parent, p);
01625 if (p->owner) {
01626
01627 if (f->frametype == AST_FRAME_VOICE) {
01628 if (!ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format)) {
01629 ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
01630 ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO);
01631 ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format);
01632 ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
01633 ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
01634 }
01635
01636
01637
01638
01639
01640 }
01641 }
01642 return f;
01643 }
01644
01645 static struct ast_frame *gtalk_read(struct ast_channel *ast)
01646 {
01647 struct ast_frame *fr;
01648 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
01649
01650 ast_mutex_lock(&p->lock);
01651 fr = gtalk_rtp_read(ast, p);
01652 ast_mutex_unlock(&p->lock);
01653 return fr;
01654 }
01655
01656
01657 static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame)
01658 {
01659 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
01660 int res = 0;
01661 char buf[256];
01662
01663 switch (frame->frametype) {
01664 case AST_FRAME_VOICE:
01665 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
01666 ast_log(LOG_WARNING,
01667 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01668 ast_getformatname(&frame->subclass.format),
01669 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
01670 ast_getformatname(ast_channel_readformat(ast)),
01671 ast_getformatname(ast_channel_writeformat(ast)));
01672 return 0;
01673 }
01674 if (p) {
01675 ast_mutex_lock(&p->lock);
01676 if (p->rtp) {
01677 res = ast_rtp_instance_write(p->rtp, frame);
01678 }
01679 ast_mutex_unlock(&p->lock);
01680 }
01681 break;
01682 case AST_FRAME_VIDEO:
01683 if (p) {
01684 ast_mutex_lock(&p->lock);
01685 if (p->vrtp) {
01686 res = ast_rtp_instance_write(p->vrtp, frame);
01687 }
01688 ast_mutex_unlock(&p->lock);
01689 }
01690 break;
01691 case AST_FRAME_IMAGE:
01692 return 0;
01693 break;
01694 default:
01695 ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
01696 frame->frametype);
01697 return 0;
01698 }
01699
01700 return res;
01701 }
01702
01703 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
01704 {
01705 struct gtalk_pvt *p = ast_channel_tech_pvt(newchan);
01706 ast_mutex_lock(&p->lock);
01707
01708 if ((p->owner != oldchan)) {
01709 ast_mutex_unlock(&p->lock);
01710 return -1;
01711 }
01712 if (p->owner == oldchan)
01713 p->owner = newchan;
01714 ast_mutex_unlock(&p->lock);
01715 return 0;
01716 }
01717
01718 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
01719 {
01720 int res = 0;
01721
01722 switch (condition) {
01723 case AST_CONTROL_HOLD:
01724 ast_moh_start(ast, data, NULL);
01725 break;
01726 case AST_CONTROL_UNHOLD:
01727 ast_moh_stop(ast);
01728 break;
01729 default:
01730 ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
01731
01732 case AST_CONTROL_PVT_CAUSE_CODE:
01733 res = -1;
01734 }
01735
01736 return res;
01737 }
01738
01739 static int gtalk_sendtext(struct ast_channel *chan, const char *text)
01740 {
01741 int res = 0;
01742 struct aji_client *client = NULL;
01743 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
01744
01745 if (!p->parent) {
01746 ast_log(LOG_ERROR, "Parent channel not found\n");
01747 return -1;
01748 }
01749 if (!p->parent->connection) {
01750 ast_log(LOG_ERROR, "XMPP client not found\n");
01751 return -1;
01752 }
01753 client = p->parent->connection;
01754 res = ast_aji_send_chat(client, p->them, text);
01755 return res;
01756 }
01757
01758 static int gtalk_digit_begin(struct ast_channel *chan, char digit)
01759 {
01760 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
01761 int res = 0;
01762
01763 ast_mutex_lock(&p->lock);
01764 if (p->rtp) {
01765 ast_rtp_instance_dtmf_begin(p->rtp, digit);
01766 } else {
01767 res = -1;
01768 }
01769 ast_mutex_unlock(&p->lock);
01770
01771 return res;
01772 }
01773
01774 static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
01775 {
01776 struct gtalk_pvt *p = ast_channel_tech_pvt(chan);
01777 int res = 0;
01778
01779 ast_mutex_lock(&p->lock);
01780 if (p->rtp) {
01781 ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration);
01782 } else {
01783 res = -1;
01784 }
01785 ast_mutex_unlock(&p->lock);
01786
01787 return res;
01788 }
01789
01790
01791
01792
01793 #if 0
01794 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
01795 {
01796 struct gtalk_pvt *p = ast->tech_pvt;
01797 struct gtalk *client = p->parent;
01798 iks *iq, *gtalk, *dtmf;
01799 char buffer[2] = {digit, '\0'};
01800 char *lowerthem = NULL;
01801 iq = iks_new("iq");
01802 gtalk = iks_new("gtalk");
01803 dtmf = iks_new("dtmf");
01804 if(!iq || !gtalk || !dtmf) {
01805 iks_delete(iq);
01806 iks_delete(gtalk);
01807 iks_delete(dtmf);
01808 ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
01809 return -1;
01810 }
01811
01812 iks_insert_attrib(iq, "type", "set");
01813 iks_insert_attrib(iq, "to", p->them);
01814 iks_insert_attrib(iq, "from", p->us);
01815 iks_insert_attrib(iq, "id", client->connection->mid);
01816 ast_aji_increment_mid(client->connection->mid);
01817 iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
01818 iks_insert_attrib(gtalk, "action", "session-info");
01819
01820
01821 if (!p->initiator) {
01822 char c;
01823 char *t = lowerthem = ast_strdupa(p->them);
01824 while (((c = *t) != '/') && (*t++ = tolower(c)));
01825 }
01826 iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem);
01827 iks_insert_attrib(gtalk, "sid", p->sid);
01828 iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
01829 iks_insert_attrib(dtmf, "code", buffer);
01830 iks_insert_node(iq, gtalk);
01831 iks_insert_node(gtalk, dtmf);
01832
01833 ast_mutex_lock(&p->lock);
01834 if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
01835 iks_insert_attrib(dtmf, "action", "button-down");
01836 } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
01837 iks_insert_attrib(dtmf, "action", "button-up");
01838 }
01839 ast_aji_send(client->connection, iq);
01840
01841 iks_delete(iq);
01842 iks_delete(gtalk);
01843 iks_delete(dtmf);
01844 ast_mutex_unlock(&p->lock);
01845 return 0;
01846 }
01847 #endif
01848
01849 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
01850 {
01851 ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01852
01853 return -1;
01854 }
01855
01856
01857
01858 static int gtalk_call(struct ast_channel *ast, const char *dest, int timeout)
01859 {
01860 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
01861
01862 if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
01863 ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
01864 return -1;
01865 }
01866
01867 ast_setstate(ast, AST_STATE_RING);
01868 if (!p->ringrule) {
01869 ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01870 p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01871 IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01872 } else {
01873 ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01874 }
01875
01876 gtalk_invite(p, p->them, p->us, p->sid, 1);
01877
01878 return 0;
01879 }
01880
01881
01882 static int gtalk_hangup(struct ast_channel *ast)
01883 {
01884 struct gtalk_pvt *p = ast_channel_tech_pvt(ast);
01885 struct gtalk *client;
01886
01887 ast_mutex_lock(&p->lock);
01888 client = p->parent;
01889 p->owner = NULL;
01890 ast_channel_tech_pvt_set(ast, NULL);
01891 if (!p->alreadygone) {
01892 gtalk_action(client, p, "terminate");
01893 }
01894 ast_mutex_unlock(&p->lock);
01895
01896 gtalk_free_pvt(client, p);
01897 ast_module_unref(ast_module_info->self);
01898
01899 return 0;
01900 }
01901
01902
01903 static struct ast_channel *gtalk_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
01904 {
01905 struct gtalk_pvt *p = NULL;
01906 struct gtalk *client = NULL;
01907 char *sender = NULL, *to = NULL, *s = NULL;
01908 struct ast_channel *chan = NULL;
01909
01910 if (data) {
01911 s = ast_strdupa(data);
01912 sender = strsep(&s, "/");
01913 if (sender && (sender[0] != '\0')) {
01914 to = strsep(&s, "/");
01915 }
01916 if (!to) {
01917 ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", data);
01918 return NULL;
01919 }
01920 if (!to) {
01921 ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01922 return NULL;
01923 }
01924 }
01925
01926 client = find_gtalk(to, sender);
01927 if (!client) {
01928 ast_log(LOG_WARNING, "Could not find recipient.\n");
01929 return NULL;
01930 }
01931 if (!strcasecmp(client->name, "guest")){
01932
01933
01934 if (client->connection) {
01935 ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
01936 }
01937 client->connection = ast_aji_get_client(sender);
01938 if (!client->connection) {
01939 ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
01940 ASTOBJ_UNREF(client, gtalk_member_destroy);
01941 return NULL;
01942 }
01943 }
01944
01945 ASTOBJ_WRLOCK(client);
01946 p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01947 if (p) {
01948 chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? ast_channel_linkedid(requestor) : NULL);
01949 }
01950 ASTOBJ_UNLOCK(client);
01951 return chan;
01952 }
01953
01954
01955 static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01956 {
01957 #define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
01958 struct gtalk_pvt *p;
01959 struct ast_channel *chan;
01960 int numchans = 0;
01961 char them[AJI_MAX_JIDLEN];
01962 char *jid = NULL;
01963 char *resource = NULL;
01964
01965 switch (cmd) {
01966 case CLI_INIT:
01967 e->command = "gtalk show channels";
01968 e->usage =
01969 "Usage: gtalk show channels\n"
01970 " Shows current state of the Gtalk channels.\n";
01971 return NULL;
01972 case CLI_GENERATE:
01973 return NULL;
01974 }
01975
01976 if (a->argc != 3)
01977 return CLI_SHOWUSAGE;
01978
01979 ast_mutex_lock(>alklock);
01980 ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01981 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
01982 ASTOBJ_WRLOCK(iterator);
01983 p = iterator->p;
01984 while(p) {
01985 chan = p->owner;
01986 ast_copy_string(them, p->them, sizeof(them));
01987 jid = them;
01988 resource = strchr(them, '/');
01989 if (!resource)
01990 resource = "None";
01991 else {
01992 *resource = '\0';
01993 resource ++;
01994 }
01995 if (chan)
01996 ast_cli(a->fd, FORMAT,
01997 ast_channel_name(chan),
01998 jid,
01999 resource,
02000 ast_getformatname(ast_channel_readformat(chan)),
02001 ast_getformatname(ast_channel_writeformat(chan))
02002 );
02003 else
02004 ast_log(LOG_WARNING, "No available channel\n");
02005 numchans ++;
02006 p = p->next;
02007 }
02008 ASTOBJ_UNLOCK(iterator);
02009 });
02010
02011 ast_mutex_unlock(>alklock);
02012
02013 ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
02014 return CLI_SUCCESS;
02015 #undef FORMAT
02016 }
02017
02018
02019 static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02020 {
02021 char codec_buf[BUFSIZ];
02022 switch (cmd) {
02023 case CLI_INIT:
02024 e->command = "gtalk show settings";
02025 e->usage =
02026 "Usage: gtalk show settings\n"
02027 " Provides detailed list of the configuration on the GoogleTalk channel.\n";
02028 return NULL;
02029 case CLI_GENERATE:
02030 return NULL;
02031 }
02032
02033 if (a->argc != 3) {
02034 return CLI_SHOWUSAGE;
02035 }
02036
02037 #define FORMAT " %-25.20s %-15.30s\n"
02038
02039 ast_cli(a->fd, "\nGlobal Settings:\n");
02040 ast_cli(a->fd, "----------------\n");
02041 ast_cli(a->fd, FORMAT, "UDP Bindaddress:", ast_inet_ntoa(bindaddr.sin_addr));
02042 ast_cli(a->fd, FORMAT, "Stun Address:", global_stunaddr != 0 ? ast_inet_ntoa(stunaddr.sin_addr) : "Disabled");
02043 ast_cli(a->fd, FORMAT, "External IP:", S_OR(externip, "Disabled"));
02044 ast_cli(a->fd, FORMAT, "Context:", global_context);
02045 ast_cli(a->fd, FORMAT, "Codecs:", ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, global_capability));
02046 ast_cli(a->fd, FORMAT, "Parking Lot:", global_parkinglot);
02047 ast_cli(a->fd, FORMAT, "Allow Guest:", AST_CLI_YESNO(global_allowguest));
02048 ast_cli(a->fd, "\n----\n");
02049
02050 return CLI_SUCCESS;
02051 #undef FORMAT
02052 }
02053
02054
02055
02056 #if 0
02057 static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02058 {
02059 switch (cmd) {
02060 case CLI_INIT:
02061 e->command = "gtalk reload";
02062 e->usage =
02063 "Usage: gtalk reload\n"
02064 " Reload gtalk channel driver.\n";
02065 return NULL;
02066 case CLI_GENERATE:
02067 return NULL;
02068 }
02069
02070 ast_verbose("IT DOES WORK!\n");
02071 return CLI_SUCCESS;
02072 }
02073 #endif
02074
02075 static int gtalk_parser(void *data, ikspak *pak)
02076 {
02077 struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
02078 int res;
02079 iks *tmp;
02080
02081 if (!strcasecmp(iks_name(pak->query), "jin:jingle") && (tmp = iks_next(pak->query)) && !strcasecmp(iks_name(tmp), "ses:session")) {
02082 ast_debug(1, "New method detected. Skipping jingle offer and using old gtalk method.\n");
02083 pak->query = tmp;
02084 }
02085
02086 if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
02087 ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
02088 }
02089
02090 if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) {
02091 ast_log(LOG_NOTICE, "No attribute \"type\" found. Ignoring message.\n");
02092 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
02093
02094 gtalk_newcall(client, pak);
02095 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
02096 ast_debug(3, "About to add candidate!\n");
02097 res = gtalk_add_candidate(client, pak);
02098 if (!res) {
02099 ast_log(LOG_WARNING, "Could not add any candidate\n");
02100 } else {
02101 ast_debug(3, "Candidate Added!\n");
02102 }
02103 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
02104 gtalk_is_answered(client, pak);
02105 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
02106 gtalk_is_accepted(client, pak);
02107 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
02108 gtalk_handle_dtmf(client, pak);
02109 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
02110 gtalk_hangup_farend(client, pak);
02111 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
02112 gtalk_hangup_farend(client, pak);
02113 }
02114 ASTOBJ_UNREF(client, gtalk_member_destroy);
02115 return IKS_FILTER_EAT;
02116 }
02117
02118 static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest,
02119 struct ast_codec_pref prefs, char *context,
02120 struct gtalk *member)
02121 {
02122 struct aji_client *client;
02123
02124 if (!member)
02125 ast_log(LOG_WARNING, "Out of memory.\n");
02126
02127 ast_copy_string(member->name, label, sizeof(member->name));
02128 ast_copy_string(member->user, label, sizeof(member->user));
02129 ast_copy_string(member->context, context, sizeof(member->context));
02130 member->allowguest = allowguest;
02131 member->prefs = prefs;
02132 while (var) {
02133 if (!strcasecmp(var->name, "username"))
02134 ast_copy_string(member->user, var->value, sizeof(member->user));
02135 else if (!strcasecmp(var->name, "disallow"))
02136 ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0);
02137 else if (!strcasecmp(var->name, "allow"))
02138 ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1);
02139 else if (!strcasecmp(var->name, "context"))
02140 ast_copy_string(member->context, var->value, sizeof(member->context));
02141 else if (!strcasecmp(var->name, "parkinglot"))
02142 ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
02143 else if (!strcasecmp(var->name, "connection")) {
02144 if ((client = ast_aji_get_client(var->value))) {
02145 member->connection = client;
02146 iks_filter_add_rule(client->f, gtalk_parser, member,
02147 IKS_RULE_TYPE, IKS_PAK_IQ,
02148 IKS_RULE_FROM_PARTIAL, member->user,
02149 IKS_RULE_NS, GOOGLE_NS,
02150 IKS_RULE_DONE);
02151 } else {
02152 ast_log(LOG_ERROR, "connection referenced not found!\n");
02153 return 0;
02154 }
02155 }
02156 var = var->next;
02157 }
02158 if (member->connection && member->user)
02159 member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
02160 else {
02161 ast_log(LOG_ERROR, "No Connection or Username!\n");
02162 }
02163 return 1;
02164 }
02165
02166 static int gtalk_load_config(void)
02167 {
02168 char *cat = NULL;
02169 struct ast_config *cfg = NULL;
02170 struct ast_variable *var;
02171 struct gtalk *member;
02172 struct ast_codec_pref prefs;
02173 struct aji_client_container *clients;
02174 struct gtalk_candidate *global_candidates = NULL;
02175 struct hostent *hp;
02176 struct ast_hostent ahp;
02177 struct ast_flags config_flags = { 0 };
02178
02179 cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
02180 if (!cfg) {
02181 return 0;
02182 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02183 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", GOOGLE_CONFIG);
02184 return 0;
02185 }
02186
02187
02188 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
02189
02190
02191 memset(&prefs, 0, sizeof(prefs));
02192 memset(&stunaddr, 0, sizeof(stunaddr));
02193 global_stunaddr = 0;
02194 global_allowguest = DEFAULT_ALLOWGUEST;
02195 ast_copy_string(global_context, DEFAULT_CONTEXT, sizeof(global_context));
02196 ast_copy_string(global_parkinglot, DEFAULT_PARKINGLOT, sizeof(global_parkinglot));
02197
02198 cat = ast_category_browse(cfg, NULL);
02199 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02200
02201 if (!ast_jb_read_conf(&global_jbconf, var->name, var->value)) {
02202 continue;
02203 }
02204
02205 if (!strcasecmp(var->name, "allowguest")) {
02206 global_allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
02207 } else if (!strcasecmp(var->name, "disallow")) {
02208 ast_parse_allow_disallow(&prefs, global_capability, var->value, 0);
02209 } else if (!strcasecmp(var->name, "allow")) {
02210 ast_parse_allow_disallow(&prefs, global_capability, var->value, 1);
02211 } else if (!strcasecmp(var->name, "context")) {
02212 ast_copy_string(global_context, var->value, sizeof(global_context));
02213 } else if (!strcasecmp(var->name, "externip")) {
02214 ast_copy_string(externip, var->value, sizeof(externip));
02215 } else if (!strcasecmp(var->name, "parkinglot")) {
02216 ast_copy_string(global_parkinglot, var->value, sizeof(global_parkinglot));
02217 } else if (!strcasecmp(var->name, "bindaddr")) {
02218 if (!(hp = ast_gethostbyname(var->value, &ahp))) {
02219 ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
02220 } else {
02221 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
02222 }
02223 } else if (!strcasecmp(var->name, "stunaddr")) {
02224 stunaddr.sin_port = htons(STANDARD_STUN_PORT);
02225 global_stunaddr = 1;
02226 if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) {
02227 ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value);
02228 }
02229 }
02230 }
02231 while (cat) {
02232 if (strcasecmp(cat, "general")) {
02233 var = ast_variable_browse(cfg, cat);
02234 member = ast_calloc(1, sizeof(*member));
02235 ASTOBJ_INIT(member);
02236 ASTOBJ_WRLOCK(member);
02237 member->cap = ast_format_cap_alloc_nolock();
02238 if (!strcasecmp(cat, "guest")) {
02239 ast_copy_string(member->name, "guest", sizeof(member->name));
02240 ast_copy_string(member->user, "guest", sizeof(member->user));
02241 ast_copy_string(member->context, global_context, sizeof(member->context));
02242 ast_copy_string(member->parkinglot, global_parkinglot, sizeof(member->parkinglot));
02243 member->allowguest = global_allowguest;
02244 member->prefs = prefs;
02245 while (var) {
02246 if (!strcasecmp(var->name, "disallow")) {
02247 ast_parse_allow_disallow(&member->prefs, member->cap,
02248 var->value, 0);
02249 } else if (!strcasecmp(var->name, "allow")) {
02250 ast_parse_allow_disallow(&member->prefs, member->cap,
02251 var->value, 1);
02252 } else if (!strcasecmp(var->name, "context")) {
02253 ast_copy_string(member->context, var->value,
02254 sizeof(member->context));
02255 } else if (!strcasecmp(var->name, "parkinglot")) {
02256 ast_copy_string(member->parkinglot, var->value,
02257 sizeof(member->parkinglot));
02258 }
02259 var = var->next;
02260 }
02261 ASTOBJ_UNLOCK(member);
02262 clients = ast_aji_get_clients();
02263 if (clients) {
02264 ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
02265 ASTOBJ_WRLOCK(iterator);
02266 ASTOBJ_WRLOCK(member);
02267 if (member->connection) {
02268 ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
02269 }
02270 member->connection = NULL;
02271 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
02272 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE);
02273 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/gtalk", IKS_RULE_DONE);
02274 ASTOBJ_UNLOCK(member);
02275 ASTOBJ_UNLOCK(iterator);
02276 });
02277 ASTOBJ_CONTAINER_LINK(>alk_list, member);
02278 ASTOBJ_UNREF(member, gtalk_member_destroy);
02279 } else {
02280 ASTOBJ_UNLOCK(member);
02281 ASTOBJ_UNREF(member, gtalk_member_destroy);
02282 }
02283 } else {
02284 ASTOBJ_UNLOCK(member);
02285 if (gtalk_create_member(cat, var, global_allowguest, prefs, global_context, member)) {
02286 ASTOBJ_CONTAINER_LINK(>alk_list, member);
02287 }
02288 ASTOBJ_UNREF(member, gtalk_member_destroy);
02289 }
02290 }
02291 cat = ast_category_browse(cfg, cat);
02292 }
02293
02294 ast_config_destroy(cfg);
02295 gtalk_update_externip();
02296 gtalk_free_candidates(global_candidates);
02297 return 1;
02298 }
02299
02300
02301 static int load_module(void)
02302 {
02303 struct ast_sockaddr bindaddr_tmp;
02304 struct ast_sockaddr ourip_tmp;
02305 char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
02306 struct ast_format tmpfmt;
02307
02308 if (!(gtalk_tech.capabilities = ast_format_cap_alloc())) {
02309 return AST_MODULE_LOAD_DECLINE;
02310 }
02311 if (!(global_capability = ast_format_cap_alloc())) {
02312 return AST_MODULE_LOAD_DECLINE;
02313 }
02314
02315 ast_format_cap_add_all_by_type(gtalk_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
02316 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
02317 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0));
02318 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
02319 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0));
02320
02321 free(jabber_loaded);
02322 if (!jabber_loaded) {
02323
02324 jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
02325 free(jabber_loaded);
02326 if (!jabber_loaded) {
02327 ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
02328 return AST_MODULE_LOAD_DECLINE;
02329 }
02330 }
02331
02332 ASTOBJ_CONTAINER_INIT(>alk_list);
02333 if (!gtalk_load_config()) {
02334 ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
02335 return 0;
02336 }
02337
02338 sched = ast_sched_context_create();
02339 if (!sched) {
02340 ast_log(LOG_WARNING, "Unable to create schedule context\n");
02341 }
02342
02343 io = io_context_create();
02344 if (!io) {
02345 ast_log(LOG_WARNING, "Unable to create I/O context\n");
02346 }
02347
02348 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
02349 if (gtalk_get_local_ip(&ourip_tmp)) {
02350 ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
02351 return 0;
02352 }
02353 __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
02354
02355 ast_rtp_glue_register(>alk_rtp_glue);
02356 ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02357
02358
02359 if (ast_channel_register(>alk_tech)) {
02360 ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
02361 return -1;
02362 }
02363 return 0;
02364 }
02365
02366
02367
02368 #if 0
02369 static int reload(void)
02370 {
02371 return 0;
02372 }
02373 #endif
02374
02375 static int unload_module(void)
02376 {
02377 struct gtalk_pvt *privates = NULL;
02378 ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02379
02380 ast_channel_unregister(>alk_tech);
02381 ast_rtp_glue_unregister(>alk_rtp_glue);
02382
02383 if (!ast_mutex_lock(>alklock)) {
02384
02385 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
02386 ASTOBJ_WRLOCK(iterator);
02387 privates = iterator->p;
02388 while(privates) {
02389 if (privates->owner)
02390 ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
02391 privates = privates->next;
02392 }
02393 iterator->p = NULL;
02394 ASTOBJ_UNLOCK(iterator);
02395 });
02396 ast_mutex_unlock(>alklock);
02397 } else {
02398 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02399 return -1;
02400 }
02401 ASTOBJ_CONTAINER_DESTROYALL(>alk_list, gtalk_member_destroy);
02402 ASTOBJ_CONTAINER_DESTROY(>alk_list);
02403 global_capability = ast_format_cap_destroy(global_capability);
02404 gtalk_tech.capabilities = ast_format_cap_destroy(gtalk_tech.capabilities);
02405 return 0;
02406 }
02407
02408 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gtalk Channel Driver",
02409 .load = load_module,
02410 .unload = unload_module,
02411
02412 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
02413 );