|
|
|
@ -67,31 +67,41 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|
|
|
|
<parameter name="followmeid" required="true" />
|
|
|
|
|
<parameter name="options">
|
|
|
|
|
<optionlist>
|
|
|
|
|
<option name="s">
|
|
|
|
|
<para>Playback the incoming status message prior to starting
|
|
|
|
|
the follow-me step(s)</para>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="a">
|
|
|
|
|
<para>Record the caller's name so it can be announced to the
|
|
|
|
|
callee on each step.</para>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="n">
|
|
|
|
|
<para>Playback the unreachable status message if we've run out
|
|
|
|
|
of steps to reach the or the callee has elected not to be reachable.</para>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="N">
|
|
|
|
|
<para>Don't answer the incoming call until we're ready to
|
|
|
|
|
connect the caller or give up. This will disable all the other
|
|
|
|
|
options while implicitly turning on the 'd' option.</para>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="d">
|
|
|
|
|
<para>Disable the 'Please hold while we try to connect your call' announcement.</para>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="I">
|
|
|
|
|
<para>Asterisk will ignore any connected line update requests
|
|
|
|
|
it may receive on this dial attempt.</para>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="l">
|
|
|
|
|
<para>Disable local call optimization so that applications with
|
|
|
|
|
audio hooks between the local bridge don't get dropped when the
|
|
|
|
|
calls get joined directly.</para>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="N">
|
|
|
|
|
<para>Don't answer the incoming call until we're ready to
|
|
|
|
|
connect the caller or give up.</para>
|
|
|
|
|
<note>
|
|
|
|
|
<para>This option is ignored if the call is already answered.</para>
|
|
|
|
|
</note>
|
|
|
|
|
<note>
|
|
|
|
|
<para>If the call is not already answered, the 'a' and 's'
|
|
|
|
|
options are ignored while the 'd' option is implicitly enabled.</para>
|
|
|
|
|
</note>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="n">
|
|
|
|
|
<para>Playback the unreachable status message if we've run out
|
|
|
|
|
of steps or the callee has elected not to be reachable.</para>
|
|
|
|
|
</option>
|
|
|
|
|
<option name="s">
|
|
|
|
|
<para>Playback the incoming status message prior to starting
|
|
|
|
|
the follow-me step(s)</para>
|
|
|
|
|
</option>
|
|
|
|
|
</optionlist>
|
|
|
|
|
</parameter>
|
|
|
|
|
</syntax>
|
|
|
|
@ -140,13 +150,23 @@ struct call_followme {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct fm_args {
|
|
|
|
|
/*! Inbound (caller) channel */
|
|
|
|
|
struct ast_channel *chan;
|
|
|
|
|
char *mohclass;
|
|
|
|
|
AST_LIST_HEAD_NOLOCK(cnumbers, number) cnumbers;
|
|
|
|
|
/*! Winning outbound (callee) channel */
|
|
|
|
|
struct ast_channel *outbound;
|
|
|
|
|
/*! Accumulated connected line information from inbound call. */
|
|
|
|
|
struct ast_party_connected_line connected_in;
|
|
|
|
|
/*! Accumulated connected line information from outbound call. */
|
|
|
|
|
struct ast_party_connected_line connected_out;
|
|
|
|
|
/*! TRUE if connected line information from inbound call changed. */
|
|
|
|
|
int pending_in_connected_update:1;
|
|
|
|
|
/*! TRUE if connected line information from outbound call is available. */
|
|
|
|
|
int pending_out_connected_update:1;
|
|
|
|
|
int status;
|
|
|
|
|
char context[AST_MAX_CONTEXT];
|
|
|
|
|
char namerecloc[AST_MAX_CONTEXT];
|
|
|
|
|
struct ast_channel *outbound;
|
|
|
|
|
char takecall[20]; /*!< Digit mapping to take a call */
|
|
|
|
|
char nextindp[20]; /*!< Digit mapping to decline a call */
|
|
|
|
|
char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */
|
|
|
|
@ -160,12 +180,17 @@ struct fm_args {
|
|
|
|
|
|
|
|
|
|
struct findme_user {
|
|
|
|
|
struct ast_channel *ochan;
|
|
|
|
|
/*! Accumulated connected line information from outgoing call. */
|
|
|
|
|
struct ast_party_connected_line connected;
|
|
|
|
|
long digts;
|
|
|
|
|
int ynidx;
|
|
|
|
|
int state;
|
|
|
|
|
char dialarg[256];
|
|
|
|
|
char yn[10];
|
|
|
|
|
int ynidx;
|
|
|
|
|
long digts;
|
|
|
|
|
int cleared;
|
|
|
|
|
/*! TRUE if call cleared. */
|
|
|
|
|
int cleared:1;
|
|
|
|
|
/*! TRUE if connected line information is available. */
|
|
|
|
|
int pending_connected_update:1;
|
|
|
|
|
AST_LIST_ENTRY(findme_user) entry;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -176,15 +201,17 @@ enum {
|
|
|
|
|
FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3),
|
|
|
|
|
FOLLOWMEFLAG_NOANSWER = (1 << 4),
|
|
|
|
|
FOLLOWMEFLAG_DISABLEOPTIMIZATION = (1 << 5),
|
|
|
|
|
FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 6),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
AST_APP_OPTIONS(followme_opts, {
|
|
|
|
|
AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG ),
|
|
|
|
|
AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME ),
|
|
|
|
|
AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG ),
|
|
|
|
|
AST_APP_OPTION('d', FOLLOWMEFLAG_DISABLEHOLDPROMPT ),
|
|
|
|
|
AST_APP_OPTION('N', FOLLOWMEFLAG_NOANSWER ),
|
|
|
|
|
AST_APP_OPTION('l', FOLLOWMEFLAG_DISABLEOPTIMIZATION ),
|
|
|
|
|
AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME),
|
|
|
|
|
AST_APP_OPTION('d', FOLLOWMEFLAG_DISABLEHOLDPROMPT),
|
|
|
|
|
AST_APP_OPTION('I', FOLLOWMEFLAG_IGNORE_CONNECTEDLINE),
|
|
|
|
|
AST_APP_OPTION('l', FOLLOWMEFLAG_DISABLEOPTIMIZATION),
|
|
|
|
|
AST_APP_OPTION('N', FOLLOWMEFLAG_NOANSWER),
|
|
|
|
|
AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG),
|
|
|
|
|
AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
static int ynlongest = 0;
|
|
|
|
@ -538,13 +565,15 @@ static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
|
|
|
|
|
if (!fmuser->cleared) {
|
|
|
|
|
clear_caller(fmuser);
|
|
|
|
|
}
|
|
|
|
|
ast_party_connected_line_free(&fmuser->connected);
|
|
|
|
|
ast_free(fmuser);
|
|
|
|
|
}
|
|
|
|
|
ast_free(findme_user_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, char *namerecloc, int *status, struct fm_args *tpargs)
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
struct ast_party_connected_line connected;
|
|
|
|
|
struct ast_channel *watchers[256];
|
|
|
|
|
int pos;
|
|
|
|
|
struct ast_channel *winner;
|
|
|
|
@ -670,12 +699,21 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
|
|
|
|
|
}
|
|
|
|
|
if (winner) {
|
|
|
|
|
/* Need to find out which channel this is */
|
|
|
|
|
dg = 0;
|
|
|
|
|
while ((winner != watchers[dg]) && (dg < 256))
|
|
|
|
|
dg++;
|
|
|
|
|
AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry)
|
|
|
|
|
if (tmpuser->ochan == winner)
|
|
|
|
|
for (dg = 0; dg < ARRAY_LEN(watchers); ++dg) {
|
|
|
|
|
if (winner == watchers[dg]) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (dg) {
|
|
|
|
|
/* The winner is an outgoing channel. */
|
|
|
|
|
AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
|
|
|
|
|
if (tmpuser->ochan == winner) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
tmpuser = NULL;
|
|
|
|
|
}
|
|
|
|
|
f = ast_read(winner);
|
|
|
|
|
if (f) {
|
|
|
|
|
if (f->frametype == AST_FRAME_CONTROL) {
|
|
|
|
@ -729,32 +767,73 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
|
|
|
|
|
ast_verb(3, "%s is ringing\n", ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_PROGRESS:
|
|
|
|
|
ast_verb(3, "%s is making progress passing it to %s\n", ast_channel_name(winner), ast_channel_name(caller));
|
|
|
|
|
ast_verb(3, "%s is making progress\n", ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_VIDUPDATE:
|
|
|
|
|
ast_verb(3, "%s requested a video update, passing it to %s\n", ast_channel_name(winner), ast_channel_name(caller));
|
|
|
|
|
ast_verb(3, "%s requested a video update\n", ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_SRCUPDATE:
|
|
|
|
|
ast_verb(3, "%s requested a source update, passing it to %s\n", ast_channel_name(winner), ast_channel_name(caller));
|
|
|
|
|
ast_verb(3, "%s requested a source update\n", ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_PROCEEDING:
|
|
|
|
|
ast_verb(3, "%s is proceeding passing it to %s\n", ast_channel_name(winner),ast_channel_name(caller));
|
|
|
|
|
ast_verb(3, "%s is proceeding\n", ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_HOLD:
|
|
|
|
|
ast_verb(3, "Call on %s placed on hold\n", ast_channel_name(winner));
|
|
|
|
|
ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_UNHOLD:
|
|
|
|
|
ast_verb(3, "Call on %s left from hold\n", ast_channel_name(winner));
|
|
|
|
|
ast_verb(3, "%s removed call from hold\n", ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_OFFHOOK:
|
|
|
|
|
case AST_CONTROL_FLASH:
|
|
|
|
|
/* Ignore going off hook and flash */
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_CONNECTED_LINE:
|
|
|
|
|
if (!tmpuser) {
|
|
|
|
|
/*
|
|
|
|
|
* Hold connected line update from caller until we have a
|
|
|
|
|
* winner.
|
|
|
|
|
*/
|
|
|
|
|
ast_verb(3,
|
|
|
|
|
"%s connected line has changed. Saving it until we have a winner.\n",
|
|
|
|
|
ast_channel_name(winner));
|
|
|
|
|
ast_party_connected_line_set_init(&connected, &tpargs->connected_in);
|
|
|
|
|
if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
|
|
|
|
|
ast_party_connected_line_set(&tpargs->connected_in,
|
|
|
|
|
&connected, NULL);
|
|
|
|
|
tpargs->pending_in_connected_update = 1;
|
|
|
|
|
}
|
|
|
|
|
ast_party_connected_line_free(&connected);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) {
|
|
|
|
|
ast_verb(3, "Connected line update from %s prevented.\n",
|
|
|
|
|
ast_channel_name(winner));
|
|
|
|
|
} else {
|
|
|
|
|
ast_verb(3,
|
|
|
|
|
"%s connected line has changed. Saving it until answer.\n",
|
|
|
|
|
ast_channel_name(winner));
|
|
|
|
|
ast_party_connected_line_set_init(&connected, &tmpuser->connected);
|
|
|
|
|
if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
|
|
|
|
|
ast_party_connected_line_set(&tmpuser->connected,
|
|
|
|
|
&connected, NULL);
|
|
|
|
|
tmpuser->pending_connected_update = 1;
|
|
|
|
|
}
|
|
|
|
|
ast_party_connected_line_free(&connected);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AST_CONTROL_REDIRECTING:
|
|
|
|
|
/*
|
|
|
|
|
* Ignore because we are masking the FollowMe search progress to
|
|
|
|
|
* the caller.
|
|
|
|
|
*/
|
|
|
|
|
break;
|
|
|
|
|
case -1:
|
|
|
|
|
ast_verb(3, "%s stopped sounds\n", ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
|
|
|
|
|
ast_debug(1, "Dunno what to do with control type %d from %s\n",
|
|
|
|
|
f->subclass.integer, ast_channel_name(winner));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -775,36 +854,35 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
|
|
|
|
|
}
|
|
|
|
|
if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
|
|
|
|
|
ast_debug(1, "Next in dial plan step requested.\n");
|
|
|
|
|
*status = 1;
|
|
|
|
|
ast_frfree(f);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ast_frfree(f);
|
|
|
|
|
} else {
|
|
|
|
|
if (winner) {
|
|
|
|
|
ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n",dg);
|
|
|
|
|
if (!dg) {
|
|
|
|
|
clear_calling_tree(findme_user_list);
|
|
|
|
|
ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n", dg);
|
|
|
|
|
if (!dg) {
|
|
|
|
|
/* Caller hung up. */
|
|
|
|
|
clear_calling_tree(findme_user_list);
|
|
|
|
|
return NULL;
|
|
|
|
|
} else {
|
|
|
|
|
/* Outgoing channel hung up. */
|
|
|
|
|
tmpuser->state = -1;
|
|
|
|
|
tmpuser->ochan = NULL;
|
|
|
|
|
ast_hangup(winner);
|
|
|
|
|
--livechannels;
|
|
|
|
|
ast_debug(1, "live channels left %d\n", livechannels);
|
|
|
|
|
if (!livechannels) {
|
|
|
|
|
ast_verb(3, "no live channels left. exiting.\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
} else {
|
|
|
|
|
tmpuser->state = -1;
|
|
|
|
|
ast_hangup(winner);
|
|
|
|
|
livechannels--;
|
|
|
|
|
ast_debug(1, "live channels left %d\n", livechannels);
|
|
|
|
|
if (!livechannels) {
|
|
|
|
|
ast_verb(3, "no live channels left. exiting.\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
} else {
|
|
|
|
|
ast_debug(1, "timed out waiting for action\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --- WAIT FOR WINNER NUMBER END! -----------*/
|
|
|
|
@ -824,7 +902,6 @@ static void findmeexec(struct fm_args *tpargs)
|
|
|
|
|
struct findme_user *tmpuser;
|
|
|
|
|
struct findme_user *fmuser;
|
|
|
|
|
struct findme_user_listptr *findme_user_list;
|
|
|
|
|
int status;
|
|
|
|
|
|
|
|
|
|
findme_user_list = ast_calloc(1, sizeof(*findme_user_list));
|
|
|
|
|
AST_LIST_HEAD_INIT_NOLOCK(findme_user_list);
|
|
|
|
@ -839,7 +916,7 @@ static void findmeexec(struct fm_args *tpargs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
caller = tpargs->chan;
|
|
|
|
|
for (idx = 1; !winner && !ast_check_hangup(caller); ++idx) {
|
|
|
|
|
for (idx = 1; !ast_check_hangup(caller); ++idx) {
|
|
|
|
|
/* Find next followme numbers to dial. */
|
|
|
|
|
AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
|
|
|
|
|
if (nm->order == idx) {
|
|
|
|
@ -930,16 +1007,29 @@ static void findmeexec(struct fm_args *tpargs)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = 0;
|
|
|
|
|
winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
|
|
|
|
|
winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, tpargs);
|
|
|
|
|
if (!winner) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clean up all calls but winner. */
|
|
|
|
|
/* Destroy losing calls up to the winner. The rest will be destroyed later. */
|
|
|
|
|
while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
|
|
|
|
|
if (!fmuser->cleared && fmuser->ochan != winner) {
|
|
|
|
|
clear_caller(fmuser);
|
|
|
|
|
if (fmuser->ochan == winner) {
|
|
|
|
|
/* Pass any connected line info up. */
|
|
|
|
|
tpargs->connected_out = fmuser->connected;
|
|
|
|
|
tpargs->pending_out_connected_update = fmuser->pending_connected_update;
|
|
|
|
|
ast_free(fmuser);
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
/* Destroy losing call. */
|
|
|
|
|
if (!fmuser->cleared) {
|
|
|
|
|
clear_caller(fmuser);
|
|
|
|
|
}
|
|
|
|
|
ast_party_connected_line_free(&fmuser->connected);
|
|
|
|
|
ast_free(fmuser);
|
|
|
|
|
}
|
|
|
|
|
ast_free(fmuser);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
destroy_calling_tree(findme_user_list);
|
|
|
|
|
if (!winner) {
|
|
|
|
@ -1066,7 +1156,6 @@ static int app_exec(struct ast_channel *chan, const char *data)
|
|
|
|
|
int res = 0;
|
|
|
|
|
char *argstr;
|
|
|
|
|
char namerecloc[255];
|
|
|
|
|
int duration = 0;
|
|
|
|
|
struct ast_channel *caller;
|
|
|
|
|
struct ast_channel *outbound;
|
|
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
@ -1133,27 +1222,36 @@ static int app_exec(struct ast_channel *chan, const char *data)
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&f->lock);
|
|
|
|
|
|
|
|
|
|
snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid);
|
|
|
|
|
duration = 5;
|
|
|
|
|
|
|
|
|
|
if (!ast_fileexists(namerecloc, NULL, chan->language))
|
|
|
|
|
ast_copy_string(namerecloc, "", sizeof(namerecloc));
|
|
|
|
|
/* Forget the 'N' option if the call is already up. */
|
|
|
|
|
if (chan->_state == AST_STATE_UP) {
|
|
|
|
|
ast_clear_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namerecloc[0] = '\0';
|
|
|
|
|
if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
|
|
|
|
|
if (chan->_state != AST_STATE_UP) {
|
|
|
|
|
ast_indicate(chan, AST_CONTROL_RINGING);
|
|
|
|
|
}
|
|
|
|
|
ast_indicate(chan, AST_CONTROL_RINGING);
|
|
|
|
|
} else {
|
|
|
|
|
/* Answer the call */
|
|
|
|
|
if (chan->_state != AST_STATE_UP)
|
|
|
|
|
if (chan->_state != AST_STATE_UP) {
|
|
|
|
|
ast_answer(chan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG))
|
|
|
|
|
ast_stream_and_wait(chan, targs.statusprompt, "");
|
|
|
|
|
|
|
|
|
|
if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME))
|
|
|
|
|
if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0)
|
|
|
|
|
if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) {
|
|
|
|
|
int duration = 5;
|
|
|
|
|
|
|
|
|
|
snprintf(namerecloc, sizeof(namerecloc), "%s/followme.%s",
|
|
|
|
|
ast_config_AST_SPOOL_DIR, chan->uniqueid);
|
|
|
|
|
if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration,
|
|
|
|
|
NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) {
|
|
|
|
|
goto outrun;
|
|
|
|
|
}
|
|
|
|
|
if (!ast_fileexists(namerecloc, NULL, chan->language)) {
|
|
|
|
|
namerecloc[0] = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) {
|
|
|
|
|
if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
|
|
|
|
@ -1167,6 +1265,9 @@ static int app_exec(struct ast_channel *chan, const char *data)
|
|
|
|
|
targs.status = 0;
|
|
|
|
|
targs.chan = chan;
|
|
|
|
|
ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc));
|
|
|
|
|
ast_channel_lock(chan);
|
|
|
|
|
ast_connected_line_copy_from_caller(&targs.connected_in, &chan->caller);
|
|
|
|
|
ast_channel_unlock(chan);
|
|
|
|
|
|
|
|
|
|
findmeexec(&targs);
|
|
|
|
|
|
|
|
|
@ -1176,15 +1277,15 @@ static int app_exec(struct ast_channel *chan, const char *data)
|
|
|
|
|
if (!ast_strlen_zero(namerecloc))
|
|
|
|
|
unlink(namerecloc);
|
|
|
|
|
|
|
|
|
|
if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
|
|
|
|
|
if (chan->_state != AST_STATE_UP) {
|
|
|
|
|
ast_answer(chan);
|
|
|
|
|
if (targs.status != 100) {
|
|
|
|
|
if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
|
|
|
|
|
if (chan->_state != AST_STATE_UP) {
|
|
|
|
|
ast_answer(chan);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ast_moh_stop(chan);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ast_moh_stop(chan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (targs.status != 100) {
|
|
|
|
|
if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG))
|
|
|
|
|
ast_stream_and_wait(chan, targs.sorryprompt, "");
|
|
|
|
|
res = 0;
|
|
|
|
@ -1201,6 +1302,21 @@ static int app_exec(struct ast_channel *chan, const char *data)
|
|
|
|
|
config.end_bridge_callback_data = chan;
|
|
|
|
|
config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
|
|
|
|
|
|
|
|
|
|
/* Update connected line to caller if available. */
|
|
|
|
|
if (targs.pending_out_connected_update) {
|
|
|
|
|
if (ast_channel_connected_line_macro(outbound, caller, &targs.connected_out, 1, 0)) {
|
|
|
|
|
ast_channel_update_connected_line(caller, &targs.connected_out, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
|
|
|
|
|
if (caller->_state != AST_STATE_UP) {
|
|
|
|
|
ast_answer(caller);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ast_moh_stop(caller);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Be sure no generators are left on it */
|
|
|
|
|
ast_deactivate_generator(caller);
|
|
|
|
|
/* Make sure channels are compatible */
|
|
|
|
@ -1210,12 +1326,21 @@ static int app_exec(struct ast_channel *chan, const char *data)
|
|
|
|
|
ast_hangup(outbound);
|
|
|
|
|
goto outrun;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update connected line to winner if changed. */
|
|
|
|
|
if (targs.pending_in_connected_update) {
|
|
|
|
|
if (ast_channel_connected_line_macro(caller, outbound, &targs.connected_in, 0, 0)) {
|
|
|
|
|
ast_channel_update_connected_line(outbound, &targs.connected_in, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = ast_bridge_call(caller, outbound, &config);
|
|
|
|
|
ast_hangup(outbound);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outrun:
|
|
|
|
|
|
|
|
|
|
ast_party_connected_line_free(&targs.connected_in);
|
|
|
|
|
ast_party_connected_line_free(&targs.connected_out);
|
|
|
|
|
if (f->realtime) {
|
|
|
|
|
/* Not in list */
|
|
|
|
|
free_numbers(f);
|
|
|
|
|