Added "Operator Services" connection mode for Zap channels, and the 'O' option

in app_dial to support the use of this mode.


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@22128 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Jim Dixon 20 years ago
parent b560433a36
commit a83297d85f

@ -154,6 +154,16 @@ static char *descrip =
" o - Specify that the CallerID that was present on the *calling* channel\n" " o - Specify that the CallerID that was present on the *calling* channel\n"
" be set as the CallerID on the *called* channel. This was the\n" " be set as the CallerID on the *called* channel. This was the\n"
" behavior of Asterisk 1.0 and earlier.\n" " behavior of Asterisk 1.0 and earlier.\n"
" O([x]) - \"Operator Services\" mode (Zaptel channel to Zaptel channel\n"
" only, if specified on non-Zaptel interface, it will be ignored).\n"
" When the destination answers (presumably an operator services\n"
" station), the originator no longer has control of their line.\n"
" They may hang up, but the switch will not release their line\n"
" until the destination party hangs up (the operator). Specified\n"
" without an arg, or with 1 as an arg, the originator hanging up\n"
" will cause the phone to ring back immediately. With a 2 specified,\n"
" when the \"operator\" flashes the trunk, it will ring their phone\n"
" back.\n"
" p - This option enables screening mode. This is basically Privacy mode\n" " p - This option enables screening mode. This is basically Privacy mode\n"
" without memory.\n" " without memory.\n"
" P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if\n" " P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if\n"
@ -213,6 +223,7 @@ enum {
OPT_CALLEE_MONITOR = (1 << 21), OPT_CALLEE_MONITOR = (1 << 21),
OPT_CALLER_MONITOR = (1 << 22), OPT_CALLER_MONITOR = (1 << 22),
OPT_GOTO = (1 << 23), OPT_GOTO = (1 << 23),
OPT_OPERMODE = (1 << 24),
} dial_exec_option_flags; } dial_exec_option_flags;
#define DIAL_STILLGOING (1 << 30) #define DIAL_STILLGOING (1 << 30)
@ -227,6 +238,7 @@ enum {
OPT_ARG_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO,
OPT_ARG_PRIVACY, OPT_ARG_PRIVACY,
OPT_ARG_DURATION_STOP, OPT_ARG_DURATION_STOP,
OPT_ARG_OPERMODE,
/* note: this entry _MUST_ be the last one in the enum */ /* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE, OPT_ARG_ARRAY_SIZE,
} dial_exec_option_args; } dial_exec_option_args;
@ -247,6 +259,7 @@ AST_APP_OPTIONS(dial_exec_options, {
AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO), AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
AST_APP_OPTION('n', OPT_SCREEN_NOINTRO), AST_APP_OPTION('n', OPT_SCREEN_NOINTRO),
AST_APP_OPTION('N', OPT_SCREEN_NOCLID), AST_APP_OPTION('N', OPT_SCREEN_NOCLID),
AST_APP_OPTION_ARG('O', OPT_OPERMODE,OPT_ARG_OPERMODE),
AST_APP_OPTION('o', OPT_ORIGINAL_CLID), AST_APP_OPTION('o', OPT_ORIGINAL_CLID),
AST_APP_OPTION('p', OPT_SCREENING), AST_APP_OPTION('p', OPT_SCREENING),
AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY), AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
@ -744,6 +757,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
char privintro[1024]; char privintro[1024];
char privcid[256]; char privcid[256];
char *parse; char *parse;
int opermode = 0;
AST_DECLARE_APP_ARGS(args, AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(peers); AST_APP_ARG(peers);
AST_APP_ARG(timeout); AST_APP_ARG(timeout);
@ -774,6 +788,14 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
goto done; goto done;
} }
if (ast_test_flag(&opts, OPT_OPERMODE)) {
if (ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]))
opermode = 1;
else opermode = atoi(opt_args[OPT_ARG_OPERMODE]);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Setting operator services mode to %d.\n", opermode);
}
if (ast_test_flag(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) { if (ast_test_flag(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
calldurationlimit = atoi(opt_args[OPT_ARG_DURATION_STOP]); calldurationlimit = atoi(opt_args[OPT_ARG_DURATION_STOP]);
if (!calldurationlimit) { if (!calldurationlimit) {
@ -1483,6 +1505,17 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
res = -1; res = -1;
goto done; goto done;
} }
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);
}
res = ast_bridge_call(chan,peer,&config); res = ast_bridge_call(chan,peer,&config);
time(&end_time); time(&end_time);
{ {

@ -543,6 +543,8 @@ static struct zt_pvt {
int sig; /*!< Signalling style */ int sig; /*!< Signalling style */
int radio; /*!< radio type */ int radio; /*!< radio type */
int outsigmod; /*!< Outbound Signalling style (modifier) */ int outsigmod; /*!< Outbound Signalling style (modifier) */
int oprmode; /*!< "Operator Services" mode */
struct zt_pvt *oprpeer; /*!< "Operator Services" peer tech_pvt ptr */
float rxgain; float rxgain;
float txgain; float txgain;
int tonezone; /*!< tone zone for this chan, or -1 for default */ int tonezone; /*!< tone zone for this chan, or -1 for default */
@ -1771,7 +1773,7 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
return -1; return -1;
} }
p->dialednone = 0; p->dialednone = 0;
if (p->radio) /* if a radio channel, up immediately */ if ((p->radio || (p->oprmode < 0))) /* if a radio channel, up immediately */
{ {
/* Special pseudo -- automatically up */ /* Special pseudo -- automatically up */
ast_setstate(ast, AST_STATE_UP); ast_setstate(ast, AST_STATE_UP);
@ -2616,7 +2618,7 @@ static int zt_hangup(struct ast_channel *ast)
ast_log(LOG_DEBUG, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook); ast_log(LOG_DEBUG, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
#endif #endif
/* If they're off hook, try playing congestion */ /* If they're off hook, try playing congestion */
if ((par.rxisoffhook) && (!p->radio)) if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
tone_zone_play_tone(p->subs[SUB_REAL].zfd, ZT_TONE_CONGESTION); tone_zone_play_tone(p->subs[SUB_REAL].zfd, ZT_TONE_CONGESTION);
else else
tone_zone_play_tone(p->subs[SUB_REAL].zfd, -1); tone_zone_play_tone(p->subs[SUB_REAL].zfd, -1);
@ -2676,6 +2678,7 @@ static int zt_hangup(struct ast_channel *ast)
p->callwaitingrepeat = 0; p->callwaitingrepeat = 0;
p->cidcwexpire = 0; p->cidcwexpire = 0;
p->oprmode = 0;
ast->tech_pvt = NULL; ast->tech_pvt = NULL;
ast_mutex_unlock(&p->lock); ast_mutex_unlock(&p->lock);
ast_mutex_lock(&usecnt_lock); ast_mutex_lock(&usecnt_lock);
@ -2717,7 +2720,7 @@ static int zt_answer(struct ast_channel *ast)
if (index < 0) if (index < 0)
index = SUB_REAL; index = SUB_REAL;
/* nothing to do if a radio channel */ /* nothing to do if a radio channel */
if (p->radio) { if ((p->radio || (p->oprmode < 0))) {
ast_mutex_unlock(&p->lock); ast_mutex_unlock(&p->lock);
return 0; return 0;
} }
@ -2803,7 +2806,9 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
signed char *scp; signed char *scp;
int x; int x;
int index; int index;
struct zt_pvt *p = chan->tech_pvt; struct zt_pvt *p = chan->tech_pvt,*pp;
struct oprmode *oprmode;
/* all supported options require data */ /* all supported options require data */
if (!data || (datalen < 1)) { if (!data || (datalen < 1)) {
@ -2939,6 +2944,22 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
if (ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &x) == -1) if (ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &x) == -1)
ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", p->channel, x); ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", p->channel, x);
break; break;
case AST_OPTION_OPRMODE: /* Operator services mode */
oprmode = (struct oprmode *) data;
pp = oprmode->peer->tech_pvt;
p->oprmode = pp->oprmode = 0;
/* setup peers */
p->oprpeer = pp;
pp->oprpeer = p;
/* setup modes, if any */
if (oprmode->mode)
{
pp->oprmode = oprmode->mode;
p->oprmode = -oprmode->mode;
}
ast_log(LOG_DEBUG, "Set Operator Services mode, value: %d on %s/%s\n",
oprmode->mode, chan->name,oprmode->peer->name);;
break;
} }
errno = 0; errno = 0;
@ -3685,7 +3706,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
break; break;
case ZT_EVENT_DIALCOMPLETE: case ZT_EVENT_DIALCOMPLETE:
if (p->inalarm) break; if (p->inalarm) break;
if (p->radio) break; if ((p->radio || (p->oprmode < 0))) break;
if (ioctl(p->subs[index].zfd,ZT_DIALING,&x) == -1) { if (ioctl(p->subs[index].zfd,ZT_DIALING,&x) == -1) {
ast_log(LOG_DEBUG, "ZT_DIALING ioctl failed on %s\n",ast->name); ast_log(LOG_DEBUG, "ZT_DIALING ioctl failed on %s\n",ast->name);
return NULL; return NULL;
@ -3760,6 +3781,19 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
p->subs[index].f.subclass = AST_CONTROL_RADIO_UNKEY; p->subs[index].f.subclass = AST_CONTROL_RADIO_UNKEY;
break; break;
} }
if (p->oprmode < 0)
{
if (p->oprmode != -1) break;
if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
{
/* Make sure it starts ringing */
zt_set_hook(p->subs[SUB_REAL].zfd, ZT_RINGOFF);
zt_set_hook(p->subs[SUB_REAL].zfd, ZT_RING);
save_conference(p->oprpeer);
tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].zfd, ZT_TONE_RINGTONE);
}
break;
}
switch(p->sig) { switch(p->sig) {
case SIG_FXOLS: case SIG_FXOLS:
case SIG_FXOGS: case SIG_FXOGS:
@ -3869,7 +3903,19 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
break; break;
case ZT_EVENT_RINGOFFHOOK: case ZT_EVENT_RINGOFFHOOK:
if (p->inalarm) break; if (p->inalarm) break;
if (p->radio) { if (p->oprmode < 0)
{
if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
{
/* Make sure it stops ringing */
zt_set_hook(p->subs[SUB_REAL].zfd, ZT_RINGOFF);
tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].zfd, -1);
restore_conference(p->oprpeer);
}
break;
}
if (p->radio)
{
p->subs[index].f.frametype = AST_FRAME_CONTROL; p->subs[index].f.frametype = AST_FRAME_CONTROL;
p->subs[index].f.subclass = AST_CONTROL_RADIO_KEY; p->subs[index].f.subclass = AST_CONTROL_RADIO_KEY;
break; break;
@ -4038,7 +4084,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
#endif #endif
case ZT_EVENT_RINGEROFF: case ZT_EVENT_RINGEROFF:
if (p->inalarm) break; if (p->inalarm) break;
if (p->radio) break; if ((p->radio || (p->oprmode < 0))) break;
ast->rings++; ast->rings++;
if ((ast->rings > p->cidrings) && (p->cidspill)) { if ((ast->rings > p->cidrings) && (p->cidspill)) {
ast_log(LOG_WARNING, "Didn't finish Caller-ID spill. Cancelling.\n"); ast_log(LOG_WARNING, "Didn't finish Caller-ID spill. Cancelling.\n");
@ -4065,6 +4111,24 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
case ZT_EVENT_WINKFLASH: case ZT_EVENT_WINKFLASH:
if (p->inalarm) break; if (p->inalarm) break;
if (p->radio) break; if (p->radio) break;
if (p->oprmode < 0) break;
if (p->oprmode > 1)
{
struct zt_params par;
if (ioctl(p->oprpeer->subs[SUB_REAL].zfd, ZT_GET_PARAMS, &par) != -1)
{
if (!par.rxisoffhook)
{
/* Make sure it stops ringing */
zt_set_hook(p->oprpeer->subs[SUB_REAL].zfd, ZT_RINGOFF);
zt_set_hook(p->oprpeer->subs[SUB_REAL].zfd, ZT_RING);
save_conference(p);
tone_zone_play_tone(p->subs[SUB_REAL].zfd, ZT_TONE_RINGTONE);
}
}
break;
}
/* Remember last time we got a flash-hook */ /* Remember last time we got a flash-hook */
gettimeofday(&p->flashtime, NULL); gettimeofday(&p->flashtime, NULL);
switch(mysig) { switch(mysig) {
@ -4267,7 +4331,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
break; break;
case ZT_EVENT_HOOKCOMPLETE: case ZT_EVENT_HOOKCOMPLETE:
if (p->inalarm) break; if (p->inalarm) break;
if (p->radio) break; if ((p->radio || (p->oprmode < 0))) break;
switch(mysig) { switch(mysig) {
case SIG_FXSLS: /* only interesting for FXS */ case SIG_FXSLS: /* only interesting for FXS */
case SIG_FXSGS: case SIG_FXSGS:
@ -4375,7 +4439,7 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
p->subs[index].f.data = NULL; p->subs[index].f.data = NULL;
if ((!p->owner) && (!p->radio)) { if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
/* If nobody owns us, absorb the event appropriately, otherwise /* If nobody owns us, absorb the event appropriately, otherwise
we loop indefinitely. This occurs when, during call waiting, the we loop indefinitely. This occurs when, during call waiting, the
other end hangs up our channel so that it no longer exists, but we other end hangs up our channel so that it no longer exists, but we
@ -4446,7 +4510,7 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
f = &p->subs[index].f; f = &p->subs[index].f;
return f; return f;
} }
if (!p->radio) ast_log(LOG_DEBUG, "Exception on %d, channel %d\n", ast->fds[0],p->channel); if (!(p->radio || (p->oprmode < 0))) ast_log(LOG_DEBUG, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
/* If it's not us, return NULL immediately */ /* If it's not us, return NULL immediately */
if (ast != p->owner) { if (ast != p->owner) {
ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name); ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name);
@ -4487,7 +4551,7 @@ struct ast_frame *zt_read(struct ast_channel *ast)
return NULL; return NULL;
} }
if (p->radio && p->inalarm) return NULL; if ((p->radio || (p->oprmode < 0)) && p->inalarm) return NULL;
p->subs[index].f.frametype = AST_FRAME_NULL; p->subs[index].f.frametype = AST_FRAME_NULL;
p->subs[index].f.datalen = 0; p->subs[index].f.datalen = 0;
@ -4500,7 +4564,7 @@ struct ast_frame *zt_read(struct ast_channel *ast)
p->subs[index].f.data = NULL; p->subs[index].f.data = NULL;
/* make sure it sends initial key state as first frame */ /* make sure it sends initial key state as first frame */
if (p->radio && (!p->firstradio)) if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
{ {
ZT_PARAMS ps; ZT_PARAMS ps;
@ -7539,7 +7603,7 @@ static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch,
return 1; return 1;
} }
#endif #endif
if (!p->radio) if (!(p->radio || (p->oprmode < 0)))
{ {
if (!p->sig || (p->sig == SIG_FXSLS)) if (!p->sig || (p->sig == SIG_FXSLS))
return 1; return 1;

@ -321,6 +321,14 @@ extern struct ast_frame ast_null_frame;
*/ */
#define AST_OPTION_RXGAIN 6 #define AST_OPTION_RXGAIN 6
/* set channel into "Operator Services" mode */
#define AST_OPTION_OPRMODE 7
struct oprmode {
struct ast_channel *peer;
int mode;
} ;
struct ast_option_header { struct ast_option_header {
/* Always keep in network byte order */ /* Always keep in network byte order */
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN

Loading…
Cancel
Save