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