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
00035
00036 #include "asterisk.h"
00037
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 365692 $")
00039
00040 #include <signal.h>
00041
00042 #include "asterisk/paths.h"
00043 #include "asterisk/lock.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/pbx.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/translate.h"
00049 #include "asterisk/say.h"
00050 #include "asterisk/features.h"
00051 #include "asterisk/musiconhold.h"
00052 #include "asterisk/cli.h"
00053 #include "asterisk/manager.h"
00054 #include "asterisk/config.h"
00055 #include "asterisk/utils.h"
00056 #include "asterisk/causes.h"
00057 #include "asterisk/astdb.h"
00058 #include "asterisk/dsp.h"
00059 #include "asterisk/app.h"
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 static char *app = "FollowMe";
00104
00105
00106 #define MAX_YN_STRING 20
00107
00108
00109 struct number {
00110 char number[512];
00111 long timeout;
00112 int order;
00113 AST_LIST_ENTRY(number) entry;
00114 };
00115
00116
00117 struct call_followme {
00118 ast_mutex_t lock;
00119 char name[AST_MAX_EXTENSION];
00120 char moh[MAX_MUSICCLASS];
00121 char context[AST_MAX_CONTEXT];
00122 unsigned int active;
00123 int realtime;
00124 char takecall[MAX_YN_STRING];
00125 char nextindp[MAX_YN_STRING];
00126 char callfromprompt[PATH_MAX];
00127 char norecordingprompt[PATH_MAX];
00128 char optionsprompt[PATH_MAX];
00129 char plsholdprompt[PATH_MAX];
00130 char statusprompt[PATH_MAX];
00131 char sorryprompt[PATH_MAX];
00132
00133 AST_LIST_HEAD_NOLOCK(numbers, number) numbers;
00134 AST_LIST_HEAD_NOLOCK(blnumbers, number) blnumbers;
00135 AST_LIST_HEAD_NOLOCK(wlnumbers, number) wlnumbers;
00136 AST_LIST_ENTRY(call_followme) entry;
00137 };
00138
00139 struct fm_args {
00140
00141 struct ast_channel *chan;
00142 char *mohclass;
00143 AST_LIST_HEAD_NOLOCK(cnumbers, number) cnumbers;
00144
00145 struct ast_channel *outbound;
00146
00147 struct ast_party_connected_line connected_in;
00148
00149 struct ast_party_connected_line connected_out;
00150
00151 unsigned int pending_in_connected_update:1;
00152
00153 unsigned int pending_out_connected_update:1;
00154 int status;
00155 char context[AST_MAX_CONTEXT];
00156 char namerecloc[PATH_MAX];
00157 char takecall[MAX_YN_STRING];
00158 char nextindp[MAX_YN_STRING];
00159 char callfromprompt[PATH_MAX];
00160 char norecordingprompt[PATH_MAX];
00161 char optionsprompt[PATH_MAX];
00162 char plsholdprompt[PATH_MAX];
00163 char statusprompt[PATH_MAX];
00164 char sorryprompt[PATH_MAX];
00165 struct ast_flags followmeflags;
00166 };
00167
00168 struct findme_user {
00169 struct ast_channel *ochan;
00170
00171 struct ast_party_connected_line connected;
00172 long digts;
00173 int ynidx;
00174 int state;
00175 char dialarg[256];
00176
00177 char yn[MAX_YN_STRING];
00178
00179 unsigned int cleared:1;
00180
00181 unsigned int pending_connected_update:1;
00182 AST_LIST_ENTRY(findme_user) entry;
00183 };
00184
00185 enum {
00186 FOLLOWMEFLAG_STATUSMSG = (1 << 0),
00187 FOLLOWMEFLAG_RECORDNAME = (1 << 1),
00188 FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2),
00189 FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3),
00190 FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 4),
00191 };
00192
00193 AST_APP_OPTIONS(followme_opts, {
00194 AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME),
00195 AST_APP_OPTION('d', FOLLOWMEFLAG_DISABLEHOLDPROMPT),
00196 AST_APP_OPTION('I', FOLLOWMEFLAG_IGNORE_CONNECTEDLINE),
00197 AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG),
00198 AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG),
00199 });
00200
00201 static const char *featuredigittostr;
00202 static int featuredigittimeout = 5000;
00203 static const char *defaultmoh = "default";
00204
00205 static char takecall[MAX_YN_STRING] = "1";
00206 static char nextindp[MAX_YN_STRING] = "2";
00207 static char callfromprompt[PATH_MAX] = "followme/call-from";
00208 static char norecordingprompt[PATH_MAX] = "followme/no-recording";
00209 static char optionsprompt[PATH_MAX] = "followme/options";
00210 static char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try";
00211 static char statusprompt[PATH_MAX] = "followme/status";
00212 static char sorryprompt[PATH_MAX] = "followme/sorry";
00213
00214
00215 static AST_RWLIST_HEAD_STATIC(followmes, call_followme);
00216 AST_LIST_HEAD_NOLOCK(findme_user_listptr, findme_user);
00217
00218 static void free_numbers(struct call_followme *f)
00219 {
00220
00221 struct number *prev;
00222
00223 while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
00224
00225 ast_free(prev);
00226 AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
00227
00228 while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
00229
00230 ast_free(prev);
00231 AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
00232
00233 while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
00234
00235 ast_free(prev);
00236 AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
00237 }
00238
00239
00240
00241 static struct call_followme *alloc_profile(const char *fmname)
00242 {
00243 struct call_followme *f;
00244
00245 if (!(f = ast_calloc(1, sizeof(*f))))
00246 return NULL;
00247
00248 ast_mutex_init(&f->lock);
00249 ast_copy_string(f->name, fmname, sizeof(f->name));
00250 f->moh[0] = '\0';
00251 f->context[0] = '\0';
00252 ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
00253 ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
00254 ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt));
00255 ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt));
00256 ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt));
00257 ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt));
00258 ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt));
00259 ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt));
00260 AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
00261 AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
00262 AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
00263 return f;
00264 }
00265
00266 static void init_profile(struct call_followme *f)
00267 {
00268 f->active = 1;
00269 ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
00270 }
00271
00272
00273
00274
00275 static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown)
00276 {
00277
00278 if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music"))
00279 ast_copy_string(f->moh, val, sizeof(f->moh));
00280 else if (!strcasecmp(param, "context"))
00281 ast_copy_string(f->context, val, sizeof(f->context));
00282 else if (!strcasecmp(param, "takecall"))
00283 ast_copy_string(f->takecall, val, sizeof(f->takecall));
00284 else if (!strcasecmp(param, "declinecall"))
00285 ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
00286 else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
00287 ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt));
00288 else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt"))
00289 ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt));
00290 else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt"))
00291 ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt));
00292 else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
00293 ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt));
00294 else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt"))
00295 ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt));
00296 else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt"))
00297 ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt));
00298 else if (failunknown) {
00299 if (linenum >= 0)
00300 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
00301 else
00302 ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
00303 }
00304 }
00305
00306
00307 static struct number *create_followme_number(const char *number, int timeout, int numorder)
00308 {
00309 struct number *cur;
00310 char *buf = ast_strdupa(number);
00311 char *tmp;
00312
00313 if (!(cur = ast_calloc(1, sizeof(*cur))))
00314 return NULL;
00315
00316 cur->timeout = timeout;
00317 if ((tmp = strchr(buf, ',')))
00318 *tmp = '\0';
00319 ast_copy_string(cur->number, buf, sizeof(cur->number));
00320 cur->order = numorder;
00321 ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
00322
00323 return cur;
00324 }
00325
00326
00327 static int reload_followme(int reload)
00328 {
00329 struct call_followme *f;
00330 struct ast_config *cfg;
00331 char *cat = NULL, *tmp;
00332 struct ast_variable *var;
00333 struct number *cur, *nm;
00334 char numberstr[90];
00335 int timeout;
00336 int numorder;
00337 const char *takecallstr;
00338 const char *declinecallstr;
00339 const char *tmpstr;
00340 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00341
00342 if (!(cfg = ast_config_load("followme.conf", config_flags))) {
00343 ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
00344 return 0;
00345 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00346 return 0;
00347 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00348 ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n");
00349 return 0;
00350 }
00351
00352 AST_RWLIST_WRLOCK(&followmes);
00353
00354
00355 featuredigittimeout = 5000;
00356
00357
00358 AST_RWLIST_TRAVERSE(&followmes, f, entry) {
00359 f->active = 0;
00360 }
00361
00362 featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
00363
00364 if (!ast_strlen_zero(featuredigittostr)) {
00365 if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
00366 featuredigittimeout = 5000;
00367 }
00368
00369 if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
00370 ast_copy_string(takecall, takecallstr, sizeof(takecall));
00371 }
00372
00373 if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
00374 ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
00375 }
00376
00377 if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
00378 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
00379 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
00380 ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
00381 }
00382
00383 if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
00384 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
00385 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
00386 ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
00387 }
00388
00389
00390 if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
00391 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
00392 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
00393 ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
00394 }
00395
00396 if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
00397 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
00398 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
00399 ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
00400 }
00401
00402 if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
00403 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
00404 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
00405 ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
00406 }
00407
00408 if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
00409 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
00410 } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
00411 ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
00412 }
00413
00414
00415 while ((cat = ast_category_browse(cfg, cat))) {
00416 int new = 0;
00417
00418 if (!strcasecmp(cat, "general"))
00419 continue;
00420
00421
00422 AST_LIST_TRAVERSE(&followmes, f, entry) {
00423 if (!strcasecmp(f->name, cat))
00424 break;
00425 }
00426
00427 ast_debug(1, "New profile %s.\n", cat);
00428
00429 if (!f) {
00430
00431 f = alloc_profile(cat);
00432 new = 1;
00433 }
00434
00435
00436 if (!f)
00437 continue;
00438
00439 if (!new)
00440 ast_mutex_lock(&f->lock);
00441
00442 init_profile(f);
00443 free_numbers(f);
00444 var = ast_variable_browse(cfg, cat);
00445 while (var) {
00446 if (!strcasecmp(var->name, "number")) {
00447 int idx = 0;
00448
00449
00450 ast_copy_string(numberstr, var->value, sizeof(numberstr));
00451 if ((tmp = strchr(numberstr, ','))) {
00452 *tmp++ = '\0';
00453 timeout = atoi(tmp);
00454 if (timeout < 0) {
00455 timeout = 25;
00456 }
00457 if ((tmp = strchr(tmp, ','))) {
00458 *tmp++ = '\0';
00459 numorder = atoi(tmp);
00460 if (numorder < 0)
00461 numorder = 0;
00462 } else
00463 numorder = 0;
00464 } else {
00465 timeout = 25;
00466 numorder = 0;
00467 }
00468
00469 if (!numorder) {
00470 idx = 1;
00471 AST_LIST_TRAVERSE(&f->numbers, nm, entry)
00472 idx++;
00473 numorder = idx;
00474 }
00475 cur = create_followme_number(numberstr, timeout, numorder);
00476 if (cur) {
00477 AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
00478 }
00479 } else {
00480 profile_set_param(f, var->name, var->value, var->lineno, 1);
00481 ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
00482 }
00483 var = var->next;
00484 }
00485
00486 if (!new)
00487 ast_mutex_unlock(&f->lock);
00488 else
00489 AST_RWLIST_INSERT_HEAD(&followmes, f, entry);
00490 }
00491
00492 ast_config_destroy(cfg);
00493
00494 AST_RWLIST_UNLOCK(&followmes);
00495
00496 return 1;
00497 }
00498
00499 static void clear_caller(struct findme_user *tmpuser)
00500 {
00501 struct ast_channel *outbound;
00502
00503 if (tmpuser && tmpuser->ochan && tmpuser->state >= 0) {
00504 outbound = tmpuser->ochan;
00505 ast_channel_lock(outbound);
00506 if (!outbound->cdr) {
00507 outbound->cdr = ast_cdr_alloc();
00508 if (outbound->cdr) {
00509 ast_cdr_init(outbound->cdr, outbound);
00510 }
00511 }
00512 if (outbound->cdr) {
00513 char tmp[256];
00514
00515 snprintf(tmp, sizeof(tmp), "%s/%s", "Local", tmpuser->dialarg);
00516 ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
00517 ast_cdr_update(outbound);
00518 ast_cdr_start(outbound->cdr);
00519 ast_cdr_end(outbound->cdr);
00520
00521 if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause)) {
00522 ast_cdr_failed(outbound->cdr);
00523 }
00524 } else {
00525 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
00526 }
00527 ast_channel_unlock(outbound);
00528 ast_hangup(outbound);
00529 tmpuser->ochan = NULL;
00530 }
00531 }
00532
00533 static void clear_calling_tree(struct findme_user_listptr *findme_user_list)
00534 {
00535 struct findme_user *tmpuser;
00536
00537 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
00538 clear_caller(tmpuser);
00539 tmpuser->cleared = 1;
00540 }
00541 }
00542
00543 static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
00544 {
00545 struct findme_user *fmuser;
00546
00547 while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
00548 if (!fmuser->cleared) {
00549 clear_caller(fmuser);
00550 }
00551 ast_party_connected_line_free(&fmuser->connected);
00552 ast_free(fmuser);
00553 }
00554 ast_free(findme_user_list);
00555 }
00556
00557 static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, char *namerecloc, struct fm_args *tpargs)
00558 {
00559 struct ast_party_connected_line connected;
00560 struct ast_channel *watchers[256];
00561 int pos;
00562 struct ast_channel *winner;
00563 struct ast_frame *f;
00564 int ctstatus = 0;
00565 int dg;
00566 struct findme_user *tmpuser;
00567 int to = 0;
00568 int livechannels = 0;
00569 int tmpto;
00570 long totalwait = 0, wtd = 0, towas = 0;
00571 char *callfromname;
00572 char *pressbuttonname;
00573
00574
00575
00576 callfromname = ast_strdupa(tpargs->callfromprompt);
00577 pressbuttonname = ast_strdupa(tpargs->optionsprompt);
00578
00579 if (AST_LIST_EMPTY(findme_user_list)) {
00580 ast_verb(3, "couldn't reach at this number.\n");
00581 return NULL;
00582 }
00583
00584 if (!caller) {
00585 ast_verb(3, "Original caller hungup. Cleanup.\n");
00586 clear_calling_tree(findme_user_list);
00587 return NULL;
00588 }
00589
00590 totalwait = nm->timeout * 1000;
00591
00592 while (!ctstatus) {
00593 to = 1000;
00594 pos = 1;
00595 livechannels = 0;
00596 watchers[0] = caller;
00597
00598 dg = 0;
00599 winner = NULL;
00600 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
00601 if (tmpuser->state >= 0 && tmpuser->ochan) {
00602 if (tmpuser->state == 3)
00603 tmpuser->digts += (towas - wtd);
00604 if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
00605 ast_verb(3, "We've been waiting for digits longer than we should have.\n");
00606 if (!ast_strlen_zero(namerecloc)) {
00607 tmpuser->state = 1;
00608 tmpuser->digts = 0;
00609 if (!ast_streamfile(tmpuser->ochan, callfromname, tmpuser->ochan->language)) {
00610 ast_sched_runq(tmpuser->ochan->sched);
00611 } else {
00612 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
00613 return NULL;
00614 }
00615 } else {
00616 tmpuser->state = 2;
00617 tmpuser->digts = 0;
00618 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
00619 ast_sched_runq(tmpuser->ochan->sched);
00620 else {
00621 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
00622 return NULL;
00623 }
00624 }
00625 }
00626 if (tmpuser->ochan->stream) {
00627 ast_sched_runq(tmpuser->ochan->sched);
00628 tmpto = ast_sched_wait(tmpuser->ochan->sched);
00629 if (tmpto > 0 && tmpto < to)
00630 to = tmpto;
00631 else if (tmpto < 0 && !tmpuser->ochan->timingfunc) {
00632 ast_stopstream(tmpuser->ochan);
00633 if (tmpuser->state == 1) {
00634 ast_verb(3, "Playback of the call-from file appears to be done.\n");
00635 if (!ast_streamfile(tmpuser->ochan, namerecloc, tmpuser->ochan->language)) {
00636 tmpuser->state = 2;
00637 } else {
00638 ast_log(LOG_NOTICE, "Unable to playback %s. Maybe the caller didn't record their name?\n", namerecloc);
00639 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
00640 tmpuser->ynidx = 0;
00641 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language))
00642 tmpuser->state = 3;
00643 else {
00644 ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
00645 return NULL;
00646 }
00647 }
00648 } else if (tmpuser->state == 2) {
00649 ast_verb(3, "Playback of name file appears to be done.\n");
00650 memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
00651 tmpuser->ynidx = 0;
00652 if (!ast_streamfile(tmpuser->ochan, pressbuttonname, tmpuser->ochan->language)) {
00653 tmpuser->state = 3;
00654 } else {
00655 return NULL;
00656 }
00657 } else if (tmpuser->state == 3) {
00658 ast_verb(3, "Playback of the next step file appears to be done.\n");
00659 tmpuser->digts = 0;
00660 }
00661 }
00662 }
00663 watchers[pos++] = tmpuser->ochan;
00664 livechannels++;
00665 }
00666 }
00667
00668 tmpto = to;
00669 if (to < 0) {
00670 to = 1000;
00671 tmpto = 1000;
00672 }
00673 towas = to;
00674 winner = ast_waitfor_n(watchers, pos, &to);
00675 tmpto -= to;
00676 totalwait -= tmpto;
00677 wtd = to;
00678 if (totalwait <= 0) {
00679 ast_verb(3, "We've hit our timeout for this step. Drop everyone and move on to the next one. %ld\n", totalwait);
00680 clear_calling_tree(findme_user_list);
00681 return NULL;
00682 }
00683 if (winner) {
00684
00685 for (dg = 0; dg < ARRAY_LEN(watchers); ++dg) {
00686 if (winner == watchers[dg]) {
00687 break;
00688 }
00689 }
00690 if (dg) {
00691
00692 AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
00693 if (tmpuser->ochan == winner) {
00694 break;
00695 }
00696 }
00697 } else {
00698 tmpuser = NULL;
00699 }
00700 f = ast_read(winner);
00701 if (f) {
00702 if (f->frametype == AST_FRAME_CONTROL) {
00703 switch (f->subclass.integer) {
00704 case AST_CONTROL_HANGUP:
00705 ast_verb(3, "%s received a hangup frame.\n", winner->name);
00706 if (f->data.uint32) {
00707 winner->hangupcause = f->data.uint32;
00708 }
00709 if (dg == 0) {
00710 ast_verb(3, "The calling channel hungup. Need to drop everyone else.\n");
00711 clear_calling_tree(findme_user_list);
00712 ctstatus = -1;
00713 }
00714 break;
00715 case AST_CONTROL_ANSWER:
00716 ast_verb(3, "%s answered %s\n", winner->name, caller->name);
00717
00718 winner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00719 caller->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00720 ast_verb(3, "Starting playback of %s\n", callfromname);
00721 if (dg > 0) {
00722 if (!ast_strlen_zero(namerecloc)) {
00723 if (!ast_streamfile(winner, callfromname, winner->language)) {
00724 ast_sched_runq(winner->sched);
00725 tmpuser->state = 1;
00726 } else {
00727 ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
00728 ast_frfree(f);
00729 return NULL;
00730 }
00731 } else {
00732 tmpuser->state = 2;
00733 if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, tmpuser->ochan->language))
00734 ast_sched_runq(tmpuser->ochan->sched);
00735 else {
00736 ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
00737 ast_frfree(f);
00738 return NULL;
00739 }
00740 }
00741 }
00742 break;
00743 case AST_CONTROL_BUSY:
00744 ast_verb(3, "%s is busy\n", winner->name);
00745 break;
00746 case AST_CONTROL_CONGESTION:
00747 ast_verb(3, "%s is circuit-busy\n", winner->name);
00748 break;
00749 case AST_CONTROL_RINGING:
00750 ast_verb(3, "%s is ringing\n", winner->name);
00751 break;
00752 case AST_CONTROL_PROGRESS:
00753 ast_verb(3, "%s is making progress\n", winner->name);
00754 break;
00755 case AST_CONTROL_VIDUPDATE:
00756 ast_verb(3, "%s requested a video update\n", winner->name);
00757 break;
00758 case AST_CONTROL_SRCUPDATE:
00759 ast_verb(3, "%s requested a source update\n", winner->name);
00760 break;
00761 case AST_CONTROL_PROCEEDING:
00762 ast_verb(3, "%s is proceeding\n", winner->name);
00763 break;
00764 case AST_CONTROL_HOLD:
00765 ast_verb(3, "%s placed call on hold\n", winner->name);
00766 break;
00767 case AST_CONTROL_UNHOLD:
00768 ast_verb(3, "%s removed call from hold\n", winner->name);
00769 break;
00770 case AST_CONTROL_OFFHOOK:
00771 case AST_CONTROL_FLASH:
00772
00773 break;
00774 case AST_CONTROL_CONNECTED_LINE:
00775 if (!tmpuser) {
00776
00777
00778
00779
00780 ast_verb(3,
00781 "%s connected line has changed. Saving it until we have a winner.\n",
00782 winner->name);
00783 ast_party_connected_line_set_init(&connected, &tpargs->connected_in);
00784 if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
00785 ast_party_connected_line_set(&tpargs->connected_in,
00786 &connected, NULL);
00787 tpargs->pending_in_connected_update = 1;
00788 }
00789 ast_party_connected_line_free(&connected);
00790 break;
00791 }
00792 if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) {
00793 ast_verb(3, "Connected line update from %s prevented.\n",
00794 winner->name);
00795 } else {
00796 ast_verb(3,
00797 "%s connected line has changed. Saving it until answer.\n",
00798 winner->name);
00799 ast_party_connected_line_set_init(&connected, &tmpuser->connected);
00800 if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
00801 ast_party_connected_line_set(&tmpuser->connected,
00802 &connected, NULL);
00803 tmpuser->pending_connected_update = 1;
00804 }
00805 ast_party_connected_line_free(&connected);
00806 }
00807 break;
00808 case AST_CONTROL_REDIRECTING:
00809
00810
00811
00812
00813 break;
00814 case -1:
00815 ast_verb(3, "%s stopped sounds\n", winner->name);
00816 break;
00817 default:
00818 ast_debug(1, "Dunno what to do with control type %d from %s\n",
00819 f->subclass.integer, winner->name);
00820 break;
00821 }
00822 }
00823 if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
00824 if (winner->stream)
00825 ast_stopstream(winner);
00826 tmpuser->digts = 0;
00827 ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
00828 if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) {
00829 tmpuser->yn[tmpuser->ynidx++] = (char) f->subclass.integer;
00830 }
00831 ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
00832 if (!strcmp(tmpuser->yn, tpargs->takecall)) {
00833 ast_debug(1, "Match to take the call!\n");
00834 ast_frfree(f);
00835 return tmpuser->ochan;
00836 }
00837 if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
00838 ast_debug(1, "Next in dial plan step requested.\n");
00839 ast_frfree(f);
00840 return NULL;
00841 }
00842 }
00843
00844 ast_frfree(f);
00845 } else {
00846 ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n", dg);
00847 if (!dg) {
00848
00849 clear_calling_tree(findme_user_list);
00850 return NULL;
00851 } else {
00852
00853 tmpuser->state = -1;
00854 tmpuser->ochan = NULL;
00855 ast_hangup(winner);
00856 --livechannels;
00857 ast_debug(1, "live channels left %d\n", livechannels);
00858 if (!livechannels) {
00859 ast_verb(3, "no live channels left. exiting.\n");
00860 return NULL;
00861 }
00862 }
00863 }
00864 } else {
00865 ast_debug(1, "timed out waiting for action\n");
00866 }
00867 }
00868
00869
00870 return NULL;
00871 }
00872
00873 static void findmeexec(struct fm_args *tpargs)
00874 {
00875 struct number *nm;
00876 struct ast_channel *outbound;
00877 struct ast_channel *caller;
00878 struct ast_channel *winner = NULL;
00879 char dialarg[512];
00880 char num[512];
00881 int dg, idx;
00882 char *rest, *number;
00883 struct findme_user *tmpuser;
00884 struct findme_user *fmuser;
00885 struct findme_user_listptr *findme_user_list;
00886
00887 findme_user_list = ast_calloc(1, sizeof(*findme_user_list));
00888 if (!findme_user_list) {
00889 ast_log(LOG_WARNING, "Failed to allocate memory for findme_user_list\n");
00890 return;
00891 }
00892 AST_LIST_HEAD_INIT_NOLOCK(findme_user_list);
00893
00894 caller = tpargs->chan;
00895 for (idx = 1; !ast_check_hangup(caller); ++idx) {
00896
00897 AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
00898 if (nm->order == idx) {
00899 break;
00900 }
00901 }
00902 if (!nm) {
00903 break;
00904 }
00905
00906 ast_debug(2, "Number %s timeout %ld\n", nm->number,nm->timeout);
00907
00908 ast_copy_string(num, nm->number, sizeof(num));
00909 for (number = num; number; number = rest) {
00910 rest = strchr(number, '&');
00911 if (rest) {
00912 *rest++ = 0;
00913 }
00914
00915
00916 if (!ast_exists_extension(caller, tpargs->context, number, 1, S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, NULL))) {
00917 ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context);
00918 continue;
00919 }
00920
00921 if (!strcmp(tpargs->context, "")) {
00922 snprintf(dialarg, sizeof(dialarg), "%s", number);
00923 } else {
00924 snprintf(dialarg, sizeof(dialarg), "%s@%s", number, tpargs->context);
00925 }
00926
00927 tmpuser = ast_calloc(1, sizeof(*tmpuser));
00928 if (!tmpuser) {
00929 continue;
00930 }
00931
00932 outbound = ast_request("Local", ast_best_codec(caller->nativeformats), caller, dialarg, &dg);
00933 if (outbound) {
00934 ast_channel_lock_both(caller, outbound);
00935 ast_connected_line_copy_from_caller(&outbound->connected, &caller->caller);
00936 ast_channel_inherit_variables(caller, outbound);
00937 ast_channel_datastore_inherit(caller, outbound);
00938 ast_string_field_set(outbound, language, caller->language);
00939 ast_string_field_set(outbound, accountcode, caller->accountcode);
00940 ast_string_field_set(outbound, musicclass, caller->musicclass);
00941 ast_channel_unlock(outbound);
00942 ast_channel_unlock(caller);
00943 ast_verb(3, "calling Local/%s\n", dialarg);
00944 if (!ast_call(outbound, dialarg, 0)) {
00945 tmpuser->ochan = outbound;
00946 tmpuser->state = 0;
00947 tmpuser->cleared = 0;
00948 ast_copy_string(tmpuser->dialarg, dialarg, sizeof(dialarg));
00949 AST_LIST_INSERT_TAIL(findme_user_list, tmpuser, entry);
00950 } else {
00951 ast_verb(3, "couldn't reach at this number.\n");
00952 ast_channel_lock(outbound);
00953 if (!outbound->cdr) {
00954 outbound->cdr = ast_cdr_alloc();
00955 }
00956 if (outbound->cdr) {
00957 char tmp[256];
00958
00959 ast_cdr_init(outbound->cdr, outbound);
00960 snprintf(tmp, sizeof(tmp), "%s/%s", "Local", dialarg);
00961 ast_cdr_setapp(outbound->cdr, "FollowMe", tmp);
00962 ast_cdr_update(outbound);
00963 ast_cdr_start(outbound->cdr);
00964 ast_cdr_end(outbound->cdr);
00965
00966 if (ast_cdr_disposition(outbound->cdr, outbound->hangupcause)) {
00967 ast_cdr_failed(outbound->cdr);
00968 }
00969 } else {
00970 ast_log(LOG_ERROR, "Unable to create Call Detail Record\n");
00971 }
00972 ast_channel_unlock(outbound);
00973 ast_hangup(outbound);
00974 ast_free(tmpuser);
00975 }
00976 } else {
00977 ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", dialarg, ast_cause2str(dg));
00978 ast_free(tmpuser);
00979 }
00980 }
00981
00982 if (AST_LIST_EMPTY(findme_user_list)) {
00983 continue;
00984 }
00985
00986 winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, tpargs);
00987 if (!winner) {
00988 continue;
00989 }
00990
00991
00992 while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
00993 if (fmuser->ochan == winner) {
00994
00995 tpargs->connected_out = fmuser->connected;
00996 tpargs->pending_out_connected_update = fmuser->pending_connected_update;
00997 ast_free(fmuser);
00998 break;
00999 } else {
01000
01001 if (!fmuser->cleared) {
01002 clear_caller(fmuser);
01003 }
01004 ast_party_connected_line_free(&fmuser->connected);
01005 ast_free(fmuser);
01006 }
01007 }
01008 break;
01009 }
01010 destroy_calling_tree(findme_user_list);
01011 if (!winner) {
01012 tpargs->status = 1;
01013 } else {
01014 tpargs->status = 100;
01015 tpargs->outbound = winner;
01016 }
01017 }
01018
01019 static struct call_followme *find_realtime(const char *name)
01020 {
01021 struct ast_variable *var;
01022 struct ast_variable *v;
01023 struct ast_config *cfg;
01024 const char *catg;
01025 struct call_followme *new_follower;
01026 struct ast_str *str;
01027
01028 str = ast_str_create(16);
01029 if (!str) {
01030 return NULL;
01031 }
01032
01033 var = ast_load_realtime("followme", "name", name, SENTINEL);
01034 if (!var) {
01035 ast_free(str);
01036 return NULL;
01037 }
01038
01039 if (!(new_follower = alloc_profile(name))) {
01040 ast_variables_destroy(var);
01041 ast_free(str);
01042 return NULL;
01043 }
01044
01045 for (v = var; v; v = v->next) {
01046 if (!strcasecmp(v->name, "active")) {
01047 if (ast_false(v->value)) {
01048 ast_mutex_destroy(&new_follower->lock);
01049 ast_free(new_follower);
01050 ast_variables_destroy(var);
01051 ast_free(str);
01052 return NULL;
01053 }
01054 } else {
01055 profile_set_param(new_follower, v->name, v->value, 0, 0);
01056 }
01057 }
01058
01059 ast_variables_destroy(var);
01060 new_follower->realtime = 1;
01061
01062
01063 cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name",
01064 name, SENTINEL);
01065 if (!cfg) {
01066 ast_mutex_destroy(&new_follower->lock);
01067 ast_free(new_follower);
01068 ast_free(str);
01069 return NULL;
01070 }
01071
01072 for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
01073 const char *numstr;
01074 const char *timeoutstr;
01075 const char *ordstr;
01076 int timeout;
01077 struct number *cur;
01078
01079 if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
01080 continue;
01081 }
01082 if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout"))
01083 || sscanf(timeoutstr, "%30d", &timeout) != 1
01084 || timeout < 1) {
01085 timeout = 25;
01086 }
01087
01088 ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
01089 ast_str_set(&str, 0, "%s", numstr);
01090 if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
01091 AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry);
01092 }
01093 }
01094 ast_config_destroy(cfg);
01095
01096 ast_free(str);
01097 return new_follower;
01098 }
01099
01100 static void end_bridge_callback(void *data)
01101 {
01102 char buf[80];
01103 time_t end;
01104 struct ast_channel *chan = data;
01105
01106 time(&end);
01107
01108 ast_channel_lock(chan);
01109 if (chan->cdr->answer.tv_sec) {
01110 snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->answer.tv_sec);
01111 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
01112 }
01113
01114 if (chan->cdr->start.tv_sec) {
01115 snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->start.tv_sec);
01116 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
01117 }
01118 ast_channel_unlock(chan);
01119 }
01120
01121 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
01122 {
01123 bconfig->end_bridge_callback_data = originator;
01124 }
01125
01126 static int app_exec(struct ast_channel *chan, const char *data)
01127 {
01128 struct fm_args targs = { 0, };
01129 struct ast_bridge_config config;
01130 struct call_followme *f;
01131 struct number *nm, *newnm;
01132 int res = 0;
01133 char *argstr;
01134 struct ast_channel *caller;
01135 struct ast_channel *outbound;
01136 AST_DECLARE_APP_ARGS(args,
01137 AST_APP_ARG(followmeid);
01138 AST_APP_ARG(options);
01139 );
01140
01141 if (ast_strlen_zero(data)) {
01142 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
01143 return -1;
01144 }
01145
01146 argstr = ast_strdupa((char *) data);
01147
01148 AST_STANDARD_APP_ARGS(args, argstr);
01149
01150 if (ast_strlen_zero(args.followmeid)) {
01151 ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
01152 return -1;
01153 }
01154
01155 AST_RWLIST_RDLOCK(&followmes);
01156 AST_RWLIST_TRAVERSE(&followmes, f, entry) {
01157 if (!strcasecmp(f->name, args.followmeid) && (f->active))
01158 break;
01159 }
01160 AST_RWLIST_UNLOCK(&followmes);
01161
01162 ast_debug(1, "New profile %s.\n", args.followmeid);
01163
01164 if (!f) {
01165 f = find_realtime(args.followmeid);
01166 }
01167
01168 if (!f) {
01169 ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
01170 return 0;
01171 }
01172
01173
01174 if (args.options)
01175 ast_app_parse_options(followme_opts, &targs.followmeflags, NULL, args.options);
01176
01177
01178 ast_mutex_lock(&f->lock);
01179 targs.mohclass = ast_strdupa(f->moh);
01180 ast_copy_string(targs.context, f->context, sizeof(targs.context));
01181 ast_copy_string(targs.takecall, f->takecall, sizeof(targs.takecall));
01182 ast_copy_string(targs.nextindp, f->nextindp, sizeof(targs.nextindp));
01183 ast_copy_string(targs.callfromprompt, f->callfromprompt, sizeof(targs.callfromprompt));
01184 ast_copy_string(targs.norecordingprompt, f->norecordingprompt, sizeof(targs.norecordingprompt));
01185 ast_copy_string(targs.optionsprompt, f->optionsprompt, sizeof(targs.optionsprompt));
01186 ast_copy_string(targs.plsholdprompt, f->plsholdprompt, sizeof(targs.plsholdprompt));
01187 ast_copy_string(targs.statusprompt, f->statusprompt, sizeof(targs.statusprompt));
01188 ast_copy_string(targs.sorryprompt, f->sorryprompt, sizeof(targs.sorryprompt));
01189
01190
01191 AST_LIST_HEAD_INIT_NOLOCK(&targs.cnumbers);
01192 AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
01193 newnm = create_followme_number(nm->number, nm->timeout, nm->order);
01194 if (newnm) {
01195 AST_LIST_INSERT_TAIL(&targs.cnumbers, newnm, entry);
01196 }
01197 }
01198 ast_mutex_unlock(&f->lock);
01199
01200
01201 if (chan->_state != AST_STATE_UP) {
01202 ast_answer(chan);
01203 }
01204
01205 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG))
01206 ast_stream_and_wait(chan, targs.statusprompt, "");
01207
01208 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) {
01209 int duration = 5;
01210
01211 snprintf(targs.namerecloc, sizeof(targs.namerecloc), "%s/followme.%s",
01212 ast_config_AST_SPOOL_DIR, chan->uniqueid);
01213
01214 if (ast_play_and_record(chan, "vm-rec-name", targs.namerecloc, 5, "sln", &duration,
01215 NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) {
01216 goto outrun;
01217 }
01218
01219 if (!ast_fileexists(targs.namerecloc, NULL, chan->language)) {
01220 targs.namerecloc[0] = '\0';
01221 }
01222 }
01223
01224 if (!ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) {
01225 if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
01226 goto outrun;
01227 if (ast_waitstream(chan, "") < 0)
01228 goto outrun;
01229 }
01230 ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL);
01231
01232 targs.status = 0;
01233 targs.chan = chan;
01234 ast_channel_lock(chan);
01235 ast_connected_line_copy_from_caller(&targs.connected_in, &chan->caller);
01236 ast_channel_unlock(chan);
01237
01238 findmeexec(&targs);
01239 if (targs.status != 100) {
01240 ast_moh_stop(chan);
01241 if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG))
01242 ast_stream_and_wait(chan, targs.sorryprompt, "");
01243 res = 0;
01244 } else {
01245 caller = chan;
01246 outbound = targs.outbound;
01247
01248
01249 memset(&config, 0, sizeof(config));
01250 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01251 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
01252 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
01253 config.end_bridge_callback = end_bridge_callback;
01254 config.end_bridge_callback_data = chan;
01255 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
01256
01257 ast_moh_stop(caller);
01258
01259 ast_deactivate_generator(caller);
01260
01261 res = ast_channel_make_compatible(caller, outbound);
01262 if (res < 0) {
01263 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", caller->name, outbound->name);
01264 ast_hangup(outbound);
01265 goto outrun;
01266 }
01267
01268
01269 if (targs.pending_out_connected_update) {
01270 if (ast_channel_connected_line_macro(outbound, caller, &targs.connected_out, 1, 0)) {
01271 ast_channel_update_connected_line(caller, &targs.connected_out, NULL);
01272 }
01273 }
01274
01275
01276 if (targs.pending_in_connected_update) {
01277 if (ast_channel_connected_line_macro(caller, outbound, &targs.connected_in, 0, 0)) {
01278 ast_channel_update_connected_line(outbound, &targs.connected_in, NULL);
01279 }
01280 }
01281
01282 res = ast_bridge_call(caller, outbound, &config);
01283 ast_hangup(outbound);
01284 }
01285
01286 outrun:
01287 while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry))) {
01288 ast_free(nm);
01289 }
01290 if (!ast_strlen_zero(targs.namerecloc)) {
01291 unlink(targs.namerecloc);
01292 }
01293 ast_party_connected_line_free(&targs.connected_in);
01294 ast_party_connected_line_free(&targs.connected_out);
01295
01296 if (f->realtime) {
01297
01298 free_numbers(f);
01299 ast_free(f);
01300 }
01301
01302 return res;
01303 }
01304
01305 static int unload_module(void)
01306 {
01307 struct call_followme *f;
01308
01309 ast_unregister_application(app);
01310
01311
01312 AST_RWLIST_WRLOCK(&followmes);
01313 while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
01314 free_numbers(f);
01315 ast_free(f);
01316 }
01317
01318 AST_RWLIST_UNLOCK(&followmes);
01319
01320 return 0;
01321 }
01322
01323 static int load_module(void)
01324 {
01325 if(!reload_followme(0))
01326 return AST_MODULE_LOAD_DECLINE;
01327
01328 return ast_register_application_xml(app, app_exec);
01329 }
01330
01331 static int reload(void)
01332 {
01333 reload_followme(1);
01334
01335 return 0;
01336 }
01337
01338 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
01339 .load = load_module,
01340 .unload = unload_module,
01341 .reload = reload,
01342 );