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 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 259899 $")
00031
00032 #include <fcntl.h>
00033 #include <sys/signal.h>
00034
00035 #include "asterisk/lock.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/sched.h"
00041 #include "asterisk/io.h"
00042 #include "asterisk/rtp.h"
00043 #include "asterisk/acl.h"
00044 #include "asterisk/callerid.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/cli.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/musiconhold.h"
00049 #include "asterisk/manager.h"
00050 #include "asterisk/stringfields.h"
00051 #include "asterisk/devicestate.h"
00052
00053 static const char tdesc[] = "Local Proxy Channel Driver";
00054
00055 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
00056
00057 static struct ast_jb_conf g_jb_conf = {
00058 .flags = 0,
00059 .max_size = -1,
00060 .resync_threshold = -1,
00061 .impl = "",
00062 .target_extra = -1,
00063 };
00064
00065 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
00066 static int local_digit_begin(struct ast_channel *ast, char digit);
00067 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00068 static int local_call(struct ast_channel *ast, char *dest, int timeout);
00069 static int local_hangup(struct ast_channel *ast);
00070 static int local_answer(struct ast_channel *ast);
00071 static struct ast_frame *local_read(struct ast_channel *ast);
00072 static int local_write(struct ast_channel *ast, struct ast_frame *f);
00073 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00074 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00075 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00076 static int local_sendtext(struct ast_channel *ast, const char *text);
00077 static int local_devicestate(void *data);
00078 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00079
00080
00081 static const struct ast_channel_tech local_tech = {
00082 .type = "Local",
00083 .description = tdesc,
00084 .capabilities = -1,
00085 .requester = local_request,
00086 .send_digit_begin = local_digit_begin,
00087 .send_digit_end = local_digit_end,
00088 .call = local_call,
00089 .hangup = local_hangup,
00090 .answer = local_answer,
00091 .read = local_read,
00092 .write = local_write,
00093 .write_video = local_write,
00094 .exception = local_read,
00095 .indicate = local_indicate,
00096 .fixup = local_fixup,
00097 .send_html = local_sendhtml,
00098 .send_text = local_sendtext,
00099 .devicestate = local_devicestate,
00100 .bridged_channel = local_bridgedchannel,
00101 };
00102
00103 struct local_pvt {
00104 ast_mutex_t lock;
00105 unsigned int flags;
00106 char context[AST_MAX_CONTEXT];
00107 char exten[AST_MAX_EXTENSION];
00108 int reqformat;
00109 struct ast_jb_conf jb_conf;
00110 struct ast_channel *owner;
00111 struct ast_channel *chan;
00112 struct ast_module_user *u_owner;
00113 struct ast_module_user *u_chan;
00114 AST_LIST_ENTRY(local_pvt) list;
00115 };
00116
00117 #define LOCAL_GLARE_DETECT (1 << 0)
00118 #define LOCAL_CANCEL_QUEUE (1 << 1)
00119 #define LOCAL_ALREADY_MASQED (1 << 2)
00120 #define LOCAL_LAUNCHED_PBX (1 << 3)
00121 #define LOCAL_NO_OPTIMIZATION (1 << 4)
00122 #define LOCAL_BRIDGE (1 << 5)
00123 #define LOCAL_MOH_PASSTHRU (1 << 6)
00124
00125 static AST_LIST_HEAD_STATIC(locals, local_pvt);
00126
00127
00128 static int local_devicestate(void *data)
00129 {
00130 char *exten = ast_strdupa(data);
00131 char *context = NULL, *opts = NULL;
00132 int res;
00133 struct local_pvt *lp;
00134
00135 if (!(context = strchr(exten, '@'))) {
00136 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00137 return AST_DEVICE_INVALID;
00138 }
00139
00140 *context++ = '\0';
00141
00142
00143 if ((opts = strchr(context, '/')))
00144 *opts = '\0';
00145
00146 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00147
00148 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00149 if (!res)
00150 return AST_DEVICE_INVALID;
00151
00152 res = AST_DEVICE_NOT_INUSE;
00153 AST_LIST_LOCK(&locals);
00154 AST_LIST_TRAVERSE(&locals, lp, list) {
00155 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00156 res = AST_DEVICE_INUSE;
00157 break;
00158 }
00159 }
00160 AST_LIST_UNLOCK(&locals);
00161
00162 return res;
00163 }
00164
00165
00166
00167
00168 static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt)
00169 {
00170 ast_mutex_destroy(&pvt->lock);
00171 ast_free(pvt);
00172 return NULL;
00173 }
00174
00175
00176 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
00177 {
00178 struct local_pvt *p = bridge->tech_pvt;
00179 struct ast_channel *bridged = bridge;
00180
00181 if (!p) {
00182 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00183 chan->name, bridge->name);
00184 return NULL;
00185 }
00186
00187 ast_mutex_lock(&p->lock);
00188
00189 if (ast_test_flag(p, LOCAL_BRIDGE)) {
00190
00191 bridged = (bridge == p->owner ? p->chan : p->owner);
00192
00193
00194 if (!bridged) {
00195 bridged = bridge;
00196 } else if (bridged->_bridge) {
00197 bridged = bridged->_bridge;
00198 }
00199 }
00200
00201 ast_mutex_unlock(&p->lock);
00202
00203 return bridged;
00204 }
00205
00206 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
00207 struct ast_channel *us, int us_locked)
00208 {
00209 struct ast_channel *other = NULL;
00210
00211
00212 other = isoutbound ? p->owner : p->chan;
00213
00214 if (!other) {
00215 return 0;
00216 }
00217
00218
00219 if (us && us->generator && other->generator) {
00220 return 0;
00221 }
00222
00223
00224 ast_set_flag(p, LOCAL_GLARE_DETECT);
00225
00226
00227 while (other && ast_channel_trylock(other)) {
00228 ast_mutex_unlock(&p->lock);
00229 if (us && us_locked) {
00230 do {
00231 CHANNEL_DEADLOCK_AVOIDANCE(us);
00232 } while (ast_mutex_trylock(&p->lock));
00233 } else {
00234 usleep(1);
00235 ast_mutex_lock(&p->lock);
00236 }
00237 other = isoutbound ? p->owner : p->chan;
00238 }
00239
00240
00241
00242
00243 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00244
00245
00246 ast_mutex_unlock(&p->lock);
00247 p = local_pvt_destroy(p);
00248 if (other) {
00249 ast_channel_unlock(other);
00250 }
00251 return -1;
00252 }
00253
00254 if (other) {
00255 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) {
00256 ast_setstate(other, AST_STATE_RINGING);
00257 }
00258 ast_queue_frame(other, f);
00259 ast_channel_unlock(other);
00260 }
00261
00262 ast_clear_flag(p, LOCAL_GLARE_DETECT);
00263
00264 return 0;
00265 }
00266
00267 static int local_answer(struct ast_channel *ast)
00268 {
00269 struct local_pvt *p = ast->tech_pvt;
00270 int isoutbound;
00271 int res = -1;
00272
00273 if (!p)
00274 return -1;
00275
00276 ast_mutex_lock(&p->lock);
00277 isoutbound = IS_OUTBOUND(ast, p);
00278 if (isoutbound) {
00279
00280 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00281 res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00282 } else
00283 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
00284 if (!res)
00285 ast_mutex_unlock(&p->lock);
00286 return res;
00287 }
00288
00289
00290
00291
00292
00293 static void check_bridge(struct local_pvt *p)
00294 {
00295 struct ast_channel_monitor *tmp;
00296 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
00297 return;
00298
00299
00300
00301
00302
00303
00304 if (p->chan->_bridge && AST_LIST_EMPTY(&p->owner->readq)) {
00305
00306
00307
00308
00309 if (!ast_channel_trylock(p->chan->_bridge)) {
00310 if (!ast_check_hangup(p->chan->_bridge)) {
00311 if (!ast_channel_trylock(p->owner)) {
00312 if (!ast_check_hangup(p->owner)) {
00313 if (p->owner->monitor && !p->chan->_bridge->monitor) {
00314
00315
00316
00317
00318
00319 tmp = p->owner->monitor;
00320 p->owner->monitor = p->chan->_bridge->monitor;
00321 p->chan->_bridge->monitor = tmp;
00322 }
00323 if (p->chan->audiohooks) {
00324 struct ast_audiohook_list *audiohooks_swapper;
00325 audiohooks_swapper = p->chan->audiohooks;
00326 p->chan->audiohooks = p->owner->audiohooks;
00327 p->owner->audiohooks = audiohooks_swapper;
00328 }
00329 ast_app_group_update(p->chan, p->owner);
00330 ast_channel_masquerade(p->owner, p->chan->_bridge);
00331 ast_set_flag(p, LOCAL_ALREADY_MASQED);
00332 }
00333 ast_channel_unlock(p->owner);
00334 }
00335 ast_channel_unlock(p->chan->_bridge);
00336 }
00337 }
00338 }
00339 }
00340
00341 static struct ast_frame *local_read(struct ast_channel *ast)
00342 {
00343 return &ast_null_frame;
00344 }
00345
00346 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00347 {
00348 struct local_pvt *p = ast->tech_pvt;
00349 int res = -1;
00350 int isoutbound;
00351
00352 if (!p)
00353 return -1;
00354
00355
00356 ast_mutex_lock(&p->lock);
00357 isoutbound = IS_OUTBOUND(ast, p);
00358 if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00359 check_bridge(p);
00360 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00361 res = local_queue_frame(p, isoutbound, f, ast, 1);
00362 else {
00363 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00364 res = 0;
00365 }
00366 if (!res)
00367 ast_mutex_unlock(&p->lock);
00368 return res;
00369 }
00370
00371 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00372 {
00373 struct local_pvt *p = newchan->tech_pvt;
00374
00375 if (!p)
00376 return -1;
00377
00378 ast_mutex_lock(&p->lock);
00379
00380 if ((p->owner != oldchan) && (p->chan != oldchan)) {
00381 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00382 ast_mutex_unlock(&p->lock);
00383 return -1;
00384 }
00385 if (p->owner == oldchan)
00386 p->owner = newchan;
00387 else
00388 p->chan = newchan;
00389 ast_mutex_unlock(&p->lock);
00390 return 0;
00391 }
00392
00393 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00394 {
00395 struct local_pvt *p = ast->tech_pvt;
00396 int res = 0;
00397 struct ast_frame f = { AST_FRAME_CONTROL, };
00398 int isoutbound;
00399
00400 if (!p)
00401 return -1;
00402
00403
00404 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00405 ast_moh_start(ast, data, NULL);
00406 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00407 ast_moh_stop(ast);
00408 } else {
00409
00410 ast_mutex_lock(&p->lock);
00411 isoutbound = IS_OUTBOUND(ast, p);
00412 f.subclass = condition;
00413 f.data.ptr = (void*)data;
00414 f.datalen = datalen;
00415 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00416 ast_mutex_unlock(&p->lock);
00417 }
00418
00419 return res;
00420 }
00421
00422 static int local_digit_begin(struct ast_channel *ast, char digit)
00423 {
00424 struct local_pvt *p = ast->tech_pvt;
00425 int res = -1;
00426 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00427 int isoutbound;
00428
00429 if (!p)
00430 return -1;
00431
00432 ast_mutex_lock(&p->lock);
00433 isoutbound = IS_OUTBOUND(ast, p);
00434 f.subclass = digit;
00435 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00436 ast_mutex_unlock(&p->lock);
00437
00438 return res;
00439 }
00440
00441 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00442 {
00443 struct local_pvt *p = ast->tech_pvt;
00444 int res = -1;
00445 struct ast_frame f = { AST_FRAME_DTMF_END, };
00446 int isoutbound;
00447
00448 if (!p)
00449 return -1;
00450
00451 ast_mutex_lock(&p->lock);
00452 isoutbound = IS_OUTBOUND(ast, p);
00453 f.subclass = digit;
00454 f.len = duration;
00455 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00456 ast_mutex_unlock(&p->lock);
00457
00458 return res;
00459 }
00460
00461 static int local_sendtext(struct ast_channel *ast, const char *text)
00462 {
00463 struct local_pvt *p = ast->tech_pvt;
00464 int res = -1;
00465 struct ast_frame f = { AST_FRAME_TEXT, };
00466 int isoutbound;
00467
00468 if (!p)
00469 return -1;
00470
00471 ast_mutex_lock(&p->lock);
00472 isoutbound = IS_OUTBOUND(ast, p);
00473 f.data.ptr = (char *) text;
00474 f.datalen = strlen(text) + 1;
00475 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00476 ast_mutex_unlock(&p->lock);
00477 return res;
00478 }
00479
00480 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00481 {
00482 struct local_pvt *p = ast->tech_pvt;
00483 int res = -1;
00484 struct ast_frame f = { AST_FRAME_HTML, };
00485 int isoutbound;
00486
00487 if (!p)
00488 return -1;
00489
00490 ast_mutex_lock(&p->lock);
00491 isoutbound = IS_OUTBOUND(ast, p);
00492 f.subclass = subclass;
00493 f.data.ptr = (char *)data;
00494 f.datalen = datalen;
00495 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00496 ast_mutex_unlock(&p->lock);
00497 return res;
00498 }
00499
00500
00501
00502 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00503 {
00504 struct local_pvt *p = ast->tech_pvt;
00505 int res;
00506 struct ast_var_t *varptr = NULL, *new;
00507 size_t len, namelen;
00508
00509 if (!p)
00510 return -1;
00511
00512 ast_mutex_lock(&p->lock);
00513
00514
00515
00516
00517
00518 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
00519 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00520 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00521 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00522 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00523 p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00524 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
00525 p->chan->cid.cid_ton = p->owner->cid.cid_ton;
00526 p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00527 ast_string_field_set(p->chan, language, p->owner->language);
00528 ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00529 ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00530 ast_cdr_update(p->chan);
00531 p->chan->cdrflags = p->owner->cdrflags;
00532
00533 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00534 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00535 ast_mutex_unlock(&p->lock);
00536 return -1;
00537 }
00538
00539
00540 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00541 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00542 }
00543
00544
00545
00546 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00547 namelen = strlen(varptr->name);
00548 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00549 if ((new = ast_calloc(1, len))) {
00550 memcpy(new, varptr, len);
00551 new->value = &(new->name[0]) + namelen + 1;
00552 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00553 }
00554 }
00555 ast_channel_datastore_inherit(p->owner, p->chan);
00556
00557
00558 if (!(res = ast_pbx_start(p->chan)))
00559 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00560
00561 ast_mutex_unlock(&p->lock);
00562 return res;
00563 }
00564
00565
00566 static int local_hangup(struct ast_channel *ast)
00567 {
00568 struct local_pvt *p = ast->tech_pvt;
00569 int isoutbound;
00570 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
00571 struct ast_channel *ochan = NULL;
00572 int glaredetect = 0, res = 0;
00573
00574 if (!p)
00575 return -1;
00576
00577 ast_mutex_lock(&p->lock);
00578
00579 isoutbound = IS_OUTBOUND(ast, p);
00580
00581 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00582 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00583 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00584 }
00585
00586 if (isoutbound) {
00587 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00588 if ((status) && (p->owner)) {
00589
00590 while (p->owner && ast_channel_trylock(p->owner)) {
00591 ast_mutex_unlock(&p->lock);
00592 if (p->chan) {
00593 ast_channel_unlock(p->chan);
00594 }
00595 usleep(1);
00596 if (p->chan) {
00597 ast_channel_lock(p->chan);
00598 }
00599 ast_mutex_lock(&p->lock);
00600 }
00601 if (p->owner) {
00602 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00603 ast_channel_unlock(p->owner);
00604 }
00605 }
00606 p->chan = NULL;
00607 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00608 ast_module_user_remove(p->u_chan);
00609 } else {
00610 ast_module_user_remove(p->u_owner);
00611 while (p->chan && ast_channel_trylock(p->chan)) {
00612 ast_mutex_unlock(&p->lock);
00613 if (p->owner) {
00614 ast_channel_unlock(p->owner);
00615 }
00616 usleep(1);
00617 if (p->owner) {
00618 ast_channel_lock(p->owner);
00619 }
00620 ast_mutex_lock(&p->lock);
00621 }
00622
00623 p->owner = NULL;
00624 if (p->chan) {
00625 ast_queue_hangup(p->chan);
00626 ast_channel_unlock(p->chan);
00627 }
00628 }
00629
00630 ast->tech_pvt = NULL;
00631
00632 if (!p->owner && !p->chan) {
00633
00634 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00635
00636
00637 if (glaredetect)
00638 ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00639
00640 AST_LIST_LOCK(&locals);
00641 AST_LIST_REMOVE(&locals, p, list);
00642 AST_LIST_UNLOCK(&locals);
00643 ast_mutex_unlock(&p->lock);
00644
00645 if (!glaredetect) {
00646 p = local_pvt_destroy(p);
00647 }
00648 return 0;
00649 }
00650 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00651
00652 ochan = p->chan;
00653 else
00654 res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00655 if (!res)
00656 ast_mutex_unlock(&p->lock);
00657 if (ochan)
00658 ast_hangup(ochan);
00659 return 0;
00660 }
00661
00662
00663 static struct local_pvt *local_alloc(const char *data, int format)
00664 {
00665 struct local_pvt *tmp = NULL;
00666 char *c = NULL, *opts = NULL;
00667
00668 if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00669 return NULL;
00670
00671
00672 ast_mutex_init(&tmp->lock);
00673 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00674
00675 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00676
00677
00678 if ((opts = strchr(tmp->exten, '/'))) {
00679 *opts++ = '\0';
00680 if (strchr(opts, 'n'))
00681 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00682 if (strchr(opts, 'j')) {
00683 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00684 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00685 else {
00686 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00687 "to use the 'j' option to enable the jitterbuffer\n");
00688 }
00689 }
00690 if (strchr(opts, 'b')) {
00691 ast_set_flag(tmp, LOCAL_BRIDGE);
00692 }
00693 if (strchr(opts, 'm')) {
00694 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
00695 }
00696 }
00697
00698
00699 if ((c = strchr(tmp->exten, '@')))
00700 *c++ = '\0';
00701
00702 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00703
00704 tmp->reqformat = format;
00705
00706 #if 0
00707
00708
00709
00710 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00711 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00712 tmp = local_pvt_destroy(tmp);
00713 } else {
00714 #endif
00715
00716 AST_LIST_LOCK(&locals);
00717 AST_LIST_INSERT_HEAD(&locals, tmp, list);
00718 AST_LIST_UNLOCK(&locals);
00719 #if 0
00720 }
00721 #endif
00722
00723 return tmp;
00724 }
00725
00726
00727 static struct ast_channel *local_new(struct local_pvt *p, int state)
00728 {
00729 struct ast_channel *tmp = NULL, *tmp2 = NULL;
00730 int randnum = ast_random() & 0xffff, fmt = 0;
00731 const char *t;
00732 int ama;
00733
00734
00735
00736 if (p->owner && p->owner->accountcode)
00737 t = p->owner->accountcode;
00738 else
00739 t = "";
00740
00741 if (p->owner)
00742 ama = p->owner->amaflags;
00743 else
00744 ama = 0;
00745 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum))
00746 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
00747 if (tmp)
00748 ast_channel_free(tmp);
00749 if (tmp2)
00750 ast_channel_free(tmp2);
00751 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00752 return NULL;
00753 }
00754
00755 tmp2->tech = tmp->tech = &local_tech;
00756
00757 tmp->nativeformats = p->reqformat;
00758 tmp2->nativeformats = p->reqformat;
00759
00760
00761 fmt = ast_best_codec(p->reqformat);
00762 tmp->writeformat = fmt;
00763 tmp2->writeformat = fmt;
00764 tmp->rawwriteformat = fmt;
00765 tmp2->rawwriteformat = fmt;
00766 tmp->readformat = fmt;
00767 tmp2->readformat = fmt;
00768 tmp->rawreadformat = fmt;
00769 tmp2->rawreadformat = fmt;
00770
00771 tmp->tech_pvt = p;
00772 tmp2->tech_pvt = p;
00773
00774 p->owner = tmp;
00775 p->chan = tmp2;
00776 p->u_owner = ast_module_user_add(p->owner);
00777 p->u_chan = ast_module_user_add(p->chan);
00778
00779 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00780 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00781 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00782 tmp->priority = 1;
00783 tmp2->priority = 1;
00784
00785 ast_jb_configure(tmp, &p->jb_conf);
00786
00787 return tmp;
00788 }
00789
00790
00791 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
00792 {
00793 struct local_pvt *p = NULL;
00794 struct ast_channel *chan = NULL;
00795
00796
00797 if ((p = local_alloc(data, format))) {
00798 if (!(chan = local_new(p, AST_STATE_DOWN))) {
00799 AST_LIST_LOCK(&locals);
00800 AST_LIST_REMOVE(&locals, p, list);
00801 AST_LIST_UNLOCK(&locals);
00802 p = local_pvt_destroy(p);
00803 }
00804 }
00805
00806 return chan;
00807 }
00808
00809
00810 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00811 {
00812 struct local_pvt *p = NULL;
00813
00814 switch (cmd) {
00815 case CLI_INIT:
00816 e->command = "local show channels";
00817 e->usage =
00818 "Usage: local show channels\n"
00819 " Provides summary information on active local proxy channels.\n";
00820 return NULL;
00821 case CLI_GENERATE:
00822 return NULL;
00823 }
00824
00825 if (a->argc != 3)
00826 return CLI_SHOWUSAGE;
00827
00828 AST_LIST_LOCK(&locals);
00829 if (!AST_LIST_EMPTY(&locals)) {
00830 AST_LIST_TRAVERSE(&locals, p, list) {
00831 ast_mutex_lock(&p->lock);
00832 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00833 ast_mutex_unlock(&p->lock);
00834 }
00835 } else
00836 ast_cli(a->fd, "No local channels in use\n");
00837 AST_LIST_UNLOCK(&locals);
00838
00839 return CLI_SUCCESS;
00840 }
00841
00842 static struct ast_cli_entry cli_local[] = {
00843 AST_CLI_DEFINE(locals_show, "List status of local channels"),
00844 };
00845
00846
00847 static int load_module(void)
00848 {
00849
00850 if (ast_channel_register(&local_tech)) {
00851 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00852 return AST_MODULE_LOAD_FAILURE;
00853 }
00854 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00855 return AST_MODULE_LOAD_SUCCESS;
00856 }
00857
00858
00859 static int unload_module(void)
00860 {
00861 struct local_pvt *p = NULL;
00862
00863
00864 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00865 ast_channel_unregister(&local_tech);
00866 if (!AST_LIST_LOCK(&locals)) {
00867
00868 AST_LIST_TRAVERSE(&locals, p, list) {
00869 if (p->owner)
00870 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00871 }
00872 AST_LIST_UNLOCK(&locals);
00873 } else {
00874 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00875 return -1;
00876 }
00877 return 0;
00878 }
00879
00880 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");