#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 369 of file res_smdi.c.
00369 { 00370 OPT_SEARCH_TERMINAL = (1 << 0), 00371 OPT_SEARCH_NUMBER = (1 << 1), 00372 };
enum smdi_message_type |
static void __reg_module | ( | void | ) | [static] |
Definition at line 1409 of file res_smdi.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1409 of file res_smdi.c.
static struct ast_smdi_interface* alloc_smdi_interface | ( | void | ) | [static] |
Definition at line 830 of file res_smdi.c.
References ast_calloc, ast_cond_init(), ast_mutex_init(), ASTOBJ_CONTAINER_INIT, and ASTOBJ_INIT.
00831 { 00832 struct ast_smdi_interface *iface; 00833 00834 if (!(iface = ast_calloc(1, sizeof(*iface)))) 00835 return NULL; 00836 00837 ASTOBJ_INIT(iface); 00838 ASTOBJ_CONTAINER_INIT(&iface->md_q); 00839 ASTOBJ_CONTAINER_INIT(&iface->mwi_q); 00840 00841 ast_mutex_init(&iface->md_q_lock); 00842 ast_cond_init(&iface->md_q_cond, NULL); 00843 00844 ast_mutex_init(&iface->mwi_q_lock); 00845 ast_cond_init(&iface->mwi_q_cond, NULL); 00846 00847 return iface; 00848 }
static void append_mailbox_mapping | ( | struct ast_variable * | var, | |
struct ast_smdi_interface * | iface | |||
) | [static] |
Definition at line 751 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.
00752 { 00753 struct mailbox_mapping *mm; 00754 char *mailbox, *context; 00755 00756 if (!(mm = ast_calloc(1, sizeof(*mm)))) 00757 return; 00758 00759 if (ast_string_field_init(mm, 32)) { 00760 free(mm); 00761 return; 00762 } 00763 00764 ast_string_field_set(mm, smdi, var->name); 00765 00766 context = ast_strdupa(var->value); 00767 mailbox = strsep(&context, "@"); 00768 if (ast_strlen_zero(context)) 00769 context = "default"; 00770 00771 ast_string_field_set(mm, mailbox, mailbox); 00772 ast_string_field_set(mm, context, context); 00773 00774 mm->iface = ASTOBJ_REF(iface); 00775 00776 ast_mutex_lock(&mwi_monitor.lock); 00777 AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry); 00778 ast_mutex_unlock(&mwi_monitor.lock); 00779 }
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 527 of file res_smdi.c.
References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.
Referenced by load_config(), and smdi_msg_retrieve_read().
00528 { 00529 return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name)); 00530 }
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 724 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 498 of file res_smdi.c.
References SMDI_MD, and smdi_msg_pop().
00499 { 00500 return smdi_msg_pop(iface, SMDI_MD); 00501 }
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 503 of file res_smdi.c.
References SMDI_MD, and smdi_message_wait().
Referenced by ss_thread().
00504 { 00505 struct ast_flags options = { 0 }; 00506 return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options); 00507 }
void ast_smdi_mwi_message_destroy | ( | struct ast_smdi_mwi_message * | msg | ) |
ast_smdi_mwi_message destructor.
Definition at line 729 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 509 of file res_smdi.c.
References smdi_msg_pop(), and SMDI_MWI.
00510 { 00511 return smdi_msg_pop(iface, SMDI_MWI); 00512 }
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 514 of file res_smdi.c.
References smdi_message_wait(), and SMDI_MWI.
00515 { 00516 struct ast_flags options = { 0 }; 00517 return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options); 00518 }
struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait_station | ( | struct ast_smdi_interface * | iface, | |
int | timeout, | |||
const char * | station | |||
) |
Definition at line 520 of file res_smdi.c.
References smdi_message_wait(), and SMDI_MWI.
Referenced by run_externnotify().
00522 { 00523 struct ast_flags options = { 0 }; 00524 return smdi_message_wait(iface, timeout, SMDI_MWI, station, options); 00525 }
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 741 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().
00742 { 00743 struct mailbox_mapping *mm; 00744 00745 ast_mutex_lock(&mwi_monitor.lock); 00746 while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry))) 00747 destroy_mailbox_mapping(mm); 00748 ast_mutex_unlock(&mwi_monitor.lock); 00749 }
static void destroy_mailbox_mapping | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 734 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().
00735 { 00736 ast_string_field_free_memory(mm); 00737 ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy); 00738 free(mm); 00739 }
static int load_module | ( | void | ) | [static] |
Definition at line 1339 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, smdi_msg_retrieve_function, and unload_module().
01340 { 01341 int res; 01342 01343 /* initialize our containers */ 01344 memset(&smdi_ifaces, 0, sizeof(smdi_ifaces)); 01345 ASTOBJ_CONTAINER_INIT(&smdi_ifaces); 01346 01347 ast_mutex_init(&mwi_monitor.lock); 01348 ast_cond_init(&mwi_monitor.cond, NULL); 01349 01350 ast_custom_function_register(&smdi_msg_retrieve_function); 01351 ast_custom_function_register(&smdi_msg_function); 01352 01353 /* load the config and start the listener threads*/ 01354 res = smdi_load(0); 01355 if (res < 0) { 01356 unload_module(); 01357 return res; 01358 } else if (res == 1) { 01359 unload_module(); 01360 ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n"); 01361 return AST_MODULE_LOAD_DECLINE; 01362 } 01363 01364 return AST_MODULE_LOAD_SUCCESS; 01365 }
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 803 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().
00804 { 00805 while (!mwi_monitor.stop) { 00806 struct timespec ts = { 0, }; 00807 struct timeval polltime; 00808 struct mailbox_mapping *mm; 00809 00810 ast_mutex_lock(&mwi_monitor.lock); 00811 00812 mwi_monitor.last_poll = ast_tvnow(); 00813 00814 AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry) 00815 poll_mailbox(mm); 00816 00817 /* Sleep up to the configured polling interval. Allow unload_module() 00818 * to signal us to wake up and exit. */ 00819 polltime = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0)); 00820 ts.tv_sec = polltime.tv_sec; 00821 ts.tv_nsec = polltime.tv_usec * 1000; 00822 ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts); 00823 00824 ast_mutex_unlock(&mwi_monitor.lock); 00825 } 00826 00827 return NULL; 00828 }
static void poll_mailbox | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 784 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().
00785 { 00786 char buf[1024]; 00787 unsigned int state; 00788 00789 snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context); 00790 00791 state = !!ast_app_has_voicemail(mm->mailbox, NULL); 00792 00793 if (state != mm->cur_state) { 00794 if (state) 00795 ast_smdi_mwi_set(mm->iface, mm->smdi); 00796 else 00797 ast_smdi_mwi_unset(mm->iface, mm->smdi); 00798 00799 mm->cur_state = state; 00800 } 00801 }
static void purge_old_messages | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [static] |
Definition at line 315 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().
00316 { 00317 struct timeval now = ast_tvnow(); 00318 long elapsed = 0; 00319 void *msg; 00320 00321 lock_msg_q(iface, type); 00322 msg = unlink_from_msg_q(iface, type); 00323 unlock_msg_q(iface, type); 00324 00325 /* purge old messages */ 00326 while (msg) { 00327 elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type)); 00328 00329 if (elapsed > iface->msg_expiry) { 00330 /* found an expired message */ 00331 unref_msg(msg, type); 00332 ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue. " 00333 "Message was %ld milliseconds too old.\n", 00334 iface->name, (type == SMDI_MD) ? "MD" : "MWI", 00335 elapsed - iface->msg_expiry); 00336 00337 lock_msg_q(iface, type); 00338 msg = unlink_from_msg_q(iface, type); 00339 unlock_msg_q(iface, type); 00340 } else { 00341 /* good message, put it back and return */ 00342 switch (type) { 00343 case SMDI_MD: 00344 ast_smdi_md_message_push(iface, msg); 00345 break; 00346 case SMDI_MWI: 00347 ast_smdi_mwi_message_push(iface, msg); 00348 break; 00349 } 00350 unref_msg(msg, type); 00351 break; 00352 } 00353 } 00354 }
static int reload | ( | void | ) | [static] |
Definition at line 1390 of file res_smdi.c.
References ast_log(), LOG_WARNING, and smdi_load().
01391 { 01392 int res; 01393 01394 res = smdi_load(1); 01395 01396 if (res < 0) { 01397 return res; 01398 } else if (res == 1) { 01399 ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n"); 01400 return 0; 01401 } else 01402 return 0; 01403 }
static int smdi_load | ( | int | reload | ) | [static] |
Definition at line 860 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().
00861 { 00862 struct ast_config *conf; 00863 struct ast_variable *v; 00864 struct ast_smdi_interface *iface = NULL; 00865 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00866 int res = 0; 00867 00868 /* Config options */ 00869 speed_t baud_rate = B9600; /* 9600 baud rate */ 00870 tcflag_t paritybit = PARENB; /* even parity checking */ 00871 tcflag_t charsize = CS7; /* seven bit characters */ 00872 int stopbits = 0; /* One stop bit */ 00873 00874 int msdstrip = 0; /* strip zero digits */ 00875 long msg_expiry = SMDI_MSG_EXPIRY_TIME; 00876 00877 if (!(conf = ast_config_load(config_file, config_flags))) { 00878 if (reload) 00879 ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file); 00880 else 00881 ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file); 00882 return 1; 00883 } else if (conf == CONFIG_STATUS_FILEUNCHANGED) 00884 return 0; 00885 00886 /* Mark all interfaces that we are listening on. We will unmark them 00887 * as we find them in the config file, this way we know any interfaces 00888 * still marked after we have finished parsing the config file should 00889 * be stopped. 00890 */ 00891 if (reload) 00892 ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces); 00893 00894 for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) { 00895 if (!strcasecmp(v->name, "baudrate")) { 00896 if (!strcasecmp(v->value, "9600")) 00897 baud_rate = B9600; 00898 else if (!strcasecmp(v->value, "4800")) 00899 baud_rate = B4800; 00900 else if (!strcasecmp(v->value, "2400")) 00901 baud_rate = B2400; 00902 else if (!strcasecmp(v->value, "1200")) 00903 baud_rate = B1200; 00904 else { 00905 ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno); 00906 baud_rate = B9600; 00907 } 00908 } else if (!strcasecmp(v->name, "msdstrip")) { 00909 if (!sscanf(v->value, "%30d", &msdstrip)) { 00910 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); 00911 msdstrip = 0; 00912 } else if (0 > msdstrip || msdstrip > 9) { 00913 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); 00914 msdstrip = 0; 00915 } 00916 } else if (!strcasecmp(v->name, "msgexpirytime")) { 00917 if (!sscanf(v->value, "%30ld", &msg_expiry)) { 00918 ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno); 00919 msg_expiry = SMDI_MSG_EXPIRY_TIME; 00920 } 00921 } else if (!strcasecmp(v->name, "paritybit")) { 00922 if (!strcasecmp(v->value, "even")) 00923 paritybit = PARENB; 00924 else if (!strcasecmp(v->value, "odd")) 00925 paritybit = PARENB | PARODD; 00926 else if (!strcasecmp(v->value, "none")) 00927 paritybit = ~PARENB; 00928 else { 00929 ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno); 00930 paritybit = PARENB; 00931 } 00932 } else if (!strcasecmp(v->name, "charsize")) { 00933 if (!strcasecmp(v->value, "7")) 00934 charsize = CS7; 00935 else if (!strcasecmp(v->value, "8")) 00936 charsize = CS8; 00937 else { 00938 ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno); 00939 charsize = CS7; 00940 } 00941 } else if (!strcasecmp(v->name, "twostopbits")) { 00942 stopbits = ast_true(v->name); 00943 } else if (!strcasecmp(v->name, "smdiport")) { 00944 if (reload) { 00945 /* we are reloading, check if we are already 00946 * monitoring this interface, if we are we do 00947 * not want to start it again. This also has 00948 * the side effect of not updating different 00949 * setting for the serial port, but it should 00950 * be trivial to rewrite this section so that 00951 * options on the port are changed without 00952 * restarting the interface. Or the interface 00953 * could be restarted with out emptying the 00954 * queue. */ 00955 if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { 00956 ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name); 00957 ASTOBJ_UNMARK(iface); 00958 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00959 continue; 00960 } 00961 } 00962 00963 if (!(iface = alloc_smdi_interface())) 00964 continue; 00965 00966 ast_copy_string(iface->name, v->value, sizeof(iface->name)); 00967 00968 iface->thread = AST_PTHREADT_NULL; 00969 00970 if (!(iface->file = fopen(iface->name, "r"))) { 00971 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno)); 00972 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00973 continue; 00974 } 00975 00976 iface->fd = fileno(iface->file); 00977 00978 /* Set the proper attributes for our serial port. */ 00979 00980 /* get the current attributes from the port */ 00981 if (tcgetattr(iface->fd, &iface->mode)) { 00982 ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno)); 00983 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00984 continue; 00985 } 00986 00987 /* set the desired speed */ 00988 if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) { 00989 ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno)); 00990 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00991 continue; 00992 } 00993 00994 /* set the stop bits */ 00995 if (stopbits) 00996 iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */ 00997 else 00998 iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */ 00999 01000 /* set the parity */ 01001 iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit; 01002 01003 /* set the character size */ 01004 iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize; 01005 01006 /* commit the desired attributes */ 01007 if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) { 01008 ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno)); 01009 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01010 continue; 01011 } 01012 01013 /* set the msdstrip */ 01014 iface->msdstrip = msdstrip; 01015 01016 /* set the message expiry time */ 01017 iface->msg_expiry = msg_expiry; 01018 01019 /* start the listener thread */ 01020 ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name); 01021 if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) { 01022 ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name); 01023 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01024 continue; 01025 } 01026 01027 ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface); 01028 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01029 ast_module_ref(ast_module_info->self); 01030 } else { 01031 ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file); 01032 } 01033 } 01034 01035 destroy_all_mailbox_mappings(); 01036 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL; 01037 01038 iface = NULL; 01039 01040 for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) { 01041 if (!strcasecmp(v->name, "smdiport")) { 01042 if (iface) 01043 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01044 01045 if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { 01046 ast_log(LOG_NOTICE, "SMDI interface %s not found\n", iface->name); 01047 continue; 01048 } 01049 } else if (!strcasecmp(v->name, "pollinginterval")) { 01050 if (sscanf(v->value, "%30u", &mwi_monitor.polling_interval) != 1) { 01051 ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value); 01052 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL; 01053 } 01054 } else { 01055 if (!iface) { 01056 ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n"); 01057 continue; 01058 } 01059 append_mailbox_mapping(v, iface); 01060 } 01061 } 01062 01063 if (iface) 01064 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01065 01066 ast_config_destroy(conf); 01067 01068 if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL 01069 && ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) { 01070 ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n"); 01071 return AST_MODULE_LOAD_FAILURE; 01072 } 01073 01074 /* Prune any interfaces we should no longer monitor. */ 01075 if (reload) 01076 ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy); 01077 01078 ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces); 01079 /* TODO: this is bad, we need an ASTOBJ method for this! */ 01080 if (!smdi_ifaces.head) 01081 res = 1; 01082 ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces); 01083 01084 return res; 01085 }
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 442 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().
00444 { 00445 struct timeval start; 00446 long diff = 0; 00447 void *msg; 00448 ast_cond_t *cond = NULL; 00449 ast_mutex_t *lock = NULL; 00450 00451 switch (type) { 00452 case SMDI_MWI: 00453 cond = &iface->mwi_q_cond; 00454 lock = &iface->mwi_q_lock; 00455 break; 00456 case SMDI_MD: 00457 cond = &iface->md_q_cond; 00458 lock = &iface->md_q_lock; 00459 break; 00460 } 00461 00462 start = ast_tvnow(); 00463 00464 while (diff < timeout) { 00465 struct timespec ts = { 0, }; 00466 struct timeval wait; 00467 00468 lock_msg_q(iface, type); 00469 00470 if ((msg = smdi_msg_find(iface, type, search_key, options))) { 00471 unlock_msg_q(iface, type); 00472 return msg; 00473 } 00474 00475 wait = ast_tvadd(start, ast_tv(0, timeout)); 00476 ts.tv_sec = wait.tv_sec; 00477 ts.tv_nsec = wait.tv_usec * 1000; 00478 00479 /* If there were no messages in the queue, then go to sleep until one 00480 * arrives. */ 00481 00482 ast_cond_timedwait(cond, lock, &ts); 00483 00484 if ((msg = smdi_msg_find(iface, type, search_key, options))) { 00485 unlock_msg_q(iface, type); 00486 return msg; 00487 } 00488 00489 unlock_msg_q(iface, type); 00490 00491 /* check timeout */ 00492 diff = ast_tvdiff_ms(ast_tvnow(), start); 00493 } 00494 00495 return NULL; 00496 }
static void smdi_msg_datastore_destroy | ( | void * | data | ) | [static] |
Definition at line 1093 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().
01094 { 01095 struct smdi_msg_datastore *smd = data; 01096 01097 if (smd->iface) 01098 ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy); 01099 01100 if (smd->md_msg) 01101 ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy); 01102 01103 free(smd); 01104 }
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 374 of file res_smdi.c.
References ast_strlen_zero(), ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_REF, mailbox_mapping::iface, ast_smdi_interface::md_q, msg, OPT_SEARCH_TERMINAL, purge_old_messages(), and SMDI_MD.
Referenced by smdi_message_wait().
00376 { 00377 void *msg = NULL; 00378 00379 purge_old_messages(iface, type); 00380 00381 switch (type) { 00382 case SMDI_MD: 00383 if (ast_strlen_zero(search_key)) { 00384 struct ast_smdi_md_message *md_msg = NULL; 00385 00386 /* No search key provided (the code from chan_dahdi does this). 00387 * Just pop the top message off of the queue. */ 00388 00389 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do { 00390 md_msg = ASTOBJ_REF(iterator); 00391 } while (0); ); 00392 00393 msg = md_msg; 00394 } else if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) { 00395 struct ast_smdi_md_message *md_msg = NULL; 00396 00397 /* Searching by the message desk terminal */ 00398 00399 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do { 00400 if (!strcasecmp(iterator->mesg_desk_term, search_key)) 00401 md_msg = ASTOBJ_REF(iterator); 00402 } while (0); ); 00403 00404 msg = md_msg; 00405 } else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) { 00406 struct ast_smdi_md_message *md_msg = NULL; 00407 00408 /* Searching by the message desk number */ 00409 00410 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do { 00411 if (!strcasecmp(iterator->mesg_desk_num, search_key)) 00412 md_msg = ASTOBJ_REF(iterator); 00413 } while (0); ); 00414 00415 msg = md_msg; 00416 } else { 00417 /* Searching by the forwarding station */ 00418 msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, search_key); 00419 } 00420 break; 00421 case SMDI_MWI: 00422 if (ast_strlen_zero(search_key)) { 00423 struct ast_smdi_mwi_message *mwi_msg = NULL; 00424 00425 /* No search key provided (the code from chan_dahdi does this). 00426 * Just pop the top message off of the queue. */ 00427 00428 ASTOBJ_CONTAINER_TRAVERSE(&iface->mwi_q, !mwi_msg, do { 00429 mwi_msg = ASTOBJ_REF(iterator); 00430 } while (0); ); 00431 00432 msg = mwi_msg; 00433 } else { 00434 msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, search_key); 00435 } 00436 break; 00437 } 00438 00439 return msg; 00440 }
static void* smdi_msg_pop | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [static] |
Definition at line 356 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().
00357 { 00358 void *msg; 00359 00360 purge_old_messages(iface, type); 00361 00362 lock_msg_q(iface, type); 00363 msg = unlink_from_msg_q(iface, type); 00364 unlock_msg_q(iface, type); 00365 00366 return msg; 00367 }
static int smdi_msg_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1220 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.
01221 { 01222 struct ast_module_user *u; 01223 int res = -1; 01224 AST_DECLARE_APP_ARGS(args, 01225 AST_APP_ARG(id); 01226 AST_APP_ARG(component); 01227 ); 01228 char *parse; 01229 struct ast_datastore *datastore = NULL; 01230 struct smdi_msg_datastore *smd = NULL; 01231 01232 u = ast_module_user_add(chan); 01233 01234 if (!chan) { 01235 ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n"); 01236 goto return_error; 01237 } 01238 01239 if (ast_strlen_zero(data)) { 01240 ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n"); 01241 goto return_error; 01242 } 01243 01244 parse = ast_strdupa(data); 01245 AST_STANDARD_APP_ARGS(args, parse); 01246 01247 if (ast_strlen_zero(args.id)) { 01248 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n"); 01249 goto return_error; 01250 } 01251 01252 if (ast_strlen_zero(args.component)) { 01253 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n"); 01254 goto return_error; 01255 } 01256 01257 ast_channel_lock(chan); 01258 datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id); 01259 ast_channel_unlock(chan); 01260 01261 if (!datastore) { 01262 ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id); 01263 goto return_error; 01264 } 01265 01266 smd = datastore->data; 01267 01268 if (!strcasecmp(args.component, "number")) { 01269 ast_copy_string(buf, smd->md_msg->mesg_desk_num, len); 01270 } else if (!strcasecmp(args.component, "terminal")) { 01271 ast_copy_string(buf, smd->md_msg->mesg_desk_term, len); 01272 } else if (!strcasecmp(args.component, "station")) { 01273 ast_copy_string(buf, smd->md_msg->fwd_st, len); 01274 } else if (!strcasecmp(args.component, "callerid")) { 01275 ast_copy_string(buf, smd->md_msg->calling_st, len); 01276 } else if (!strcasecmp(args.component, "type")) { 01277 snprintf(buf, len, "%c", smd->md_msg->type); 01278 } else { 01279 ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n", 01280 args.component); 01281 goto return_error; 01282 } 01283 01284 res = 0; 01285 01286 return_error: 01287 ast_module_user_remove(u); 01288 01289 return res; 01290 }
static int smdi_msg_retrieve_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1121 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.
01122 { 01123 struct ast_module_user *u; 01124 AST_DECLARE_APP_ARGS(args, 01125 AST_APP_ARG(port); 01126 AST_APP_ARG(search_key); 01127 AST_APP_ARG(timeout); 01128 AST_APP_ARG(options); 01129 ); 01130 struct ast_flags options = { 0 }; 01131 unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT; 01132 int res = -1; 01133 char *parse = NULL; 01134 struct smdi_msg_datastore *smd = NULL; 01135 struct ast_datastore *datastore = NULL; 01136 struct ast_smdi_interface *iface = NULL; 01137 struct ast_smdi_md_message *md_msg = NULL; 01138 01139 u = ast_module_user_add(chan); 01140 01141 if (ast_strlen_zero(data)) { 01142 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n"); 01143 goto return_error; 01144 } 01145 01146 if (!chan) { 01147 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n"); 01148 goto return_error; 01149 } 01150 01151 ast_autoservice_start(chan); 01152 01153 parse = ast_strdupa(data); 01154 AST_STANDARD_APP_ARGS(args, parse); 01155 01156 if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) { 01157 ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n"); 01158 goto return_error; 01159 } 01160 01161 if (!(iface = ast_smdi_interface_find(args.port))) { 01162 ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port); 01163 goto return_error; 01164 } 01165 01166 if (!ast_strlen_zero(args.options)) { 01167 ast_app_parse_options(smdi_msg_ret_options, &options, NULL, args.options); 01168 } 01169 01170 if (!ast_strlen_zero(args.timeout)) { 01171 if (sscanf(args.timeout, "%30u", &timeout) != 1) { 01172 ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout); 01173 timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT; 01174 } 01175 } 01176 01177 if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) { 01178 ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after " 01179 "waiting %u ms.\n", args.search_key, timeout); 01180 goto return_error; 01181 } 01182 01183 if (!(smd = ast_calloc(1, sizeof(*smd)))) 01184 goto return_error; 01185 01186 smd->iface = ASTOBJ_REF(iface); 01187 smd->md_msg = ASTOBJ_REF(md_msg); 01188 smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1); 01189 snprintf(buf, len, "%u", smd->id); 01190 01191 if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf))) 01192 goto return_error; 01193 01194 datastore->data = smd; 01195 01196 ast_channel_lock(chan); 01197 ast_channel_datastore_add(chan, datastore); 01198 ast_channel_unlock(chan); 01199 01200 res = 0; 01201 01202 return_error: 01203 if (iface) 01204 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01205 01206 if (md_msg) 01207 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 01208 01209 if (smd && !datastore) 01210 smdi_msg_datastore_destroy(smd); 01211 01212 if (parse) 01213 ast_autoservice_stop(chan); 01214 01215 ast_module_user_remove(u); 01216 01217 return res; 01218 }
static void* smdi_read | ( | void * | iface_p | ) | [static] |
Definition at line 541 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.
00542 { 00543 struct ast_smdi_interface *iface = iface_p; 00544 struct ast_smdi_md_message *md_msg; 00545 struct ast_smdi_mwi_message *mwi_msg; 00546 char c = '\0'; 00547 char *cp = NULL; 00548 int i; 00549 int start = 0; 00550 00551 /* read an smdi message */ 00552 while ((c = fgetc(iface->file))) { 00553 00554 /* check if this is the start of a message */ 00555 if (!start) { 00556 if (c == 'M') { 00557 ast_log(LOG_DEBUG, "Read an 'M' to start an SMDI message\n"); 00558 start = 1; 00559 } 00560 continue; 00561 } 00562 00563 if (c == 'D') { /* MD message */ 00564 start = 0; 00565 00566 ast_log(LOG_DEBUG, "Read a 'D' ... it's an MD message.\n"); 00567 00568 if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) { 00569 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00570 return NULL; 00571 } 00572 00573 ASTOBJ_INIT(md_msg); 00574 00575 /* read the message desk number */ 00576 for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) { 00577 md_msg->mesg_desk_num[i] = fgetc(iface->file); 00578 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_num[i]); 00579 } 00580 00581 md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0'; 00582 00583 ast_log(LOG_DEBUG, "The message desk number is '%s'\n", md_msg->mesg_desk_num); 00584 00585 /* read the message desk terminal number */ 00586 for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) { 00587 md_msg->mesg_desk_term[i] = fgetc(iface->file); 00588 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_term[i]); 00589 } 00590 00591 md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0'; 00592 00593 ast_log(LOG_DEBUG, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term); 00594 00595 /* read the message type */ 00596 md_msg->type = fgetc(iface->file); 00597 00598 ast_log(LOG_DEBUG, "Message type is '%c'\n", md_msg->type); 00599 00600 /* read the forwarding station number (may be blank) */ 00601 cp = &md_msg->fwd_st[0]; 00602 for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) { 00603 if ((c = fgetc(iface->file)) == ' ') { 00604 *cp = '\0'; 00605 ast_log(LOG_DEBUG, "Read a space, done looking for the forwarding station\n"); 00606 break; 00607 } 00608 00609 /* store c in md_msg->fwd_st */ 00610 if (i >= iface->msdstrip) { 00611 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the forwarding station buffer\n", c); 00612 *cp++ = c; 00613 } else { 00614 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); 00615 } 00616 } 00617 00618 /* make sure the value is null terminated, even if this truncates it */ 00619 md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0'; 00620 cp = NULL; 00621 00622 ast_log(LOG_DEBUG, "The forwarding station is '%s'\n", md_msg->fwd_st); 00623 00624 /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look 00625 * up a message on this field */ 00626 ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name)); 00627 00628 /* read the calling station number (may be blank) */ 00629 cp = &md_msg->calling_st[0]; 00630 for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) { 00631 if (!isdigit((c = fgetc(iface->file)))) { 00632 *cp = '\0'; 00633 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); 00634 if (c == ' ') { 00635 /* Don't break on a space. We may read the space before the calling station 00636 * here if the forwarding station buffer filled up. */ 00637 i--; /* We're still on the same character */ 00638 continue; 00639 } 00640 break; 00641 } 00642 00643 /* store c in md_msg->calling_st */ 00644 if (i >= iface->msdstrip) { 00645 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the calling station buffer\n", c); 00646 *cp++ = c; 00647 } else { 00648 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); 00649 } 00650 } 00651 00652 /* make sure the value is null terminated, even if this truncates it */ 00653 md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0'; 00654 cp = NULL; 00655 00656 ast_log(LOG_DEBUG, "The calling station is '%s'\n", md_msg->calling_st); 00657 00658 /* add the message to the message queue */ 00659 md_msg->timestamp = ast_tvnow(); 00660 ast_smdi_md_message_push(iface, md_msg); 00661 ast_log(LOG_DEBUG, "Received SMDI MD message on %s\n", iface->name); 00662 00663 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 00664 00665 } else if (c == 'W') { /* MWI message */ 00666 start = 0; 00667 00668 ast_log(LOG_DEBUG, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n"); 00669 00670 if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) { 00671 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy); 00672 return NULL; 00673 } 00674 00675 ASTOBJ_INIT(mwi_msg); 00676 00677 /* discard the 'I' (from 'MWI') */ 00678 fgetc(iface->file); 00679 00680 /* read the forwarding station number (may be blank) */ 00681 cp = &mwi_msg->fwd_st[0]; 00682 for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) { 00683 if ((c = fgetc(iface->file)) == ' ') { 00684 *cp = '\0'; 00685 break; 00686 } 00687 00688 /* store c in md_msg->fwd_st */ 00689 if (i >= iface->msdstrip) 00690 *cp++ = c; 00691 } 00692 00693 /* make sure the station number is null terminated, even if this will truncate it */ 00694 mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0'; 00695 cp = NULL; 00696 00697 /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look 00698 * up a message on this field */ 00699 ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name)); 00700 00701 /* read the mwi failure cause */ 00702 for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) 00703 mwi_msg->cause[i] = fgetc(iface->file); 00704 00705 mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0'; 00706 00707 /* add the message to the message queue */ 00708 mwi_msg->timestamp = ast_tvnow(); 00709 ast_smdi_mwi_message_push(iface, mwi_msg); 00710 ast_log(LOG_DEBUG, "Received SMDI MWI message on %s\n", iface->name); 00711 00712 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); 00713 } else { 00714 ast_log(LOG_ERROR, "Unknown SMDI message type received on %s (M%c).\n", iface->name, c); 00715 start = 0; 00716 } 00717 } 00718 00719 ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name); 00720 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy); 00721 return NULL; 00722 }
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 1367 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.
01368 { 01369 /* this destructor stops any running smdi_read threads */ 01370 ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy); 01371 ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces); 01372 01373 destroy_all_mailbox_mappings(); 01374 01375 ast_mutex_lock(&mwi_monitor.lock); 01376 mwi_monitor.stop = 1; 01377 ast_cond_signal(&mwi_monitor.cond); 01378 ast_mutex_unlock(&mwi_monitor.lock); 01379 01380 if (mwi_monitor.thread != AST_PTHREADT_NULL) { 01381 pthread_join(mwi_monitor.thread, NULL); 01382 } 01383 01384 ast_custom_function_unregister(&smdi_msg_retrieve_function); 01385 ast_custom_function_unregister(&smdi_msg_function); 01386 01387 return 0; 01388 }
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 break; 00309 case SMDI_MD: 00310 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 00311 break; 00312 } 00313 }
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 1409 of file res_smdi.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1409 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 1106 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 1111 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.