Merged revisions 198311 via svnmerge from
[asterisk/asterisk.git] / res / res_smdi.c
index 3a8a5f4..d1d40f0 100644 (file)
@@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
 #include "asterisk/utils.h"
+#define AST_API_MODULE
 #include "asterisk/smdi.h"
 #include "asterisk/config.h"
 #include "asterisk/astobj.h"
@@ -305,8 +306,10 @@ static inline void unref_msg(void *msg, enum smdi_message_type type)
        switch (type) {
        case SMDI_MWI:
                ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
+               break;
        case SMDI_MD:
                ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
+               break;
        }
 }
 
@@ -364,8 +367,13 @@ static void *smdi_msg_pop(struct ast_smdi_interface *iface, enum smdi_message_ty
        return msg;
 }
 
+enum {
+       OPT_SEARCH_TERMINAL = (1 << 0),
+       OPT_SEARCH_NUMBER   = (1 << 1),
+};
+
 static void *smdi_msg_find(struct ast_smdi_interface *iface,
-       enum smdi_message_type type, const char *station)
+       enum smdi_message_type type, const char *search_key, struct ast_flags options)
 {
        void *msg = NULL;
 
@@ -373,10 +381,59 @@ static void *smdi_msg_find(struct ast_smdi_interface *iface,
 
        switch (type) {
        case SMDI_MD:
-               msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, station);
+               if (ast_strlen_zero(search_key)) {
+                       struct ast_smdi_md_message *md_msg = NULL;
+
+                       /* No search key provided (the code from chan_dahdi does this).
+                        * Just pop the top message off of the queue. */
+
+                       ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
+                               md_msg = ASTOBJ_REF(iterator);
+                       } while (0); );
+
+                       msg = md_msg;
+               } else if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) {
+                       struct ast_smdi_md_message *md_msg = NULL;
+
+                       /* Searching by the message desk terminal */
+
+                       ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
+                               if (!strcasecmp(iterator->mesg_desk_term, search_key))
+                                       md_msg = ASTOBJ_REF(iterator);
+                       } while (0); );
+
+                       msg = md_msg;
+               } else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) {
+                       struct ast_smdi_md_message *md_msg = NULL;
+
+                       /* Searching by the message desk number */
+
+                       ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
+                               if (!strcasecmp(iterator->mesg_desk_num, search_key))
+                                       md_msg = ASTOBJ_REF(iterator);
+                       } while (0); );
+
+                       msg = md_msg;
+               } else {
+                       /* Searching by the forwarding station */
+                       msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, search_key);
+               }
                break;
        case SMDI_MWI:
-               msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, station);
+               if (ast_strlen_zero(search_key)) {
+                       struct ast_smdi_mwi_message *mwi_msg = NULL;
+
+                       /* No search key provided (the code from chan_dahdi does this).
+                        * Just pop the top message off of the queue. */
+
+                       ASTOBJ_CONTAINER_TRAVERSE(&iface->mwi_q, !mwi_msg, do {
+                               mwi_msg = ASTOBJ_REF(iterator);
+                       } while (0); );
+
+                       msg = mwi_msg;
+               } else {
+                       msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, search_key);
+               }
                break;
        }
 
