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