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 #include "asterisk.h"
00034
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00036
00037 #include <stdlib.h>
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <unistd.h>
00041 #include <sys/socket.h>
00042 #include <errno.h>
00043 #include <stdlib.h>
00044 #include <fcntl.h>
00045 #include <netdb.h>
00046 #include <netinet/in.h>
00047 #include <arpa/inet.h>
00048 #include <sys/signal.h>
00049 #include <iksemel.h>
00050 #include <pthread.h>
00051
00052 #ifdef HAVE_GNUTLS
00053 #include <gcrypt.h>
00054 GCRY_THREAD_OPTION_PTHREAD_IMPL;
00055 #endif
00056
00057 #include "asterisk/lock.h"
00058 #include "asterisk/channel.h"
00059 #include "asterisk/config.h"
00060 #include "asterisk/logger.h"
00061 #include "asterisk/module.h"
00062 #include "asterisk/pbx.h"
00063 #include "asterisk/options.h"
00064 #include "asterisk/lock.h"
00065 #include "asterisk/sched.h"
00066 #include "asterisk/io.h"
00067 #include "asterisk/rtp.h"
00068 #include "asterisk/acl.h"
00069 #include "asterisk/callerid.h"
00070 #include "asterisk/file.h"
00071 #include "asterisk/cli.h"
00072 #include "asterisk/app.h"
00073 #include "asterisk/musiconhold.h"
00074 #include "asterisk/manager.h"
00075 #include "asterisk/stringfields.h"
00076 #include "asterisk/utils.h"
00077 #include "asterisk/causes.h"
00078 #include "asterisk/astobj.h"
00079 #include "asterisk/abstract_jb.h"
00080 #include "asterisk/jabber.h"
00081
00082 #define GOOGLE_CONFIG "gtalk.conf"
00083
00084 #define GOOGLE_NS "http://www.google.com/session"
00085
00086
00087
00088 static struct ast_jb_conf default_jbconf =
00089 {
00090 .flags = 0,
00091 .max_size = -1,
00092 .resync_threshold = -1,
00093 .impl = ""
00094 };
00095 static struct ast_jb_conf global_jbconf;
00096
00097 enum gtalk_protocol {
00098 AJI_PROTOCOL_UDP = 1,
00099 AJI_PROTOCOL_SSLTCP = 2,
00100 };
00101
00102 enum gtalk_connect_type {
00103 AJI_CONNECT_STUN = 1,
00104 AJI_CONNECT_LOCAL = 2,
00105 AJI_CONNECT_RELAY = 3,
00106 };
00107
00108 struct gtalk_pvt {
00109 ast_mutex_t lock;
00110 time_t laststun;
00111 struct gtalk *parent;
00112 char sid[100];
00113 char us[AJI_MAX_JIDLEN];
00114 char them[AJI_MAX_JIDLEN];
00115 char ring[10];
00116 iksrule *ringrule;
00117 int initiator;
00118 int alreadygone;
00119 int capability;
00120 struct ast_codec_pref prefs;
00121 struct gtalk_candidate *theircandidates;
00122 struct gtalk_candidate *ourcandidates;
00123 char cid_num[80];
00124 char cid_name[80];
00125 char exten[80];
00126 struct ast_channel *owner;
00127 struct ast_rtp *rtp;
00128 struct ast_rtp *vrtp;
00129 int jointcapability;
00130 int peercapability;
00131 struct gtalk_pvt *next;
00132 };
00133
00134 struct gtalk_candidate {
00135 char name[100];
00136 enum gtalk_protocol protocol;
00137 double preference;
00138 char username[100];
00139 char password[100];
00140 enum gtalk_connect_type type;
00141 char network[6];
00142 int generation;
00143 char ip[16];
00144 int port;
00145 int receipt;
00146 struct gtalk_candidate *next;
00147 };
00148
00149 struct gtalk {
00150 ASTOBJ_COMPONENTS(struct gtalk);
00151 struct aji_client *connection;
00152 struct aji_buddy *buddy;
00153 struct gtalk_pvt *p;
00154 struct ast_codec_pref prefs;
00155 int amaflags;
00156 char user[AJI_MAX_JIDLEN];
00157 char context[AST_MAX_CONTEXT];
00158 char accountcode[AST_MAX_ACCOUNT_CODE];
00159 int capability;
00160 ast_group_t callgroup;
00161 ast_group_t pickupgroup;
00162 int callingpres;
00163 int allowguest;
00164 char language[MAX_LANGUAGE];
00165 char musicclass[MAX_MUSICCLASS];
00166 };
00167
00168 struct gtalk_container {
00169 ASTOBJ_CONTAINER_COMPONENTS(struct gtalk);
00170 };
00171
00172 static const char desc[] = "Gtalk Channel";
00173
00174 static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
00175
00176 AST_MUTEX_DEFINE_STATIC(gtalklock);
00177
00178
00179 static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause);
00180 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);
00181 static int gtalk_digit_begin(struct ast_channel *ast, char digit);
00182 static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00183 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout);
00184 static int gtalk_hangup(struct ast_channel *ast);
00185 static int gtalk_answer(struct ast_channel *ast);
00186 static int gtalk_newcall(struct gtalk *client, ikspak *pak);
00187 static struct ast_frame *gtalk_read(struct ast_channel *ast);
00188 static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);
00189 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00190 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00191 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00192 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
00193 static int gtalk_do_reload(int fd, int argc, char **argv);
00194 static int gtalk_show_channels(int fd, int argc, char **argv);
00195
00196 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
00197 struct ast_rtp *vrtp, int codecs, int nat_active);
00198 static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
00199 static int gtalk_get_codec(struct ast_channel *chan);
00200
00201
00202 static const struct ast_channel_tech gtalk_tech = {
00203 .type = "Gtalk",
00204 .description = "Gtalk Channel Driver",
00205 .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
00206 .requester = gtalk_request,
00207 .send_digit_begin = gtalk_digit_begin,
00208 .send_digit_end = gtalk_digit_end,
00209 .bridge = ast_rtp_bridge,
00210 .call = gtalk_call,
00211 .hangup = gtalk_hangup,
00212 .answer = gtalk_answer,
00213 .read = gtalk_read,
00214 .write = gtalk_write,
00215 .exception = gtalk_read,
00216 .indicate = gtalk_indicate,
00217 .fixup = gtalk_fixup,
00218 .send_html = gtalk_sendhtml,
00219 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
00220 };
00221
00222 static struct sockaddr_in bindaddr = { 0, };
00223
00224 static struct sched_context *sched;
00225 static struct io_context *io;
00226 static struct in_addr __ourip;
00227
00228
00229
00230 static struct ast_rtp_protocol gtalk_rtp = {
00231 type: "Gtalk",
00232 get_rtp_info: gtalk_get_rtp_peer,
00233 set_rtp_peer: gtalk_set_rtp_peer,
00234 get_codec: gtalk_get_codec,
00235 };
00236
00237 static char show_channels_usage[] =
00238 "Usage: gtalk show channels\n"
00239 " Shows current state of the Gtalk channels.\n";
00240
00241 static char reload_usage[] =
00242 "Usage: gtalk reload\n"
00243 " Reload gtalk channel driver.\n";
00244
00245
00246 static struct ast_cli_entry gtalk_cli[] = {
00247 {{ "gtalk", "reload", NULL}, gtalk_do_reload, "Reload GoogleTalk configuration", reload_usage },
00248 {{ "gtalk", "show", "channels", NULL}, gtalk_show_channels, "Show GoogleTalk channels", show_channels_usage },
00249 };
00250
00251
00252
00253 static char externip[16];
00254
00255 static struct gtalk_container gtalk_list;
00256
00257 static void gtalk_member_destroy(struct gtalk *obj)
00258 {
00259 free(obj);
00260 }
00261
00262 static struct gtalk *find_gtalk(char *name, char *connection)
00263 {
00264 struct gtalk *gtalk = NULL;
00265 char *domain = NULL , *s = NULL;
00266
00267 if(strchr(connection, '@')) {
00268 s = ast_strdupa(connection);
00269 domain = strsep(&s, "@");
00270 ast_verbose("OOOOH domain = %s\n", domain);
00271 }
00272 gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name);
00273 if (!gtalk && strchr(name, '@'))
00274 gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp);
00275
00276 if (!gtalk) {
00277 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
00278 ASTOBJ_RDLOCK(iterator);
00279 if (!strcasecmp(iterator->name, "guest")) {
00280 if (!strcasecmp(iterator->connection->jid->partial, connection)) {
00281 gtalk = iterator;
00282 } else if (!strcasecmp(iterator->connection->name, connection)) {
00283 gtalk = iterator;
00284 } else if (iterator->connection->component && !strcasecmp(iterator->connection->user,domain)) {
00285 gtalk = iterator;
00286 }
00287 }
00288 ASTOBJ_UNLOCK(iterator);
00289
00290 if (gtalk)
00291 break;
00292 });
00293
00294 }
00295 return gtalk;
00296 }
00297
00298
00299 static int add_codec_to_answer(const struct gtalk_pvt *p, int codec, iks *dcodecs)
00300 {
00301 char *format = ast_getformatname(codec);
00302
00303 if (!strcasecmp("ulaw", format)) {
00304 iks *payload_eg711u, *payload_pcmu;
00305 payload_pcmu = iks_new("payload-type");
00306 payload_eg711u = iks_new("payload-type");
00307
00308 if(!payload_eg711u || !payload_pcmu) {
00309 if(payload_pcmu)
00310 iks_delete(payload_pcmu);
00311 if(payload_eg711u)
00312 iks_delete(payload_eg711u);
00313 ast_log(LOG_WARNING,"Failed to allocate iks node");
00314 return -1;
00315 }
00316 iks_insert_attrib(payload_pcmu, "id", "0");
00317 iks_insert_attrib(payload_pcmu, "name", "PCMU");
00318 iks_insert_attrib(payload_pcmu, "clockrate","8000");
00319 iks_insert_attrib(payload_pcmu, "bitrate","64000");
00320 iks_insert_attrib(payload_eg711u, "id", "100");
00321 iks_insert_attrib(payload_eg711u, "name", "EG711U");
00322 iks_insert_attrib(payload_eg711u, "clockrate","8000");
00323 iks_insert_attrib(payload_eg711u, "bitrate","64000");
00324 iks_insert_node(dcodecs, payload_pcmu);
00325 iks_insert_node(dcodecs, payload_eg711u);
00326 }
00327 if (!strcasecmp("alaw", format)) {
00328 iks *payload_eg711a, *payload_pcma;
00329 payload_pcma = iks_new("payload-type");
00330 payload_eg711a = iks_new("payload-type");
00331 if(!payload_eg711a || !payload_pcma) {
00332 if(payload_eg711a)
00333 iks_delete(payload_eg711a);
00334 if(payload_pcma)
00335 iks_delete(payload_pcma);
00336 ast_log(LOG_WARNING,"Failed to allocate iks node");
00337 return -1;
00338 }
00339 iks_insert_attrib(payload_pcma, "id", "8");
00340 iks_insert_attrib(payload_pcma, "name", "PCMA");
00341 iks_insert_attrib(payload_pcma, "clockrate","8000");
00342 iks_insert_attrib(payload_pcma, "bitrate","64000");
00343 payload_eg711a = iks_new("payload-type");
00344 iks_insert_attrib(payload_eg711a, "id", "101");
00345 iks_insert_attrib(payload_eg711a, "name", "EG711A");
00346 iks_insert_attrib(payload_eg711a, "clockrate","8000");
00347 iks_insert_attrib(payload_eg711a, "bitrate","64000");
00348 iks_insert_node(dcodecs, payload_pcma);
00349 iks_insert_node(dcodecs, payload_eg711a);
00350 }
00351 if (!strcasecmp("ilbc", format)) {
00352 iks *payload_ilbc = iks_new("payload-type");
00353 if(!payload_ilbc) {
00354 ast_log(LOG_WARNING,"Failed to allocate iks node");
00355 return -1;
00356 }
00357 iks_insert_attrib(payload_ilbc, "id", "97");
00358 iks_insert_attrib(payload_ilbc, "name", "iLBC");
00359 iks_insert_attrib(payload_ilbc, "clockrate","8000");
00360 iks_insert_attrib(payload_ilbc, "bitrate","13300");
00361 iks_insert_node(dcodecs, payload_ilbc);
00362 }
00363 if (!strcasecmp("g723", format)) {
00364 iks *payload_g723 = iks_new("payload-type");
00365 if(!payload_g723) {
00366 ast_log(LOG_WARNING,"Failed to allocate iks node");
00367 return -1;
00368 }
00369 iks_insert_attrib(payload_g723, "id", "4");
00370 iks_insert_attrib(payload_g723, "name", "G723");
00371 iks_insert_attrib(payload_g723, "clockrate","8000");
00372 iks_insert_attrib(payload_g723, "bitrate","6300");
00373 iks_insert_node(dcodecs, payload_g723);
00374 }
00375 if (!strcasecmp("speex", format)) {
00376 iks *payload_speex = iks_new("payload-type");
00377 if(!payload_speex) {
00378 ast_log(LOG_WARNING,"Failed to allocate iks node");
00379 return -1;
00380 }
00381 iks_insert_attrib(payload_speex, "id", "110");
00382 iks_insert_attrib(payload_speex, "name", "speex");
00383 iks_insert_attrib(payload_speex, "clockrate","8000");
00384 iks_insert_attrib(payload_speex, "bitrate","11000");
00385 iks_insert_node(dcodecs, payload_speex);
00386 }
00387 ast_rtp_lookup_code(p->rtp, 1, codec);
00388 return 0;
00389 }
00390
00391 static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
00392 {
00393 struct gtalk *client = p->parent;
00394 iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
00395 int x;
00396 int pref_codec = 0;
00397 int alreadysent = 0;
00398
00399
00400 iq = iks_new("iq");
00401 gtalk = iks_new("session");
00402 dcodecs = iks_new("description");
00403 transport = iks_new("transport");
00404 payload_telephone = iks_new("payload-type");
00405 if (!(iq && gtalk && dcodecs && transport && payload_telephone)){
00406 if(iq)
00407 iks_delete(iq);
00408 if(gtalk)
00409 iks_delete(gtalk);
00410 if(dcodecs)
00411 iks_delete(dcodecs);
00412 if(transport)
00413 iks_delete(transport);
00414 if(payload_telephone)
00415 iks_delete(payload_telephone);
00416
00417 ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
00418 return 0;
00419 }
00420 iks_insert_attrib(dcodecs, "xmlns", "http://www.google.com/session/phone");
00421 iks_insert_attrib(dcodecs, "xml:lang", "en");
00422
00423 for (x = 0; x < 32; x++) {
00424 if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
00425 break;
00426 if (!(client->capability & pref_codec))
00427 continue;
00428 if (alreadysent & pref_codec)
00429 continue;
00430 add_codec_to_answer(p, pref_codec, dcodecs);
00431 alreadysent |= pref_codec;
00432 }
00433
00434 iks_insert_attrib(payload_telephone, "id", "106");
00435 iks_insert_attrib(payload_telephone, "name", "telephone-event");
00436 iks_insert_attrib(payload_telephone, "clockrate", "8000");
00437
00438 iks_insert_attrib(transport,"xmlns","http://www.google.com/transport/p2p");
00439
00440 iks_insert_attrib(iq, "type", "set");
00441 iks_insert_attrib(iq, "to", to);
00442 iks_insert_attrib(iq, "from", from);
00443 iks_insert_attrib(iq, "id", client->connection->mid);
00444 ast_aji_increment_mid(client->connection->mid);
00445
00446 iks_insert_attrib(gtalk, "xmlns", "http://www.google.com/session");
00447 iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
00448 iks_insert_attrib(gtalk, "initiator", initiator ? from : to);
00449 iks_insert_attrib(gtalk, "id", sid);
00450 iks_insert_node(iq, gtalk);
00451 iks_insert_node(gtalk, dcodecs);
00452 iks_insert_node(gtalk, transport);
00453 iks_insert_node(dcodecs, payload_telephone);
00454
00455 iks_send(client->connection->p, iq);
00456 iks_delete(payload_telephone);
00457 iks_delete(transport);
00458 iks_delete(dcodecs);
00459 iks_delete(gtalk);
00460 iks_delete(iq);
00461 return 1;
00462 }
00463
00464 static int gtalk_invite_response(struct gtalk_pvt *p, char *to , char *from, char *sid, int initiator)
00465 {
00466 iks *iq, *session, *transport;
00467 iq = iks_new("iq");
00468 session = iks_new("session");
00469 transport = iks_new("transport");
00470 if(!(iq && session && transport)) {
00471 if(iq)
00472 iks_delete(iq);
00473 if(session)
00474 iks_delete(session);
00475 if(transport)
00476 iks_delete(transport);
00477 ast_log(LOG_ERROR, " Unable to allocate IKS node\n");
00478 return -1;
00479 }
00480 iks_insert_attrib(iq, "from", from);
00481 iks_insert_attrib(iq, "to", to);
00482 iks_insert_attrib(iq, "type", "set");
00483 iks_insert_attrib(iq, "id",p->parent->connection->mid);
00484 ast_aji_increment_mid(p->parent->connection->mid);
00485 iks_insert_attrib(session, "type", "transport-accept");
00486 iks_insert_attrib(session, "id", sid);
00487 iks_insert_attrib(session, "initiator", initiator ? from : to);
00488 iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
00489 iks_insert_attrib(transport, "xmlns", "http://www.google.com/transport/p2p");
00490 iks_insert_node(iq,session);
00491 iks_insert_node(session,transport);
00492 iks_send(p->parent->connection->p, iq);
00493 iks_delete(transport);
00494 iks_delete(session);
00495 iks_delete(iq);
00496 return 1;
00497
00498 }
00499
00500 static int gtalk_ringing_ack(void *data, ikspak *pak)
00501 {
00502 struct gtalk_pvt *p = data;
00503
00504 if (p->ringrule)
00505 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00506 p->ringrule = NULL;
00507 if (p->owner)
00508 ast_queue_control(p->owner, AST_CONTROL_RINGING);
00509 return IKS_FILTER_EAT;
00510 }
00511
00512 static int gtalk_answer(struct ast_channel *ast)
00513 {
00514 struct gtalk_pvt *p = ast->tech_pvt;
00515 int res = 0;
00516
00517 if (option_debug)
00518 ast_log(LOG_DEBUG, "Answer!\n");
00519 ast_mutex_lock(&p->lock);
00520 gtalk_invite(p, p->them, p->us,p->sid, 0);
00521 ast_mutex_unlock(&p->lock);
00522 return res;
00523 }
00524
00525 static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
00526 {
00527 struct gtalk_pvt *p = chan->tech_pvt;
00528 enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
00529
00530 if (!p)
00531 return res;
00532
00533 ast_mutex_lock(&p->lock);
00534 if (p->rtp){
00535 *rtp = p->rtp;
00536 res = AST_RTP_TRY_PARTIAL;
00537 }
00538 ast_mutex_unlock(&p->lock);
00539
00540 return res;
00541 }
00542
00543 static int gtalk_get_codec(struct ast_channel *chan)
00544 {
00545 struct gtalk_pvt *p = chan->tech_pvt;
00546 return p->peercapability;
00547 }
00548
00549 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
00550 {
00551 struct gtalk_pvt *p;
00552
00553 p = chan->tech_pvt;
00554 if (!p)
00555 return -1;
00556 ast_mutex_lock(&p->lock);
00557
00558
00559
00560
00561
00562
00563
00564
00565 ast_mutex_unlock(&p->lock);
00566 return 0;
00567 }
00568
00569 static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
00570 {
00571 iks *response = NULL, *error = NULL, *reason = NULL;
00572 int res = -1;
00573
00574 response = iks_new("iq");
00575 if (response) {
00576 iks_insert_attrib(response, "type", "result");
00577 iks_insert_attrib(response, "from", from);
00578 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00579 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00580 if (reasonstr) {
00581 error = iks_new("error");
00582 if (error) {
00583 iks_insert_attrib(error, "type", "cancel");
00584 reason = iks_new(reasonstr);
00585 if (reason)
00586 iks_insert_node(error, reason);
00587 iks_insert_node(response, error);
00588 }
00589 }
00590 iks_send(client->connection->p, response);
00591 if (reason)
00592 iks_delete(reason);
00593 if (error)
00594 iks_delete(error);
00595 iks_delete(response);
00596 res = 0;
00597 }
00598 return res;
00599 }
00600
00601 static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
00602 {
00603 struct gtalk_pvt *tmp;
00604 char *from;
00605 ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00606
00607 for (tmp = client->p; tmp; tmp = tmp->next) {
00608 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00609 break;
00610 }
00611
00612 from = iks_find_attrib(pak->x, "to");
00613 if(!from)
00614 from = client->connection->jid->full;
00615
00616 if (tmp) {
00617 if (tmp->owner)
00618 ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00619 } else
00620 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00621 gtalk_response(client, from, pak, NULL, NULL);
00622 return 1;
00623 }
00624
00625 static int gtalk_is_accepted(struct gtalk *client, ikspak *pak)
00626 {
00627 struct gtalk_pvt *tmp;
00628 char *from;
00629
00630 ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00631
00632 for (tmp = client->p; tmp; tmp = tmp->next) {
00633 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00634 break;
00635 }
00636
00637 from = iks_find_attrib(pak->x, "to");
00638 if(!from)
00639 from = client->connection->jid->full;
00640
00641 if (!tmp)
00642 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00643
00644
00645 gtalk_response(client, from, pak, NULL, NULL);
00646 return 1;
00647 }
00648
00649 static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
00650 {
00651 struct gtalk_pvt *tmp;
00652 iks *dtmfnode = NULL, *dtmfchild = NULL;
00653 char *dtmf;
00654 char *from;
00655
00656 for (tmp = client->p; tmp; tmp = tmp->next) {
00657 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
00658 break;
00659 }
00660 from = iks_find_attrib(pak->x, "to");
00661 if(!from)
00662 from = client->connection->jid->full;
00663
00664
00665 if (tmp) {
00666 if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00667 gtalk_response(client, from, pak,
00668 "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00669 "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00670 return -1;
00671 }
00672 if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00673 if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00674 if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00675 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00676 f.subclass = dtmf[0];
00677 ast_queue_frame(tmp->owner, &f);
00678 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00679 } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00680 struct ast_frame f = {AST_FRAME_DTMF_END, };
00681 f.subclass = dtmf[0];
00682 ast_queue_frame(tmp->owner, &f);
00683 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00684 } else if(iks_find_attrib(pak->x, "dtmf")) {
00685 struct ast_frame f = {AST_FRAME_DTMF, };
00686 f.subclass = dtmf[0];
00687 ast_queue_frame(tmp->owner, &f);
00688 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00689 }
00690 }
00691 } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
00692 if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
00693 if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
00694 if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
00695 struct ast_frame f = {AST_FRAME_DTMF_END, };
00696 f.subclass = dtmf[0];
00697 ast_queue_frame(tmp->owner, &f);
00698 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00699 } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
00700 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00701 f.subclass = dtmf[0];
00702 ast_queue_frame(tmp->owner, &f);
00703 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00704 }
00705 }
00706 }
00707 }
00708 gtalk_response(client, from, pak, NULL, NULL);
00709 return 1;
00710 } else
00711 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00712
00713 gtalk_response(client, from, pak, NULL, NULL);
00714 return 1;
00715 }
00716
00717 static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
00718 {
00719 struct gtalk_pvt *tmp;
00720 char *from;
00721
00722 ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00723
00724 for (tmp = client->p; tmp; tmp = tmp->next) {
00725 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00726 break;
00727 }
00728 from = iks_find_attrib(pak->x, "to");
00729 if(!from)
00730 from = client->connection->jid->full;
00731
00732 if (tmp) {
00733 tmp->alreadygone = 1;
00734 if (tmp->owner)
00735 ast_queue_hangup(tmp->owner);
00736 } else
00737 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00738 gtalk_response(client, from, pak, NULL, NULL);
00739 return 1;
00740 }
00741
00742 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
00743 {
00744 struct gtalk_candidate *tmp;
00745 struct aji_client *c = client->connection;
00746 struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
00747 struct sockaddr_in sin;
00748 struct sockaddr_in dest;
00749 struct in_addr us;
00750 iks *iq, *gtalk, *candidate, *transport;
00751 char user[17], pass[17], preference[5], port[7];
00752
00753
00754 iq = iks_new("iq");
00755 gtalk = iks_new("session");
00756 candidate = iks_new("candidate");
00757 transport = iks_new("transport");
00758 if (!iq || !gtalk || !candidate || !transport) {
00759 ast_log(LOG_ERROR, "Memory allocation error\n");
00760 goto safeout;
00761 }
00762 ours1 = ast_calloc(1, sizeof(*ours1));
00763 ours2 = ast_calloc(1, sizeof(*ours2));
00764 if (!ours1 || !ours2)
00765 goto safeout;
00766
00767 iks_insert_attrib(transport, "xmlns","http://www.google.com/transport/p2p");
00768 iks_insert_node(iq, gtalk);
00769 iks_insert_node(gtalk,transport);
00770 iks_insert_node(transport, candidate);
00771
00772 for (; p; p = p->next) {
00773 if (!strcasecmp(p->sid, sid))
00774 break;
00775 }
00776
00777 if (!p) {
00778 ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
00779 goto safeout;
00780 }
00781
00782 ast_rtp_get_us(p->rtp, &sin);
00783 ast_find_ourip(&us, bindaddr);
00784
00785
00786 ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
00787 ours1->port = ntohs(sin.sin_port);
00788 ours1->preference = 1;
00789 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00790 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00791 ast_copy_string(ours1->username, user, sizeof(ours1->username));
00792 ast_copy_string(ours1->password, pass, sizeof(ours1->password));
00793 ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
00794 ours1->protocol = AJI_PROTOCOL_UDP;
00795 ours1->type = AJI_CONNECT_LOCAL;
00796 ours1->generation = 0;
00797 p->ourcandidates = ours1;
00798
00799 if (!ast_strlen_zero(externip)) {
00800
00801 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00802 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00803 ast_copy_string(ours2->username, user, sizeof(ours2->username));
00804 ast_copy_string(ours2->password, pass, sizeof(ours2->password));
00805 ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
00806 ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
00807 ours2->port = ntohs(sin.sin_port);
00808 ours2->preference = 0.9;
00809 ours2->protocol = AJI_PROTOCOL_UDP;
00810 ours2->type = AJI_CONNECT_STUN;
00811 ours2->generation = 0;
00812 ours1->next = ours2;
00813 ours2 = NULL;
00814 }
00815 ours1 = NULL;
00816 dest.sin_addr = __ourip;
00817 dest.sin_port = sin.sin_port;
00818
00819
00820 for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
00821 snprintf(port, sizeof(port), "%d", tmp->port);
00822 snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
00823 iks_insert_attrib(iq, "from", to);
00824 iks_insert_attrib(iq, "to", from);
00825 iks_insert_attrib(iq, "type", "set");
00826 iks_insert_attrib(iq, "id", c->mid);
00827 ast_aji_increment_mid(c->mid);
00828 iks_insert_attrib(gtalk, "type", "transport-info");
00829 iks_insert_attrib(gtalk, "id", sid);
00830 iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : from);
00831 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00832 iks_insert_attrib(candidate, "name", tmp->name);
00833 iks_insert_attrib(candidate, "address", tmp->ip);
00834 iks_insert_attrib(candidate, "port", port);
00835 iks_insert_attrib(candidate, "username", tmp->username);
00836 iks_insert_attrib(candidate, "password", tmp->password);
00837 iks_insert_attrib(candidate, "preference", preference);
00838 if (tmp->protocol == AJI_PROTOCOL_UDP)
00839 iks_insert_attrib(candidate, "protocol", "udp");
00840 if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
00841 iks_insert_attrib(candidate, "protocol", "ssltcp");
00842 if (tmp->type == AJI_CONNECT_STUN)
00843 iks_insert_attrib(candidate, "type", "stun");
00844 if (tmp->type == AJI_CONNECT_LOCAL)
00845 iks_insert_attrib(candidate, "type", "local");
00846 if (tmp->type == AJI_CONNECT_RELAY)
00847 iks_insert_attrib(candidate, "type", "relay");
00848 iks_insert_attrib(candidate, "network", "0");
00849 iks_insert_attrib(candidate, "generation", "0");
00850 iks_send(c->p, iq);
00851 }
00852 p->laststun = 0;
00853
00854 safeout:
00855 if (ours1)
00856 free(ours1);
00857 if (ours2)
00858 free(ours2);
00859 if (iq)
00860 iks_delete(iq);
00861 if (gtalk)
00862 iks_delete(gtalk);
00863 if (candidate)
00864 iks_delete(candidate);
00865 if(transport)
00866 iks_delete(transport);
00867 return 1;
00868 }
00869
00870 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
00871 {
00872 struct gtalk_pvt *tmp = NULL;
00873 struct aji_resource *resources = NULL;
00874 struct aji_buddy *buddy;
00875 char idroster[200];
00876 char *data, *exten = NULL;
00877
00878 if (option_debug)
00879 ast_log(LOG_DEBUG, "The client is %s for alloc\n", client->name);
00880 if (!sid && !strchr(them, '/')) {
00881 if (!strcasecmp(client->name, "guest")) {
00882 buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
00883 if (buddy)
00884 resources = buddy->resources;
00885 } else if (client->buddy)
00886 resources = client->buddy->resources;
00887 while (resources) {
00888 if (resources->cap->jingle) {
00889 break;
00890 }
00891 resources = resources->next;
00892 }
00893 if (resources)
00894 snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
00895 else {
00896 ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
00897 return NULL;
00898 }
00899 }
00900 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
00901 return NULL;
00902 }
00903 if (sid) {
00904 ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
00905 ast_copy_string(tmp->them, them, sizeof(tmp->them));
00906 ast_copy_string(tmp->us, us, sizeof(tmp->us));
00907 } else {
00908 snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
00909 ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
00910 ast_copy_string(tmp->us, us, sizeof(tmp->us));
00911 tmp->initiator = 1;
00912 }
00913 tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
00914 tmp->parent = client;
00915 if (!tmp->rtp) {
00916 ast_log(LOG_WARNING, "Out of RTP sessions?\n");
00917 free(tmp);
00918 return NULL;
00919 }
00920
00921
00922 ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
00923
00924 if(strchr(tmp->us, '/')) {
00925 data = ast_strdupa(tmp->us);
00926 exten = strsep(&data, "/");
00927 } else
00928 exten = tmp->us;
00929 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
00930 ast_mutex_init(&tmp->lock);
00931 ast_mutex_lock(>alklock);
00932 tmp->next = client->p;
00933 client->p = tmp;
00934 ast_mutex_unlock(>alklock);
00935 return tmp;
00936 }
00937
00938
00939 static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title)
00940 {
00941 struct ast_channel *tmp;
00942 int fmt;
00943 int what;
00944 const char *n2;
00945
00946 if (title)
00947 n2 = title;
00948 else
00949 n2 = i->us;
00950 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff);
00951 if (!tmp) {
00952 ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
00953 return NULL;
00954 }
00955 tmp->tech = >alk_tech;
00956
00957
00958
00959
00960 if (i->jointcapability)
00961 what = i->jointcapability;
00962 else if (i->capability)
00963 what = i->capability;
00964 else
00965 what = global_capability;
00966 tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
00967 fmt = ast_best_codec(tmp->nativeformats);
00968
00969 if (i->rtp) {
00970 ast_rtp_setstun(i->rtp, 1);
00971 tmp->fds[0] = ast_rtp_fd(i->rtp);
00972 tmp->fds[1] = ast_rtcp_fd(i->rtp);
00973 }
00974 if (i->vrtp) {
00975 ast_rtp_setstun(i->rtp, 1);
00976 tmp->fds[2] = ast_rtp_fd(i->vrtp);
00977 tmp->fds[3] = ast_rtcp_fd(i->vrtp);
00978 }
00979 if (state == AST_STATE_RING)
00980 tmp->rings = 1;
00981 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
00982 tmp->writeformat = fmt;
00983 tmp->rawwriteformat = fmt;
00984 tmp->readformat = fmt;
00985 tmp->rawreadformat = fmt;
00986 tmp->tech_pvt = i;
00987
00988 tmp->callgroup = client->callgroup;
00989 tmp->pickupgroup = client->pickupgroup;
00990 tmp->cid.cid_pres = client->callingpres;
00991 if (!ast_strlen_zero(client->accountcode))
00992 ast_string_field_set(tmp, accountcode, client->accountcode);
00993 if (client->amaflags)
00994 tmp->amaflags = client->amaflags;
00995 if (!ast_strlen_zero(client->language))
00996 ast_string_field_set(tmp, language, client->language);
00997 if (!ast_strlen_zero(client->musicclass))
00998 ast_string_field_set(tmp, musicclass, client->musicclass);
00999 i->owner = tmp;
01000 ast_module_ref(ast_module_info->self);
01001 ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
01002 ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01003
01004 if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
01005 tmp->cid.cid_dnid = ast_strdup(i->exten);
01006 tmp->priority = 1;
01007 if (i->rtp)
01008 ast_jb_configure(tmp, &global_jbconf);
01009 if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
01010 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01011 tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
01012 ast_hangup(tmp);
01013 tmp = NULL;
01014 }
01015
01016 return tmp;
01017 }
01018
01019 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
01020 {
01021 iks *request, *session = NULL;
01022 int res = -1;
01023
01024 request = iks_new("iq");
01025 if (request) {
01026 iks_insert_attrib(request, "type", "set");
01027 iks_insert_attrib(request, "from", p->us);
01028 iks_insert_attrib(request, "to", p->them);
01029 iks_insert_attrib(request, "id", client->connection->mid);
01030 ast_aji_increment_mid(client->connection->mid);
01031 session = iks_new("session");
01032 if (session) {
01033 iks_insert_attrib(session, "type", action);
01034 iks_insert_attrib(session, "id", p->sid);
01035 iks_insert_attrib(session, "initiator", p->initiator ? p->us : p->them);
01036 iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
01037 iks_insert_node(request, session);
01038 iks_send(client->connection->p, request);
01039 iks_delete(session);
01040 res = 0;
01041 }
01042 iks_delete(request);
01043 }
01044 return res;
01045 }
01046
01047 static void gtalk_free_candidates(struct gtalk_candidate *candidate)
01048 {
01049 struct gtalk_candidate *last;
01050 while (candidate) {
01051 last = candidate;
01052 candidate = candidate->next;
01053 free(last);
01054 }
01055 }
01056
01057 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
01058 {
01059 struct gtalk_pvt *cur, *prev = NULL;
01060 cur = client->p;
01061 while (cur) {
01062 if (cur == p) {
01063 if (prev)
01064 prev->next = p->next;
01065 else
01066 client->p = p->next;
01067 break;
01068 }
01069 prev = cur;
01070 cur = cur->next;
01071 }
01072 if (p->ringrule)
01073 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01074 if (p->owner)
01075 ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01076 if (p->rtp)
01077 ast_rtp_destroy(p->rtp);
01078 if (p->vrtp)
01079 ast_rtp_destroy(p->vrtp);
01080 gtalk_free_candidates(p->theircandidates);
01081 free(p);
01082 }
01083
01084
01085 static int gtalk_newcall(struct gtalk *client, ikspak *pak)
01086 {
01087 struct gtalk_pvt *p, *tmp = client->p;
01088 struct ast_channel *chan;
01089 int res;
01090 iks *codec;
01091 char *from = NULL;
01092
01093 from = iks_find_attrib(pak->x,"to");
01094 if(!from)
01095 from = client->connection->jid->full;
01096
01097 while (tmp) {
01098 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
01099 ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01100 gtalk_response(client, from, pak, "out-of-order", NULL);
01101 return -1;
01102 }
01103 tmp = tmp->next;
01104 }
01105
01106 p = gtalk_alloc(client, from, pak->from->full, iks_find_attrib(pak->query, "id"));
01107 if (!p) {
01108 ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01109 return -1;
01110 }
01111 chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user);
01112 if (chan) {
01113 ast_mutex_lock(&p->lock);
01114 ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01115 if (iks_find_attrib(pak->query, "id")) {
01116 ast_copy_string(p->sid, iks_find_attrib(pak->query, "id"),
01117 sizeof(p->sid));
01118 }
01119
01120 codec = iks_child(iks_child(iks_child(pak->x)));
01121 while (codec) {
01122 ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
01123 ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio",
01124 iks_find_attrib(codec, "name"), 0);
01125 codec = iks_next(codec);
01126 }
01127
01128 ast_mutex_unlock(&p->lock);
01129 ast_setstate(chan, AST_STATE_RING);
01130 res = ast_pbx_start(chan);
01131
01132 switch (res) {
01133 case AST_PBX_FAILED:
01134 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01135 gtalk_response(client, from, pak, "service-unavailable", NULL);
01136 break;
01137 case AST_PBX_CALL_LIMIT:
01138 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01139 gtalk_response(client, from, pak, "service-unavailable", NULL);
01140 break;
01141 case AST_PBX_SUCCESS:
01142 gtalk_response(client, from, pak, NULL, NULL);
01143 gtalk_invite_response(p, p->them, p->us,p->sid, 0);
01144 gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01145
01146 break;
01147 }
01148 } else {
01149 gtalk_free_pvt(client, p);
01150 }
01151 return 1;
01152 }
01153
01154 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
01155 {
01156 struct gtalk_candidate *tmp;
01157 struct hostent *hp;
01158 struct ast_hostent ahp;
01159 struct sockaddr_in sin;
01160 struct sockaddr_in aux;
01161
01162 if (time(NULL) == p->laststun)
01163 return 0;
01164
01165 tmp = p->theircandidates;
01166 p->laststun = time(NULL);
01167 while (tmp) {
01168 char username[256];
01169
01170
01171 hp = ast_gethostbyname(tmp->ip, &ahp);
01172 sin.sin_family = AF_INET;
01173 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01174 sin.sin_port = htons(tmp->port);
01175 snprintf(username, sizeof(username), "%s%s", tmp->username,
01176 p->ourcandidates->username);
01177
01178
01179 ast_rtp_get_peer(p->rtp, &aux);
01180
01181
01182
01183
01184 if (aux.sin_addr.s_addr &&
01185 aux.sin_addr.s_addr != sin.sin_addr.s_addr)
01186 ast_rtp_stun_request(p->rtp, &aux, username);
01187 else
01188 ast_rtp_stun_request(p->rtp, &sin, username);
01189
01190 if (aux.sin_addr.s_addr && option_debug > 3) {
01191 ast_log(LOG_DEBUG, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
01192 ast_log(LOG_DEBUG, "Sending STUN request to %s\n", tmp->ip);
01193 }
01194
01195 tmp = tmp->next;
01196 }
01197 return 1;
01198 }
01199
01200 static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
01201 {
01202 struct gtalk_pvt *p = NULL, *tmp = NULL;
01203 struct aji_client *c = client->connection;
01204 struct gtalk_candidate *newcandidate = NULL;
01205 iks *traversenodes = NULL, *receipt = NULL;
01206 char *from;
01207
01208 from = iks_find_attrib(pak->x,"to");
01209 if(!from)
01210 from = c->jid->full;
01211
01212 for (tmp = client->p; tmp; tmp = tmp->next) {
01213 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
01214 p = tmp;
01215 break;
01216 }
01217 }
01218
01219 if (!p)
01220 return -1;
01221
01222 traversenodes = pak->query;
01223 while(traversenodes) {
01224 if(!strcasecmp(iks_name(traversenodes), "session")) {
01225 traversenodes = iks_child(traversenodes);
01226 continue;
01227 }
01228 if(!strcasecmp(iks_name(traversenodes), "transport")) {
01229 traversenodes = iks_child(traversenodes);
01230 continue;
01231 }
01232 if(!strcasecmp(iks_name(traversenodes), "candidate")) {
01233 newcandidate = ast_calloc(1, sizeof(*newcandidate));
01234 if (!newcandidate)
01235 return 0;
01236 ast_copy_string(newcandidate->name, iks_find_attrib(traversenodes, "name"),
01237 sizeof(newcandidate->name));
01238 ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "address"),
01239 sizeof(newcandidate->ip));
01240 newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01241 ast_copy_string(newcandidate->username, iks_find_attrib(traversenodes, "username"),
01242 sizeof(newcandidate->username));
01243 ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "password"),
01244 sizeof(newcandidate->password));
01245 newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01246 if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
01247 newcandidate->protocol = AJI_PROTOCOL_UDP;
01248 if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
01249 newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01250
01251 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "stun"))
01252 newcandidate->type = AJI_CONNECT_STUN;
01253 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "local"))
01254 newcandidate->type = AJI_CONNECT_LOCAL;
01255 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
01256 newcandidate->type = AJI_CONNECT_RELAY;
01257 ast_copy_string(newcandidate->network, iks_find_attrib(traversenodes, "network"),
01258 sizeof(newcandidate->network));
01259 newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
01260 newcandidate->next = NULL;
01261
01262 newcandidate->next = p->theircandidates;
01263 p->theircandidates = newcandidate;
01264 p->laststun = 0;
01265 gtalk_update_stun(p->parent, p);
01266 newcandidate = NULL;
01267 }
01268 traversenodes = iks_next(traversenodes);
01269 }
01270
01271 receipt = iks_new("iq");
01272 iks_insert_attrib(receipt, "type", "result");
01273 iks_insert_attrib(receipt, "from", from);
01274 iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
01275 iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
01276 iks_send(c->p, receipt);
01277 iks_delete(receipt);
01278
01279 return 1;
01280 }
01281
01282 static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
01283 {
01284 struct ast_frame *f;
01285
01286 if (!p->rtp)
01287 return &ast_null_frame;
01288 f = ast_rtp_read(p->rtp);
01289 gtalk_update_stun(p->parent, p);
01290 if (p->owner) {
01291
01292 if (f->frametype == AST_FRAME_VOICE) {
01293 if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
01294 if (option_debug)
01295 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
01296 p->owner->nativeformats =
01297 (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
01298 ast_set_read_format(p->owner, p->owner->readformat);
01299 ast_set_write_format(p->owner, p->owner->writeformat);
01300 }
01301
01302
01303
01304
01305
01306 }
01307 }
01308 return f;
01309 }
01310
01311 static struct ast_frame *gtalk_read(struct ast_channel *ast)
01312 {
01313 struct ast_frame *fr;
01314 struct gtalk_pvt *p = ast->tech_pvt;
01315
01316 ast_mutex_lock(&p->lock);
01317 fr = gtalk_rtp_read(ast, p);
01318 ast_mutex_unlock(&p->lock);
01319 return fr;
01320 }
01321
01322
01323 static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame)
01324 {
01325 struct gtalk_pvt *p = ast->tech_pvt;
01326 int res = 0;
01327
01328 switch (frame->frametype) {
01329 case AST_FRAME_VOICE:
01330 if (!(frame->subclass & ast->nativeformats)) {
01331 ast_log(LOG_WARNING,
01332 "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
01333 frame->subclass, ast->nativeformats, ast->readformat,
01334 ast->writeformat);
01335 return 0;
01336 }
01337 if (p) {
01338 ast_mutex_lock(&p->lock);
01339 if (p->rtp) {
01340 res = ast_rtp_write(p->rtp, frame);
01341 }
01342 ast_mutex_unlock(&p->lock);
01343 }
01344 break;
01345 case AST_FRAME_VIDEO:
01346 if (p) {
01347 ast_mutex_lock(&p->lock);
01348 if (p->vrtp) {
01349 res = ast_rtp_write(p->vrtp, frame);
01350 }
01351 ast_mutex_unlock(&p->lock);
01352 }
01353 break;
01354 case AST_FRAME_IMAGE:
01355 return 0;
01356 break;
01357 default:
01358 ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
01359 frame->frametype);
01360 return 0;
01361 }
01362
01363 return res;
01364 }
01365
01366 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
01367 {
01368 struct gtalk_pvt *p = newchan->tech_pvt;
01369 ast_mutex_lock(&p->lock);
01370
01371 if ((p->owner != oldchan)) {
01372 ast_mutex_unlock(&p->lock);
01373 return -1;
01374 }
01375 if (p->owner == oldchan)
01376 p->owner = newchan;
01377 ast_mutex_unlock(&p->lock);
01378 return 0;
01379 }
01380
01381 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
01382 {
01383 int res = 0;
01384
01385 switch (condition) {
01386 case AST_CONTROL_HOLD:
01387 ast_moh_start(ast, data, NULL);
01388 break;
01389 case AST_CONTROL_UNHOLD:
01390 ast_moh_stop(ast);
01391 break;
01392 default:
01393 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
01394 res = -1;
01395 }
01396
01397 return res;
01398 }
01399
01400 static int gtalk_digit_begin(struct ast_channel *chan, char digit)
01401 {
01402 return gtalk_digit(chan, digit, 0);
01403 }
01404
01405 static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
01406 {
01407 return gtalk_digit(chan, digit, duration);
01408 }
01409
01410 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
01411 {
01412 struct gtalk_pvt *p = ast->tech_pvt;
01413 struct gtalk *client = p->parent;
01414 iks *iq, *gtalk, *dtmf;
01415 char buffer[2] = {digit, '\0'};
01416 iq = iks_new("iq");
01417 gtalk = iks_new("gtalk");
01418 dtmf = iks_new("dtmf");
01419 if(!iq || !gtalk || !dtmf) {
01420 if(iq)
01421 iks_delete(iq);
01422 if(gtalk)
01423 iks_delete(gtalk);
01424 if(dtmf)
01425 iks_delete(dtmf);
01426 ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
01427 return -1;
01428 }
01429
01430 iks_insert_attrib(iq, "type", "set");
01431 iks_insert_attrib(iq, "to", p->them);
01432 iks_insert_attrib(iq, "from", p->us);
01433 iks_insert_attrib(iq, "id", client->connection->mid);
01434 ast_aji_increment_mid(client->connection->mid);
01435 iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
01436 iks_insert_attrib(gtalk, "action", "session-info");
01437 iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: p->them);
01438 iks_insert_attrib(gtalk, "sid", p->sid);
01439 iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
01440 iks_insert_attrib(dtmf, "code", buffer);
01441 iks_insert_node(iq, gtalk);
01442 iks_insert_node(gtalk, dtmf);
01443
01444 ast_mutex_lock(&p->lock);
01445 if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
01446 iks_insert_attrib(dtmf, "action", "button-down");
01447 } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
01448 iks_insert_attrib(dtmf, "action", "button-up");
01449 }
01450 iks_send(client->connection->p, iq);
01451 iks_delete(iq);
01452 iks_delete(gtalk);
01453 iks_delete(dtmf);
01454 ast_mutex_unlock(&p->lock);
01455 return 0;
01456 }
01457
01458 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
01459 {
01460 ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01461
01462 return -1;
01463 }
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout)
01486 {
01487 struct gtalk_pvt *p = ast->tech_pvt;
01488
01489 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01490 ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
01491 return -1;
01492 }
01493
01494 ast_setstate(ast, AST_STATE_RING);
01495 p->jointcapability = p->capability;
01496 if (!p->ringrule) {
01497 ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01498 p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01499 IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01500 } else
01501 ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01502
01503 gtalk_invite(p, p->them, p->us, p->sid, 1);
01504 gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
01505
01506 return 0;
01507 }
01508
01509
01510 static int gtalk_hangup(struct ast_channel *ast)
01511 {
01512 struct gtalk_pvt *p = ast->tech_pvt;
01513 struct gtalk *client;
01514
01515 ast_mutex_lock(&p->lock);
01516 client = p->parent;
01517 p->owner = NULL;
01518 ast->tech_pvt = NULL;
01519 if (!p->alreadygone)
01520 gtalk_action(client, p, "terminate");
01521 ast_mutex_unlock(&p->lock);
01522
01523 gtalk_free_pvt(client, p);
01524 ast_module_unref(ast_module_info->self);
01525
01526 return 0;
01527 }
01528
01529
01530 static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause)
01531 {
01532 struct gtalk_pvt *p = NULL;
01533 struct gtalk *client = NULL;
01534 char *sender = NULL, *to = NULL, *s = NULL;
01535 struct ast_channel *chan = NULL;
01536
01537 if (data) {
01538 s = ast_strdupa(data);
01539 if (s) {
01540 sender = strsep(&s, "/");
01541 if (sender && (sender[0] != '\0'))
01542 to = strsep(&s, "/");
01543 if (!to) {
01544 ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01545 return NULL;
01546 }
01547 }
01548 }
01549 client = find_gtalk(to, sender);
01550 if (!client) {
01551 ast_log(LOG_WARNING, "Could not find recipient.\n");
01552 return NULL;
01553 }
01554 ASTOBJ_WRLOCK(client);
01555 p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01556 if (p)
01557 chan = gtalk_new(client, p, AST_STATE_DOWN, to);
01558
01559 ASTOBJ_UNLOCK(client);
01560 return chan;
01561 }
01562
01563
01564 static int gtalk_show_channels(int fd, int argc, char **argv)
01565 {
01566 #define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
01567 struct gtalk_pvt *p;
01568 struct ast_channel *chan;
01569 int numchans = 0;
01570 char them[AJI_MAX_JIDLEN];
01571 char *jid = NULL;
01572 char *resource = NULL;
01573
01574 if (argc != 3)
01575 return RESULT_SHOWUSAGE;
01576
01577 ast_mutex_lock(>alklock);
01578 ast_cli(fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01579 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
01580 ASTOBJ_WRLOCK(iterator);
01581 p = iterator->p;
01582 while(p) {
01583 chan = p->owner;
01584 ast_copy_string(them, p->them, sizeof(them));
01585 jid = them;
01586 resource = strchr(them, '/');
01587 if (!resource)
01588 resource = "None";
01589 else {
01590 *resource = '\0';
01591 resource ++;
01592 }
01593 if (chan)
01594 ast_cli(fd, FORMAT,
01595 chan->name,
01596 jid,
01597 resource,
01598 ast_getformatname(chan->readformat),
01599 ast_getformatname(chan->writeformat)
01600 );
01601 else
01602 ast_log(LOG_WARNING, "No available channel\n");
01603 numchans ++;
01604 p = p->next;
01605 }
01606 ASTOBJ_UNLOCK(iterator);
01607 });
01608
01609 ast_mutex_unlock(>alklock);
01610
01611 ast_cli(fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
01612 return RESULT_SUCCESS;
01613 #undef FORMAT
01614 }
01615
01616
01617 static int gtalk_do_reload(int fd, int argc, char **argv)
01618 {
01619 ast_verbose("IT DOES WORK!\n");
01620 return RESULT_SUCCESS;
01621 }
01622
01623 static int gtalk_parser(void *data, ikspak *pak)
01624 {
01625 struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
01626
01627 if (iks_find_with_attrib(pak->x, "session", "type", "initiate")) {
01628
01629 gtalk_newcall(client, pak);
01630 } else if (iks_find_with_attrib(pak->x, "session", "type", "candidates") || iks_find_with_attrib(pak->x, "session", "type", "transport-info")) {
01631 if (option_debug > 2)
01632 ast_log(LOG_DEBUG, "About to add candidate!\n");
01633 gtalk_add_candidate(client, pak);
01634 if (option_debug > 2)
01635 ast_log(LOG_DEBUG, "Candidate Added!\n");
01636 } else if (iks_find_with_attrib(pak->x, "session", "type", "accept")) {
01637 gtalk_is_answered(client, pak);
01638 } else if (iks_find_with_attrib(pak->x, "session", "type", "transport-accept")) {
01639 gtalk_is_accepted(client, pak);
01640 } else if (iks_find_with_attrib(pak->x, "session", "type", "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
01641 gtalk_handle_dtmf(client, pak);
01642 } else if (iks_find_with_attrib(pak->x, "session", "type", "terminate")) {
01643 gtalk_hangup_farend(client, pak);
01644 } else if (iks_find_with_attrib(pak->x, "session", "type", "reject")) {
01645 gtalk_hangup_farend(client, pak);
01646 }
01647 ASTOBJ_UNREF(client, gtalk_member_destroy);
01648 return IKS_FILTER_EAT;
01649 }
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699 static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest,
01700 struct ast_codec_pref prefs, char *context,
01701 struct gtalk *member)
01702 {
01703 struct aji_client *client;
01704
01705 if (!member)
01706 ast_log(LOG_WARNING, "Out of memory.\n");
01707
01708 ast_copy_string(member->name, label, sizeof(member->name));
01709 ast_copy_string(member->user, label, sizeof(member->user));
01710 ast_copy_string(member->context, context, sizeof(member->context));
01711 member->allowguest = allowguest;
01712 member->prefs = prefs;
01713 while (var) {
01714 #if 0
01715 struct gtalk_candidate *candidate = NULL;
01716 #endif
01717 if (!strcasecmp(var->name, "username"))
01718 ast_copy_string(member->user, var->value, sizeof(member->user));
01719 else if (!strcasecmp(var->name, "disallow"))
01720 ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
01721 else if (!strcasecmp(var->name, "allow"))
01722 ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
01723 else if (!strcasecmp(var->name, "context"))
01724 ast_copy_string(member->context, var->value, sizeof(member->context));
01725 #if 0
01726 else if (!strcasecmp(var->name, "candidate")) {
01727 candidate = gtalk_create_candidate(var->value);
01728 if (candidate) {
01729 candidate->next = member->ourcandidates;
01730 member->ourcandidates = candidate;
01731 }
01732 }
01733 #endif
01734 else if (!strcasecmp(var->name, "connection")) {
01735 if ((client = ast_aji_get_client(var->value))) {
01736 member->connection = client;
01737 iks_filter_add_rule(client->f, gtalk_parser, member,
01738 IKS_RULE_TYPE, IKS_PAK_IQ,
01739 IKS_RULE_FROM_PARTIAL, member->user,
01740 IKS_RULE_NS, "http://www.google.com/session",
01741 IKS_RULE_DONE);
01742
01743 } else {
01744 ast_log(LOG_ERROR, "connection referenced not found!\n");
01745 return 0;
01746 }
01747 }
01748 var = var->next;
01749 }
01750 if (member->connection && member->user)
01751 member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
01752 else {
01753 ast_log(LOG_ERROR, "No Connection or Username!\n");
01754 }
01755 return 1;
01756 }
01757
01758 static int gtalk_load_config(void)
01759 {
01760 char *cat = NULL;
01761 struct ast_config *cfg = NULL;
01762 char context[AST_MAX_CONTEXT];
01763 int allowguest = 1;
01764 struct ast_variable *var;
01765 struct gtalk *member;
01766 struct ast_codec_pref prefs;
01767 struct aji_client_container *clients;
01768 struct gtalk_candidate *global_candidates = NULL;
01769 struct hostent *hp;
01770 struct ast_hostent ahp;
01771
01772 cfg = ast_config_load(GOOGLE_CONFIG);
01773 if (!cfg)
01774 return 0;
01775
01776
01777 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01778
01779 cat = ast_category_browse(cfg, NULL);
01780 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
01781
01782 if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
01783 continue;
01784
01785 if (!strcasecmp(var->name, "allowguest"))
01786 allowguest =
01787 (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
01788 else if (!strcasecmp(var->name, "disallow"))
01789 ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
01790 else if (!strcasecmp(var->name, "allow"))
01791 ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
01792 else if (!strcasecmp(var->name, "context"))
01793 ast_copy_string(context, var->value, sizeof(context));
01794 else if (!strcasecmp(var->name, "bindaddr")) {
01795 if (!(hp = ast_gethostbyname(var->value, &ahp))) {
01796 ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
01797 } else {
01798 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
01799 }
01800 }
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811 }
01812 while (cat) {
01813 if (strcasecmp(cat, "general")) {
01814 var = ast_variable_browse(cfg, cat);
01815 member = (struct gtalk *) malloc(sizeof(struct gtalk));
01816 memset(member, 0, sizeof(struct gtalk));
01817 ASTOBJ_INIT(member);
01818 ASTOBJ_WRLOCK(member);
01819 if (!strcasecmp(cat, "guest")) {
01820 ast_copy_string(member->name, "guest", sizeof(member->name));
01821 ast_copy_string(member->user, "guest", sizeof(member->user));
01822 ast_copy_string(member->context, context, sizeof(member->context));
01823 member->allowguest = allowguest;
01824 member->prefs = prefs;
01825 while (var) {
01826 if (!strcasecmp(var->name, "disallow"))
01827 ast_parse_allow_disallow(&member->prefs, &member->capability,
01828 var->value, 0);
01829 else if (!strcasecmp(var->name, "allow"))
01830 ast_parse_allow_disallow(&member->prefs, &member->capability,
01831 var->value, 1);
01832 else if (!strcasecmp(var->name, "context"))
01833 ast_copy_string(member->context, var->value,
01834 sizeof(member->context));
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845 var = var->next;
01846 }
01847 ASTOBJ_UNLOCK(member);
01848 clients = ast_aji_get_clients();
01849 if (clients) {
01850 ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
01851 ASTOBJ_WRLOCK(iterator);
01852 ASTOBJ_WRLOCK(member);
01853 member->connection = iterator;
01854 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://www.google.com/session", IKS_RULE_DONE);
01855 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);
01856 ASTOBJ_UNLOCK(member);
01857 ASTOBJ_CONTAINER_LINK(>alk_list, member);
01858 ASTOBJ_UNLOCK(iterator);
01859 });
01860 } else {
01861 ASTOBJ_UNLOCK(member);
01862 ASTOBJ_UNREF(member, gtalk_member_destroy);
01863 }
01864 } else {
01865 ASTOBJ_UNLOCK(member);
01866 if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
01867 ASTOBJ_CONTAINER_LINK(>alk_list, member);
01868 ASTOBJ_UNREF(member, gtalk_member_destroy);
01869 }
01870 }
01871 cat = ast_category_browse(cfg, cat);
01872 }
01873 gtalk_free_candidates(global_candidates);
01874 return 1;
01875 }
01876
01877
01878 static int load_module(void)
01879 {
01880 char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
01881 free(jabber_loaded);
01882 if (!jabber_loaded) {
01883 ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
01884 return AST_MODULE_LOAD_DECLINE;
01885 }
01886
01887 #ifdef HAVE_GNUTLS
01888 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
01889 #endif
01890
01891 ASTOBJ_CONTAINER_INIT(>alk_list);
01892 if (!gtalk_load_config()) {
01893 ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
01894 return 0;
01895 }
01896
01897 sched = sched_context_create();
01898 if (!sched)
01899 ast_log(LOG_WARNING, "Unable to create schedule context\n");
01900
01901 io = io_context_create();
01902 if (!io)
01903 ast_log(LOG_WARNING, "Unable to create I/O context\n");
01904
01905 if (ast_find_ourip(&__ourip, bindaddr)) {
01906 ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
01907 return 0;
01908 }
01909
01910 ast_rtp_proto_register(>alk_rtp);
01911 ast_cli_register_multiple(gtalk_cli, sizeof(gtalk_cli) / sizeof(gtalk_cli[0]));
01912
01913
01914 if (ast_channel_register(>alk_tech)) {
01915 ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
01916 return -1;
01917 }
01918 return 0;
01919 }
01920
01921
01922 static int reload(void)
01923 {
01924 return 0;
01925 }
01926
01927
01928 static int unload_module(void)
01929 {
01930 struct gtalk_pvt *privates = NULL;
01931 ast_cli_unregister_multiple(gtalk_cli, sizeof(gtalk_cli) / sizeof(gtalk_cli[0]));
01932
01933 ast_channel_unregister(>alk_tech);
01934 ast_rtp_proto_unregister(>alk_rtp);
01935
01936 if (!ast_mutex_lock(>alklock)) {
01937
01938 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
01939 ASTOBJ_WRLOCK(iterator);
01940 privates = iterator->p;
01941 while(privates) {
01942 if (privates->owner)
01943 ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
01944 privates = privates->next;
01945 }
01946 iterator->p = NULL;
01947 ASTOBJ_UNLOCK(iterator);
01948 });
01949 ast_mutex_unlock(>alklock);
01950 } else {
01951 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01952 return -1;
01953 }
01954 ASTOBJ_CONTAINER_DESTROYALL(>alk_list, gtalk_member_destroy);
01955 ASTOBJ_CONTAINER_DESTROY(>alk_list);
01956 return 0;
01957 }
01958
01959 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Gtalk Channel Driver",
01960 .load = load_module,
01961 .unload = unload_module,
01962 .reload = reload,
01963 );