@@ -384,33 +441,48 @@ static void *smdi_msg_find(struct ast_smdi_interface *iface,
 }
 
 static void *smdi_message_wait(struct ast_smdi_interface *iface, int timeout, 
-       enum smdi_message_type type, const char *station)
+       enum smdi_message_type type, const char *search_key, struct ast_flags options)
 {
        struct timeval start;
        long diff = 0;
        void *msg;
+       ast_cond_t *cond = NULL;
+       ast_mutex_t *lock = NULL;
+
+       switch (type) {
+       case SMDI_MWI:
+               cond = &iface->mwi_q_cond;
+               lock = &iface->mwi_q_lock;
+               break;
+       case SMDI_MD:
+               cond = &iface->md_q_cond;
+               lock = &iface->md_q_lock;
+               break;
+       }
+
+       start = ast_tvnow();
 
        while (diff < timeout) {
                struct timespec ts = { 0, };
-               struct timeval tv;
+               struct timeval wait;
 
                lock_msg_q(iface, type);
 
-               if ((msg = smdi_msg_find(iface, type, station))) {
+               if ((msg = smdi_msg_find(iface, type, search_key, options))) {
                        unlock_msg_q(iface, type);
                        return msg;
                }
 
-               tv = ast_tvadd(start, ast_tv(0, timeout));
-               ts.tv_sec = tv.tv_sec;
-               ts.tv_nsec = tv.tv_usec * 1000;
+               wait = ast_tvadd(start, ast_tv(0, timeout));
+               ts.tv_sec = wait.tv_sec;
+               ts.tv_nsec = wait.tv_usec * 1000;
 
                /* If there were no messages in the queue, then go to sleep until one
                 * arrives. */
 
-               ast_cond_timedwait(&iface->md_q_cond, &iface->md_q_lock, &ts);
+               ast_cond_timedwait(cond, lock, &ts);
 
-               if ((msg = smdi_msg_find(iface, type, station))) {
+               if ((msg = smdi_msg_find(iface, type, search_key, options))) {
                        unlock_msg_q(iface, type);
                        return msg;
                }
@@ -431,7 +503,8 @@ struct ast_smdi_md_message *ast_smdi_md_message_pop(struct ast_smdi_interface *i
 
 struct ast_smdi_md_message *ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout)
 {
-       return smdi_message_wait(iface, timeout, SMDI_MD, NULL);
+       struct ast_flags options = { 0 };
+       return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
 }
 
 struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface *iface)
@@ -441,13 +514,15 @@ struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface
 
 struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait(struct ast_smdi_interface *iface, int timeout)
 {
-       return smdi_message_wait(iface, timeout, SMDI_MWI, NULL);
+       struct ast_flags options = { 0 };
+       return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
 }
 
 struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait_station(struct ast_smdi_interface *iface, int timeout,
        const char *station)
 {
-       return smdi_message_wait(iface, timeout, SMDI_MWI, station);
+       struct ast_flags options = { 0 };
+       return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
 }
 
 struct ast_smdi_interface *ast_smdi_interface_find(const char *iface_name)
@@ -730,7 +805,7 @@ static void *mwi_monitor_handler(void *data)
 {
        while (!mwi_monitor.stop) {
                struct timespec ts = { 0, };
-               struct timeval tv;
+               struct timeval polltime;
                struct mailbox_mapping *mm;
 
                ast_mutex_lock(&mwi_monitor.lock);
@@ -742,9 +817,9 @@ static void *mwi_monitor_handler(void *data)
 
                /* Sleep up to the configured polling interval.  Allow unload_module()
                 * to signal us to wake up and exit. */
-               tv = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0));
-               ts.tv_sec = tv.tv_sec;
-               ts.tv_nsec = tv.tv_usec * 1000;
+               polltime = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0));
+               ts.tv_sec = polltime.tv_sec;
+               ts.tv_nsec = polltime.tv_usec * 1000;
                ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts);
 
                ast_mutex_unlock(&mwi_monitor.lock);
@@ -800,7 +875,7 @@ static int smdi_load(int reload)
        int msdstrip = 0;              /* strip zero digits */
        long msg_expiry = SMDI_MSG_EXPIRY_TIME;
 
-       if (!(conf = ast_config_load(config_file, config_flags))) {
+       if (!(conf = ast_config_load(config_file, config_flags)) || conf == CONFIG_STATUS_FILEINVALID) {
                if (reload)
                        ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
                else
@@ -1039,14 +1114,21 @@ static int smdi_msg_id;
 /*! In milliseconds */
 #define SMDI_RETRIEVE_TIMEOUT_DEFAULT 3000
 
+AST_APP_OPTIONS(smdi_msg_ret_options, BEGIN_OPTIONS
+       AST_APP_OPTION('t', OPT_SEARCH_TERMINAL),
+       AST_APP_OPTION('n', OPT_SEARCH_NUMBER),
+END_OPTIONS );
+
 static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
        struct ast_module_user *u;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(port);
-               AST_APP_ARG(station);
+               AST_APP_ARG(search_key);
                AST_APP_ARG(timeout);
+               AST_APP_ARG(options);
        );
+       struct ast_flags options = { 0 };
        unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
        int res = -1;
        char *parse = NULL;
@@ -1072,7 +1154,7 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, cha
        parse = ast_strdupa(data);
        AST_STANDARD_APP_ARGS(args, parse);
 
-       if (ast_strlen_zero(args.port) || ast_strlen_zero(args.station)) {
+       if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) {
                ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n");
                goto return_error;
        }
@@ -1082,6 +1164,10 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, cha
                goto return_error;
        }
 
+       if (!ast_strlen_zero(args.options)) {
+               ast_app_parse_options(smdi_msg_ret_options, &options, NULL, args.options);
+       }
+
        if (!ast_strlen_zero(args.timeout)) {
                if (sscanf(args.timeout, "%u", &timeout) != 1) {
                        ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
@@ -1089,9 +1175,9 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, cha
                }
        }
 
