diff -pruN asterisk-trunk/channels/chan_zap.c asterisk-trunk-pc/channels/chan_zap.c --- asterisk-trunk/channels/chan_zap.c 2007-03-13 09:51:57.697868238 +1100 +++ asterisk-trunk-pc/channels/chan_zap.c 2007-03-13 10:08:48.141006890 +1100 @@ -535,6 +535,7 @@ static struct zt_pvt { unsigned int setup_ack:1; #endif unsigned int use_smdi:1; /* Whether to use SMDI on this channel */ + unsigned int smdimatchterm:1; /* Whether to match Zap channel number to SMDI desk terminal */ struct ast_smdi_interface *smdi_iface; /* The serial port to listen for SMDI data on */ struct zt_distRings drings; @@ -6379,7 +6380,23 @@ static void *ss_thread(void *data) #endif /* check for SMDI messages */ if (p->use_smdi && p->smdi_iface) { - smdi_msg = ast_smdi_md_message_wait(p->smdi_iface, SMDI_MD_WAIT_TIMEOUT); + char *ptr1, *ptr2; + char cnbuf[BUFSIZ]; + + ast_copy_string(cnbuf, chan->name, BUFSIZ); + + if (p->smdimatchterm) { + if ((ptr1 = strrchr(cnbuf, '/'))) { + ptr1++; + if ((ptr2 = strchr(ptr1, '-'))) { + *ptr2 = 0; + ast_log(LOG_DEBUG, "Looking for SMDI message in queue for MD terminal %d\n", atoi(ptr1)); + smdi_msg = ast_smdi_md_message_for_term_wait(p->smdi_iface, atoi(ptr1), SMDI_MD_WAIT_TIMEOUT); + } + } + } else { + smdi_msg = ast_smdi_md_message_wait(p->smdi_iface, SMDI_MD_WAIT_TIMEOUT); + } if (smdi_msg != NULL) { ast_copy_string(chan->exten, smdi_msg->fwd_st, sizeof(chan->exten)); @@ -6390,7 +6407,7 @@ static void *ss_thread(void *data) pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u"); if (option_debug) - ast_log(LOG_DEBUG, "Recieved SMDI message on %s\n", chan->name); + ast_log(LOG_DEBUG, "Found SMDI message for %s: TERM='%s', CALLST='%s', FWDST='%s'\n", chan->name, smdi_msg->mesg_desk_term, smdi_msg->calling_st, smdi_msg->fwd_st); } else { ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n"); } @@ -11875,6 +11892,8 @@ static int process_zap(struct zt_chan_co confp->chan.use_smdi = ast_true(v->value); } else if (!strcasecmp(v->name, "smdiport")) { ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port)); + } else if (!strcasecmp(v->name, "smdiuseterm")) { + confp->chan.smdiuseterm = ast_true(v->value); } else if (!strcasecmp(v->name, "transfer")) { confp->chan.transfer = ast_true(v->value); } else if (!strcasecmp(v->name, "canpark")) { diff -pruN asterisk-trunk/include/asterisk/smdi.h asterisk-trunk-pc/include/asterisk/smdi.h --- asterisk-trunk/include/asterisk/smdi.h 2007-03-13 09:52:09.366967272 +1100 +++ asterisk-trunk-pc/include/asterisk/smdi.h 2007-03-13 09:54:20.851349351 +1100 @@ -42,6 +42,8 @@ #define SMDI_MAX_STATION_NUM_LEN 10 #define SMDI_MAX_FILENAME_LEN 256 +#define MWI_PREFIX_LEN 50 + /*! * \brief An SMDI message waiting indicator message. * @@ -99,13 +101,16 @@ struct ast_smdi_interface { pthread_t thread; struct termios mode; int msdstrip; + char mwiprefix[MWI_PREFIX_LEN]; long msg_expiry; }; /* MD message queue functions */ struct ast_smdi_md_message *ast_smdi_md_message_pop(struct ast_smdi_interface *iface); +struct ast_smdi_md_message *ast_smdi_md_message_for_term_pop(struct ast_smdi_interface *iface, int term); struct ast_smdi_md_message *ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout); +struct ast_smdi_md_message *ast_smdi_md_message_for_term_wait(struct ast_smdi_interface *iface, int term, int timeout); void ast_smdi_md_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_md_message *msg); /* MWI message queue functions */ diff -pruN asterisk-trunk/.lastclean asterisk-trunk-pc/.lastclean --- asterisk-trunk/.lastclean 1970-01-01 10:00:00.000000000 +1000 +++ asterisk-trunk-pc/.lastclean 2007-03-13 10:20:51.681131948 +1100 @@ -0,0 +1 @@ +30 diff -pruN asterisk-trunk/res/res_smdi.c asterisk-trunk-pc/res/res_smdi.c --- asterisk-trunk/res/res_smdi.c 2007-03-13 09:52:22.064163134 +1100 +++ asterisk-trunk-pc/res/res_smdi.c 2007-03-13 10:14:17.760042027 +1100 @@ -93,7 +93,7 @@ int ast_smdi_mwi_set(struct ast_smdi_int { FILE *file; int i; - + file = fopen(iface->name, "w"); if(!file) { ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno)); @@ -107,6 +107,9 @@ int ast_smdi_mwi_set(struct ast_smdi_int for(i = 0; i < iface->msdstrip; i++) fprintf(file, "0"); + if (iface->mwiprefix[0] != 0) + fprintf(file, "%s", iface->mwiprefix); + fprintf(file, "%s!\x04", mailbox); fclose(file); @@ -125,7 +128,7 @@ int ast_smdi_mwi_unset(struct ast_smdi_i { FILE *file; int i; - + file = fopen(iface->name, "w"); if(!file) { ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno)); @@ -139,6 +142,9 @@ int ast_smdi_mwi_unset(struct ast_smdi_i for(i = 0; i < iface->msdstrip; i++) fprintf(file, "0"); + if (iface->mwiprefix[0] != 0) + fprintf(file, "%s", iface->mwiprefix); + fprintf(file, "%s!\x04", mailbox); fclose(file); @@ -213,6 +219,53 @@ struct ast_smdi_md_message *ast_smdi_md_ return md_msg; } +/*! + * \brief Get the next SMDI message for terminal "term" from the queue. + * \param iface a pointer to the interface to use. + * \param term an integer to filter messages by desk terminal + * + * This function pulls the first unexpired message from the SMDI message queue + * on the specified interface that match desk terminal "term". It will purge + * all expired SMDI messages before returning. + * + * \return the next SMDI message, or NULL if there were no pending messages. + */ +struct ast_smdi_md_message *ast_smdi_md_message_for_term_pop(struct ast_smdi_interface *iface, int term) +{ + struct ast_smdi_md_message *md_msg = NULL; + struct timeval now; + long elapsed = 0; + + /* purge old messages */ + now = ast_tvnow(); + + ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, 1, { + ASTOBJ_RDLOCK(iterator); + + elapsed = ast_tvdiff_ms(now, iterator->timestamp); + + if (elapsed > iface->msg_expiry) { + /* found an expired message */ + ASTOBJ_MARK(iterator); + ast_log(LOG_NOTICE, "Purged expired message from %s SMDI MD message queue. Message was %ld milliseconds too old.\n", + iface->name, elapsed - iface->msg_expiry); + } else { + if (term == atoi(iterator->mesg_desk_term)) { + ASTOBJ_MARK(iterator); + md_msg = ASTOBJ_REF(iterator); + ASTOBJ_UNLOCK(iterator); + break; + } + } + + ASTOBJ_UNLOCK(iterator); + } ); + + ASTOBJ_CONTAINER_PRUNE_MARKED(&iface->md_q, ast_smdi_md_message_destroy); + + return md_msg; +} + /*! * \brief Get the next SMDI message from the queue. * \param iface a pointer to the interface to use. @@ -245,6 +298,39 @@ extern struct ast_smdi_md_message *ast_s } /*! + * \brief Get the next SMDI message from the queue + * \param iface a pointer to the interface to use. + * \param term an integer to filter messages by desk terminal + * \param timeout the time to wait before returning in milliseconds. + * + * This function pulls a message from the SMDI message queue on the specified + * interface. If no message is available this function will wait the specified + * amount of time before returning. Will only pop messages that match the + * terminal "term". + * + * \return the next SMDI message, or NULL if there were no pending messages and + * the timeout has expired. + */ +extern struct ast_smdi_md_message *ast_smdi_md_message_for_term_wait(struct ast_smdi_interface *iface, int term, int timeout) +{ + struct timeval start; + long diff = 0; + struct ast_smdi_md_message *msg; + + start = ast_tvnow(); + while (diff < timeout) { + + if ((msg = ast_smdi_md_message_for_term_pop(iface, term))) + return msg; + + /* check timeout */ + diff = ast_tvdiff_ms(ast_tvnow(), start); + } + + return (ast_smdi_md_message_for_term_pop(iface, term)); +} + +/*! * \brief Get the next SMDI message from the queue. * \param iface a pointer to the interface to use. * @@ -414,7 +500,7 @@ static void *smdi_read(void *iface_p) md_msg->timestamp = ast_tvnow(); ast_smdi_md_message_push(iface, md_msg); if (option_debug) - ast_log(LOG_DEBUG, "Recieved SMDI MD message on %s\n", iface->name); + ast_log(LOG_DEBUG, "Received SMDI MD message on %s: TERM='%s', CALLST='%s', FWDST='%s'\n", iface->name, md_msg->mesg_desk_term, md_msg->calling_st, md_msg->fwd_st); ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); @@ -458,7 +544,7 @@ static void *smdi_read(void *iface_p) mwi_msg->timestamp = ast_tvnow(); ast_smdi_mwi_message_push(iface, mwi_msg); if (option_debug) - ast_log(LOG_DEBUG, "Recieved SMDI MWI message on %s\n", iface->name); + ast_log(LOG_DEBUG, "Received SMDI MWI message on %s: FWDST='%s', CAUSE='%s'\n", iface->name, mwi_msg->fwd_st, mwi_msg->cause); ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); } else { @@ -531,6 +617,7 @@ static int smdi_load(int reload) int stopbits = 0; /* One stop bit */ int msdstrip = 0; /* strip zero digits */ + char mwiprefix[MWI_PREFIX_LEN]; long msg_expiry = SMDI_MSG_EXPIRY_TIME; conf = ast_config_load(config_file); @@ -551,6 +638,8 @@ static int smdi_load(int reload) if (reload) ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces); + mwiprefix[0] = 0; + for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) { if (!strcasecmp(v->name, "baudrate")) { if (!strcasecmp(v->value, "9600")) @@ -573,6 +662,16 @@ static int smdi_load(int reload) ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); msdstrip = 0; } + } else if (!strcasecmp(v->name, "mwiprefix")) { + char *p; + int parsed = 1; + for (p = v->value; *p != 0; p++) + if (!isdigit(*p)) + parsed = 0; + if (parsed) { + strncpy(mwiprefix, v->value, MWI_PREFIX_LEN); + } else + ast_log(LOG_NOTICE, "Invalid MWI prefix value '%s' in %s (line %d)\n", v->value, config_file, v->lineno); } else if (!strcasecmp(v->name, "msgexpirytime")) { if (!sscanf(v->value, "%ld", &msg_expiry)) { ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno); @@ -675,6 +774,9 @@ static int smdi_load(int reload) /* set the msdstrip */ iface->msdstrip = msdstrip; + /* set the mwi prefix (added before mbox extension for outgoing MWI) */ + strncpy(iface->mwiprefix, mwiprefix, MWI_PREFIX_LEN); + /* set the message expiry time */ iface->msg_expiry = msg_expiry;