Newer
Older
ast_copy_string(status, "DONTCALL", sizeof(status));
if (ast_opt_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
}
res = 0;
goto out; /* Is this right? */
}
ast_copy_string(status, "TORTURE", sizeof(status));
if (ast_opt_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 301);
}
res = 0;
goto out; /* is this right??? */
}
/* Get the user's intro, store it in priv-callerintros/$CID,
unless it is already there-- this should be done before the
call is actually dialed */
/* make sure the priv-callerintros dir actually exists */
snprintf(privintro, sizeof(privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR);
if (mkdir(privintro, 0755) && errno != EEXIST) {
ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(errno));
res = -1;
goto out;
}
snprintf(privintro,sizeof(privintro), "priv-callerintros/%s", privcid);
if( ast_fileexists(privintro,NULL,NULL ) > 0 && strncmp(privcid,"NOCALLERID",10) != 0) {
/* the DELUX version of this code would allow this caller the
option to hear and retape their previously recorded intro.
*/
}
else {
int duration; /* for feedback from play_and_wait */
/* the file doesn't exist yet. Let the caller submit his
vocal intro for posterity */
/* priv-recordintro script:
"At the tone, please say your name:"
*/
res = ast_play_and_record(chan, "priv-recordintro", privintro, 4, "gsm", &duration, 128, 2000, 0); /* NOTE: I've reduced the total time to 4 sec */
/* don't think we'll need a lock removed, we took care of
conflicts by naming the privintro file */
if (res == -1) {
/* Delete the file regardless since they hung up during recording */
ast_filedelete(privintro, NULL);
if( ast_fileexists(privintro,NULL,NULL ) > 0 )
ast_log(LOG_NOTICE,"privacy: ast_filedelete didn't do its job on %s\n", privintro);
else if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Successfully deleted %s intro file\n", privintro);
goto out;
}
if( !ast_streamfile(chan, "vm-dialout", chan->language) )
ast_waitstream(chan, "");
/* If a channel group has been specified, get it for use when we create peer channels */
outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING);
/* loop through the list of dial destinations */
rest = args.peers;
while ((cur = strsep(&rest, "&")) ) {
char *number = cur;
char *tech = strsep(&number, "/");
ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
if (!(tmp = ast_calloc(1, sizeof(*tmp))))
if (opts.flags) {
ast_copy_flags(tmp, &opts,
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
OPT_CALLEE_PARK | OPT_CALLER_PARK |
OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
ast_set2_flag(tmp, args.url, DIAL_NOFORWARDHTML);
ast_copy_string(numsubst, number, sizeof(numsubst));
Mark Spencer
committed
tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
if (!tmp->chan) {
/* If we can't, just go on to the next call */
ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n", tech, cause, ast_cause2str(cause));
Mark Spencer
committed
HANDLE_CAUSE(cause, chan);
if (!rest) /* we are on the last destination */
Kevin P. Fleming
committed
chan->hangupcause = cause;
pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", numsubst);
Mark Spencer
committed
if (!ast_strlen_zero(tmp->chan->call_forward)) {
char tmpchan[256];
ast_copy_string(tmpchan, tmp->chan->call_forward, sizeof(tmpchan));
*stuff++ = '\0';
tech = tmpchan;
} else {
snprintf(tmpchan, sizeof(tmpchan), "%s@%s", tmp->chan->call_forward, tmp->chan->context);
stuff = tmpchan;
tech = "Local";
}
tmp->forwards++;
if (tmp->forwards < AST_MAX_FORWARDS) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
ast_hangup(tmp->chan);
/* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
if (ast_test_flag(&opts, OPT_IGNORE_FORWARDING)) {
Kevin P. Fleming
committed
tmp->chan = NULL;
cause = AST_CAUSE_BUSY;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s/%s' prevented.\n", chan->name, tech, stuff);
} else {
tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
}
if (!tmp->chan)
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
Joshua Colp
committed
else
ast_channel_inherit_variables(chan, tmp->chan);
} else {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", tmp->chan->name);
ast_hangup(tmp->chan);
tmp->chan = NULL;
cause = AST_CAUSE_CONGESTION;
}
if (!tmp->chan) {
Mark Spencer
committed
HANDLE_CAUSE(cause, chan);
continue;
}
/* Setup outgoing SDP to match incoming one */
ast_rtp_make_compatible(tmp->chan, chan, !outgoing && !rest);
/* Inherit specially named variables from parent channel */
ast_channel_inherit_variables(chan, tmp->chan);
tmp->chan->appl = "AppDial";
tmp->chan->data = "(Outgoing Line)";
S_REPLACE(tmp->chan->cid.cid_num, ast_strdup(chan->cid.cid_num));
S_REPLACE(tmp->chan->cid.cid_name, ast_strdup(chan->cid.cid_name));
S_REPLACE(tmp->chan->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
S_REPLACE(tmp->chan->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
ast_string_field_set(tmp->chan, language, chan->language);
ast_string_field_set(tmp->chan, accountcode, chan->accountcode);
Mark Spencer
committed
tmp->chan->cdrflags = chan->cdrflags;
Mark Spencer
committed
if (ast_strlen_zero(tmp->chan->musicclass))
ast_string_field_set(tmp->chan, musicclass, chan->musicclass);
Martin Pycko
committed
/* Pass callingpres setting */
tmp->chan->cid.cid_pres = chan->cid.cid_pres;
/* Pass type of number */
tmp->chan->cid.cid_ton = chan->cid.cid_ton;
/* Pass type of tns */
tmp->chan->cid.cid_tns = chan->cid.cid_tns;
/* Presense of ADSI CPE on outgoing channel follows ours */
tmp->chan->adsicpe = chan->adsicpe;
/* Pass the transfer capability */
tmp->chan->transfercapability = chan->transfercapability;
/* If we have an outbound group, set this peer channel to it */
if (outbound_group)
ast_app_group_set_channel(tmp->chan, outbound_group);
/* Inherit context and extension */
ast_copy_string(tmp->chan->context, chan->context, sizeof(tmp->chan->context));
ast_copy_string(tmp->chan->exten, chan->exten, sizeof(tmp->chan->exten));
/* Place the call, but don't wait on the answer */
Martin Pycko
committed
/* Save the info in cdr's that we called them */
if (chan->cdr)
ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
if (res) {
/* Again, keep going even if there's an error */
if (option_debug)
ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
Mark Spencer
committed
tmp->chan = NULL;
Mark Spencer
committed
} else {
senddialevent(chan, tmp->chan);
ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID))
ast_set_callerid(tmp->chan, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL);
Mark Spencer
committed
}
/* Put them in the list of outgoing thingies... We're ready now.
XXX If we're forcibly removed, these outgoing calls won't get
hung up XXX */
/* If this line is up, don't try anybody else */
if (outgoing->chan->_state == AST_STATE_UP)
break;
if (ast_strlen_zero(args.timeout)) {
to = -1;
} else {
to = atoi(args.timeout);
if (to > 0)
to *= 1000;
else
ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
if (!outgoing) {
strcpy(status, "CHANUNAVAIL");
} else {
Mark Spencer
committed
/* Our status will at least be NOANSWER */
if (ast_test_flag(outgoing, OPT_MUSICBACK)) {
Kevin P. Fleming
committed
moh = 1;
ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
} else if (ast_test_flag(outgoing, OPT_RINGBACK)) {
ast_indicate(chan, AST_CONTROL_RINGING);
sentringing++;
}
time(&start_time);
peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, ast_test_flag(&opts, OPT_PRIORITY_JUMP), &result);
if (result) {
res = result;
} else if (to) { /* Musta gotten hung up */
} else { /* Nobody answered, next please? */
res = 0;
/* almost done, although the 'else' block is 400 lines */
} else {
const char *number;
time_t end_time, answer_time = time(NULL);
/* Ah ha! Someone answered within the desired timeframe. Of course after this
we will always return with -1 so that it is hung up properly after the
conversation. */
hanguptree(outgoing, peer);
outgoing = NULL;
/* If appropriate, log that we have a destination channel */
if (chan->cdr)
ast_cdr_setdestchan(chan->cdr, peer->name);
if (peer->name)
pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
if (!number)
number = numsubst;
pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
if (option_debug)
ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", args.url);
ast_channel_sendurl( peer, args.url );
if ( (ast_test_flag(&opts, OPT_PRIVACY) || ast_test_flag(&opts, OPT_SCREENING)) && privdb_val == AST_PRIVACY_UNKNOWN) {
/* Get the user's intro, store it in priv-callerintros/$CID,
unless it is already there-- this should be done before the
call is actually dialed */
/* all ring indications and moh for the caller has been halted as soon as the
target extension was picked up. We are going to have to kill some
time and make the caller believe the peer hasn't picked up yet */
if (ast_test_flag(&opts, OPT_MUSICBACK) && !ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
ast_indicate(chan, -1);
Kevin P. Fleming
committed
ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
} else if (ast_test_flag(&opts, OPT_RINGBACK)) {
ast_indicate(chan, AST_CONTROL_RINGING);
sentringing++;
}
/* Start autoservice on the other chan ?? */
res2 = ast_autoservice_start(chan);
/* Now Stream the File */
for (loopcount = 0; loopcount < 3; loopcount++) {
if (res2 && loopcount == 0) /* error in ast_autoservice_start() */
break;
if (!res2) /* on timeout, play the message again */
res2 = ast_play_and_wait(peer,"priv-callpending");
if (!valid_priv_reply(&opts, res2))
res2 = 0;
/* priv-callpending script:
"I have a caller waiting, who introduces themselves as:"
*/
if (!res2)
res2 = ast_play_and_wait(peer,privintro);
if (!valid_priv_reply(&opts, res2))
res2 = 0;
/* now get input from the called party, as to their choice */
if( !res2 ) {
/* XXX can we have both, or they are mutually exclusive ? */
if( ast_test_flag(&opts, OPT_PRIVACY) )
res2 = ast_play_and_wait(peer,"priv-callee-options");
if( ast_test_flag(&opts, OPT_SCREENING) )
res2 = ast_play_and_wait(peer,"screen-callee-options");
}
/*! \page DialPrivacy Dial Privacy scripts
\par priv-callee-options script:
"Dial 1 if you wish this caller to reach you directly in the future,
and immediately connect to their incoming call
Dial 2 if you wish to send this caller to voicemail now and
forevermore.
Dial 3 to send this caller to the torture menus, now and forevermore.
Dial 4 to send this caller to a simple "go away" menu, now and forevermore.
Dial 5 to allow this caller to come straight thru to you in the future,
but right now, just this once, send them to voicemail."
\par screen-callee-options script:
"Dial 1 if you wish to immediately connect to the incoming call
Dial 2 if you wish to send this caller to voicemail.
Dial 3 to send this caller to the torture menus.
Dial 4 to send this caller to a simple "go away" menu.
*/
if (valid_priv_reply(&opts, res2))
break;
/* invalid option */
res2 = ast_play_and_wait(peer, "vm-sorry");
}
if (ast_test_flag(&opts, OPT_MUSICBACK)) {
ast_moh_stop(chan);
} else if (ast_test_flag(&opts, OPT_RINGBACK)) {
ast_indicate(chan, -1);
sentringing=0;
}
ast_autoservice_stop(chan);
switch (res2) {
case '1':
if( ast_test_flag(&opts, OPT_PRIVACY) ) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n",
opt_args[OPT_ARG_PRIVACY], privcid);
ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_ALLOW);
}
break;
case '2':
if( ast_test_flag(&opts, OPT_PRIVACY) ) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to DENY\n",
opt_args[OPT_ARG_PRIVACY], privcid);
ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_DENY);
}
ast_copy_string(status, "NOANSWER", sizeof(status));
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
res=0;
goto out;
case '3':
if( ast_test_flag(&opts, OPT_PRIVACY) ) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to TORTURE\n",
opt_args[OPT_ARG_PRIVACY], privcid);
ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_TORTURE);
}
ast_copy_string(status, "TORTURE", sizeof(status));
res = 0;
ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
goto out; /* Is this right? */
case '4':
if( ast_test_flag(&opts, OPT_PRIVACY) ) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to KILL\n",
opt_args[OPT_ARG_PRIVACY], privcid);
ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_KILL);
ast_copy_string(status, "DONTCALL", sizeof(status));
res = 0;
ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
goto out; /* Is this right? */
case '5':
if( ast_test_flag(&opts, OPT_PRIVACY) ) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n",
opt_args[OPT_ARG_PRIVACY], privcid);
ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_ALLOW);
ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
res=0;
goto out;
} /* if not privacy, then 5 is the same as "default" case */
default: /* bad input or -1 if failure to start autoservice */
/* well, if the user messes up, ... he had his chance... What Is The Best Thing To Do? */
/* well, there seems basically two choices. Just patch the caller thru immediately,
or,... put 'em thru to voicemail. */
/* since the callee may have hung up, let's do the voicemail thing, no database decision */
ast_log(LOG_NOTICE, "privacy: no valid response from the callee. Sending the caller to voicemail, the callee isn't responding\n");
ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
res=0;
goto out;
}
/* XXX once again, this path is only taken in the case '1', so it could be
* moved there, although i am not really sure that this is correct - maybe
* the check applies to other cases as well.
*/
/* if the intro is NOCALLERID, then there's no reason to leave it on disk, it'll
just clog things up, and it's not useful information, not being tied to a CID */
if( strncmp(privcid,"NOCALLERID",10) == 0 || ast_test_flag(&opts, OPT_SCREEN_NOINTRO) ) {
ast_filedelete(privintro, NULL);
if( ast_fileexists(privintro, NULL, NULL ) > 0 )
ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", privintro);
else if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Successfully deleted %s intro file\n", privintro);
}
if (!ast_test_flag(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) {
res = 0;
} else {
/* Start autoservice on the other chan */
res = ast_autoservice_start(chan);
res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language);
if (!res) {
digit = ast_waitstream(peer, AST_DIGIT_ANY);
}
res = ast_autoservice_stop(chan);
if (digit > 0 && !res)
res = ast_senddigit(chan, digit);
else
res = digit;
if (chan && peer && ast_test_flag(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) {
replace_macro_delimiter(opt_args[OPT_ARG_GOTO]);
ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
ast_parseable_goto(peer, opt_args[OPT_ARG_GOTO]);
ast_pbx_start(peer);
hanguptree(outgoing, NULL);
res = 0;
goto done;
if (ast_test_flag(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
const char *macro_result;
res = ast_autoservice_start(chan);
if (res) {
ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
res = -1;
}
if (theapp && !res) { /* XXX why check res here ? */
replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]);
if (option_debug)
ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
res = 0;
} else {
ast_log(LOG_ERROR, "Could not find application Macro\n");
res = -1;
}
if (ast_autoservice_stop(chan) < 0) {
ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
res = -1;
}
if (!res && (macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
if (!strcasecmp(macro_result, "BUSY")) {
ast_copy_string(status, macro_result, sizeof(status));
Russell Bryant
committed
if (ast_opt_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
ast_set_flag(peerflags, OPT_GO_ON);
}
} else
} else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
ast_copy_string(status, macro_result, sizeof(status));
} else if (!strcasecmp(macro_result, "CONTINUE")) {
/* hangup peer and keep chan alive assuming the macro has changed
the context / exten / priority or perhaps
the next priority in the current exten is desired.
*/
res = -1;
} else if (!strcasecmp(macro_result, "ABORT")) {
/* Hangup both ends unless the caller has the g flag */
res = -1;
} else if (!strncasecmp(macro_result, "GOTO:", 5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
res = -1;
/* perform a transfer to a new extension */
if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/
replace_macro_delimiter(macro_transfer_dest);
if (!ast_parseable_goto(chan, macro_transfer_dest))
chan->whentohangup = time(NULL) + calldurationlimit;
if (!ast_strlen_zero(dtmfcalled)) {
ast_verbose(VERBOSE_PREFIX_3 "Sending DTMF '%s' to the called party.\n", dtmfcalled);
res = ast_dtmf_stream(peer,chan,dtmfcalled,250);
}
if (!ast_strlen_zero(dtmfcalling)) {
ast_verbose(VERBOSE_PREFIX_3 "Sending DTMF '%s' to the calling party.\n", dtmfcalling);
res = ast_dtmf_stream(chan,peer,dtmfcalling,250);
}
ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER))
ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER))
ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP))
ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
if (ast_test_flag(peerflags, OPT_CALLER_HANGUP))
ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR))
ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
if (ast_test_flag(peerflags, OPT_CALLER_MONITOR))
ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
if (ast_test_flag(peerflags, OPT_CALLEE_PARK))
ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
if (ast_test_flag(peerflags, OPT_CALLER_PARK))
ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
config.timelimit = timelimit;
config.play_warning = play_warning;
config.warning_freq = warning_freq;
config.warning_sound = warning_sound;
config.end_sound = end_sound;
config.start_sound = start_sound;
if (moh) {
moh = 0;
ast_moh_stop(chan);
} else if (sentringing) {
sentringing = 0;
ast_indicate(chan, -1);
}
Mark Spencer
committed
/* Be sure no generators are left on it */
ast_deactivate_generator(chan);
/* Make sure channels are compatible */
res = ast_channel_make_compatible(chan, peer);
if (res < 0) {
ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
ast_hangup(peer);
Mark Spencer
committed
}
if (opermode && (!strncmp(chan->name,"Zap",3)) &&
(!strncmp(peer->name,"Zap",3)))
{
struct oprmode oprmode;
oprmode.peer = peer;
oprmode.mode = opermode;
ast_channel_setoption(chan,
AST_OPTION_OPRMODE,&oprmode,sizeof(struct oprmode),0);
}
time(&end_time);
{
char toast[80];
snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", toast);
}
} else {
time(&end_time);
{
char toast[80];
snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
pbx_builtin_setvar_helper(chan, "DIALEDTIME", toast);
}
if (res != AST_PBX_NO_HANGUP_PEER) {
if (!chan->_softhangup)
chan->hangupcause = peer->hangupcause;
if (moh) {
moh = 0;
ast_moh_stop(chan);
} else if (sentringing) {
sentringing = 0;
ast_indicate(chan, -1);
}
Joshua Colp
committed
ast_channel_early_bridge(chan, NULL);
Mark Spencer
committed
pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
senddialendevent(chan, status);
if (option_debug)
ast_log(LOG_DEBUG, "Exiting with DIALSTATUS=%s.\n", status);
Mark Spencer
committed
if ((ast_test_flag(peerflags, OPT_GO_ON)) && (!chan->_softhangup) && (res != AST_PBX_KEEPALIVE))
done:
ast_module_user_remove(u);
static int dial_exec(struct ast_channel *chan, void *data)
{
struct ast_flags peerflags;
memset(&peerflags, 0, sizeof(peerflags));
return dial_exec_full(chan, data, &peerflags);
}
static int retrydial_exec(struct ast_channel *chan, void *data)
{
char *announce = NULL, *dialdata = NULL;
const char *context = NULL;
int sleep = 0, loops = 0, res = -1;
struct ast_module_user *u;
struct ast_flags peerflags;
if (ast_strlen_zero(data)) {
Russell Bryant
committed
ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
return -1;
}
u = ast_module_user_add(chan);
Russell Bryant
committed
Russell Bryant
committed
announce = ast_strdupa(data);
Russell Bryant
committed
memset(&peerflags, 0, sizeof(peerflags));
if ((dialdata = strchr(announce, '|'))) {
*dialdata++ = '\0';
if ((sleep = atoi(dialdata))) {
sleep *= 1000;
} else {
ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp);
goto done;
}
if ((dialdata = strchr(dialdata, '|'))) {
*dialdata++ = '\0';
if (!(loops = atoi(dialdata))) {
ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp);
goto done;
}
}
}
if ((dialdata = strchr(dialdata, '|'))) {
*dialdata++ = '\0';
ast_log(LOG_ERROR, "%s requires more arguments\n",rapp);
goto done;
}
if (sleep < 1000)
sleep = 10000;
loops = -1; /* run forever */
context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
res = 0;
while (loops) {
chan->data = "Retrying";
if (ast_test_flag(chan, AST_FLAG_MOH))
ast_moh_stop(chan);
if ((res = dial_exec_full(chan, dialdata, &peerflags)) == 0) {
if (ast_test_flag(&peerflags, OPT_DTMF_EXIT)) {
if (!(res = ast_streamfile(chan, announce, chan->language)))
res = ast_waitstream(chan, AST_DIGIT_ANY);
if (!ast_test_flag(chan, AST_FLAG_MOH))
Kevin P. Fleming
committed
ast_moh_start(chan, NULL, NULL);
res = ast_waitfordigit(chan, sleep);
}
} else {
if (!(res = ast_streamfile(chan, announce, chan->language)))
res = ast_waitstream(chan, "");
if (sleep) {
if (!ast_test_flag(chan, AST_FLAG_MOH))
Kevin P. Fleming
committed
ast_moh_start(chan, NULL, NULL);
res = ast_waitfordigit(chan, sleep);
}
}
if (res < 0)
break;
else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
Kevin P. Fleming
committed
if (onedigit_goto(chan, context, (char) res, 1)) {
res = 0;
break;
}
}
loops--;
}
if (loops == 0)
res = 0;
if (ast_test_flag(chan, AST_FLAG_MOH))
ast_moh_stop(chan);
ast_module_user_remove(u);
return res;
static int unload_module(void)
Russell Bryant
committed
int res;
res = ast_unregister_application(app);
res |= ast_unregister_application(rapp);
ast_module_user_hangup_all();
Russell Bryant
committed
return res;
static int load_module(void)
Russell Bryant
committed
res = ast_register_application(app, dial_exec, synopsis, descrip);
res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialing Application");