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