-       if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.station))) {
-               ast_log(LOG_WARNING, "No SMDI message retrieved for station '%s' after "
-                       "waiting %u ms.\n", args.station, timeout);
+       if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) {
+               ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after "
+                       "waiting %u ms.\n", args.search_key, timeout);
                goto return_error;
        }
 
@@ -1103,7 +1189,7 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, cha
        smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
        snprintf(buf, len, "%u", smd->id);
 
-       if (!(datastore = ast_channel_datastore_alloc(&smdi_msg_datastore_info, buf)))
+       if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf)))
                goto return_error;
 
        datastore->data = smd;
@@ -1180,7 +1266,11 @@ static int smdi_msg_read(struct ast_channel *chan, const char *cmd, char *data,
 
        smd = datastore->data;
 
-       if (!strcasecmp(args.component, "station")) {
+       if (!strcasecmp(args.component, "number")) {
+               ast_copy_string(buf, smd->md_msg->mesg_desk_num, len);
+       } else if (!strcasecmp(args.component, "terminal")) {
+               ast_copy_string(buf, smd->md_msg->mesg_desk_term, len);
+       } else if (!strcasecmp(args.component, "station")) {
                ast_copy_string(buf, smd->md_msg->fwd_st, len);
        } else if (!strcasecmp(args.component, "callerid")) {
                ast_copy_string(buf, smd->md_msg->calling_st, len);
@@ -1197,13 +1287,13 @@ static int smdi_msg_read(struct ast_channel *chan, const char *cmd, char *data,
 return_error:
        ast_module_user_remove(u);
 
-       return 0;
+       return res;
 }
 
 static struct ast_custom_function smdi_msg_retrieve_function = {
        .name = "SMDI_MSG_RETRIEVE",
        .synopsis = "Retrieve an SMDI message.",
-       .syntax = "SMDI_MSG_RETRIEVE(<smdi port>,<station>[,timeout])",
+       .syntax = "SMDI_MSG_RETRIEVE(<smdi port>,<search key>[,timeout[,options]])",
        .desc = 
        "   This function is used to retrieve an incoming SMDI message.  It returns\n"
        "an ID which can be used with the SMDI_MSG() function to access details of\n"
@@ -1212,6 +1302,14 @@ static struct ast_custom_function smdi_msg_retrieve_function = {
        "the global SMDI message queue, and can not be accessed by any other Asterisk\n"
        "channels.  The timeout for this function is optional, and the default is\n"
        "3 seconds.  When providing a timeout, it should be in milliseconds.\n"
+       "   The default search is done on the forwarding station ID.  However, if\n"
+       "you set one of the search key options in the options field, you can change\n"
+       "this behavior.\n"
+       "   Options:\n"
+       "     t - Instead of searching on the forwarding station, search on the message\n"
+       "         desk terminal.\n"
+       "     n - Instead of searching on the forwarding station, search on the message\n"
+       "         desk number.\n"
        "",
        .read = smdi_msg_retrieve_read,
 };
@@ -1225,6 +1323,8 @@ static struct ast_custom_function smdi_msg_function = {
        "pulled from the incoming SMDI message queue using the SMDI_MSG_RETRIEVE()\n"
        "function.\n"
        "   Valid message components are:\n"
+       "      number   - The message desk number\n"
+       "      terminal - The message desk terminal\n"
        "      station  - The forwarding station\n"
        "      callerid - The callerID of the calling party that was forwarded\n"
        "      type     - The call type.  The value here is the exact character\n"
@@ -1235,6 +1335,8 @@ static struct ast_custom_function smdi_msg_function = {
        .read = smdi_msg_read,
 };
 
+static int unload_module(void);
+
 static int load_module(void)
 {
        int res;
@@ -1252,8 +1354,10 @@ static int load_module(void)
        /* load the config and start the listener threads*/
        res = smdi_load(0);
        if (res < 0) {
+               unload_module();
                return res;
        } else if (res == 1) {
+               unload_module();
                ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
                return AST_MODULE_LOAD_DECLINE;
        }
@@ -1274,7 +1378,9 @@ static int unload_module(void)
        ast_cond_signal(&mwi_monitor.cond);
        ast_mutex_unlock(&mwi_monitor.lock);
 
-       pthread_join(mwi_monitor.thread, NULL);
+       if (mwi_monitor.thread != AST_PTHREADT_NULL) {
+               pthread_join(mwi_monitor.thread, NULL);
+       }
 
        ast_custom_function_unregister(&smdi_msg_retrieve_function);
        ast_custom_function_unregister(&smdi_msg_function);