Added "Operator Services" connection mode for Zap channels, and the 'O' option
authorJim Dixon <telesistant@hotmail.com>
Sat, 22 Apr 2006 11:30:06 +0000 (11:30 +0000)
committerJim Dixon <telesistant@hotmail.com>
Sat, 22 Apr 2006 11:30:06 +0000 (11:30 +0000)
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

apps/app_dial.c
channels/chan_zap.c
include/asterisk/frame.h

index f4bdd11..bdf7f7f 100644 (file)
@@ -154,6 +154,16 @@ static char *descrip =
 "    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"
 "           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"
 "           without memory.\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_CALLER_MONITOR =    (1 << 22),
        OPT_GOTO =              (1 << 23),
+       OPT_OPERMODE =          (1 << 24),
 } dial_exec_option_flags;
 
 #define DIAL_STILLGOING                        (1 << 30)
@@ -227,6 +238,7 @@ enum {
        OPT_ARG_CALLEE_MACRO,
        OPT_ARG_PRIVACY,
        OPT_ARG_DURATION_STOP,
+       OPT_ARG_OPERMODE,
        /* note: this entry _MUST_ be the last one in the enum */
        OPT_ARG_ARRAY_SIZE,
 } 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('n', OPT_SCREEN_NOINTRO),
        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('p', OPT_SCREENING),
        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 privcid[256];
        char *parse;
+       int opermode = 0;
        AST_DECLARE_APP_ARGS(args,
                             AST_APP_ARG(peers);
                             AST_APP_ARG(timeout);
@@ -774,6 +788,14 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                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])) {
                calldurationlimit = atoi(opt_args[OPT_ARG_DURATION_STOP]);
                if (!calldurationlimit) {
@@ -1483,6 +1505,17 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                                res = -1;
                                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);
                        time(&end_time);
                        {
index c7341d2..13d26e5 100644 (file)
@@ -543,6 +543,8 @@ static struct zt_pvt {
        int sig;                                        /*!< Signalling style */
        int radio;                                      /*!< radio type */
        int outsigmod;                                  /*!< Outbound Signalling style (modifier) */
+       int oprmode;                                    /*!< "Operator Services" mode */
+       struct zt_pvt *oprpeer;                         /*!< "Operator Services" peer tech_pvt ptr */
        float rxgain;
        float txgain;
        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;
        }
        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 */
                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);
 #endif
                                /* 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);
                                else
                                        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->cidcwexpire = 0;
+       p->oprmode = 0;
        ast->tech_pvt = NULL;
        ast_mutex_unlock(&p->lock);
        ast_mutex_lock(&usecnt_lock);
@@ -2717,7 +2720,7 @@ static int zt_answer(struct ast_channel *ast)
        if (index < 0)
                index = SUB_REAL;
        /* nothing to do if a radio channel */
-       if (p->radio) {
+       if ((p->radio || (p->oprmode < 0))) {
                ast_mutex_unlock(&p->lock);
                return 0;
        }
@@ -2803,7 +2806,9 @@ static int zt_setoption(struct ast_channel *chan, int option, void *data, int da
        signed char *scp;
        int x;
        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 */
        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)
                        ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", p->channel, x);
                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;
 
@@ -3685,7 +3706,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                        break;  
                case ZT_EVENT_DIALCOMPLETE:
                        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) {
                                ast_log(LOG_DEBUG, "ZT_DIALING ioctl failed on %s\n",ast->name);
                                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;
                                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) {
                        case SIG_FXOLS:
                        case SIG_FXOGS:
@@ -3869,11 +3903,23 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                        break;
                case ZT_EVENT_RINGOFFHOOK:
                        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.subclass = AST_CONTROL_RADIO_KEY;
                                break;
-                       }
+                       }
                        /* for E911, its supposed to wait for offhook then dial
                           the second half of the dial string */
                        if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
@@ -4038,7 +4084,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
 #endif                 
                case ZT_EVENT_RINGEROFF:
                        if (p->inalarm) break;
-                       if (p->radio) break;
+                       if ((p->radio || (p->oprmode < 0))) break;
                        ast->rings++;
                        if ((ast->rings > p->cidrings) && (p->cidspill)) {
                                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:
                        if (p->inalarm) 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 */
                        gettimeofday(&p->flashtime, NULL);
                        switch(mysig) {
@@ -4267,7 +4331,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                        break;
                case ZT_EVENT_HOOKCOMPLETE:
                        if (p->inalarm) break;
-                       if (p->radio) break;
+                       if ((p->radio || (p->oprmode < 0))) break;
                        switch(mysig) {
                        case SIG_FXSLS:  /* only interesting for FXS */
                        case SIG_FXSGS:
@@ -4375,7 +4439,7 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
        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
                   we loop indefinitely.  This occurs when, during call waiting, the
                   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;
                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 (ast != p->owner) {
                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;
        }
        
-       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.datalen = 0;
@@ -4500,7 +4564,7 @@ struct ast_frame  *zt_read(struct ast_channel *ast)
        p->subs[index].f.data = NULL;
        
        /* 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;
 
@@ -7539,7 +7603,7 @@ static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch,
                                return 1;
                }
 #endif
-               if (!p->radio)
+               if (!(p->radio || (p->oprmode < 0)))
                {
                        if (!p->sig || (p->sig == SIG_FXSLS))
                                return 1;
index 099e200..dd1a417 100644 (file)
@@ -321,6 +321,14 @@ extern struct ast_frame ast_null_frame;
 */
 #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 {
        /* Always keep in network byte order */
 #if __BYTE_ORDER == __BIG_ENDIAN