Index: channels/chan_zap.c =================================================================== --- channels/chan_zap.c (revision 48463) +++ channels/chan_zap.c (working copy) @@ -208,6 +208,9 @@ #define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP) +#define OMD_MWI 0 /*!< Send On-hook mwi message */ +#define OMD_JUMP 1 /*!< Jump to mboxchanged context */ + static char context[AST_MAX_CONTEXT] = "default"; static char cid_num[256] = ""; static char cid_name[256] = ""; @@ -232,6 +235,8 @@ static int cur_signalling = -1; static int cur_outsignalling = -1; +static int on_mbox_change = OMD_MWI; /*!< what will we do when we find out that mailbox state changed for that FXS channel? */ + static ast_group_t cur_group = 0; static ast_group_t cur_callergroup = 0; static ast_group_t cur_pickupgroup = 0; @@ -639,6 +644,7 @@ unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */ unsigned int use_callingpres:1; /*!< Whether to use the callingpres the calling switch sends */ unsigned int usedistinctiveringdetection:1; + unsigned int callerid_ismwi:1; /*!< Whether or not to use mwi instead of caller id on this channel */ unsigned int zaptrcallerid:1; /*!< should we use the callerid from incoming call on zap transfer or not */ unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */ /* Channel state or unavilability flags */ @@ -691,6 +697,7 @@ time_t guardtime; /*!< Must wait this much time before using for new call */ int cid_signalling; /*!< CID signalling type bell202 or v23 */ int cid_start; /*!< CID start indicator, polarity or ring */ + int on_mbox_change; /*!< What to do when mailbox state changed */ int callingpres; /*!< The value of callling presentation that we're going to use when placing a PRI call */ int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */ int cidcwexpire; /*!< When to expire our muting for CID/CW */ @@ -1923,6 +1930,7 @@ struct zt_pvt *p = ast->tech_pvt; int x, res, index,mysig; char *c, *n, *l; + const char* has_vm; #ifdef HAVE_PRI char *s = NULL; #endif @@ -1977,7 +1985,14 @@ } p->callwaitcas = 0; if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) { - p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p)); + + /* is this channel configured to send callerid info or message waiting indication ? */ + if(p->callerid_ismwi) { + has_vm = pbx_builtin_getvar_helper(ast, "HASVOICEMAIL"); + p->cidlen = ast_vmwi_generate(p->cidspill, (ast_true(has_vm)? 1 : 0), ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p)); + } else { + p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p)); + } p->cidpos = 0; send_callerid(p); } @@ -2926,7 +2941,7 @@ #endif restart_monitor(); } - + p->callerid_ismwi = 0; p->callwaitingrepeat = 0; p->cidcwexpire = 0; p->oprmode = 0; @@ -4038,7 +4053,12 @@ case SIG_FXOGS: case SIG_FXOKS: p->onhooktime = time(NULL); - p->msgstate = -1; + + /* only reset message state if we are in 'send mwi' mode because mbox state didn't change */ + if(p->on_mbox_change == OMD_MWI) { + p->msgstate = -1; + } + /* Check for some special conditions regarding call waiting */ if (index == SUB_REAL) { /* The normal line was hung up */ @@ -4342,6 +4362,13 @@ p->subs[index].f.subclass = AST_CONTROL_RINGING; break; case ZT_EVENT_RINGERON: + /* + For MWI indication we should stop the ringer after cidspill is sent + because rings are not allowed after mwi cidspill + */ + if((ast->rings == p->cidrings) && p->callerid_ismwi) { + zt_set_hook(p->subs[index].zfd, ZT_RINGOFF); + } break; case ZT_EVENT_NOALARM: p->inalarm = 0; @@ -5745,7 +5772,13 @@ int len = 0; int res; int index; - + + /* variables for extra callerid handling*/ + int cidtype; + char *ciddata = NULL; + int cidcount; + int cidlen; + if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s'\n", chan->name); index = zt_get_index(chan, p, 1); @@ -6857,6 +6890,57 @@ if (smdi_msg) ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy); + /* + Here we can put custom caller id handling + callerid.h and callerid.c are not related to channels + that's why some processing should be done outside + The flag CID_UNKNOWN_DATA tells us that callerid_feed messed something + */ + if(flags & CID_UNKNOWN_DATA) { + + + /* So get the cidspill raw data */ + callerid_get_rawdata(cs, &ciddata, &cidlen, &cidtype); + + /* We ignored voice mail information */ + if(cidtype == CID_TYPE_MDMF_CLI_VM) { + + for(cidcount=0; cidcount < cidlen;) { + + /* Got 0x0b => that's VoiceMail tag*/ + if(ciddata[cidcount++] == 0x0b) { + + /* length should be always 1 or ignore it */ + if(ciddata[cidcount] == 0x01) { + + /* two values possible */ + if((ciddata[cidcount+1] == (char)0xFF) || (ciddata[cidcount+1] == 0x00)) { + + pbx_builtin_setvar_helper(chan, "HASVOICEMAIL", (ciddata[cidcount+1]? "1":"0")); + + /* does mwi extension exists ? */ + + if (ast_exists_extension(chan, chan->context, "mwi", 1, chan->cid.cid_num)) { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Starting %s from mwi extension\n", chan->name); + + /* starting extension for channel will be "mwi" */ + strcpy(chan->exten, "mwi"); + + } else { + ast_log(LOG_NOTICE, "Message Waiting Indication detected, but no 'mwi'extension for %s\n", chan->name); + } + } + } + /* Ok we got info that we needed don't process the entire loop then */ + break; + } + /* go to next TagLengthValue info */ + cidcount += ciddata[cidcount] + 1; + } + } + } + if (cs) callerid_free(cs); @@ -7086,6 +7170,10 @@ char buf[1024]; struct pollfd *pfds=NULL; int lastalloc = -1; + char localtype[AST_MAX_CONTEXT+15]; + int state; + struct ast_channel *chan; + /* This thread monitors all the frame relay interfaces which are not yet in use (and thus do not have a separate thread) indefinitely */ /* From here on out, we die whenever asked */ @@ -7156,8 +7244,9 @@ if (!found && ((i == last) || ((i == iflist) && !last))) { last = i; if (last) { - if (!last->cidspill && !last->owner && !ast_strlen_zero(last->mailbox) && (thispass - last->onhooktime > 3) && - (last->sig & __ZT_SIG_FXO)) { + /* mwi send mode, FXS channel not owned, without cidspill that has been hangedup 3 seconds ago at least (so as to be sure we won't send two cidspills at the same time) */ + if ((i->on_mbox_change == OMD_MWI) && !last->cidspill && !last->owner && !ast_strlen_zero(last->mailbox) && + (thispass - last->onhooktime > 3) && (last->sig & __ZT_SIG_FXO)) { res = ast_app_has_voicemail(last->mailbox, NULL); if (last->msgstate != res) { int x; @@ -7171,7 +7260,7 @@ /* Turn on on hook transfer for 4 seconds */ x = 4000; ioctl(last->subs[SUB_REAL].zfd, ZT_ONHOOKTRANSFER, &x); - last->cidlen = vmwi_generate(last->cidspill, res, 1, AST_LAW(last)); + last->cidlen = vmwi_generate(last->cidspill, res, 1, AST_LAW(last), NULL, NULL, 0); last->cidpos = 0; last->msgstate = res; last->onhooktime = thispass; @@ -7183,6 +7272,60 @@ } } } + /* we are in mwi jump mode */ + if(i->on_mbox_change == OMD_JUMP) { + /* make sure user has hangedup since 3 seconds at least... maybe not necesssary but actually it's not a bad user experience */ + if(!i->owner && !ast_strlen_zero(i->mailbox) && (thispass - i->onhooktime > 3) && (i->sig & __ZT_SIG_FXO)) { + res = ast_app_has_voicemail(i->mailbox, NULL); + + if (i->msgstate != res) { + + ast_mutex_unlock(&iflock); + + /* + workarround so as to let the i channel free, we start the pbx on a local channel + that way i is not owned and can be dialed from pbx extension + mboxchanged must exist in i's context + + Take care of not anwering any call made from this channel in the dialplan as it will loop on mboxchanged extension + */ + snprintf(localtype, sizeof(localtype), "mboxchanged@%s/n", i->context); + + + + chan = ast_request("Local", AST_FORMAT_ALAW | AST_FORMAT_ULAW, localtype, &state); + + if(chan) { + + /* That variable should be inherited at least once */ + pbx_builtin_setvar_helper(chan, "_HASVOICEMAIL", (res? "1":"0")); + + /* choose mboxchanged as starting point since local channel would point at 's' by default */ + strcpy(chan->exten, "mboxchanged"); + + if(ast_pbx_start(chan)) { + ast_log(LOG_WARNING, "Couldn't start PBX on %s\n", chan->name); + ast_hangup(chan); + } + + + } else { + /* We failed to request that channel, maybe because mboxchanged extension doest not exist */ + ast_log(LOG_WARNING, "MailBox changed it's state but couldn't get a channel, does 'mboxchanged' extension exists for Zap/%d?\n", i->channel); + } + + /* acknowledge this try, won't try again even if failed */ + i->msgstate = res; + ast_mutex_lock(&iflock); + + /* + we intentionnaly let i to be processed as normal so as to get events in case + of going off hook... => mboxchanged exten should correctly handle busy states + */ + + } + } + } if ((i->subs[SUB_REAL].zfd > -1) && i->sig) { if (i->radio && !i->owner) { @@ -7797,6 +7940,8 @@ tmp->use_callerid = use_callerid; tmp->cid_signalling = cid_signalling; tmp->cid_start = cid_start; + tmp->on_mbox_change = on_mbox_change; + tmp->callerid_ismwi = 0; tmp->zaptrcallerid = zaptrcallerid; tmp->restrictcid = restrictcid; tmp->use_callingpres = use_callingpres; @@ -8287,6 +8432,15 @@ if (opt == 'c') { /* Confirm answer */ p->confirmanswer = 1; + } else if (opt == 'm') { + /* Instead of sending callerid only we will be sending message waiting indicator also */ + p->callerid_ismwi = 1; + + /* we can use distinctivering with mwi */ + if(res >= 3) { + p->distinctivering = y; + } + } else if (opt == 'r') { /* Distinctive ring */ if (res < 3) @@ -11805,6 +11959,16 @@ cid_start = CID_START_POLARITY; else if (ast_true(v->value)) cid_start = CID_START_RING; + } else if(!strcasecmp(v->name, "onmboxchange")) { + if(!strcasecmp(v->value, "jumptomboxchanged")) { + on_mbox_change = OMD_JUMP; + } else if(!strcasecmp(v->value, "sendmwi")){ + on_mbox_change = OMD_MWI; + } else { + /* i think it's a good practice to produce a warning when value is unknown */ + ast_log(LOG_WARNING, "Unknown onmboxchange value '%s', assuming 'sendmwi'\n", v->value); + on_mbox_change = OMD_MWI; + } } else if (!strcasecmp(v->name, "threewaycalling")) { threewaycalling = ast_true(v->value); } else if (!strcasecmp(v->name, "cancallforward")) {