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