SMDI support for Asterisk. More...
#include "asterisk.h"#include <termios.h>#include <sys/time.h>#include <time.h>#include <ctype.h>#include "asterisk/module.h"#include "asterisk/lock.h"#include "asterisk/utils.h"#include "asterisk/smdi.h"#include "asterisk/config.h"#include "asterisk/astobj.h"#include "asterisk/io.h"#include "asterisk/stringfields.h"#include "asterisk/linkedlists.h"#include "asterisk/app.h"#include "asterisk/pbx.h"#include "asterisk/channel.h"
Go to the source code of this file.
Data Structures | |
| struct | ast_smdi_interface |
| struct | ast_smdi_interface_container |
| SMDI interface container. More... | |
| struct | ast_smdi_md_queue |
| SMDI message desk message queue. More... | |
| struct | ast_smdi_mwi_queue |
| SMDI message waiting indicator message queue. More... | |
| struct | mailbox_mapping |
| A mapping between an SMDI mailbox ID and an Asterisk mailbox. More... | |
| struct | smdi_msg_datastore |
Defines | |
| #define | AST_API_MODULE |
| #define | DEFAULT_POLLING_INTERVAL 10 |
| #define | SMDI_MSG_EXPIRY_TIME 30000 /* 30 seconds */ |
| #define | SMDI_RETRIEVE_TIMEOUT_DEFAULT 3000 |
Enumerations | |
| enum | { OPT_SEARCH_TERMINAL = (1 << 0), OPT_SEARCH_NUMBER = (1 << 1) } |
| enum | smdi_message_type { SMDI_MWI, SMDI_MD } |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | _unload_module (int fromload) |
| static struct ast_smdi_interface * | alloc_smdi_interface (void) |
| static void | append_mailbox_mapping (struct ast_variable *var, struct ast_smdi_interface *iface) |
| static void | ast_smdi_interface_destroy (struct ast_smdi_interface *iface) |
| struct ast_smdi_interface *AST_OPTIONAL_API_NAME() | ast_smdi_interface_find (const char *iface_name) |
| Find an SMDI interface with the specified name. | |
| void AST_OPTIONAL_API_NAME() | ast_smdi_interface_unref (struct ast_smdi_interface *iface) |
| void AST_OPTIONAL_API_NAME() | ast_smdi_md_message_destroy (struct ast_smdi_md_message *msg) |
| ast_smdi_md_message destructor. | |
| struct ast_smdi_md_message *AST_OPTIONAL_API_NAME() | ast_smdi_md_message_pop (struct ast_smdi_interface *iface) |
| Get the next SMDI message from the queue. | |
| static void | ast_smdi_md_message_push (struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg) |
| void AST_OPTIONAL_API_NAME() | ast_smdi_md_message_putback (struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg) |
| Put an SMDI message back in the front of the queue. | |
| struct ast_smdi_md_message *AST_OPTIONAL_API_NAME() | ast_smdi_md_message_wait (struct ast_smdi_interface *iface, int timeout) |
| Get the next SMDI message from the queue. | |
| void AST_OPTIONAL_API_NAME() | ast_smdi_mwi_message_destroy (struct ast_smdi_mwi_message *msg) |
| ast_smdi_mwi_message destructor. | |
| struct ast_smdi_mwi_message *AST_OPTIONAL_API_NAME() | ast_smdi_mwi_message_pop (struct ast_smdi_interface *iface) |
| Get the next SMDI message from the queue. | |
| static void | ast_smdi_mwi_message_push (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg) |
| void AST_OPTIONAL_API_NAME() | ast_smdi_mwi_message_putback (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg) |
| Put an SMDI message back in the front of the queue. | |
| struct ast_smdi_mwi_message *AST_OPTIONAL_API_NAME() | ast_smdi_mwi_message_wait (struct ast_smdi_interface *iface, int timeout) |
| Get the next SMDI message from the queue. | |
| struct ast_smdi_mwi_message *AST_OPTIONAL_API_NAME() | ast_smdi_mwi_message_wait_station (struct ast_smdi_interface *iface, int timeout, const char *station) |
| int AST_OPTIONAL_API_NAME() | ast_smdi_mwi_set (struct ast_smdi_interface *iface, const char *mailbox) |
| Set the MWI indicator for a mailbox. | |
| int AST_OPTIONAL_API_NAME() | ast_smdi_mwi_unset (struct ast_smdi_interface *iface, const char *mailbox) |
| Unset the MWI indicator for a mailbox. | |
| static void | destroy_all_mailbox_mappings (void) |
| static void | destroy_mailbox_mapping (struct mailbox_mapping *mm) |
| static int | load_module (void) |
| static int | lock_msg_q (struct ast_smdi_interface *iface, enum smdi_message_type type) |
| static struct timeval | msg_timestamp (void *msg, enum smdi_message_type type) |
| static void * | mwi_monitor_handler (void *data) |
| static void | poll_mailbox (struct mailbox_mapping *mm) |
| static void | purge_old_messages (struct ast_smdi_interface *iface, enum smdi_message_type type) |
| static int | reload (void) |
| static int | smdi_load (int reload) |
| static void * | smdi_message_wait (struct ast_smdi_interface *iface, int timeout, enum smdi_message_type type, const char *search_key, struct ast_flags options) |
| static void | smdi_msg_datastore_destroy (void *data) |
| static void * | smdi_msg_find (struct ast_smdi_interface *iface, enum smdi_message_type type, const char *search_key, struct ast_flags options) |
| static void * | smdi_msg_pop (struct ast_smdi_interface *iface, enum smdi_message_type type) |
| static int | smdi_msg_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| static int | smdi_msg_retrieve_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| static void * | smdi_read (void *iface_p) |
| static int | smdi_toggle_mwi (struct ast_smdi_interface *iface, const char *mailbox, int on) |
| static void * | unlink_from_msg_q (struct ast_smdi_interface *iface, enum smdi_message_type type) |
| static int | unload_module (void) |
| static int | unlock_msg_q (struct ast_smdi_interface *iface, enum smdi_message_type type) |
| static void | unref_msg (void *msg, enum smdi_message_type type) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Simplified Message Desk Interface (SMDI) Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static const char | config_file [] = "smdi.conf" |
| struct { | |
| ast_cond_t cond | |
| struct timeval last_poll | |
| ast_mutex_t lock | |
| struct { | |
| struct mailbox_mapping * first | |
| struct mailbox_mapping * last | |
| } mailbox_mappings | |
| unsigned int polling_interval | |
| unsigned int stop:1 | |
| pthread_t thread | |
| } | mwi_monitor |
| Data that gets used by the SMDI MWI monitoring thread. | |
| static struct ast_smdi_interface_container | smdi_ifaces |
| static int | smdi_loaded |
| static struct ast_datastore_info | smdi_msg_datastore_info |
| static struct ast_custom_function | smdi_msg_function |
| static int | smdi_msg_id |
| static struct ast_app_option | smdi_msg_ret_options [128] = { [ 't' ] = { .flag = OPT_SEARCH_TERMINAL }, [ 'n' ] = { .flag = OPT_SEARCH_NUMBER }, } |
| static struct ast_custom_function | smdi_msg_retrieve_function |
SMDI support for Asterisk.
Here is a useful mailing list post that describes SMDI protocol details: http://lists.digium.com/pipermail/asterisk-dev/2003-June/000884.html
Definition in file res_smdi.c.
| #define AST_API_MODULE |
Definition at line 50 of file res_smdi.c.
| #define DEFAULT_POLLING_INTERVAL 10 |
| #define SMDI_MSG_EXPIRY_TIME 30000 /* 30 seconds */ |
Definition at line 62 of file res_smdi.c.
Referenced by smdi_load().
| #define SMDI_RETRIEVE_TIMEOUT_DEFAULT 3000 |
| anonymous enum |
Definition at line 469 of file res_smdi.c.
{
OPT_SEARCH_TERMINAL = (1 << 0),
OPT_SEARCH_NUMBER = (1 << 1),
};
| enum smdi_message_type |
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1483 of file res_smdi.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1483 of file res_smdi.c.
| static int _unload_module | ( | int | fromload | ) | [static] |
Definition at line 1428 of file res_smdi.c.
References ast_cond_signal, ast_custom_function_unregister(), ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, ast_smdi_interface_destroy(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, destroy_all_mailbox_mappings(), mwi_monitor, and smdi_ifaces.
Referenced by load_module(), and unload_module().
{
if (!smdi_loaded) {
return 0;
}
/* this destructor stops any running smdi_read threads */
ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy);
ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces);
destroy_all_mailbox_mappings();
ast_mutex_lock(&mwi_monitor.lock);
mwi_monitor.stop = 1;
ast_cond_signal(&mwi_monitor.cond);
ast_mutex_unlock(&mwi_monitor.lock);
if (mwi_monitor.thread != AST_PTHREADT_NULL) {
pthread_join(mwi_monitor.thread, NULL);
}
if (!fromload) {
ast_custom_function_unregister(&smdi_msg_retrieve_function);
ast_custom_function_unregister(&smdi_msg_function);
}
smdi_loaded = 0;
return 0;
}
| static struct ast_smdi_interface* alloc_smdi_interface | ( | void | ) | [static, read] |
Definition at line 925 of file res_smdi.c.
References ast_calloc, ast_cond_init, ast_mutex_init, ASTOBJ_CONTAINER_INIT, ASTOBJ_INIT, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, and ast_smdi_interface::mwi_q_lock.
Referenced by smdi_load().
{
struct ast_smdi_interface *iface;
if (!(iface = ast_calloc(1, sizeof(*iface))))
return NULL;
ASTOBJ_INIT(iface);
ASTOBJ_CONTAINER_INIT(&iface->md_q);
ASTOBJ_CONTAINER_INIT(&iface->mwi_q);
ast_mutex_init(&iface->md_q_lock);
ast_cond_init(&iface->md_q_cond, NULL);
ast_mutex_init(&iface->mwi_q_lock);
ast_cond_init(&iface->mwi_q_cond, NULL);
return iface;
}
| static void append_mailbox_mapping | ( | struct ast_variable * | var, |
| struct ast_smdi_interface * | iface | ||
| ) | [static] |
Definition at line 851 of file res_smdi.c.
References ast_calloc_with_stringfields, AST_LIST_INSERT_TAIL, ast_mutex_lock, ast_mutex_unlock, ast_string_field_set, ast_strlen_zero(), ASTOBJ_REF, context, mailbox_mapping::iface, mailbox, mwi_monitor, ast_variable::name, mailbox_mapping::smdi, and ast_variable::value.
Referenced by smdi_load().
{
struct mailbox_mapping *mm;
char *mailbox, *context;
if (!(mm = ast_calloc_with_stringfields(1, struct mailbox_mapping, 32)))
return;
ast_string_field_set(mm, smdi, var->name);
context = ast_strdupa(var->value);
mailbox = strsep(&context, "@");
if (ast_strlen_zero(context))
context = "default";
ast_string_field_set(mm, mailbox, mailbox);
ast_string_field_set(mm, context, context);
mm->iface = ASTOBJ_REF(iface);
ast_mutex_lock(&mwi_monitor.lock);
AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry);
ast_mutex_unlock(&mwi_monitor.lock);
}
| static void ast_smdi_interface_destroy | ( | struct ast_smdi_interface * | iface | ) | [static] |
Definition at line 231 of file res_smdi.c.
References ast_cond_destroy, ast_module_unref(), ast_mutex_destroy, AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_smdi_md_message_destroy(), ast_smdi_mwi_message_destroy(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ast_smdi_interface::file, free, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, ast_smdi_interface::mwi_q_lock, ast_module_info::self, and ast_smdi_interface::thread.
Referenced by _unload_module(), ast_smdi_interface_unref(), destroy_mailbox_mapping(), smdi_load(), smdi_msg_datastore_destroy(), smdi_msg_retrieve_read(), and smdi_read().
{
if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
pthread_cancel(iface->thread);
pthread_join(iface->thread, NULL);
}
iface->thread = AST_PTHREADT_STOP;
if (iface->file)
fclose(iface->file);
ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy);
ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy);
ASTOBJ_CONTAINER_DESTROY(&iface->md_q);
ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q);
ast_mutex_destroy(&iface->md_q_lock);
ast_cond_destroy(&iface->md_q_cond);
ast_mutex_destroy(&iface->mwi_q_lock);
ast_cond_destroy(&iface->mwi_q_cond);
free(iface);
ast_module_unref(ast_module_info->self);
}
| struct ast_smdi_interface* AST_OPTIONAL_API_NAME() ast_smdi_interface_find | ( | const char * | iface_name | ) | [read] |
Find an SMDI interface with the specified name.
| iface_name | the name/port of the interface to search for. |
Definition at line 627 of file res_smdi.c.
References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.
Referenced by actual_load_config(), mkintf(), and smdi_msg_retrieve_read().
{
return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
}
| void AST_OPTIONAL_API_NAME() ast_smdi_interface_unref | ( | struct ast_smdi_interface * | iface | ) |
Definition at line 259 of file res_smdi.c.
References ast_smdi_interface_destroy(), ASTOBJ_UNREF, and mailbox_mapping::iface.
Referenced by destroy_dahdi_pvt().
{
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
}
| void AST_OPTIONAL_API_NAME() ast_smdi_md_message_destroy | ( | struct ast_smdi_md_message * | msg | ) |
ast_smdi_md_message destructor.
Definition at line 824 of file res_smdi.c.
References ast_free.
Referenced by __analog_ss_thread(), analog_ss_thread(), ast_smdi_interface_destroy(), smdi_msg_datastore_destroy(), smdi_msg_retrieve_read(), smdi_read(), and unref_msg().
{
ast_free(msg);
}
| struct ast_smdi_md_message* AST_OPTIONAL_API_NAME() ast_smdi_md_message_pop | ( | struct ast_smdi_interface * | iface | ) | [read] |
Get the next SMDI message from the queue.
| iface | a pointer to the interface to use. |
This function pulls the first unexpired message from the SMDI message queue on the specified interface. It will purge all expired SMDI messages before returning.
Definition at line 598 of file res_smdi.c.
References SMDI_MD, and smdi_msg_pop().
{
return smdi_msg_pop(iface, SMDI_MD);
}
| static void ast_smdi_md_message_push | ( | struct ast_smdi_interface * | iface, |
| struct ast_smdi_md_message * | md_msg | ||
| ) | [static] |
Definition at line 270 of file res_smdi.c.
References ast_cond_broadcast, ast_mutex_lock, ast_mutex_unlock, ASTOBJ_CONTAINER_LINK_END, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, and ast_smdi_interface::md_q_lock.
Referenced by purge_old_messages(), and smdi_read().
{
ast_mutex_lock(&iface->md_q_lock);
ASTOBJ_CONTAINER_LINK_END(&iface->md_q, md_msg);
ast_cond_broadcast(&iface->md_q_cond);
ast_mutex_unlock(&iface->md_q_lock);
}
| void AST_OPTIONAL_API_NAME() ast_smdi_md_message_putback | ( | struct ast_smdi_interface * | iface, |
| struct ast_smdi_md_message * | msg | ||
| ) |
Put an SMDI message back in the front of the queue.
| iface | a pointer to the interface to use. |
| msg | a pointer to the message to use. |
This function puts a message back in the front of the specified queue. It should be used if a message was popped but is not going to be processed for some reason, and the message needs to be returned to the queue.
Definition at line 329 of file res_smdi.c.
References ast_cond_broadcast, ast_mutex_lock, ast_mutex_unlock, ASTOBJ_CONTAINER_LINK_START, mailbox_mapping::iface, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, and ast_smdi_interface::md_q_lock.
{
ast_mutex_lock(&iface->md_q_lock);
ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg);
ast_cond_broadcast(&iface->md_q_cond);
ast_mutex_unlock(&iface->md_q_lock);
}
| struct ast_smdi_md_message* AST_OPTIONAL_API_NAME() ast_smdi_md_message_wait | ( | struct ast_smdi_interface * | iface, |
| int | timeout | ||
| ) | [read] |
Get the next SMDI message from the queue.
| iface | a pointer to the interface to use. |
| 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.
Definition at line 603 of file res_smdi.c.
References SMDI_MD, and smdi_message_wait().
Referenced by __analog_ss_thread(), and analog_ss_thread().
{
struct ast_flags options = { 0 };
return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
}
| void AST_OPTIONAL_API_NAME() ast_smdi_mwi_message_destroy | ( | struct ast_smdi_mwi_message * | msg | ) |
ast_smdi_mwi_message destructor.
Definition at line 829 of file res_smdi.c.
References ast_free.
Referenced by ast_smdi_interface_destroy(), run_externnotify(), smdi_read(), and unref_msg().
{
ast_free(msg);
}
| struct ast_smdi_mwi_message* AST_OPTIONAL_API_NAME() ast_smdi_mwi_message_pop | ( | struct ast_smdi_interface * | iface | ) | [read] |
Get the next SMDI message from the queue.
| iface | a pointer to the interface to use. |
This function pulls the first unexpired message from the SMDI message queue on the specified interface. It will purge all expired SMDI messages before returning.
Definition at line 609 of file res_smdi.c.
References smdi_msg_pop(), and SMDI_MWI.
{
return smdi_msg_pop(iface, SMDI_MWI);
}
| static void ast_smdi_mwi_message_push | ( | struct ast_smdi_interface * | iface, |
| struct ast_smdi_mwi_message * | mwi_msg | ||
| ) | [static] |
Definition at line 284 of file res_smdi.c.
References ast_cond_broadcast, ast_mutex_lock, ast_mutex_unlock, ASTOBJ_CONTAINER_LINK_END, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, and ast_smdi_interface::mwi_q_lock.
Referenced by purge_old_messages(), and smdi_read().
{
ast_mutex_lock(&iface->mwi_q_lock);
ASTOBJ_CONTAINER_LINK_END(&iface->mwi_q, mwi_msg);
ast_cond_broadcast(&iface->mwi_q_cond);
ast_mutex_unlock(&iface->mwi_q_lock);
}
| void AST_OPTIONAL_API_NAME() ast_smdi_mwi_message_putback | ( | struct ast_smdi_interface * | iface, |
| struct ast_smdi_mwi_message * | msg | ||
| ) |
Put an SMDI message back in the front of the queue.
| iface | a pointer to the interface to use. |
| msg | a pointer to the message to use. |
This function puts a message back in the front of the specified queue. It should be used if a message was popped but is not going to be processed for some reason, and the message needs to be returned to the queue.
Definition at line 337 of file res_smdi.c.
References ast_cond_broadcast, ast_mutex_lock, ast_mutex_unlock, ASTOBJ_CONTAINER_LINK_START, mailbox_mapping::iface, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, and ast_smdi_interface::mwi_q_lock.
{
ast_mutex_lock(&iface->mwi_q_lock);
ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
ast_cond_broadcast(&iface->mwi_q_cond);
ast_mutex_unlock(&iface->mwi_q_lock);
}
| struct ast_smdi_mwi_message* AST_OPTIONAL_API_NAME() ast_smdi_mwi_message_wait | ( | struct ast_smdi_interface * | iface, |
| int | timeout | ||
| ) | [read] |
Get the next SMDI message from the queue.
| iface | a pointer to the interface to use. |
| 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.
Definition at line 614 of file res_smdi.c.
References smdi_message_wait(), and SMDI_MWI.
{
struct ast_flags options = { 0 };
return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
}
| struct ast_smdi_mwi_message* AST_OPTIONAL_API_NAME() ast_smdi_mwi_message_wait_station | ( | struct ast_smdi_interface * | iface, |
| int | timeout, | ||
| const char * | station | ||
| ) | [read] |
Definition at line 620 of file res_smdi.c.
References smdi_message_wait(), and SMDI_MWI.
Referenced by run_externnotify().
{
struct ast_flags options = { 0 };
return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
}
| int AST_OPTIONAL_API_NAME() ast_smdi_mwi_set | ( | struct ast_smdi_interface * | iface, |
| const char * | mailbox | ||
| ) |
Set the MWI indicator for a mailbox.
| iface | the interface to use. |
| mailbox | the mailbox to use. |
Definition at line 319 of file res_smdi.c.
References mailbox_mapping::iface, mailbox_mapping::mailbox, and smdi_toggle_mwi().
Referenced by poll_mailbox(), and run_externnotify().
{
return smdi_toggle_mwi(iface, mailbox, 1);
}
| int AST_OPTIONAL_API_NAME() ast_smdi_mwi_unset | ( | struct ast_smdi_interface * | iface, |
| const char * | mailbox | ||
| ) |
Unset the MWI indicator for a mailbox.
| iface | the interface to use. |
| mailbox | the mailbox to use. |
Definition at line 324 of file res_smdi.c.
References mailbox_mapping::iface, mailbox_mapping::mailbox, and smdi_toggle_mwi().
Referenced by poll_mailbox(), and run_externnotify().
{
return smdi_toggle_mwi(iface, mailbox, 0);
}
| static void destroy_all_mailbox_mappings | ( | void | ) | [static] |
Definition at line 841 of file res_smdi.c.
References AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, destroy_mailbox_mapping(), and mwi_monitor.
Referenced by _unload_module(), and smdi_load().
{
struct mailbox_mapping *mm;
ast_mutex_lock(&mwi_monitor.lock);
while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry)))
destroy_mailbox_mapping(mm);
ast_mutex_unlock(&mwi_monitor.lock);
}
| static void destroy_mailbox_mapping | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 834 of file res_smdi.c.
References ast_smdi_interface_destroy(), ast_string_field_free_memory, ASTOBJ_UNREF, free, and mailbox_mapping::iface.
Referenced by destroy_all_mailbox_mappings().
{
ast_string_field_free_memory(mm);
ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy);
free(mm);
}
| static int load_module | ( | void | ) | [static] |
Definition at line 1399 of file res_smdi.c.
References _unload_module(), ast_cond_init, ast_custom_function_register, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_mutex_init, ASTOBJ_CONTAINER_INIT, LOG_NOTICE, mwi_monitor, smdi_ifaces, and smdi_load().
{
int res;
smdi_loaded = 1;
/* initialize our containers */
memset(&smdi_ifaces, 0, sizeof(smdi_ifaces));
ASTOBJ_CONTAINER_INIT(&smdi_ifaces);
ast_mutex_init(&mwi_monitor.lock);
ast_cond_init(&mwi_monitor.cond, NULL);
/* load the config and start the listener threads*/
res = smdi_load(0);
if (res < 0) {
_unload_module(1);
return res;
} else if (res == 1) {
_unload_module(1);
ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
return AST_MODULE_LOAD_DECLINE;
}
ast_custom_function_register(&smdi_msg_retrieve_function);
ast_custom_function_register(&smdi_msg_function);
return AST_MODULE_LOAD_SUCCESS;
}
| static int lock_msg_q | ( | struct ast_smdi_interface * | iface, |
| enum smdi_message_type | type | ||
| ) | [inline, static] |
Definition at line 350 of file res_smdi.c.
References ast_mutex_lock, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_lock, SMDI_MD, and SMDI_MWI.
Referenced by purge_old_messages(), smdi_message_wait(), and smdi_msg_pop().
{
switch (type) {
case SMDI_MWI:
return ast_mutex_lock(&iface->mwi_q_lock);
case SMDI_MD:
return ast_mutex_lock(&iface->md_q_lock);
}
return -1;
}
| static struct timeval msg_timestamp | ( | void * | msg, |
| enum smdi_message_type | type | ||
| ) | [static, read] |
Definition at line 385 of file res_smdi.c.
References ast_tv(), SMDI_MD, SMDI_MWI, ast_smdi_mwi_message::timestamp, ast_smdi_md_message::timestamp, and type.
Referenced by purge_old_messages().
{
struct ast_smdi_md_message *md_msg = msg;
struct ast_smdi_mwi_message *mwi_msg = msg;
switch (type) {
case SMDI_MWI:
return mwi_msg->timestamp;
case SMDI_MD:
return md_msg->timestamp;
}
return ast_tv(0, 0);
}
| static void* mwi_monitor_handler | ( | void * | data | ) | [static] |
Definition at line 898 of file res_smdi.c.
References ast_cond_timedwait, AST_LIST_TRAVERSE, ast_mutex_lock, ast_mutex_unlock, ast_tv(), ast_tvadd(), ast_tvnow(), mwi_monitor, and poll_mailbox().
Referenced by smdi_load().
{
while (!mwi_monitor.stop) {
struct timespec ts = { 0, };
struct timeval polltime;
struct mailbox_mapping *mm;
ast_mutex_lock(&mwi_monitor.lock);
mwi_monitor.last_poll = ast_tvnow();
AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry)
poll_mailbox(mm);
/* Sleep up to the configured polling interval. Allow unload_module()
* to signal us to wake up and exit. */
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);
}
return NULL;
}
| static void poll_mailbox | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 879 of file res_smdi.c.
References ast_app_has_voicemail(), ast_smdi_mwi_set(), ast_smdi_mwi_unset(), mailbox_mapping::context, mailbox_mapping::cur_state, mailbox_mapping::iface, mailbox_mapping::mailbox, mailbox_mapping::smdi, and state.
Referenced by mwi_monitor_handler().
{
char buf[1024];
unsigned int state;
snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context);
state = !!ast_app_has_voicemail(mm->mailbox, NULL);
if (state != mm->cur_state) {
if (state)
ast_smdi_mwi_set(mm->iface, mm->smdi);
else
ast_smdi_mwi_unset(mm->iface, mm->smdi);
mm->cur_state = state;
}
}
| static void purge_old_messages | ( | struct ast_smdi_interface * | iface, |
| enum smdi_message_type | type | ||
| ) | [static] |
Definition at line 415 of file res_smdi.c.
References ast_log(), ast_smdi_md_message_push(), ast_smdi_mwi_message_push(), ast_tvdiff_ms(), ast_tvnow(), lock_msg_q(), LOG_NOTICE, ast_smdi_interface::msg_expiry, msg_timestamp(), ast_smdi_interface::name, SMDI_MD, SMDI_MWI, unlink_from_msg_q(), unlock_msg_q(), and unref_msg().
Referenced by smdi_msg_find(), and smdi_msg_pop().
{
struct timeval now = ast_tvnow();
long elapsed = 0;
void *msg;
lock_msg_q(iface, type);
msg = unlink_from_msg_q(iface, type);
unlock_msg_q(iface, type);
/* purge old messages */
while (msg) {
elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type));
if (elapsed > iface->msg_expiry) {
/* found an expired message */
unref_msg(msg, type);
ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue. "
"Message was %ld milliseconds too old.\n",
iface->name, (type == SMDI_MD) ? "MD" : "MWI",
elapsed - iface->msg_expiry);
lock_msg_q(iface, type);
msg = unlink_from_msg_q(iface, type);
unlock_msg_q(iface, type);
} else {
/* good message, put it back and return */
switch (type) {
case SMDI_MD:
ast_smdi_md_message_push(iface, msg);
break;
case SMDI_MWI:
ast_smdi_mwi_message_push(iface, msg);
break;
}
unref_msg(msg, type);
break;
}
}
}
| static int reload | ( | void | ) | [static] |
Definition at line 1463 of file res_smdi.c.
References ast_log(), LOG_WARNING, and smdi_load().
{
int res;
res = smdi_load(1);
if (res < 0) {
return res;
} else if (res == 1) {
ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
return 0;
} else
return 0;
}
| static int smdi_load | ( | int | reload | ) | [static] |
Definition at line 955 of file res_smdi.c.
References alloc_smdi_interface(), append_mailbox_mapping(), ast_config_destroy(), ast_config_load, ast_copy_string(), AST_LIST_EMPTY, ast_log(), AST_MODULE_LOAD_FAILURE, ast_module_ref(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_smdi_interface_destroy(), ast_true(), ast_variable_browse(), ast_verb, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_CONTAINER_PRUNE_MARKED, ASTOBJ_CONTAINER_RDLOCK, ASTOBJ_CONTAINER_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_POLLING_INTERVAL, destroy_all_mailbox_mappings(), errno, ast_smdi_interface::fd, ast_smdi_interface::file, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, ast_smdi_interface::mode, ast_smdi_interface::msdstrip, ast_smdi_interface::msg_expiry, mwi_monitor, mwi_monitor_handler(), ast_variable::name, ast_smdi_interface::name, ast_variable::next, ast_module_info::self, smdi_ifaces, SMDI_MSG_EXPIRY_TIME, smdi_read(), ast_smdi_interface::thread, and ast_variable::value.
Referenced by load_module(), and reload().
{
struct ast_config *conf;
struct ast_variable *v;
struct ast_smdi_interface *iface = NULL;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
int res = 0;
/* Config options */
speed_t baud_rate = B9600; /* 9600 baud rate */
tcflag_t paritybit = PARENB; /* even parity checking */
tcflag_t charsize = CS7; /* seven bit characters */
int stopbits = 0; /* One stop bit */
int msdstrip = 0; /* strip zero digits */
long msg_expiry = SMDI_MSG_EXPIRY_TIME;
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
ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file);
return 1;
} else if (conf == CONFIG_STATUS_FILEUNCHANGED)
return 0;
/* Mark all interfaces that we are listening on. We will unmark them
* as we find them in the config file, this way we know any interfaces
* still marked after we have finished parsing the config file should
* be stopped.
*/
if (reload)
ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces);
for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
if (!strcasecmp(v->name, "baudrate")) {
if (!strcasecmp(v->value, "9600"))
baud_rate = B9600;
else if (!strcasecmp(v->value, "4800"))
baud_rate = B4800;
else if (!strcasecmp(v->value, "2400"))
baud_rate = B2400;
else if (!strcasecmp(v->value, "1200"))
baud_rate = B1200;
else {
ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno);
baud_rate = B9600;
}
} else if (!strcasecmp(v->name, "msdstrip")) {
if (!sscanf(v->value, "%30d", &msdstrip)) {
ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
msdstrip = 0;
} else if (0 > msdstrip || msdstrip > 9) {
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, "msgexpirytime")) {
if (!sscanf(v->value, "%30ld", &msg_expiry)) {
ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno);
msg_expiry = SMDI_MSG_EXPIRY_TIME;
}
} else if (!strcasecmp(v->name, "paritybit")) {
if (!strcasecmp(v->value, "even"))
paritybit = PARENB;
else if (!strcasecmp(v->value, "odd"))
paritybit = PARENB | PARODD;
else if (!strcasecmp(v->value, "none"))
paritybit = ~PARENB;
else {
ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno);
paritybit = PARENB;
}
} else if (!strcasecmp(v->name, "charsize")) {
if (!strcasecmp(v->value, "7"))
charsize = CS7;
else if (!strcasecmp(v->value, "8"))
charsize = CS8;
else {
ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno);
charsize = CS7;
}
} else if (!strcasecmp(v->name, "twostopbits")) {
stopbits = ast_true(v->name);
} else if (!strcasecmp(v->name, "smdiport")) {
if (reload) {
/* we are reloading, check if we are already
* monitoring this interface, if we are we do
* not want to start it again. This also has
* the side effect of not updating different
* setting for the serial port, but it should
* be trivial to rewrite this section so that
* options on the port are changed without
* restarting the interface. Or the interface
* could be restarted with out emptying the
* queue. */
if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
ASTOBJ_UNMARK(iface);
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
continue;
}
}
if (!(iface = alloc_smdi_interface()))
continue;
ast_copy_string(iface->name, v->value, sizeof(iface->name));
iface->thread = AST_PTHREADT_NULL;
if (!(iface->file = fopen(iface->name, "r"))) {
ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
continue;
}
iface->fd = fileno(iface->file);
/* Set the proper attributes for our serial port. */
/* get the current attributes from the port */
if (tcgetattr(iface->fd, &iface->mode)) {
ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno));
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
continue;
}
/* set the desired speed */
if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
continue;
}
/* set the stop bits */
if (stopbits)
iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */
else
iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */
/* set the parity */
iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit;
/* set the character size */
iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize;
/* commit the desired attributes */
if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
continue;
}
/* set the msdstrip */
iface->msdstrip = msdstrip;
/* set the message expiry time */
iface->msg_expiry = msg_expiry;
/* start the listener thread */
ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name);
if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
continue;
}
ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface);
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
ast_module_ref(ast_module_info->self);
} else {
ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
}
}
destroy_all_mailbox_mappings();
mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
iface = NULL;
for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) {
if (!strcasecmp(v->name, "smdiport")) {
if (iface)
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
ast_log(LOG_NOTICE, "SMDI interface %s not found\n", v->value);
continue;
}
} else if (!strcasecmp(v->name, "pollinginterval")) {
if (sscanf(v->value, "%30u", &mwi_monitor.polling_interval) != 1) {
ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value);
mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
}
} else {
if (!iface) {
ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n");
continue;
}
append_mailbox_mapping(v, iface);
}
}
if (iface)
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
ast_config_destroy(conf);
if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL
&& ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) {
ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n");
return AST_MODULE_LOAD_FAILURE;
}
/* Prune any interfaces we should no longer monitor. */
if (reload)
ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy);
ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces);
/* TODO: this is bad, we need an ASTOBJ method for this! */
if (!smdi_ifaces.head)
res = 1;
ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces);
return res;
}
| static void* smdi_message_wait | ( | struct ast_smdi_interface * | iface, |
| int | timeout, | ||
| enum smdi_message_type | type, | ||
| const char * | search_key, | ||
| struct ast_flags | options | ||
| ) | [static] |
Definition at line 542 of file res_smdi.c.
References ast_cond_timedwait, ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), cond, lock, lock_msg_q(), ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_cond, ast_smdi_interface::mwi_q_lock, SMDI_MD, smdi_msg_find(), SMDI_MWI, and unlock_msg_q().
Referenced by ast_smdi_md_message_wait(), ast_smdi_mwi_message_wait(), ast_smdi_mwi_message_wait_station(), and smdi_msg_retrieve_read().
{
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 wait;
lock_msg_q(iface, type);
if ((msg = smdi_msg_find(iface, type, search_key, options))) {
unlock_msg_q(iface, type);
return msg;
}
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(cond, lock, &ts);
if ((msg = smdi_msg_find(iface, type, search_key, options))) {
unlock_msg_q(iface, type);
return msg;
}
unlock_msg_q(iface, type);
/* check timeout */
diff = ast_tvdiff_ms(ast_tvnow(), start);
}
return NULL;
}
| static void smdi_msg_datastore_destroy | ( | void * | data | ) | [static] |
Definition at line 1188 of file res_smdi.c.
References ast_smdi_interface_destroy(), ast_smdi_md_message_destroy(), ASTOBJ_UNREF, free, smdi_msg_datastore::iface, and smdi_msg_datastore::md_msg.
Referenced by smdi_msg_retrieve_read().
{
struct smdi_msg_datastore *smd = data;
if (smd->iface)
ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy);
if (smd->md_msg)
ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy);
free(smd);
}
| static void* smdi_msg_find | ( | struct ast_smdi_interface * | iface, |
| enum smdi_message_type | type, | ||
| const char * | search_key, | ||
| struct ast_flags | options | ||
| ) | [static] |
Definition at line 474 of file res_smdi.c.
References ast_strlen_zero(), ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_REF, ast_smdi_interface::md_q, OPT_SEARCH_TERMINAL, purge_old_messages(), and SMDI_MD.
Referenced by smdi_message_wait().
{
void *msg = NULL;
purge_old_messages(iface, type);
switch (type) {
case SMDI_MD:
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:
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;
}
return msg;
}
| static void* smdi_msg_pop | ( | struct ast_smdi_interface * | iface, |
| enum smdi_message_type | type | ||
| ) | [static] |
Definition at line 456 of file res_smdi.c.
References lock_msg_q(), purge_old_messages(), unlink_from_msg_q(), and unlock_msg_q().
Referenced by ast_smdi_md_message_pop(), and ast_smdi_mwi_message_pop().
{
void *msg;
purge_old_messages(iface, type);
lock_msg_q(iface, type);
msg = unlink_from_msg_q(iface, type);
unlock_msg_q(iface, type);
return msg;
}
| static int smdi_msg_read | ( | struct ast_channel * | chan, |
| const char * | cmd, | ||
| char * | data, | ||
| char * | buf, | ||
| size_t | len | ||
| ) | [static] |
Definition at line 1315 of file res_smdi.c.
References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_smdi_md_message::calling_st, ast_datastore::data, ast_smdi_md_message::fwd_st, LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, parse(), and ast_smdi_md_message::type.
{
struct ast_module_user *u;
int res = -1;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(id);
AST_APP_ARG(component);
);
char *parse;
struct ast_datastore *datastore = NULL;
struct smdi_msg_datastore *smd = NULL;
u = ast_module_user_add(chan);
if (!chan) {
ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n");
goto return_error;
}
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n");
goto return_error;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.id)) {
ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
goto return_error;
}
if (ast_strlen_zero(args.component)) {
ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
goto return_error;
}
ast_channel_lock(chan);
datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id);
ast_channel_unlock(chan);
if (!datastore) {
ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id);
goto return_error;
}
smd = datastore->data;
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);
} else if (!strcasecmp(args.component, "type")) {
snprintf(buf, len, "%c", smd->md_msg->type);
} else {
ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n",
args.component);
goto return_error;
}
res = 0;
return_error:
ast_module_user_remove(u);
return res;
}
| static int smdi_msg_retrieve_read | ( | struct ast_channel * | chan, |
| const char * | cmd, | ||
| char * | data, | ||
| char * | buf, | ||
| size_t | len | ||
| ) | [static] |
Definition at line 1216 of file res_smdi.c.
References args, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc(), AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, ast_smdi_interface_destroy(), ast_smdi_interface_find(), ast_smdi_md_message_destroy(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ASTOBJ_REF, ASTOBJ_UNREF, ast_datastore::data, smdi_msg_datastore::id, smdi_msg_datastore::iface, LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, parse(), SMDI_MD, smdi_message_wait(), smdi_msg_datastore_destroy(), smdi_msg_ret_options, and SMDI_RETRIEVE_TIMEOUT_DEFAULT.
{
struct ast_module_user *u;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(port);
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;
struct smdi_msg_datastore *smd = NULL;
struct ast_datastore *datastore = NULL;
struct ast_smdi_interface *iface = NULL;
struct ast_smdi_md_message *md_msg = NULL;
u = ast_module_user_add(chan);
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n");
goto return_error;
}
if (!chan) {
ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n");
goto return_error;
}
ast_autoservice_start(chan);
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
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;
}
if (!(iface = ast_smdi_interface_find(args.port))) {
ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port);
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, "%30u", &timeout) != 1) {
ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
}
}
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;
}
if (!(smd = ast_calloc(1, sizeof(*smd))))
goto return_error;
smd->iface = ASTOBJ_REF(iface);
smd->md_msg = ASTOBJ_REF(md_msg);
smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
snprintf(buf, len, "%u", smd->id);
if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf)))
goto return_error;
datastore->data = smd;
ast_channel_lock(chan);
ast_channel_datastore_add(chan, datastore);
ast_channel_unlock(chan);
res = 0;
return_error:
if (iface)
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
if (md_msg)
ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
if (smd && !datastore)
smdi_msg_datastore_destroy(smd);
if (parse)
ast_autoservice_stop(chan);
ast_module_user_remove(u);
return res;
}
| static void* smdi_read | ( | void * | iface_p | ) | [static] |
Definition at line 641 of file res_smdi.c.
References ast_calloc, ast_copy_string(), ast_debug, ast_log(), ast_smdi_interface_destroy(), ast_smdi_md_message_destroy(), ast_smdi_md_message_push(), ast_smdi_mwi_message_destroy(), ast_smdi_mwi_message_push(), ast_tvnow(), ASTOBJ_INIT, ASTOBJ_UNREF, ast_smdi_md_message::calling_st, ast_smdi_mwi_message::cause, ast_smdi_interface::file, ast_smdi_mwi_message::fwd_st, ast_smdi_md_message::fwd_st, LOG_ERROR, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, ast_smdi_interface::msdstrip, ast_smdi_mwi_message::name, ast_smdi_md_message::name, ast_smdi_interface::name, ast_smdi_mwi_message::timestamp, ast_smdi_md_message::timestamp, and ast_smdi_md_message::type.
Referenced by smdi_load().
{
struct ast_smdi_interface *iface = iface_p;
struct ast_smdi_md_message *md_msg;
struct ast_smdi_mwi_message *mwi_msg;
char c = '\0';
char *cp = NULL;
int i;
int start = 0;
/* read an smdi message */
while ((c = fgetc(iface->file))) {
/* check if this is the start of a message */
if (!start) {
if (c == 'M') {
ast_debug(1, "Read an 'M' to start an SMDI message\n");
start = 1;
}
continue;
}
if (c == 'D') { /* MD message */
start = 0;
ast_debug(1, "Read a 'D' ... it's an MD message.\n");
if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) {
ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
return NULL;
}
ASTOBJ_INIT(md_msg);
/* read the message desk number */
for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) {
md_msg->mesg_desk_num[i] = fgetc(iface->file);
ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_num[i]);
}
md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0';
ast_debug(1, "The message desk number is '%s'\n", md_msg->mesg_desk_num);
/* read the message desk terminal number */
for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) {
md_msg->mesg_desk_term[i] = fgetc(iface->file);
ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_term[i]);
}
md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0';
ast_debug(1, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term);
/* read the message type */
md_msg->type = fgetc(iface->file);
ast_debug(1, "Message type is '%c'\n", md_msg->type);
/* read the forwarding station number (may be blank) */
cp = &md_msg->fwd_st[0];
for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) {
if ((c = fgetc(iface->file)) == ' ') {
*cp = '\0';
ast_debug(1, "Read a space, done looking for the forwarding station\n");
break;
}
/* store c in md_msg->fwd_st */
if (i >= iface->msdstrip) {
ast_debug(1, "Read a '%c' and stored it in the forwarding station buffer\n", c);
*cp++ = c;
} else {
ast_debug(1, "Read a '%c', but didn't store it in the fwd station buffer, because of the msdstrip setting (%d < %d)\n", c, i, iface->msdstrip);
}
}
/* make sure the value is null terminated, even if this truncates it */
md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0';
cp = NULL;
ast_debug(1, "The forwarding station is '%s'\n", md_msg->fwd_st);
/* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look
* up a message on this field */
ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name));
/* read the calling station number (may be blank) */
cp = &md_msg->calling_st[0];
for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) {
if (!isdigit((c = fgetc(iface->file)))) {
*cp = '\0';
ast_debug(1, "Read a '%c', but didn't store it in the calling station buffer because it's not a digit\n", c);
if (c == ' ') {
/* Don't break on a space. We may read the space before the calling station
* here if the forwarding station buffer filled up. */
i--; /* We're still on the same character */
continue;
}
break;
}
/* store c in md_msg->calling_st */
if (i >= iface->msdstrip) {
ast_debug(1, "Read a '%c' and stored it in the calling station buffer\n", c);
*cp++ = c;
} else {
ast_debug(1, "Read a '%c', but didn't store it in the calling station buffer, because of the msdstrip setting (%d < %d)\n", c, i, iface->msdstrip);
}
}
/* make sure the value is null terminated, even if this truncates it */
md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0';
cp = NULL;
ast_debug(1, "The calling station is '%s'\n", md_msg->calling_st);
/* add the message to the message queue */
md_msg->timestamp = ast_tvnow();
ast_smdi_md_message_push(iface, md_msg);
ast_debug(1, "Received SMDI MD message on %s\n", iface->name);
ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
} else if (c == 'W') { /* MWI message */
start = 0;
ast_debug(1, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n");
if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) {
ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
return NULL;
}
ASTOBJ_INIT(mwi_msg);
/* discard the 'I' (from 'MWI') */
fgetc(iface->file);
/* read the forwarding station number (may be blank) */
cp = &mwi_msg->fwd_st[0];
for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) {
if ((c = fgetc(iface->file)) == ' ') {
*cp = '\0';
break;
}
/* store c in md_msg->fwd_st */
if (i >= iface->msdstrip)
*cp++ = c;
}
/* make sure the station number is null terminated, even if this will truncate it */
mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0';
cp = NULL;
/* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look
* up a message on this field */
ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name));
/* read the mwi failure cause */
for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++)
mwi_msg->cause[i] = fgetc(iface->file);
mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0';
/* add the message to the message queue */
mwi_msg->timestamp = ast_tvnow();
ast_smdi_mwi_message_push(iface, mwi_msg);
ast_debug(1, "Received SMDI MWI message on %s\n", iface->name);
ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
} else {
ast_log(LOG_ERROR, "Unknown SMDI message type received on %s (M%c).\n", iface->name, c);
start = 0;
}
}
ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
return NULL;
}
| static int smdi_toggle_mwi | ( | struct ast_smdi_interface * | iface, |
| const char * | mailbox, | ||
| int | on | ||
| ) | [static] |
Definition at line 292 of file res_smdi.c.
References ast_debug, ast_log(), ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, errno, ast_smdi_interface::file, LOG_ERROR, ast_smdi_interface::msdstrip, and ast_smdi_interface::name.
Referenced by ast_smdi_mwi_set(), and ast_smdi_mwi_unset().
{
FILE *file;
int i;
if (!(file = fopen(iface->name, "w"))) {
ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
return 1;
}
ASTOBJ_WRLOCK(iface);
fprintf(file, "%s:MWI ", on ? "OP" : "RMV");
for (i = 0; i < iface->msdstrip; i++)
fprintf(file, "0");
fprintf(file, "%s!\x04", mailbox);
fclose(file);
ASTOBJ_UNLOCK(iface);
ast_debug(1, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
return 0;
}
| static void* unlink_from_msg_q | ( | struct ast_smdi_interface * | iface, |
| enum smdi_message_type | type | ||
| ) | [inline, static] |
Definition at line 374 of file res_smdi.c.
References ASTOBJ_CONTAINER_UNLINK_START, ast_smdi_interface::md_q, ast_smdi_interface::mwi_q, SMDI_MD, and SMDI_MWI.
Referenced by purge_old_messages(), and smdi_msg_pop().
{
switch (type) {
case SMDI_MWI:
return ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
case SMDI_MD:
return ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
}
return NULL;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 1458 of file res_smdi.c.
References _unload_module().
{
return _unload_module(0);
}
| static int unlock_msg_q | ( | struct ast_smdi_interface * | iface, |
| enum smdi_message_type | type | ||
| ) | [inline, static] |
Definition at line 362 of file res_smdi.c.
References ast_mutex_unlock, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_lock, SMDI_MD, and SMDI_MWI.
Referenced by purge_old_messages(), smdi_message_wait(), and smdi_msg_pop().
{
switch (type) {
case SMDI_MWI:
return ast_mutex_unlock(&iface->mwi_q_lock);
case SMDI_MD:
return ast_mutex_unlock(&iface->md_q_lock);
}
return -1;
}
| static void unref_msg | ( | void * | msg, |
| enum smdi_message_type | type | ||
| ) | [inline, static] |
Definition at line 400 of file res_smdi.c.
References ast_smdi_md_message_destroy(), ast_smdi_mwi_message_destroy(), ASTOBJ_UNREF, SMDI_MD, and SMDI_MWI.
Referenced by purge_old_messages().
{
struct ast_smdi_md_message *md_msg = msg;
struct ast_smdi_mwi_message *mwi_msg = msg;
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;
}
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Simplified Message Desk Interface (SMDI) Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static] |
Definition at line 1483 of file res_smdi.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1483 of file res_smdi.c.
Definition at line 218 of file res_smdi.c.
const char config_file[] = "smdi.conf" [static] |
Definition at line 158 of file res_smdi.c.
| struct mailbox_mapping* first |
Definition at line 220 of file res_smdi.c.
| struct mailbox_mapping* last |
Definition at line 220 of file res_smdi.c.
| struct timeval last_poll |
The time that the last poll began
Definition at line 226 of file res_smdi.c.
Definition at line 217 of file res_smdi.c.
| struct { ... } mailbox_mappings |
A list of mailboxes that need to be monitored
struct { ... } mwi_monitor [static] |
Data that gets used by the SMDI MWI monitoring thread.
Referenced by _unload_module(), append_mailbox_mapping(), destroy_all_mailbox_mappings(), load_module(), mwi_monitor_handler(), and smdi_load().
| unsigned int polling_interval |
Polling Interval for checking mailbox status
Definition at line 222 of file res_smdi.c.
struct ast_smdi_interface_container smdi_ifaces [static] |
Referenced by _unload_module(), ast_smdi_interface_find(), load_module(), and smdi_load().
int smdi_loaded [static] |
Definition at line 159 of file res_smdi.c.
struct ast_datastore_info smdi_msg_datastore_info [static] |
{
.type = "SMDIMSG",
.destroy = smdi_msg_datastore_destroy,
}
Definition at line 1201 of file res_smdi.c.
struct ast_custom_function smdi_msg_function [static] |
{
.name = "SMDI_MSG",
.read = smdi_msg_read,
}
Definition at line 1392 of file res_smdi.c.
int smdi_msg_id [static] |
Definition at line 1206 of file res_smdi.c.
struct ast_app_option smdi_msg_ret_options[128] = { [ 't' ] = { .flag = OPT_SEARCH_TERMINAL }, [ 'n' ] = { .flag = OPT_SEARCH_NUMBER }, } [static] |
Definition at line 1214 of file res_smdi.c.
Referenced by smdi_msg_retrieve_read().
struct ast_custom_function smdi_msg_retrieve_function [static] |
{
.name = "SMDI_MSG_RETRIEVE",
.read = smdi_msg_retrieve_read,
}
Definition at line 1387 of file res_smdi.c.
| unsigned int stop |
Set to 1 to tell the polling thread to stop
Definition at line 224 of file res_smdi.c.
| pthread_t thread |
The thread ID
Definition at line 216 of file res_smdi.c.