#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 struct ast_smdi_interface * | alloc_smdi_interface (void) |
static void | append_mailbox_mapping (struct ast_variable *var, struct ast_smdi_interface *iface) |
AST_APP_OPTIONS (smdi_msg_ret_options, BEGIN_OPTIONS AST_APP_OPTION('t', OPT_SEARCH_TERMINAL), AST_APP_OPTION('n', OPT_SEARCH_NUMBER), END_OPTIONS) | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Simplified Message Desk Interface (SMDI) Resource",.load=load_module,.unload=unload_module,.reload=reload,) | |
static void | ast_smdi_interface_destroy (struct ast_smdi_interface *iface) |
struct 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. | |
struct 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. | |
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. | |
void | ast_smdi_mwi_message_destroy (struct ast_smdi_mwi_message *msg) |
ast_smdi_mwi_message destructor. | |
struct 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. | |
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. | |
struct 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 const char | config_file [] = "smdi.conf" |
struct { | |
ast_cond_t cond | |
ast_mutex_t lock | |
pthread_t thread | |
} | mwi_monitor |
Data that gets used by the SMDI MWI monitoring thread. | |
struct 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 |
Here is a useful mailing list post that describes SMDI protocol details: http://lists.digium.com/pipermail/asterisk-dev/2003-June/000884.html
Definition in file res_smdi.c.
#define DEFAULT_POLLING_INTERVAL 10 |
#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 struct ast_smdi_interface* alloc_smdi_interface | ( | void | ) | [static, read] |
Definition at line 808 of file res_smdi.c.
References ast_calloc, ast_cond_init(), ast_mutex_init(), ASTOBJ_CONTAINER_INIT, ASTOBJ_INIT, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, and ast_smdi_interface::mwi_q_lock.
Referenced by smdi_load().
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, free, mailbox_mapping::iface, mailbox, mwi_monitor, ast_variable::name, strsep(), and ast_variable::value.
Referenced by smdi_load().
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 }
AST_APP_OPTIONS | ( | smdi_msg_ret_options | , | |
BEGIN_OPTIONS | AST_APP_OPTION't', OPT_SEARCH_TERMINAL, | |||
AST_APP_OPTION('n', OPT_SEARCH_NUMBER) | , | |||
END_OPTIONS | ||||
) |
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_GLOBAL_SYMBOLS | , | |||
"Simplified Message Desk Interface (SMDI) Resource" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
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, 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_load(), 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 | ) | [read] |
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(), mkintf(), 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(), and ASTOBJ_UNREF.
Referenced by destroy_zt_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(), smdi_read(), ss_thread(), and unref_msg().
00703 { 00704 free(msg); 00705 }
struct ast_smdi_md_message* ast_smdi_md_message_pop | ( | struct ast_smdi_interface * | iface | ) | [read] |
Get the next SMDI message from the queue.
iface | a pointer to the interface to use. |
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, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, and ast_smdi_interface::md_q_lock.
Referenced by purge_old_messages(), and smdi_read().
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, 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 | |||
) | [read] |
Get the next SMDI message from the queue.
iface | a pointer to the interface to use. | |
timeout | the time to wait before returning in milliseconds. |
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(), smdi_read(), and unref_msg().
00708 { 00709 free(msg); 00710 }
struct ast_smdi_mwi_message* ast_smdi_mwi_message_pop | ( | struct ast_smdi_interface * | iface | ) | [read] |
Get the next SMDI message from the queue.
iface | a pointer to the interface to use. |
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, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, and ast_smdi_interface::mwi_q_lock.
Referenced by purge_old_messages(), and smdi_read().
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, 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 | |||
) | [read] |
Get the next SMDI message from the queue.
iface | a pointer to the interface to use. | |
timeout | the time to wait before returning in milliseconds. |
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 | |||
) | [read] |
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 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 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(), and mwi_monitor.
Referenced by smdi_load(), and 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, and smdi_load().
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(), 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 | |||
) | [static, read] |
Definition at line 289 of file res_smdi.c.
References SMDI_MD, SMDI_MWI, ast_smdi_md_message::timestamp, 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_tvadd(), mwi_monitor, and poll_mailbox().
Referenced by smdi_load().
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::cur_state, and mailbox_mapping::iface.
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(), lock_msg_q(), LOG_NOTICE, ast_smdi_interface::msg_expiry, msg_timestamp(), 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 alloc_smdi_interface(), append_mailbox_mapping(), ast_config_destroy(), ast_config_load(), AST_LIST_EMPTY, ast_log(), AST_MODULE_LOAD_FAILURE, ast_module_ref(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_smdi_interface_destroy(), ast_true(), ast_variable_browse(), ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_CONTAINER_PRUNE_MARKED, ASTOBJ_CONTAINER_RDLOCK, ASTOBJ_CONTAINER_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, DEFAULT_POLLING_INTERVAL, destroy_all_mailbox_mappings(), errno, ast_smdi_interface::fd, ast_smdi_interface::file, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, ast_smdi_interface::mode, ast_smdi_interface::msdstrip, ast_smdi_interface::msg_expiry, mwi_monitor, mwi_monitor_handler(), ast_variable::name, ast_variable::next, option_verbose, smdi_ifaces, SMDI_MSG_EXPIRY_TIME, smdi_read(), ast_smdi_interface::thread, ast_variable::value, and VERBOSE_PREFIX_3.
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_tvadd(), 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, 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 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_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(), 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 0; 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_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, smdi_msg_datastore::id, smdi_msg_datastore::iface, LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, parse(), SMDI_MD, smdi_message_wait(), smdi_msg_datastore_destroy(), 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_log(), ast_smdi_interface_destroy(), ast_smdi_md_message_destroy(), ast_smdi_md_message_push(), ast_smdi_mwi_message_destroy(), ast_smdi_mwi_message_push(), ASTOBJ_INIT, ASTOBJ_UNREF, ast_smdi_md_message::calling_st, ast_smdi_mwi_message::cause, ast_smdi_interface::file, ast_smdi_mwi_message::fwd_st, ast_smdi_md_message::fwd_st, LOG_DEBUG, LOG_ERROR, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, ast_smdi_interface::msdstrip, ast_smdi_mwi_message::timestamp, ast_smdi_md_message::timestamp, and ast_smdi_md_message::type.
Referenced by smdi_load().
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, file, LOG_DEBUG, LOG_ERROR, and ast_smdi_interface::msdstrip.
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, 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, and smdi_ifaces.
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(), 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 }
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.
Definition at line 118 of file res_smdi.c.
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(), smdi_load(), and unload_module().
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.
struct ast_custom_function smdi_msg_function [static] |
Definition at line 1295 of file res_smdi.c.
int smdi_msg_id [static] |
Definition at line 1090 of file res_smdi.c.
struct ast_custom_function smdi_msg_retrieve_function [static] |
Definition at line 1271 of file res_smdi.c.
pthread_t thread |
The thread ID
Definition at line 117 of file res_smdi.c.