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