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