diff --git a/CHANGES b/CHANGES index b045127bad9252b8bca615460d3eaa0ebddedbc7..476baf55469e6a56f3082df3debe64f492066a47 100644 --- a/CHANGES +++ b/CHANGES @@ -277,7 +277,12 @@ Zaptel channel driver (chan_zap) Changes * CID matching information is now shown when doing 'dialplan show'. * Added zap show version CLI command to chan_zap. * Added setvar support to zapata.conf channel entries. - + * Added two new options: mwimonitor and mwimonitornotify. These options allow + you to enable MWI monitoring on FXO lines. When the MWI state changes, + the script specified in the mwimonitornotify option is executed. An internal + event indicating the new state of the mailbox is also generated, so that + the normal MWI facilities in Asterisk work as usual. + H.323 Changes ------------- * H323 remote hold notification support added (by NOTIFY message diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 37fecd7c0390a3fc1160cf8560f90ac5fe71f7d7..763ed001e474ecbdb6bfc3319daa5d5f3dff50f0 100644 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -225,6 +225,9 @@ static const char config[] = "zapata.conf"; static char defaultcic[64] = ""; static char defaultozz[64] = ""; +/*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */ +static char mwimonitornotify[PATH_MAX] = ""; + static char progzone[10] = ""; static int usedistinctiveringdetection = 0; @@ -552,6 +555,7 @@ static struct zt_pvt { unsigned int usedistinctiveringdetection:1; 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 */ + unsigned int mwimonitor:1; /* Channel state or unavilability flags */ unsigned int inservice:1; unsigned int locallyblocked:1; @@ -608,6 +612,7 @@ static struct zt_pvt { int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */ int cidcwexpire; /*!< When to expire our muting for CID/CW */ unsigned char *cidspill; + struct callerid_state *mwi_state; int cidpos; int cidlen; int ringt; @@ -1844,6 +1849,56 @@ static int save_conference(struct zt_pvt *p) return 0; } +/*! + * \brief Send MWI state change + * + * \arg mailbox_full This is the mailbox associated with the FXO line that the + * MWI state has changed on. + * \arg thereornot This argument should simply be set to 1 or 0, to indicate + * whether there are messages waiting or not. + * + * \return nothing + * + * This function does two things: + * + * 1) It generates an internal Asterisk event notifying any other module that + * cares about MWI that the state of a mailbox has changed. + * + * 2) It runs the script specified by the mwimonitornotify option to allow + * some custom handling of the state change. + */ +static void notify_message(char *mailbox_full, int thereornot) +{ + char s[sizeof(mwimonitornotify) + 80]; + struct ast_event *event; + char *mailbox, *context; + + /* Strip off @default */ + context = mailbox = ast_strdupa(mailbox_full); + strsep(&context, "@"); + if (ast_strlen_zero(context)) + context = "default"; + + if (!(event = ast_event_new(AST_EVENT_MWI, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, + AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot, + AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot, + AST_EVENT_IE_END))) { + return; + } + + ast_event_queue_and_cache(event, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, + AST_EVENT_IE_END); + + if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) { + snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot); + ast_safe_system(s); + } +} + static int restore_conference(struct zt_pvt *p) { int res; @@ -7328,7 +7383,14 @@ static void *do_monitor(void *data) pfds[count].events = POLLPRI; pfds[count].revents = 0; /* Message waiting or r2 channels also get watched for reading */ - if (i->cidspill) + if (i->mwimonitor && (i->sig & __ZT_SIG_FXS) && !i->mwi_state) { + if (!i->mwi_state) { + i->mwi_state = callerid_new(i->cid_signalling); + bump_gains(i); + zt_setlinear(i->subs[SUB_REAL].zfd, 0); + } + } + if (i->cidspill || i->mwi_state) pfds[count].events |= POLLIN; count++; } @@ -7417,29 +7479,57 @@ static void *do_monitor(void *data) i = i->next; continue; } - if (!i->cidspill) { + if (!i->cidspill && !i->mwi_state) { ast_log(LOG_WARNING, "Whoa.... I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].zfd); i = i->next; continue; } res = read(i->subs[SUB_REAL].zfd, buf, sizeof(buf)); if (res > 0) { - /* We read some number of bytes. Write an equal amount of data */ - if (res > i->cidlen - i->cidpos) - res = i->cidlen - i->cidpos; - res2 = write(i->subs[SUB_REAL].zfd, i->cidspill + i->cidpos, res); - if (res2 > 0) { - i->cidpos += res2; - if (i->cidpos >= i->cidlen) { - ast_free(i->cidspill); - i->cidspill = 0; - i->cidpos = 0; - i->cidlen = 0; - } - } else { - ast_log(LOG_WARNING, "Write failed: %s\n", strerror(errno)); - i->msgstate = -1; - } + if (i->mwi_state) { + if (i->cid_signalling == CID_SIG_V23_JP) { + res = callerid_feed_jp(i->mwi_state, (unsigned char *)buf, res, AST_LAW(i)); + } else { + res = callerid_feed(i->mwi_state, (unsigned char *)buf, res, AST_LAW(i)); + } + if (res < 0) { + ast_log(LOG_WARNING, "MWI CallerID feed failed: %s!\n", strerror(errno)); + callerid_free(i->mwi_state); + i->mwi_state = NULL; + } else if (res) { + char *name, *number; + int flags; + callerid_get(i->mwi_state, &number, &name, &flags); + if (flags & CID_MSGWAITING) { + ast_log(LOG_NOTICE, "MWI: Channel %d message waiting!\n",i->channel); + notify_message(i->mailbox, 1); + } else if (flags & CID_NOMSGWAITING) { + ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting!\n",i->channel); + notify_message(i->mailbox, 0); + } else + ast_log(LOG_NOTICE, "MWI: Channel %d status unknown\n", i->channel); + callerid_free(i->mwi_state); + i->mwi_state = NULL; + } + } else if (i->cidspill) { + /* We read some number of bytes. Write an equal amount of data */ + if (res > i->cidlen - i->cidpos) + res = i->cidlen - i->cidpos; + res2 = write(i->subs[SUB_REAL].zfd, i->cidspill + i->cidpos, res); + if (res2 > 0) { + i->cidpos += res2; + if (i->cidpos >= i->cidlen) { + free(i->cidspill); + i->cidspill = 0; + i->cidpos = 0; + i->cidlen = 0; + } + } else { + ast_log(LOG_WARNING, "Write failed: %s\n", strerror(errno)); + i->msgstate = -1; + } + } + } else { ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno)); } @@ -7458,6 +7548,12 @@ static void *do_monitor(void *data) i = i->next; continue; } + if (i->mwi_state) { + callerid_free(i->mwi_state); + i->mwi_state = NULL; + zt_setlinear(i->subs[SUB_REAL].zfd, i->subs[SUB_REAL].linear); + restore_gains(i); + } res = zt_get_event(i->subs[SUB_REAL].zfd); ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel); /* Don't hold iflock while handling init events */ @@ -7973,6 +8069,7 @@ static struct zt_pvt *mkintf(int channel, struct zt_chan_conf conf, struct zt_pr #endif tmp->immediate = conf.chan.immediate; tmp->transfertobusy = conf.chan.transfertobusy; + tmp->mwimonitor = conf.chan.mwimonitor; tmp->sig = conf.chan.sig; tmp->outsigmod = conf.chan.outsigmod; tmp->radio = conf.chan.radio; @@ -11339,6 +11436,7 @@ static char *zap_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num); ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton); ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name); + ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none")); if (tmp->vars) { struct ast_variable *v; ast_cli(a->fd, "Variables:\n"); @@ -12512,6 +12610,8 @@ static int process_zap(struct zt_chan_conf *confp, struct ast_variable *v, int r confp->chan.immediate = ast_true(v->value); } else if (!strcasecmp(v->name, "transfertobusy")) { confp->chan.transfertobusy = ast_true(v->value); + } else if (!strcasecmp(v->name, "mwimonitor")) { + confp->chan.mwimonitor = ast_true(v->value) ? 1 : 0; } else if (!strcasecmp(v->name, "cid_rxgain")) { if (sscanf(v->value, "%f", &confp->chan.cid_rxgain) != 1) { ast_log(LOG_WARNING, "Invalid cid_rxgain: %s\n", v->value); @@ -13074,7 +13174,9 @@ static int process_zap(struct zt_chan_conf *confp, struct ast_variable *v, int r ast_copy_string(defaultcic, v->value, sizeof(defaultcic)); } else if (!strcasecmp(v->name, "defaultozz")) { ast_copy_string(defaultozz, v->value, sizeof(defaultozz)); - } + } else if (!strcasecmp(v->name, "mwimonitornotify")) { + ast_copy_string(mwimonitornotify, v->value, sizeof(mwimonitornotify)); + } } else if (!skipchannels) ast_log(LOG_WARNING, "Ignoring %s\n", v->name); } diff --git a/configs/zapata.conf.sample b/configs/zapata.conf.sample index c2ee8e454497b3bf7b2e35aed0ad11076b9a245b..a8577b610c45597de820112eb0d9fd36cae42aa2 100644 --- a/configs/zapata.conf.sample +++ b/configs/zapata.conf.sample @@ -337,6 +337,19 @@ usecallerid=yes ; ;hidecallerid=yes ; +; The following option enables receiving MWI on FXO lines. The default +; value is no. When this is enabled, and MWI notification indicates on or off, +; the script specified by the mwimonitornotify option is executed. +; +;mwimonitor=no +; +; This option is used in conjunction with mwimonitor. This will get executed +; when incoming MWI state changes. The script is passed 2 arguments. The +; first is the corresponding mailbox, and the second is 1 or 0, indicating if +; there are messages waiting or not. +; +;mwimonitornotify=/usr/local/bin/zapnotify.sh +; ; Whether or not to enable call waiting on internal extensions ; With this set to 'yes', busy extensions will hear the call-waiting ; tone, and can use hook-flash to switch between callers. The Dial() diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h index efc8e874adbba7f5ad17353dbd022a81211e3ccc..b7568c27fc684af4a6bb0e8cad0afd21ad1e8980 100644 --- a/include/asterisk/callerid.h +++ b/include/asterisk/callerid.h @@ -49,6 +49,8 @@ #define CID_PRIVATE_NUMBER (1 << 1) #define CID_UNKNOWN_NAME (1 << 2) #define CID_UNKNOWN_NUMBER (1 << 3) +#define CID_MSGWAITING (1 << 4) +#define CID_NOMSGWAITING (1 << 5) #define CID_SIG_BELL 1 #define CID_SIG_V23 2 diff --git a/main/callerid.c b/main/callerid.c index 04b45ab4f3ed33bec616945fe9f17a2bed17fa0c..c1d5e80b9d640ffba5195aaefdce8f57dcae785e 100644 --- a/main/callerid.c +++ b/main/callerid.c @@ -555,7 +555,7 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int cid->sawflag = 2; break; case 2: /* Get lead-in */ - if ((b == 0x04) || (b == 0x80)) { + if ((b == 0x04) || (b == 0x80) || (b == 0x06) || (b == 0x82)) { cid->type = b; cid->sawflag = 3; cid->cksum = b; @@ -591,8 +591,10 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int cid->number[0] = '\0'; cid->name[0] = '\0'; + /* Update flags */ + cid->flags = 0; /* If we get this far we're fine. */ - if (cid->type == 0x80) { + if ((cid->type == 0x80) || (cid->type == 0x82)) { /* MDMF */ /* Go through each element and process */ for (x = 0; x < cid->pos;) { @@ -626,6 +628,13 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int memcpy(cid->name, cid->rawdata + x + 1, res); cid->name[res] = '\0'; break; + case 11: /* Message Waiting */ + res = cid->rawdata[x + 1]; + if (res) + cid->flags |= CID_MSGWAITING; + else + cid->flags |= CID_NOMSGWAITING; + break; case 17: /* UK: Call type, 1=Voice Call, 2=Ringback when free, 129=Message waiting */ case 19: /* UK: Network message system status (Number of messages waiting) */ case 22: /* Something French */ @@ -643,12 +652,17 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int x += cid->rawdata[x]; x++; } + } else if (cid->type == 0x6) { + /* VMWI SDMF */ + if (cid->rawdata[2] == 0x42) { + cid->flags |= CID_MSGWAITING; + } else if (cid->rawdata[2] == 0x6f) { + cid->flags |= CID_NOMSGWAITING; + } } else { /* SDMF */ ast_copy_string(cid->number, cid->rawdata + 8, sizeof(cid->number)); } - /* Update flags */ - cid->flags = 0; if (!strcmp(cid->number, "P")) { strcpy(cid->number, ""); cid->flags |= CID_PRIVATE_NUMBER;