#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 | 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 *station) |
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 *station) |
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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } |
static const 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_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 |
enum smdi_message_type |
static void __reg_module | ( | void | ) | [static] |
Definition at line 1327 of file res_smdi.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1327 of file res_smdi.c.
static struct ast_smdi_interface* alloc_smdi_interface | ( | void | ) | [static] |
Definition at line 773 of file res_smdi.c.
References ast_calloc, ast_cond_init(), ast_mutex_init(), ASTOBJ_CONTAINER_INIT, and ASTOBJ_INIT.
00774 { 00775 struct ast_smdi_interface *iface; 00776 00777 if (!(iface = ast_calloc(1, sizeof(*iface)))) 00778 return NULL; 00779 00780 ASTOBJ_INIT(iface); 00781 ASTOBJ_CONTAINER_INIT(&iface->md_q); 00782 ASTOBJ_CONTAINER_INIT(&iface->mwi_q); 00783 00784 ast_mutex_init(&iface->md_q_lock); 00785 ast_cond_init(&iface->md_q_cond, NULL); 00786 00787 ast_mutex_init(&iface->mwi_q_lock); 00788 ast_cond_init(&iface->mwi_q_cond, NULL); 00789 00790 return iface; 00791 }
static void append_mailbox_mapping | ( | struct ast_variable * | var, | |
struct ast_smdi_interface * | iface | |||
) | [static] |
Definition at line 694 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.
00695 { 00696 struct mailbox_mapping *mm; 00697 char *mailbox, *context; 00698 00699 if (!(mm = ast_calloc(1, sizeof(*mm)))) 00700 return; 00701 00702 if (ast_string_field_init(mm, 32)) { 00703 free(mm); 00704 return; 00705 } 00706 00707 ast_string_field_set(mm, smdi, var->name); 00708 00709 context = ast_strdupa(var->value); 00710 mailbox = strsep(&context, "@"); 00711 if (ast_strlen_zero(context)) 00712 context = "default"; 00713 00714 ast_string_field_set(mm, mailbox, mailbox); 00715 ast_string_field_set(mm, context, context); 00716 00717 mm->iface = ASTOBJ_REF(iface); 00718 00719 ast_mutex_lock(&mwi_monitor.lock); 00720 AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry); 00721 ast_mutex_unlock(&mwi_monitor.lock); 00722 }
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 470 of file res_smdi.c.
References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.
Referenced by load_config(), and smdi_msg_retrieve_read().
00471 { 00472 return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name)); 00473 }
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 667 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 444 of file res_smdi.c.
References mailbox_mapping::iface, SMDI_MD, and smdi_msg_pop().
00445 { 00446 return smdi_msg_pop(iface, SMDI_MD); 00447 }
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 449 of file res_smdi.c.
References mailbox_mapping::iface, SMDI_MD, and smdi_message_wait().
Referenced by ss_thread().
00450 { 00451 return smdi_message_wait(iface, timeout, SMDI_MD, NULL); 00452 }
void ast_smdi_mwi_message_destroy | ( | struct ast_smdi_mwi_message * | msg | ) |
ast_smdi_mwi_message destructor.
Definition at line 672 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 454 of file res_smdi.c.
References mailbox_mapping::iface, smdi_msg_pop(), and SMDI_MWI.
00455 { 00456 return smdi_msg_pop(iface, SMDI_MWI); 00457 }
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 459 of file res_smdi.c.
References mailbox_mapping::iface, smdi_message_wait(), and SMDI_MWI.
00460 { 00461 return smdi_message_wait(iface, timeout, SMDI_MWI, NULL); 00462 }
struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait_station | ( | struct ast_smdi_interface * | iface, | |
int | timeout, | |||
const char * | station | |||
) |
Definition at line 464 of file res_smdi.c.
References mailbox_mapping::iface, smdi_message_wait(), and SMDI_MWI.
Referenced by run_externnotify().
00466 { 00467 return smdi_message_wait(iface, timeout, SMDI_MWI, station); 00468 }
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 684 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().
00685 { 00686 struct mailbox_mapping *mm; 00687 00688 ast_mutex_lock(&mwi_monitor.lock); 00689 while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry))) 00690 destroy_mailbox_mapping(mm); 00691 ast_mutex_unlock(&mwi_monitor.lock); 00692 }
static void destroy_mailbox_mapping | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 677 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().
00678 { 00679 ast_string_field_free_memory(mm); 00680 ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy); 00681 free(mm); 00682 }
static int load_module | ( | void | ) | [static] |
Definition at line 1257 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().
01258 { 01259 int res; 01260 01261 /* initialize our containers */ 01262 memset(&smdi_ifaces, 0, sizeof(smdi_ifaces)); 01263 ASTOBJ_CONTAINER_INIT(&smdi_ifaces); 01264 01265 ast_mutex_init(&mwi_monitor.lock); 01266 ast_cond_init(&mwi_monitor.cond, NULL); 01267 01268 ast_custom_function_register(&smdi_msg_retrieve_function); 01269 ast_custom_function_register(&smdi_msg_function); 01270 01271 /* load the config and start the listener threads*/ 01272 res = smdi_load(0); 01273 if (res < 0) { 01274 unload_module(); 01275 return res; 01276 } else if (res == 1) { 01277 unload_module(); 01278 ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n"); 01279 return AST_MODULE_LOAD_DECLINE; 01280 } 01281 01282 return AST_MODULE_LOAD_SUCCESS; 01283 }
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 746 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().
00747 { 00748 while (!mwi_monitor.stop) { 00749 struct timespec ts = { 0, }; 00750 struct timeval tv; 00751 struct mailbox_mapping *mm; 00752 00753 ast_mutex_lock(&mwi_monitor.lock); 00754 00755 mwi_monitor.last_poll = ast_tvnow(); 00756 00757 AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry) 00758 poll_mailbox(mm); 00759 00760 /* Sleep up to the configured polling interval. Allow unload_module() 00761 * to signal us to wake up and exit. */ 00762 tv = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0)); 00763 ts.tv_sec = tv.tv_sec; 00764 ts.tv_nsec = tv.tv_usec * 1000; 00765 ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts); 00766 00767 ast_mutex_unlock(&mwi_monitor.lock); 00768 } 00769 00770 return NULL; 00771 }
static void poll_mailbox | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 727 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().
00728 { 00729 char buf[1024]; 00730 unsigned int state; 00731 00732 snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context); 00733 00734 state = !!ast_app_has_voicemail(mm->mailbox, NULL); 00735 00736 if (state != mm->cur_state) { 00737 if (state) 00738 ast_smdi_mwi_set(mm->iface, mm->smdi); 00739 else 00740 ast_smdi_mwi_unset(mm->iface, mm->smdi); 00741 00742 mm->cur_state = state; 00743 } 00744 }
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 1308 of file res_smdi.c.
References ast_log(), LOG_WARNING, and smdi_load().
01309 { 01310 int res; 01311 01312 res = smdi_load(1); 01313 01314 if (res < 0) { 01315 return res; 01316 } else if (res == 1) { 01317 ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n"); 01318 return 0; 01319 } else 01320 return 0; 01321 }
static int smdi_load | ( | int | reload | ) | [static] |
Definition at line 803 of file res_smdi.c.
References ast_config_load, ast_log(), ast_variable_browse(), ASTOBJ_CONTAINER_MARKALL, CONFIG_FLAG_FILEUNCHANGED, 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().
00804 { 00805 struct ast_config *conf; 00806 struct ast_variable *v; 00807 struct ast_smdi_interface *iface = NULL; 00808 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00809 int res = 0; 00810 00811 /* Config options */ 00812 speed_t baud_rate = B9600; /* 9600 baud rate */ 00813 tcflag_t paritybit = PARENB; /* even parity checking */ 00814 tcflag_t charsize = CS7; /* seven bit characters */ 00815 int stopbits = 0; /* One stop bit */ 00816 00817 int msdstrip = 0; /* strip zero digits */ 00818 long msg_expiry = SMDI_MSG_EXPIRY_TIME; 00819 00820 if (!(conf = ast_config_load(config_file, config_flags))) { 00821 if (reload) 00822 ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file); 00823 else 00824 ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file); 00825 return 1; 00826 } else if (conf == CONFIG_STATUS_FILEUNCHANGED) 00827 return 0; 00828 00829 /* Mark all interfaces that we are listening on. We will unmark them 00830 * as we find them in the config file, this way we know any interfaces 00831 * still marked after we have finished parsing the config file should 00832 * be stopped. 00833 */ 00834 if (reload) 00835 ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces); 00836 00837 for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) { 00838 if (!strcasecmp(v->name, "baudrate")) { 00839 if (!strcasecmp(v->value, "9600")) 00840 baud_rate = B9600; 00841 else if (!strcasecmp(v->value, "4800")) 00842 baud_rate = B4800; 00843 else if (!strcasecmp(v->value, "2400")) 00844 baud_rate = B2400; 00845 else if (!strcasecmp(v->value, "1200")) 00846 baud_rate = B1200; 00847 else { 00848 ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno); 00849 baud_rate = B9600; 00850 } 00851 } else if (!strcasecmp(v->name, "msdstrip")) { 00852 if (!sscanf(v->value, "%d", &msdstrip)) { 00853 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); 00854 msdstrip = 0; 00855 } else if (0 > msdstrip || msdstrip > 9) { 00856 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); 00857 msdstrip = 0; 00858 } 00859 } else if (!strcasecmp(v->name, "msgexpirytime")) { 00860 if (!sscanf(v->value, "%ld", &msg_expiry)) { 00861 ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno); 00862 msg_expiry = SMDI_MSG_EXPIRY_TIME; 00863 } 00864 } else if (!strcasecmp(v->name, "paritybit")) { 00865 if (!strcasecmp(v->value, "even")) 00866 paritybit = PARENB; 00867 else if (!strcasecmp(v->value, "odd")) 00868 paritybit = PARENB | PARODD; 00869 else if (!strcasecmp(v->value, "none")) 00870 paritybit = ~PARENB; 00871 else { 00872 ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno); 00873 paritybit = PARENB; 00874 } 00875 } else if (!strcasecmp(v->name, "charsize")) { 00876 if (!strcasecmp(v->value, "7")) 00877 charsize = CS7; 00878 else if (!strcasecmp(v->value, "8")) 00879 charsize = CS8; 00880 else { 00881 ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno); 00882 charsize = CS7; 00883 } 00884 } else if (!strcasecmp(v->name, "twostopbits")) { 00885 stopbits = ast_true(v->name); 00886 } else if (!strcasecmp(v->name, "smdiport")) { 00887 if (reload) { 00888 /* we are reloading, check if we are already 00889 * monitoring this interface, if we are we do 00890 * not want to start it again. This also has 00891 * the side effect of not updating different 00892 * setting for the serial port, but it should 00893 * be trivial to rewrite this section so that 00894 * options on the port are changed without 00895 * restarting the interface. Or the interface 00896 * could be restarted with out emptying the 00897 * queue. */ 00898 if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { 00899 ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name); 00900 ASTOBJ_UNMARK(iface); 00901 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00902 continue; 00903 } 00904 } 00905 00906 if (!(iface = alloc_smdi_interface())) 00907 continue; 00908 00909 ast_copy_string(iface->name, v->value, sizeof(iface->name)); 00910 00911 iface->thread = AST_PTHREADT_NULL; 00912 00913 if (!(iface->file = fopen(iface->name, "r"))) { 00914 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno)); 00915 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00916 continue; 00917 } 00918 00919 iface->fd = fileno(iface->file); 00920 00921 /* Set the proper attributes for our serial port. */ 00922 00923 /* get the current attributes from the port */ 00924 if (tcgetattr(iface->fd, &iface->mode)) { 00925 ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno)); 00926 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00927 continue; 00928 } 00929 00930 /* set the desired speed */ 00931 if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) { 00932 ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno)); 00933 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00934 continue; 00935 } 00936 00937 /* set the stop bits */ 00938 if (stopbits) 00939 iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */ 00940 else 00941 iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */ 00942 00943 /* set the parity */ 00944 iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit; 00945 00946 /* set the character size */ 00947 iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize; 00948 00949 /* commit the desired attributes */ 00950 if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) { 00951 ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno)); 00952 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00953 continue; 00954 } 00955 00956 /* set the msdstrip */ 00957 iface->msdstrip = msdstrip; 00958 00959 /* set the message expiry time */ 00960 iface->msg_expiry = msg_expiry; 00961 00962 /* start the listener thread */ 00963 ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name); 00964 if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) { 00965 ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name); 00966 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00967 continue; 00968 } 00969 00970 ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface); 00971 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00972 ast_module_ref(ast_module_info->self); 00973 } else { 00974 ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file); 00975 } 00976 } 00977 00978 destroy_all_mailbox_mappings(); 00979 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL; 00980 00981 iface = NULL; 00982 00983 for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) { 00984 if (!strcasecmp(v->name, "smdiport")) { 00985 if (iface) 00986 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00987 00988 if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { 00989 ast_log(LOG_NOTICE, "SMDI interface %s not found\n", iface->name); 00990 continue; 00991 } 00992 } else if (!strcasecmp(v->name, "pollinginterval")) { 00993 if (sscanf(v->value, "%u", &mwi_monitor.polling_interval) != 1) { 00994 ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value); 00995 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL; 00996 } 00997 } else { 00998 if (!iface) { 00999 ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n"); 01000 continue; 01001 } 01002 append_mailbox_mapping(v, iface); 01003 } 01004 } 01005 01006 if (iface) 01007 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01008 01009 ast_config_destroy(conf); 01010 01011 if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL 01012 && ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) { 01013 ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n"); 01014 return AST_MODULE_LOAD_FAILURE; 01015 } 01016 01017 /* Prune any interfaces we should no longer monitor. */ 01018 if (reload) 01019 ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy); 01020 01021 ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces); 01022 /* TODO: this is bad, we need an ASTOBJ method for this! */ 01023 if (!smdi_ifaces.head) 01024 res = 1; 01025 ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces); 01026 01027 return res; 01028 }
static void* smdi_message_wait | ( | struct ast_smdi_interface * | iface, | |
int | timeout, | |||
enum smdi_message_type | type, | |||
const char * | station | |||
) | [static] |
Definition at line 388 of file res_smdi.c.
References ast_cond_timedwait(), ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), cond, mailbox_mapping::iface, 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().
00390 { 00391 struct timeval start; 00392 long diff = 0; 00393 void *msg; 00394 ast_cond_t *cond = NULL; 00395 ast_mutex_t *lock = NULL; 00396 00397 switch (type) { 00398 case SMDI_MWI: 00399 cond = &iface->mwi_q_cond; 00400 lock = &iface->mwi_q_lock; 00401 break; 00402 case SMDI_MD: 00403 cond = &iface->md_q_cond; 00404 lock = &iface->md_q_lock; 00405 break; 00406 } 00407 00408 start = ast_tvnow(); 00409 00410 while (diff < timeout) { 00411 struct timespec ts = { 0, }; 00412 struct timeval tv; 00413 00414 lock_msg_q(iface, type); 00415 00416 if ((msg = smdi_msg_find(iface, type, station))) { 00417 unlock_msg_q(iface, type); 00418 return msg; 00419 } 00420 00421 tv = ast_tvadd(start, ast_tv(0, timeout)); 00422 ts.tv_sec = tv.tv_sec; 00423 ts.tv_nsec = tv.tv_usec * 1000; 00424 00425 /* If there were no messages in the queue, then go to sleep until one 00426 * arrives. */ 00427 00428 ast_cond_timedwait(cond, lock, &ts); 00429 00430 if ((msg = smdi_msg_find(iface, type, station))) { 00431 unlock_msg_q(iface, type); 00432 return msg; 00433 } 00434 00435 unlock_msg_q(iface, type); 00436 00437 /* check timeout */ 00438 diff = ast_tvdiff_ms(ast_tvnow(), start); 00439 } 00440 00441 return NULL; 00442 }
static void smdi_msg_datastore_destroy | ( | void * | data | ) | [static] |
Definition at line 1036 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().
01037 { 01038 struct smdi_msg_datastore *smd = data; 01039 01040 if (smd->iface) 01041 ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy); 01042 01043 if (smd->md_msg) 01044 ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy); 01045 01046 free(smd); 01047 }
static void* smdi_msg_find | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type, | |||
const char * | station | |||
) | [static] |
Definition at line 369 of file res_smdi.c.
References ASTOBJ_CONTAINER_FIND, mailbox_mapping::iface, ast_smdi_interface::md_q, msg, ast_smdi_interface::mwi_q, purge_old_messages(), SMDI_MD, and SMDI_MWI.
Referenced by smdi_message_wait().
00371 { 00372 void *msg = NULL; 00373 00374 purge_old_messages(iface, type); 00375 00376 switch (type) { 00377 case SMDI_MD: 00378 msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, station); 00379 break; 00380 case SMDI_MWI: 00381 msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, station); 00382 break; 00383 } 00384 00385 return msg; 00386 }
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 1152 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, parse(), smdi_msg_datastore_info, and ast_smdi_md_message::type.
01153 { 01154 struct ast_module_user *u; 01155 int res = -1; 01156 AST_DECLARE_APP_ARGS(args, 01157 AST_APP_ARG(id); 01158 AST_APP_ARG(component); 01159 ); 01160 char *parse; 01161 struct ast_datastore *datastore = NULL; 01162 struct smdi_msg_datastore *smd = NULL; 01163 01164 u = ast_module_user_add(chan); 01165 01166 if (!chan) { 01167 ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n"); 01168 goto return_error; 01169 } 01170 01171 if (ast_strlen_zero(data)) { 01172 ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n"); 01173 goto return_error; 01174 } 01175 01176 parse = ast_strdupa(data); 01177 AST_STANDARD_APP_ARGS(args, parse); 01178 01179 if (ast_strlen_zero(args.id)) { 01180 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n"); 01181 goto return_error; 01182 } 01183 01184 if (ast_strlen_zero(args.component)) { 01185 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n"); 01186 goto return_error; 01187 } 01188 01189 ast_channel_lock(chan); 01190 datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id); 01191 ast_channel_unlock(chan); 01192 01193 if (!datastore) { 01194 ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id); 01195 goto return_error; 01196 } 01197 01198 smd = datastore->data; 01199 01200 if (!strcasecmp(args.component, "station")) { 01201 ast_copy_string(buf, smd->md_msg->fwd_st, len); 01202 } else if (!strcasecmp(args.component, "callerid")) { 01203 ast_copy_string(buf, smd->md_msg->calling_st, len); 01204 } else if (!strcasecmp(args.component, "type")) { 01205 snprintf(buf, len, "%c", smd->md_msg->type); 01206 } else { 01207 ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n", 01208 args.component); 01209 goto return_error; 01210 } 01211 01212 res = 0; 01213 01214 return_error: 01215 ast_module_user_remove(u); 01216 01217 return 0; 01218 }
static int smdi_msg_retrieve_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1059 of file res_smdi.c.
References AST_APP_ARG, ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_lock, ast_channel_unlock, 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, and SMDI_RETRIEVE_TIMEOUT_DEFAULT.
01060 { 01061 struct ast_module_user *u; 01062 AST_DECLARE_APP_ARGS(args, 01063 AST_APP_ARG(port); 01064 AST_APP_ARG(station); 01065 AST_APP_ARG(timeout); 01066 ); 01067 unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT; 01068 int res = -1; 01069 char *parse = NULL; 01070 struct smdi_msg_datastore *smd = NULL; 01071 struct ast_datastore *datastore = NULL; 01072 struct ast_smdi_interface *iface = NULL; 01073 struct ast_smdi_md_message *md_msg = NULL; 01074 01075 u = ast_module_user_add(chan); 01076 01077 if (ast_strlen_zero(data)) { 01078 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n"); 01079 goto return_error; 01080 } 01081 01082 if (!chan) { 01083 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n"); 01084 goto return_error; 01085 } 01086 01087 ast_autoservice_start(chan); 01088 01089 parse = ast_strdupa(data); 01090 AST_STANDARD_APP_ARGS(args, parse); 01091 01092 if (ast_strlen_zero(args.port) || ast_strlen_zero(args.station)) { 01093 ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n"); 01094 goto return_error; 01095 } 01096 01097 if (!(iface = ast_smdi_interface_find(args.port))) { 01098 ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port); 01099 goto return_error; 01100 } 01101 01102 if (!ast_strlen_zero(args.timeout)) { 01103 if (sscanf(args.timeout, "%u", &timeout) != 1) { 01104 ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout); 01105 timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT; 01106 } 01107 } 01108 01109 if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.station))) { 01110 ast_log(LOG_WARNING, "No SMDI message retrieved for station '%s' after " 01111 "waiting %u ms.\n", args.station, timeout); 01112 goto return_error; 01113 } 01114 01115 if (!(smd = ast_calloc(1, sizeof(*smd)))) 01116 goto return_error; 01117 01118 smd->iface = ASTOBJ_REF(iface); 01119 smd->md_msg = ASTOBJ_REF(md_msg); 01120 smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1); 01121 snprintf(buf, len, "%u", smd->id); 01122 01123 if (!(datastore = ast_channel_datastore_alloc(&smdi_msg_datastore_info, buf))) 01124 goto return_error; 01125 01126 datastore->data = smd; 01127 01128 ast_channel_lock(chan); 01129 ast_channel_datastore_add(chan, datastore); 01130 ast_channel_unlock(chan); 01131 01132 res = 0; 01133 01134 return_error: 01135 if (iface) 01136 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01137 01138 if (md_msg) 01139 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 01140 01141 if (smd && !datastore) 01142 smdi_msg_datastore_destroy(smd); 01143 01144 if (parse) 01145 ast_autoservice_stop(chan); 01146 01147 ast_module_user_remove(u); 01148 01149 return res; 01150 }
static void* smdi_read | ( | void * | iface_p | ) | [static] |
Definition at line 484 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, mailbox_mapping::iface, LOG_DEBUG, ast_smdi_interface::msdstrip, and ast_smdi_md_message::name.
00485 { 00486 struct ast_smdi_interface *iface = iface_p; 00487 struct ast_smdi_md_message *md_msg; 00488 struct ast_smdi_mwi_message *mwi_msg; 00489 char c = '\0'; 00490 char *cp = NULL; 00491 int i; 00492 int start = 0; 00493 00494 /* read an smdi message */ 00495 while ((c = fgetc(iface->file))) { 00496 00497 /* check if this is the start of a message */ 00498 if (!start) { 00499 if (c == 'M') { 00500 ast_log(LOG_DEBUG, "Read an 'M' to start an SMDI message\n"); 00501 start = 1; 00502 } 00503 continue; 00504 } 00505 00506 if (c == 'D') { /* MD message */ 00507 start = 0; 00508 00509 ast_log(LOG_DEBUG, "Read a 'D' ... it's an MD message.\n"); 00510 00511 if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) { 00512 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00513 return NULL; 00514 } 00515 00516 ASTOBJ_INIT(md_msg); 00517 00518 /* read the message desk number */ 00519 for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) { 00520 md_msg->mesg_desk_num[i] = fgetc(iface->file); 00521 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_num[i]); 00522 } 00523 00524 md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0'; 00525 00526 ast_log(LOG_DEBUG, "The message desk number is '%s'\n", md_msg->mesg_desk_num); 00527 00528 /* read the message desk terminal number */ 00529 for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) { 00530 md_msg->mesg_desk_term[i] = fgetc(iface->file); 00531 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_term[i]); 00532 } 00533 00534 md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0'; 00535 00536 ast_log(LOG_DEBUG, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term); 00537 00538 /* read the message type */ 00539 md_msg->type = fgetc(iface->file); 00540 00541 ast_log(LOG_DEBUG, "Message type is '%c'\n", md_msg->type); 00542 00543 /* read the forwarding station number (may be blank) */ 00544 cp = &md_msg->fwd_st[0]; 00545 for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) { 00546 if ((c = fgetc(iface->file)) == ' ') { 00547 *cp = '\0'; 00548 ast_log(LOG_DEBUG, "Read a space, done looking for the forwarding station\n"); 00549 break; 00550 } 00551 00552 /* store c in md_msg->fwd_st */ 00553 if (i >= iface->msdstrip) { 00554 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the forwarding station buffer\n", c); 00555 *cp++ = c; 00556 } else { 00557 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); 00558 } 00559 } 00560 00561 /* make sure the value is null terminated, even if this truncates it */ 00562 md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0'; 00563 cp = NULL; 00564 00565 ast_log(LOG_DEBUG, "The forwarding station is '%s'\n", md_msg->fwd_st); 00566 00567 /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look 00568 * up a message on this field */ 00569 ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name)); 00570 00571 /* read the calling station number (may be blank) */ 00572 cp = &md_msg->calling_st[0]; 00573 for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) { 00574 if (!isdigit((c = fgetc(iface->file)))) { 00575 *cp = '\0'; 00576 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); 00577 if (c == ' ') { 00578 /* Don't break on a space. We may read the space before the calling station 00579 * here if the forwarding station buffer filled up. */ 00580 i--; /* We're still on the same character */ 00581 continue; 00582 } 00583 break; 00584 } 00585 00586 /* store c in md_msg->calling_st */ 00587 if (i >= iface->msdstrip) { 00588 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the calling station buffer\n", c); 00589 *cp++ = c; 00590 } else { 00591 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); 00592 } 00593 } 00594 00595 /* make sure the value is null terminated, even if this truncates it */ 00596 md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0'; 00597 cp = NULL; 00598 00599 ast_log(LOG_DEBUG, "The calling station is '%s'\n", md_msg->calling_st); 00600 00601 /* add the message to the message queue */ 00602 md_msg->timestamp = ast_tvnow(); 00603 ast_smdi_md_message_push(iface, md_msg); 00604 ast_log(LOG_DEBUG, "Recieved SMDI MD message on %s\n", iface->name); 00605 00606 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 00607 00608 } else if (c == 'W') { /* MWI message */ 00609 start = 0; 00610 00611 ast_log(LOG_DEBUG, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n"); 00612 00613 if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) { 00614 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy); 00615 return NULL; 00616 } 00617 00618 ASTOBJ_INIT(mwi_msg); 00619 00620 /* discard the 'I' (from 'MWI') */ 00621 fgetc(iface->file); 00622 00623 /* read the forwarding station number (may be blank) */ 00624 cp = &mwi_msg->fwd_st[0]; 00625 for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) { 00626 if ((c = fgetc(iface->file)) == ' ') { 00627 *cp = '\0'; 00628 break; 00629 } 00630 00631 /* store c in md_msg->fwd_st */ 00632 if (i >= iface->msdstrip) 00633 *cp++ = c; 00634 } 00635 00636 /* make sure the station number is null terminated, even if this will truncate it */ 00637 mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0'; 00638 cp = NULL; 00639 00640 /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look 00641 * up a message on this field */ 00642 ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name)); 00643 00644 /* read the mwi failure cause */ 00645 for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) 00646 mwi_msg->cause[i] = fgetc(iface->file); 00647 00648 mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0'; 00649 00650 /* add the message to the message queue */ 00651 mwi_msg->timestamp = ast_tvnow(); 00652 ast_smdi_mwi_message_push(iface, mwi_msg); 00653 ast_log(LOG_DEBUG, "Recieved SMDI MWI message on %s\n", iface->name); 00654 00655 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); 00656 } else { 00657 ast_log(LOG_ERROR, "Unknown SMDI message type recieved on %s (M%c).\n", iface->name, c); 00658 start = 0; 00659 } 00660 } 00661 00662 ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name); 00663 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy); 00664 return NULL; 00665 }
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 1285 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.
01286 { 01287 /* this destructor stops any running smdi_read threads */ 01288 ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy); 01289 ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces); 01290 01291 destroy_all_mailbox_mappings(); 01292 01293 ast_mutex_lock(&mwi_monitor.lock); 01294 mwi_monitor.stop = 1; 01295 ast_cond_signal(&mwi_monitor.cond); 01296 ast_mutex_unlock(&mwi_monitor.lock); 01297 01298 if (mwi_monitor.thread != AST_PTHREADT_NULL) { 01299 pthread_join(mwi_monitor.thread, NULL); 01300 } 01301 01302 ast_custom_function_unregister(&smdi_msg_retrieve_function); 01303 ast_custom_function_unregister(&smdi_msg_function); 01304 01305 return 0; 01306 }
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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1327 of file res_smdi.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1327 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 1049 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 1054 of file res_smdi.c.
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.