#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 | DEFAULT_POLLING_INTERVAL 10 |
#define | SMDI_MSG_EXPIRY_TIME 30000 |
#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 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) |
ast_smdi_interface * | ast_smdi_interface_find (const char *iface_name) |
Find an SMDI interface with the specified name. | |
void | ast_smdi_interface_unref (struct ast_smdi_interface *iface) |
void | ast_smdi_md_message_destroy (struct ast_smdi_md_message *msg) |
ast_smdi_md_message destructor. | |
ast_smdi_md_message * | 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_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. | |
ast_smdi_md_message * | ast_smdi_md_message_wait (struct ast_smdi_interface *iface, int timeout) |
Get the next SMDI message from the queue. | |
void | ast_smdi_mwi_message_destroy (struct ast_smdi_mwi_message *msg) |
ast_smdi_mwi_message destructor. | |
ast_smdi_mwi_message * | 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_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. | |
ast_smdi_mwi_message * | ast_smdi_mwi_message_wait (struct ast_smdi_interface *iface, int timeout) |
Get the next SMDI message from the queue. | |
ast_smdi_mwi_message * | ast_smdi_mwi_message_wait_station (struct ast_smdi_interface *iface, int timeout, const char *station) |
int | ast_smdi_mwi_set (struct ast_smdi_interface *iface, const char *mailbox) |
Set the MWI indicator for a mailbox. | |
int | 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 , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static const char | config_file [] = "smdi.conf" |
struct { | |
ast_cond_t cond | |
timeval last_poll | |
ast_mutex_t lock | |
struct { | |
mailbox_mapping * first | |
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. | |
ast_smdi_interface_container | smdi_ifaces |
SMDI interface container. | |
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 |
Russell Bryant <russell@digium.com>
Definition in file res_smdi.c.
#define DEFAULT_POLLING_INTERVAL 10 |
10 seconds
Definition at line 111 of file res_smdi.c.
#define SMDI_MSG_EXPIRY_TIME 30000 |
#define SMDI_RETRIEVE_TIMEOUT_DEFAULT 3000 |
anonymous enum |
Definition at line 367 of file res_smdi.c.
00367 { 00368 OPT_SEARCH_TERMINAL = (1 << 0), 00369 OPT_SEARCH_NUMBER = (1 << 1), 00370 };
enum smdi_message_type |
static void __reg_module | ( | void | ) | [static] |
Definition at line 1379 of file res_smdi.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1379 of file res_smdi.c.
static struct ast_smdi_interface* alloc_smdi_interface | ( | void | ) | [static] |
Definition at line 804 of file res_smdi.c.
References ast_calloc, ast_cond_init(), ast_mutex_init(), ASTOBJ_CONTAINER_INIT, and ASTOBJ_INIT.
00805 { 00806 struct ast_smdi_interface *iface; 00807 00808 if (!(iface = ast_calloc(1, sizeof(*iface)))) 00809 return NULL; 00810 00811 ASTOBJ_INIT(iface); 00812 ASTOBJ_CONTAINER_INIT(&iface->md_q); 00813 ASTOBJ_CONTAINER_INIT(&iface->mwi_q); 00814 00815 ast_mutex_init(&iface->md_q_lock); 00816 ast_cond_init(&iface->md_q_cond, NULL); 00817 00818 ast_mutex_init(&iface->mwi_q_lock); 00819 ast_cond_init(&iface->mwi_q_cond, NULL); 00820 00821 return iface; 00822 }
static void append_mailbox_mapping | ( | struct ast_variable * | var, | |
struct ast_smdi_interface * | iface | |||
) | [static] |
Definition at line 725 of file res_smdi.c.
References ast_calloc, AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ASTOBJ_REF, context, mailbox_mapping::entry, free, mailbox_mapping::iface, mailbox, mwi_monitor, mailbox_mapping::smdi, strsep(), and var.
00726 { 00727 struct mailbox_mapping *mm; 00728 char *mailbox, *context; 00729 00730 if (!(mm = ast_calloc(1, sizeof(*mm)))) 00731 return; 00732 00733 if (ast_string_field_init(mm, 32)) { 00734 free(mm); 00735 return; 00736 } 00737 00738 ast_string_field_set(mm, smdi, var->name); 00739 00740 context = ast_strdupa(var->value); 00741 mailbox = strsep(&context, "@"); 00742 if (ast_strlen_zero(context)) 00743 context = "default"; 00744 00745 ast_string_field_set(mm, mailbox, mailbox); 00746 ast_string_field_set(mm, context, context); 00747 00748 mm->iface = ASTOBJ_REF(iface); 00749 00750 ast_mutex_lock(&mwi_monitor.lock); 00751 AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry); 00752 ast_mutex_unlock(&mwi_monitor.lock); 00753 }
static void ast_smdi_interface_destroy | ( | struct ast_smdi_interface * | iface | ) | [static] |
Definition at line 131 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, mailbox_mapping::iface, 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, and ast_smdi_interface::thread.
Referenced by ast_smdi_interface_unref(), destroy_mailbox_mapping(), smdi_msg_datastore_destroy(), smdi_msg_retrieve_read(), smdi_read(), and unload_module().
00132 { 00133 if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) { 00134 pthread_cancel(iface->thread); 00135 pthread_join(iface->thread, NULL); 00136 } 00137 00138 iface->thread = AST_PTHREADT_STOP; 00139 00140 if (iface->file) 00141 fclose(iface->file); 00142 00143 ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy); 00144 ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy); 00145 ASTOBJ_CONTAINER_DESTROY(&iface->md_q); 00146 ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q); 00147 00148 ast_mutex_destroy(&iface->md_q_lock); 00149 ast_cond_destroy(&iface->md_q_cond); 00150 00151 ast_mutex_destroy(&iface->mwi_q_lock); 00152 ast_cond_destroy(&iface->mwi_q_cond); 00153 00154 free(iface); 00155 00156 ast_module_unref(ast_module_info->self); 00157 }
struct ast_smdi_interface* ast_smdi_interface_find | ( | const char * | iface_name | ) |
Find an SMDI interface with the specified name.
iface_name | the name/port of the interface to search for. |
Definition at line 501 of file res_smdi.c.
References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.
Referenced by load_config(), and smdi_msg_retrieve_read().
00502 { 00503 return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name)); 00504 }
void ast_smdi_interface_unref | ( | struct ast_smdi_interface * | iface | ) |
Definition at line 159 of file res_smdi.c.
References ast_smdi_interface_destroy(), ASTOBJ_UNREF, and mailbox_mapping::iface.
Referenced by destroy_dahdi_pvt().
00160 { 00161 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00162 }
void ast_smdi_md_message_destroy | ( | struct ast_smdi_md_message * | msg | ) |
ast_smdi_md_message destructor.
Definition at line 698 of file res_smdi.c.
Referenced by ast_smdi_interface_destroy(), smdi_msg_datastore_destroy(), smdi_msg_retrieve_read(), and unref_msg().
struct ast_smdi_md_message* ast_smdi_md_message_pop | ( | struct ast_smdi_interface * | iface | ) |
Get the next SMDI message from the queue.
iface | a pointer to the interface to use. |
Definition at line 472 of file res_smdi.c.
References SMDI_MD, and smdi_msg_pop().
00473 { 00474 return smdi_msg_pop(iface, SMDI_MD); 00475 }
static void ast_smdi_md_message_push | ( | struct ast_smdi_interface * | iface, | |
struct ast_smdi_md_message * | md_msg | |||
) | [static] |
Definition at line 170 of file res_smdi.c.
References ast_cond_broadcast(), ast_mutex_lock(), ast_mutex_unlock(), ASTOBJ_CONTAINER_LINK_END, mailbox_mapping::iface, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, and ast_smdi_interface::md_q_lock.
Referenced by purge_old_messages().
00171 { 00172 ast_mutex_lock(&iface->md_q_lock); 00173 ASTOBJ_CONTAINER_LINK_END(&iface->md_q, md_msg); 00174 ast_cond_broadcast(&iface->md_q_cond); 00175 ast_mutex_unlock(&iface->md_q_lock); 00176 }
void 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. | |
md_msg | a pointer to the message to use. |
Definition at line 229 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.
00230 { 00231 ast_mutex_lock(&iface->md_q_lock); 00232 ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg); 00233 ast_cond_broadcast(&iface->md_q_cond); 00234 ast_mutex_unlock(&iface->md_q_lock); 00235 }
struct ast_smdi_md_message* ast_smdi_md_message_wait | ( | struct ast_smdi_interface * | iface, | |
int | timeout | |||
) |
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. |
Definition at line 477 of file res_smdi.c.
References SMDI_MD, and smdi_message_wait().
Referenced by ss_thread().
00478 { 00479 struct ast_flags options = { 0 }; 00480 return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options); 00481 }
void ast_smdi_mwi_message_destroy | ( | struct ast_smdi_mwi_message * | msg | ) |
ast_smdi_mwi_message destructor.
Definition at line 703 of file res_smdi.c.
Referenced by ast_smdi_interface_destroy(), run_externnotify(), and unref_msg().
struct ast_smdi_mwi_message* ast_smdi_mwi_message_pop | ( | struct ast_smdi_interface * | iface | ) |
Get the next SMDI message from the queue.
iface | a pointer to the interface to use. |
Definition at line 483 of file res_smdi.c.
References smdi_msg_pop(), and SMDI_MWI.
00484 { 00485 return smdi_msg_pop(iface, SMDI_MWI); 00486 }
static void ast_smdi_mwi_message_push | ( | struct ast_smdi_interface * | iface, | |
struct ast_smdi_mwi_message * | mwi_msg | |||
) | [static] |
Definition at line 184 of file res_smdi.c.
References ast_cond_broadcast(), ast_mutex_lock(), ast_mutex_unlock(), ASTOBJ_CONTAINER_LINK_END, mailbox_mapping::iface, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, and ast_smdi_interface::mwi_q_lock.
Referenced by purge_old_messages().
00185 { 00186 ast_mutex_lock(&iface->mwi_q_lock); 00187 ASTOBJ_CONTAINER_LINK_END(&iface->mwi_q, mwi_msg); 00188 ast_cond_broadcast(&iface->mwi_q_cond); 00189 ast_mutex_unlock(&iface->mwi_q_lock); 00190 }
void 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. | |
mwi_msg | a pointer to the message to use. |
Definition at line 237 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.
00238 { 00239 ast_mutex_lock(&iface->mwi_q_lock); 00240 ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg); 00241 ast_cond_broadcast(&iface->mwi_q_cond); 00242 ast_mutex_unlock(&iface->mwi_q_lock); 00243 }
struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait | ( | struct ast_smdi_interface * | iface, | |
int | timeout | |||
) |
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. |
Definition at line 488 of file res_smdi.c.
References smdi_message_wait(), and SMDI_MWI.
00489 { 00490 struct ast_flags options = { 0 }; 00491 return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options); 00492 }
struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait_station | ( | struct ast_smdi_interface * | iface, | |
int | timeout, | |||
const char * | station | |||
) |
Definition at line 494 of file res_smdi.c.
References smdi_message_wait(), and SMDI_MWI.
Referenced by run_externnotify().
00496 { 00497 struct ast_flags options = { 0 }; 00498 return smdi_message_wait(iface, timeout, SMDI_MWI, station, options); 00499 }
int 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 219 of file res_smdi.c.
References mailbox_mapping::iface, and smdi_toggle_mwi().
Referenced by poll_mailbox(), and run_externnotify().
00220 { 00221 return smdi_toggle_mwi(iface, mailbox, 1); 00222 }
int 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 224 of file res_smdi.c.
References mailbox_mapping::iface, and smdi_toggle_mwi().
Referenced by poll_mailbox(), and run_externnotify().
00225 { 00226 return smdi_toggle_mwi(iface, mailbox, 0); 00227 }
static void destroy_all_mailbox_mappings | ( | void | ) | [static] |
Definition at line 715 of file res_smdi.c.
References AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), destroy_mailbox_mapping(), mailbox_mapping::entry, and mwi_monitor.
Referenced by unload_module().
00716 { 00717 struct mailbox_mapping *mm; 00718 00719 ast_mutex_lock(&mwi_monitor.lock); 00720 while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry))) 00721 destroy_mailbox_mapping(mm); 00722 ast_mutex_unlock(&mwi_monitor.lock); 00723 }
static void destroy_mailbox_mapping | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 708 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().
00709 { 00710 ast_string_field_free_memory(mm); 00711 ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy); 00712 free(mm); 00713 }
static int load_module | ( | void | ) | [static] |
Definition at line 1311 of file res_smdi.c.
References 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, smdi_load(), smdi_msg_function, and smdi_msg_retrieve_function.
01312 { 01313 int res; 01314 01315 /* initialize our containers */ 01316 memset(&smdi_ifaces, 0, sizeof(smdi_ifaces)); 01317 ASTOBJ_CONTAINER_INIT(&smdi_ifaces); 01318 01319 ast_mutex_init(&mwi_monitor.lock); 01320 ast_cond_init(&mwi_monitor.cond, NULL); 01321 01322 ast_custom_function_register(&smdi_msg_retrieve_function); 01323 ast_custom_function_register(&smdi_msg_function); 01324 01325 /* load the config and start the listener threads*/ 01326 res = smdi_load(0); 01327 if (res < 0) { 01328 return res; 01329 } else if (res == 1) { 01330 ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n"); 01331 return AST_MODULE_LOAD_DECLINE; 01332 } 01333 01334 return AST_MODULE_LOAD_SUCCESS; 01335 }
static int lock_msg_q | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [inline, static] |
Definition at line 250 of file res_smdi.c.
References ast_mutex_lock(), mailbox_mapping::iface, 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().
00251 { 00252 switch (type) { 00253 case SMDI_MWI: 00254 return ast_mutex_lock(&iface->mwi_q_lock); 00255 case SMDI_MD: 00256 return ast_mutex_lock(&iface->md_q_lock); 00257 } 00258 00259 return -1; 00260 }
static struct timeval msg_timestamp | ( | void * | msg, | |
enum smdi_message_type | type | |||
) | [inline, static] |
Definition at line 285 of file res_smdi.c.
References ast_tv(), msg, SMDI_MD, SMDI_MWI, ast_smdi_mwi_message::timestamp, and type.
Referenced by purge_old_messages().
00286 { 00287 struct ast_smdi_md_message *md_msg = msg; 00288 struct ast_smdi_mwi_message *mwi_msg = msg; 00289 00290 switch (type) { 00291 case SMDI_MWI: 00292 return mwi_msg->timestamp; 00293 case SMDI_MD: 00294 return md_msg->timestamp; 00295 } 00296 00297 return ast_tv(0, 0); 00298 }
static void* mwi_monitor_handler | ( | void * | data | ) | [static] |
Definition at line 777 of file res_smdi.c.
References ast_cond_timedwait(), AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_tv(), ast_tvadd(), ast_tvnow(), mailbox_mapping::entry, mwi_monitor, and poll_mailbox().
00778 { 00779 while (!mwi_monitor.stop) { 00780 struct timespec ts = { 0, }; 00781 struct timeval polltime; 00782 struct mailbox_mapping *mm; 00783 00784 ast_mutex_lock(&mwi_monitor.lock); 00785 00786 mwi_monitor.last_poll = ast_tvnow(); 00787 00788 AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry) 00789 poll_mailbox(mm); 00790 00791 /* Sleep up to the configured polling interval. Allow unload_module() 00792 * to signal us to wake up and exit. */ 00793 polltime = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0)); 00794 ts.tv_sec = polltime.tv_sec; 00795 ts.tv_nsec = polltime.tv_usec * 1000; 00796 ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts); 00797 00798 ast_mutex_unlock(&mwi_monitor.lock); 00799 } 00800 00801 return NULL; 00802 }
static void poll_mailbox | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 758 of file res_smdi.c.
References ast_app_has_voicemail(), ast_smdi_mwi_set(), ast_smdi_mwi_unset(), buf, mailbox_mapping::context, mailbox_mapping::cur_state, mailbox_mapping::iface, mailbox_mapping::mailbox, and mailbox_mapping::smdi.
Referenced by mwi_monitor_handler().
00759 { 00760 char buf[1024]; 00761 unsigned int state; 00762 00763 snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context); 00764 00765 state = !!ast_app_has_voicemail(mm->mailbox, NULL); 00766 00767 if (state != mm->cur_state) { 00768 if (state) 00769 ast_smdi_mwi_set(mm->iface, mm->smdi); 00770 else 00771 ast_smdi_mwi_unset(mm->iface, mm->smdi); 00772 00773 mm->cur_state = state; 00774 } 00775 }
static void purge_old_messages | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [static] |
Definition at line 313 of file res_smdi.c.
References ast_log(), ast_smdi_md_message_push(), ast_smdi_mwi_message_push(), ast_tvdiff_ms(), ast_tvnow(), mailbox_mapping::iface, lock_msg_q(), LOG_NOTICE, msg, 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().
00314 { 00315 struct timeval now = ast_tvnow(); 00316 long elapsed = 0; 00317 void *msg; 00318 00319 lock_msg_q(iface, type); 00320 msg = unlink_from_msg_q(iface, type); 00321 unlock_msg_q(iface, type); 00322 00323 /* purge old messages */ 00324 while (msg) { 00325 elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type)); 00326 00327 if (elapsed > iface->msg_expiry) { 00328 /* found an expired message */ 00329 unref_msg(msg, type); 00330 ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue. " 00331 "Message was %ld milliseconds too old.\n", 00332 iface->name, (type == SMDI_MD) ? "MD" : "MWI", 00333 elapsed - iface->msg_expiry); 00334 00335 lock_msg_q(iface, type); 00336 msg = unlink_from_msg_q(iface, type); 00337 unlock_msg_q(iface, type); 00338 } else { 00339 /* good message, put it back and return */ 00340 switch (type) { 00341 case SMDI_MD: 00342 ast_smdi_md_message_push(iface, msg); 00343 break; 00344 case SMDI_MWI: 00345 ast_smdi_mwi_message_push(iface, msg); 00346 break; 00347 } 00348 unref_msg(msg, type); 00349 break; 00350 } 00351 } 00352 }
static int reload | ( | void | ) | [static] |
Definition at line 1360 of file res_smdi.c.
References ast_log(), LOG_WARNING, and smdi_load().
01361 { 01362 int res; 01363 01364 res = smdi_load(1); 01365 01366 if (res < 0) { 01367 return res; 01368 } else if (res == 1) { 01369 ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n"); 01370 return 0; 01371 } else 01372 return 0; 01373 }
static int smdi_load | ( | int | reload | ) | [static] |
Definition at line 834 of file res_smdi.c.
References ast_config_load, ast_log(), ast_variable_browse(), ASTOBJ_CONTAINER_MARKALL, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEUNCHANGED, ast_variable::lineno, LOG_NOTICE, ast_variable::name, ast_variable::next, smdi_ifaces, SMDI_MSG_EXPIRY_TIME, and ast_variable::value.
Referenced by load_module(), and reload().
00835 { 00836 struct ast_config *conf; 00837 struct ast_variable *v; 00838 struct ast_smdi_interface *iface = NULL; 00839 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00840 int res = 0; 00841 00842 /* Config options */ 00843 speed_t baud_rate = B9600; /* 9600 baud rate */ 00844 tcflag_t paritybit = PARENB; /* even parity checking */ 00845 tcflag_t charsize = CS7; /* seven bit characters */ 00846 int stopbits = 0; /* One stop bit */ 00847 00848 int msdstrip = 0; /* strip zero digits */ 00849 long msg_expiry = SMDI_MSG_EXPIRY_TIME; 00850 00851 if (!(conf = ast_config_load(config_file, config_flags))) { 00852 if (reload) 00853 ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file); 00854 else 00855 ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file); 00856 return 1; 00857 } else if (conf == CONFIG_STATUS_FILEUNCHANGED) 00858 return 0; 00859 00860 /* Mark all interfaces that we are listening on. We will unmark them 00861 * as we find them in the config file, this way we know any interfaces 00862 * still marked after we have finished parsing the config file should 00863 * be stopped. 00864 */ 00865 if (reload) 00866 ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces); 00867 00868 for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) { 00869 if (!strcasecmp(v->name, "baudrate")) { 00870 if (!strcasecmp(v->value, "9600")) 00871 baud_rate = B9600; 00872 else if (!strcasecmp(v->value, "4800")) 00873 baud_rate = B4800; 00874 else if (!strcasecmp(v->value, "2400")) 00875 baud_rate = B2400; 00876 else if (!strcasecmp(v->value, "1200")) 00877 baud_rate = B1200; 00878 else { 00879 ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno); 00880 baud_rate = B9600; 00881 } 00882 } else if (!strcasecmp(v->name, "msdstrip")) { 00883 if (!sscanf(v->value, "%d", &msdstrip)) { 00884 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); 00885 msdstrip = 0; 00886 } else if (0 > msdstrip || msdstrip > 9) { 00887 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); 00888 msdstrip = 0; 00889 } 00890 } else if (!strcasecmp(v->name, "msgexpirytime")) { 00891 if (!sscanf(v->value, "%ld", &msg_expiry)) { 00892 ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno); 00893 msg_expiry = SMDI_MSG_EXPIRY_TIME; 00894 } 00895 } else if (!strcasecmp(v->name, "paritybit")) { 00896 if (!strcasecmp(v->value, "even")) 00897 paritybit = PARENB; 00898 else if (!strcasecmp(v->value, "odd")) 00899 paritybit = PARENB | PARODD; 00900 else if (!strcasecmp(v->value, "none")) 00901 paritybit = ~PARENB; 00902 else { 00903 ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno); 00904 paritybit = PARENB; 00905 } 00906 } else if (!strcasecmp(v->name, "charsize")) { 00907 if (!strcasecmp(v->value, "7")) 00908 charsize = CS7; 00909 else if (!strcasecmp(v->value, "8")) 00910 charsize = CS8; 00911 else { 00912 ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno); 00913 charsize = CS7; 00914 } 00915 } else if (!strcasecmp(v->name, "twostopbits")) { 00916 stopbits = ast_true(v->name); 00917 } else if (!strcasecmp(v->name, "smdiport")) { 00918 if (reload) { 00919 /* we are reloading, check if we are already 00920 * monitoring this interface, if we are we do 00921 * not want to start it again. This also has 00922 * the side effect of not updating different 00923 * setting for the serial port, but it should 00924 * be trivial to rewrite this section so that 00925 * options on the port are changed without 00926 * restarting the interface. Or the interface 00927 * could be restarted with out emptying the 00928 * queue. */ 00929 if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { 00930 ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name); 00931 ASTOBJ_UNMARK(iface); 00932 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00933 continue; 00934 } 00935 } 00936 00937 if (!(iface = alloc_smdi_interface())) 00938 continue; 00939 00940 ast_copy_string(iface->name, v->value, sizeof(iface->name)); 00941 00942 iface->thread = AST_PTHREADT_NULL; 00943 00944 if (!(iface->file = fopen(iface->name, "r"))) { 00945 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno)); 00946 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00947 continue; 00948 } 00949 00950 iface->fd = fileno(iface->file); 00951 00952 /* Set the proper attributes for our serial port. */ 00953 00954 /* get the current attributes from the port */ 00955 if (tcgetattr(iface->fd, &iface->mode)) { 00956 ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno)); 00957 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00958 continue; 00959 } 00960 00961 /* set the desired speed */ 00962 if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) { 00963 ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno)); 00964 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00965 continue; 00966 } 00967 00968 /* set the stop bits */ 00969 if (stopbits) 00970 iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */ 00971 else 00972 iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */ 00973 00974 /* set the parity */ 00975 iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit; 00976 00977 /* set the character size */ 00978 iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize; 00979 00980 /* commit the desired attributes */ 00981 if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) { 00982 ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno)); 00983 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00984 continue; 00985 } 00986 00987 /* set the msdstrip */ 00988 iface->msdstrip = msdstrip; 00989 00990 /* set the message expiry time */ 00991 iface->msg_expiry = msg_expiry; 00992 00993 /* start the listener thread */ 00994 ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name); 00995 if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) { 00996 ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name); 00997 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00998 continue; 00999 } 01000 01001 ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface); 01002 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01003 ast_module_ref(ast_module_info->self); 01004 } else { 01005 ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file); 01006 } 01007 } 01008 01009 destroy_all_mailbox_mappings(); 01010 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL; 01011 01012 iface = NULL; 01013 01014 for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) { 01015 if (!strcasecmp(v->name, "smdiport")) { 01016 if (iface) 01017 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01018 01019 if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { 01020 ast_log(LOG_NOTICE, "SMDI interface %s not found\n", iface->name); 01021 continue; 01022 } 01023 } else if (!strcasecmp(v->name, "pollinginterval")) { 01024 if (sscanf(v->value, "%u", &mwi_monitor.polling_interval) != 1) { 01025 ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value); 01026 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL; 01027 } 01028 } else { 01029 if (!iface) { 01030 ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n"); 01031 continue; 01032 } 01033 append_mailbox_mapping(v, iface); 01034 } 01035 } 01036 01037 if (iface) 01038 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01039 01040 ast_config_destroy(conf); 01041 01042 if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL 01043 && ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) { 01044 ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n"); 01045 return AST_MODULE_LOAD_FAILURE; 01046 } 01047 01048 /* Prune any interfaces we should no longer monitor. */ 01049 if (reload) 01050 ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy); 01051 01052 ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces); 01053 /* TODO: this is bad, we need an ASTOBJ method for this! */ 01054 if (!smdi_ifaces.head) 01055 res = 1; 01056 ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces); 01057 01058 return res; 01059 }
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 416 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, msg, 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().
00418 { 00419 struct timeval start; 00420 long diff = 0; 00421 void *msg; 00422 ast_cond_t *cond = NULL; 00423 ast_mutex_t *lock = NULL; 00424 00425 switch (type) { 00426 case SMDI_MWI: 00427 cond = &iface->mwi_q_cond; 00428 lock = &iface->mwi_q_lock; 00429 break; 00430 case SMDI_MD: 00431 cond = &iface->md_q_cond; 00432 lock = &iface->md_q_lock; 00433 break; 00434 } 00435 00436 start = ast_tvnow(); 00437 00438 while (diff < timeout) { 00439 struct timespec ts = { 0, }; 00440 struct timeval wait; 00441 00442 lock_msg_q(iface, type); 00443 00444 if ((msg = smdi_msg_find(iface, type, search_key, options))) { 00445 unlock_msg_q(iface, type); 00446 return msg; 00447 } 00448 00449 wait = ast_tvadd(start, ast_tv(0, timeout)); 00450 ts.tv_sec = wait.tv_sec; 00451 ts.tv_nsec = wait.tv_usec * 1000; 00452 00453 /* If there were no messages in the queue, then go to sleep until one 00454 * arrives. */ 00455 00456 ast_cond_timedwait(cond, lock, &ts); 00457 00458 if ((msg = smdi_msg_find(iface, type, search_key, options))) { 00459 unlock_msg_q(iface, type); 00460 return msg; 00461 } 00462 00463 unlock_msg_q(iface, type); 00464 00465 /* check timeout */ 00466 diff = ast_tvdiff_ms(ast_tvnow(), start); 00467 } 00468 00469 return NULL; 00470 }
static void smdi_msg_datastore_destroy | ( | void * | data | ) | [static] |
Definition at line 1067 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().
01068 { 01069 struct smdi_msg_datastore *smd = data; 01070 01071 if (smd->iface) 01072 ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy); 01073 01074 if (smd->md_msg) 01075 ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy); 01076 01077 free(smd); 01078 }
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 372 of file res_smdi.c.
References ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_REF, mailbox_mapping::iface, ast_smdi_interface::md_q, msg, OPT_SEARCH_NUMBER, OPT_SEARCH_TERMINAL, purge_old_messages(), and SMDI_MD.
Referenced by smdi_message_wait().
00374 { 00375 void *msg = NULL; 00376 00377 purge_old_messages(iface, type); 00378 00379 switch (type) { 00380 case SMDI_MD: 00381 if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) { 00382 struct ast_smdi_md_message *md_msg = NULL; 00383 00384 /* Searching by the message desk terminal */ 00385 00386 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do { 00387 if (!strcasecmp(iterator->mesg_desk_term, search_key)) 00388 md_msg = ASTOBJ_REF(iterator); 00389 } while (0); ); 00390 00391 msg = md_msg; 00392 } else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) { 00393 struct ast_smdi_md_message *md_msg = NULL; 00394 00395 /* Searching by the message desk number */ 00396 00397 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do { 00398 if (!strcasecmp(iterator->mesg_desk_num, search_key)) 00399 md_msg = ASTOBJ_REF(iterator); 00400 } while (0); ); 00401 00402 msg = md_msg; 00403 } else { 00404 /* Searching by the forwarding station */ 00405 msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, search_key); 00406 } 00407 break; 00408 case SMDI_MWI: 00409 msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, search_key); 00410 break; 00411 } 00412 00413 return msg; 00414 }
static void* smdi_msg_pop | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [static] |
Definition at line 354 of file res_smdi.c.
References mailbox_mapping::iface, lock_msg_q(), msg, purge_old_messages(), unlink_from_msg_q(), and unlock_msg_q().
Referenced by ast_smdi_md_message_pop(), and ast_smdi_mwi_message_pop().
00355 { 00356 void *msg; 00357 00358 purge_old_messages(iface, type); 00359 00360 lock_msg_q(iface, type); 00361 msg = unlink_from_msg_q(iface, type); 00362 unlock_msg_q(iface, type); 00363 00364 return msg; 00365 }
static int smdi_msg_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1194 of file res_smdi.c.
References 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_strdupa, ast_strlen_zero(), ast_smdi_md_message::calling_st, chan, 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(), smdi_msg_datastore_info, and ast_smdi_md_message::type.
01195 { 01196 struct ast_module_user *u; 01197 int res = -1; 01198 AST_DECLARE_APP_ARGS(args, 01199 AST_APP_ARG(id); 01200 AST_APP_ARG(component); 01201 ); 01202 char *parse; 01203 struct ast_datastore *datastore = NULL; 01204 struct smdi_msg_datastore *smd = NULL; 01205 01206 u = ast_module_user_add(chan); 01207 01208 if (!chan) { 01209 ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n"); 01210 goto return_error; 01211 } 01212 01213 if (ast_strlen_zero(data)) { 01214 ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n"); 01215 goto return_error; 01216 } 01217 01218 parse = ast_strdupa(data); 01219 AST_STANDARD_APP_ARGS(args, parse); 01220 01221 if (ast_strlen_zero(args.id)) { 01222 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n"); 01223 goto return_error; 01224 } 01225 01226 if (ast_strlen_zero(args.component)) { 01227 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n"); 01228 goto return_error; 01229 } 01230 01231 ast_channel_lock(chan); 01232 datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id); 01233 ast_channel_unlock(chan); 01234 01235 if (!datastore) { 01236 ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id); 01237 goto return_error; 01238 } 01239 01240 smd = datastore->data; 01241 01242 if (!strcasecmp(args.component, "number")) { 01243 ast_copy_string(buf, smd->md_msg->mesg_desk_num, len); 01244 } else if (!strcasecmp(args.component, "terminal")) { 01245 ast_copy_string(buf, smd->md_msg->mesg_desk_term, len); 01246 } else if (!strcasecmp(args.component, "station")) { 01247 ast_copy_string(buf, smd->md_msg->fwd_st, len); 01248 } else if (!strcasecmp(args.component, "callerid")) { 01249 ast_copy_string(buf, smd->md_msg->calling_st, len); 01250 } else if (!strcasecmp(args.component, "type")) { 01251 snprintf(buf, len, "%c", smd->md_msg->type); 01252 } else { 01253 ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n", 01254 args.component); 01255 goto return_error; 01256 } 01257 01258 res = 0; 01259 01260 return_error: 01261 ast_module_user_remove(u); 01262 01263 return res; 01264 }
static int smdi_msg_retrieve_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1095 of file res_smdi.c.
References 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_strdupa, ast_strlen_zero(), ASTOBJ_REF, ASTOBJ_UNREF, chan, ast_datastore::data, LOG_ERROR, LOG_WARNING, parse(), SMDI_MD, smdi_message_wait(), smdi_msg_datastore_destroy(), smdi_msg_datastore_info, smdi_msg_ret_options, and SMDI_RETRIEVE_TIMEOUT_DEFAULT.
01096 { 01097 struct ast_module_user *u; 01098 AST_DECLARE_APP_ARGS(args, 01099 AST_APP_ARG(port); 01100 AST_APP_ARG(search_key); 01101 AST_APP_ARG(timeout); 01102 AST_APP_ARG(options); 01103 ); 01104 struct ast_flags options = { 0 }; 01105 unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT; 01106 int res = -1; 01107 char *parse = NULL; 01108 struct smdi_msg_datastore *smd = NULL; 01109 struct ast_datastore *datastore = NULL; 01110 struct ast_smdi_interface *iface = NULL; 01111 struct ast_smdi_md_message *md_msg = NULL; 01112 01113 u = ast_module_user_add(chan); 01114 01115 if (ast_strlen_zero(data)) { 01116 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n"); 01117 goto return_error; 01118 } 01119 01120 if (!chan) { 01121 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n"); 01122 goto return_error; 01123 } 01124 01125 ast_autoservice_start(chan); 01126 01127 parse = ast_strdupa(data); 01128 AST_STANDARD_APP_ARGS(args, parse); 01129 01130 if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) { 01131 ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n"); 01132 goto return_error; 01133 } 01134 01135 if (!(iface = ast_smdi_interface_find(args.port))) { 01136 ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port); 01137 goto return_error; 01138 } 01139 01140 if (!ast_strlen_zero(args.options)) { 01141 ast_app_parse_options(smdi_msg_ret_options, &options, NULL, args.options); 01142 } 01143 01144 if (!ast_strlen_zero(args.timeout)) { 01145 if (sscanf(args.timeout, "%u", &timeout) != 1) { 01146 ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout); 01147 timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT; 01148 } 01149 } 01150 01151 if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) { 01152 ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after " 01153 "waiting %u ms.\n", args.search_key, timeout); 01154 goto return_error; 01155 } 01156 01157 if (!(smd = ast_calloc(1, sizeof(*smd)))) 01158 goto return_error; 01159 01160 smd->iface = ASTOBJ_REF(iface); 01161 smd->md_msg = ASTOBJ_REF(md_msg); 01162 smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1); 01163 snprintf(buf, len, "%u", smd->id); 01164 01165 if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf))) 01166 goto return_error; 01167 01168 datastore->data = smd; 01169 01170 ast_channel_lock(chan); 01171 ast_channel_datastore_add(chan, datastore); 01172 ast_channel_unlock(chan); 01173 01174 res = 0; 01175 01176 return_error: 01177 if (iface) 01178 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01179 01180 if (md_msg) 01181 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 01182 01183 if (smd && !datastore) 01184 smdi_msg_datastore_destroy(smd); 01185 01186 if (parse) 01187 ast_autoservice_stop(chan); 01188 01189 ast_module_user_remove(u); 01190 01191 return res; 01192 }
static void* smdi_read | ( | void * | iface_p | ) | [static] |
Definition at line 515 of file res_smdi.c.
References ast_calloc, ast_copy_string(), ast_log(), ast_smdi_interface_destroy(), ASTOBJ_INIT, ASTOBJ_UNREF, ast_smdi_md_message::calling_st, ast_smdi_interface::file, ast_smdi_md_message::fwd_st, LOG_DEBUG, ast_smdi_interface::msdstrip, and ast_smdi_md_message::name.
00516 { 00517 struct ast_smdi_interface *iface = iface_p; 00518 struct ast_smdi_md_message *md_msg; 00519 struct ast_smdi_mwi_message *mwi_msg; 00520 char c = '\0'; 00521 char *cp = NULL; 00522 int i; 00523 int start = 0; 00524 00525 /* read an smdi message */ 00526 while ((c = fgetc(iface->file))) { 00527 00528 /* check if this is the start of a message */ 00529 if (!start) { 00530 if (c == 'M') { 00531 ast_log(LOG_DEBUG, "Read an 'M' to start an SMDI message\n"); 00532 start = 1; 00533 } 00534 continue; 00535 } 00536 00537 if (c == 'D') { /* MD message */ 00538 start = 0; 00539 00540 ast_log(LOG_DEBUG, "Read a 'D' ... it's an MD message.\n"); 00541 00542 if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) { 00543 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00544 return NULL; 00545 } 00546 00547 ASTOBJ_INIT(md_msg); 00548 00549 /* read the message desk number */ 00550 for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) { 00551 md_msg->mesg_desk_num[i] = fgetc(iface->file); 00552 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_num[i]); 00553 } 00554 00555 md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0'; 00556 00557 ast_log(LOG_DEBUG, "The message desk number is '%s'\n", md_msg->mesg_desk_num); 00558 00559 /* read the message desk terminal number */ 00560 for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) { 00561 md_msg->mesg_desk_term[i] = fgetc(iface->file); 00562 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_term[i]); 00563 } 00564 00565 md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0'; 00566 00567 ast_log(LOG_DEBUG, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term); 00568 00569 /* read the message type */ 00570 md_msg->type = fgetc(iface->file); 00571 00572 ast_log(LOG_DEBUG, "Message type is '%c'\n", md_msg->type); 00573 00574 /* read the forwarding station number (may be blank) */ 00575 cp = &md_msg->fwd_st[0]; 00576 for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) { 00577 if ((c = fgetc(iface->file)) == ' ') { 00578 *cp = '\0'; 00579 ast_log(LOG_DEBUG, "Read a space, done looking for the forwarding station\n"); 00580 break; 00581 } 00582 00583 /* store c in md_msg->fwd_st */ 00584 if (i >= iface->msdstrip) { 00585 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the forwarding station buffer\n", c); 00586 *cp++ = c; 00587 } else { 00588 ast_log(LOG_DEBUG, "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); 00589 } 00590 } 00591 00592 /* make sure the value is null terminated, even if this truncates it */ 00593 md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0'; 00594 cp = NULL; 00595 00596 ast_log(LOG_DEBUG, "The forwarding station is '%s'\n", md_msg->fwd_st); 00597 00598 /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look 00599 * up a message on this field */ 00600 ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name)); 00601 00602 /* read the calling station number (may be blank) */ 00603 cp = &md_msg->calling_st[0]; 00604 for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) { 00605 if (!isdigit((c = fgetc(iface->file)))) { 00606 *cp = '\0'; 00607 ast_log(LOG_DEBUG, "Read a '%c', but didn't store it in the calling station buffer because it's not a digit\n", c); 00608 if (c == ' ') { 00609 /* Don't break on a space. We may read the space before the calling station 00610 * here if the forwarding station buffer filled up. */ 00611 i--; /* We're still on the same character */ 00612 continue; 00613 } 00614 break; 00615 } 00616 00617 /* store c in md_msg->calling_st */ 00618 if (i >= iface->msdstrip) { 00619 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the calling station buffer\n", c); 00620 *cp++ = c; 00621 } else { 00622 ast_log(LOG_DEBUG, "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); 00623 } 00624 } 00625 00626 /* make sure the value is null terminated, even if this truncates it */ 00627 md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0'; 00628 cp = NULL; 00629 00630 ast_log(LOG_DEBUG, "The calling station is '%s'\n", md_msg->calling_st); 00631 00632 /* add the message to the message queue */ 00633 md_msg->timestamp = ast_tvnow(); 00634 ast_smdi_md_message_push(iface, md_msg); 00635 ast_log(LOG_DEBUG, "Recieved SMDI MD message on %s\n", iface->name); 00636 00637 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 00638 00639 } else if (c == 'W') { /* MWI message */ 00640 start = 0; 00641 00642 ast_log(LOG_DEBUG, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n"); 00643 00644 if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) { 00645 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy); 00646 return NULL; 00647 } 00648 00649 ASTOBJ_INIT(mwi_msg); 00650 00651 /* discard the 'I' (from 'MWI') */ 00652 fgetc(iface->file); 00653 00654 /* read the forwarding station number (may be blank) */ 00655 cp = &mwi_msg->fwd_st[0]; 00656 for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) { 00657 if ((c = fgetc(iface->file)) == ' ') { 00658 *cp = '\0'; 00659 break; 00660 } 00661 00662 /* store c in md_msg->fwd_st */ 00663 if (i >= iface->msdstrip) 00664 *cp++ = c; 00665 } 00666 00667 /* make sure the station number is null terminated, even if this will truncate it */ 00668 mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0'; 00669 cp = NULL; 00670 00671 /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look 00672 * up a message on this field */ 00673 ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name)); 00674 00675 /* read the mwi failure cause */ 00676 for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) 00677 mwi_msg->cause[i] = fgetc(iface->file); 00678 00679 mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0'; 00680 00681 /* add the message to the message queue */ 00682 mwi_msg->timestamp = ast_tvnow(); 00683 ast_smdi_mwi_message_push(iface, mwi_msg); 00684 ast_log(LOG_DEBUG, "Recieved SMDI MWI message on %s\n", iface->name); 00685 00686 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); 00687 } else { 00688 ast_log(LOG_ERROR, "Unknown SMDI message type recieved on %s (M%c).\n", iface->name, c); 00689 start = 0; 00690 } 00691 } 00692 00693 ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name); 00694 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy); 00695 return NULL; 00696 }
static int smdi_toggle_mwi | ( | struct ast_smdi_interface * | iface, | |
const char * | mailbox, | |||
int | on | |||
) | [static] |
Definition at line 192 of file res_smdi.c.
References ast_debug, ast_log(), ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, errno, mailbox_mapping::iface, LOG_ERROR, ast_smdi_interface::msdstrip, and ast_smdi_interface::name.
Referenced by ast_smdi_mwi_set(), and ast_smdi_mwi_unset().
00193 { 00194 FILE *file; 00195 int i; 00196 00197 if (!(file = fopen(iface->name, "w"))) { 00198 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno)); 00199 return 1; 00200 } 00201 00202 ASTOBJ_WRLOCK(iface); 00203 00204 fprintf(file, "%s:MWI ", on ? "OP" : "RMV"); 00205 00206 for (i = 0; i < iface->msdstrip; i++) 00207 fprintf(file, "0"); 00208 00209 fprintf(file, "%s!\x04", mailbox); 00210 00211 fclose(file); 00212 00213 ASTOBJ_UNLOCK(iface); 00214 ast_debug(1, "Sent MWI set message for %s on %s\n", mailbox, iface->name); 00215 00216 return 0; 00217 }
static void* unlink_from_msg_q | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [inline, static] |
Definition at line 274 of file res_smdi.c.
References ASTOBJ_CONTAINER_UNLINK_START, mailbox_mapping::iface, ast_smdi_interface::md_q, ast_smdi_interface::mwi_q, SMDI_MD, and SMDI_MWI.
Referenced by purge_old_messages(), and smdi_msg_pop().
00275 { 00276 switch (type) { 00277 case SMDI_MWI: 00278 return ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q); 00279 case SMDI_MD: 00280 return ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q); 00281 } 00282 return NULL; 00283 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1337 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, smdi_ifaces, smdi_msg_function, and smdi_msg_retrieve_function.
01338 { 01339 /* this destructor stops any running smdi_read threads */ 01340 ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy); 01341 ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces); 01342 01343 destroy_all_mailbox_mappings(); 01344 01345 ast_mutex_lock(&mwi_monitor.lock); 01346 mwi_monitor.stop = 1; 01347 ast_cond_signal(&mwi_monitor.cond); 01348 ast_mutex_unlock(&mwi_monitor.lock); 01349 01350 if (mwi_monitor.thread != AST_PTHREADT_NULL) { 01351 pthread_join(mwi_monitor.thread, NULL); 01352 } 01353 01354 ast_custom_function_unregister(&smdi_msg_retrieve_function); 01355 ast_custom_function_unregister(&smdi_msg_function); 01356 01357 return 0; 01358 }
static int unlock_msg_q | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [inline, static] |
Definition at line 262 of file res_smdi.c.
References ast_mutex_unlock(), mailbox_mapping::iface, 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().
00263 { 00264 switch (type) { 00265 case SMDI_MWI: 00266 return ast_mutex_unlock(&iface->mwi_q_lock); 00267 case SMDI_MD: 00268 return ast_mutex_unlock(&iface->md_q_lock); 00269 } 00270 00271 return -1; 00272 }
static void unref_msg | ( | void * | msg, | |
enum smdi_message_type | type | |||
) | [inline, static] |
Definition at line 300 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().
00301 { 00302 struct ast_smdi_md_message *md_msg = msg; 00303 struct ast_smdi_mwi_message *mwi_msg = msg; 00304 00305 switch (type) { 00306 case SMDI_MWI: 00307 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); 00308 case SMDI_MD: 00309 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 00310 } 00311 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1379 of file res_smdi.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1379 of file res_smdi.c.
Definition at line 118 of file res_smdi.c.
const char config_file[] = "smdi.conf" [static] |
Definition at line 59 of file res_smdi.c.
struct mailbox_mapping* first |
Definition at line 120 of file res_smdi.c.
struct mailbox_mapping* last |
Definition at line 120 of file res_smdi.c.
struct timeval last_poll |
The time that the last poll began
Definition at line 126 of file res_smdi.c.
Definition at line 117 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 append_mailbox_mapping(), destroy_all_mailbox_mappings(), load_module(), mwi_monitor_handler(), and unload_module().
unsigned int polling_interval |
Polling Interval for checking mailbox status
Definition at line 122 of file res_smdi.c.
SMDI interface container.
Referenced by ast_smdi_interface_find(), load_module(), smdi_load(), and unload_module().
struct ast_datastore_info smdi_msg_datastore_info [static] |
Initial value:
{ .type = "SMDIMSG", .destroy = smdi_msg_datastore_destroy, }
Definition at line 1080 of file res_smdi.c.
Referenced by smdi_msg_read(), and smdi_msg_retrieve_read().
struct ast_custom_function smdi_msg_function [static] |
int smdi_msg_id [static] |
Definition at line 1085 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] |
struct ast_custom_function smdi_msg_retrieve_function [static] |
unsigned int stop |
Set to 1 to tell the polling thread to stop
Definition at line 124 of file res_smdi.c.
pthread_t thread |
The thread ID
Definition at line 116 of file res_smdi.c.