#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <termios.h>
#include <sys/time.h>
#include <time.h>
#include <ctype.h>
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/smdi.h"
#include "asterisk/config.h"
#include "asterisk/astobj.h"
#include "asterisk/io.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
Go to the source code of this file.
Data Structures | |
struct | ast_smdi_interface |
struct | ast_smdi_interface_container |
SMDI interface container. More... | |
struct | ast_smdi_md_queue |
SMDI message desk message queue. More... | |
struct | ast_smdi_mwi_queue |
SMDI message waiting indicator message queue. More... | |
struct | mailbox_mapping |
A mapping between an SMDI mailbox ID and an Asterisk mailbox. More... | |
struct | smdi_msg_datastore |
Defines | |
#define | DEFAULT_POLLING_INTERVAL 10 |
#define | SMDI_MSG_EXPIRY_TIME 30000 |
#define | SMDI_RETRIEVE_TIMEOUT_DEFAULT 3000 |
Enumerations | |
enum | { OPT_SEARCH_TERMINAL = (1 << 0), OPT_SEARCH_NUMBER = (1 << 1) } |
enum | smdi_message_type { SMDI_MWI, SMDI_MD } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static struct ast_smdi_interface * | alloc_smdi_interface (void) |
static void | append_mailbox_mapping (struct ast_variable *var, struct ast_smdi_interface *iface) |
static void | ast_smdi_interface_destroy (struct ast_smdi_interface *iface) |
ast_smdi_interface * | ast_smdi_interface_find (const char *iface_name) |
Find an SMDI interface with the specified name. | |
void | ast_smdi_interface_unref (struct ast_smdi_interface *iface) |
void | ast_smdi_md_message_destroy (struct ast_smdi_md_message *msg) |
ast_smdi_md_message destructor. | |
ast_smdi_md_message * | ast_smdi_md_message_pop (struct ast_smdi_interface *iface) |
Get the next SMDI message from the queue. | |
static void | ast_smdi_md_message_push (struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg) |
void | ast_smdi_md_message_putback (struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg) |
Put an SMDI message back in the front of the queue. | |
ast_smdi_md_message * | ast_smdi_md_message_wait (struct ast_smdi_interface *iface, int timeout) |
Get the next SMDI message from the queue. | |
void | ast_smdi_mwi_message_destroy (struct ast_smdi_mwi_message *msg) |
ast_smdi_mwi_message destructor. | |
ast_smdi_mwi_message * | ast_smdi_mwi_message_pop (struct ast_smdi_interface *iface) |
Get the next SMDI message from the queue. | |
static void | ast_smdi_mwi_message_push (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg) |
void | ast_smdi_mwi_message_putback (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg) |
Put an SMDI message back in the front of the queue. | |
ast_smdi_mwi_message * | ast_smdi_mwi_message_wait (struct ast_smdi_interface *iface, int timeout) |
Get the next SMDI message from the queue. | |
ast_smdi_mwi_message * | ast_smdi_mwi_message_wait_station (struct ast_smdi_interface *iface, int timeout, const char *station) |
int | ast_smdi_mwi_set (struct ast_smdi_interface *iface, const char *mailbox) |
Set the MWI indicator for a mailbox. | |
int | ast_smdi_mwi_unset (struct ast_smdi_interface *iface, const char *mailbox) |
Unset the MWI indicator for a mailbox. | |
static void | destroy_all_mailbox_mappings (void) |
static void | destroy_mailbox_mapping (struct mailbox_mapping *mm) |
static int | load_module (void) |
static int | lock_msg_q (struct ast_smdi_interface *iface, enum smdi_message_type type) |
static struct timeval | msg_timestamp (void *msg, enum smdi_message_type type) |
static void * | mwi_monitor_handler (void *data) |
static void | poll_mailbox (struct mailbox_mapping *mm) |
static void | purge_old_messages (struct ast_smdi_interface *iface, enum smdi_message_type type) |
static int | reload (void) |
static int | smdi_load (int reload) |
static void * | smdi_message_wait (struct ast_smdi_interface *iface, int timeout, enum smdi_message_type type, const char *search_key, struct ast_flags options) |
static void | smdi_msg_datastore_destroy (void *data) |
static void * | smdi_msg_find (struct ast_smdi_interface *iface, enum smdi_message_type type, const char *search_key, struct ast_flags options) |
static void * | smdi_msg_pop (struct ast_smdi_interface *iface, enum smdi_message_type type) |
static int | smdi_msg_read (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static int | smdi_msg_retrieve_read (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static void * | smdi_read (void *iface_p) |
static int | smdi_toggle_mwi (struct ast_smdi_interface *iface, const char *mailbox, int on) |
static void * | unlink_from_msg_q (struct ast_smdi_interface *iface, enum smdi_message_type type) |
static int | unload_module (void) |
static int | unlock_msg_q (struct ast_smdi_interface *iface, enum smdi_message_type type) |
static void | unref_msg (void *msg, enum smdi_message_type type) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Simplified Message Desk Interface (SMDI) Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static const char | config_file [] = "smdi.conf" |
struct { | |
ast_cond_t cond | |
timeval last_poll | |
ast_mutex_t lock | |
struct { | |
mailbox_mapping * first | |
mailbox_mapping * last | |
} mailbox_mappings | |
unsigned int polling_interval | |
unsigned int stop:1 | |
pthread_t thread | |
} | mwi_monitor |
Data that gets used by the SMDI MWI monitoring thread. | |
ast_smdi_interface_container | smdi_ifaces |
SMDI interface container. | |
static struct ast_datastore_info | smdi_msg_datastore_info |
static struct ast_custom_function | smdi_msg_function |
static int | smdi_msg_id |
static struct ast_app_option | smdi_msg_ret_options [128] = { [ 't' ] = { .flag = OPT_SEARCH_TERMINAL }, [ 'n' ] = { .flag = OPT_SEARCH_NUMBER }, } |
static struct ast_custom_function | smdi_msg_retrieve_function |
Russell Bryant <russell@digium.com>
Definition in file res_smdi.c.
#define DEFAULT_POLLING_INTERVAL 10 |
10 seconds
Definition at line 112 of file res_smdi.c.
#define SMDI_MSG_EXPIRY_TIME 30000 |
#define SMDI_RETRIEVE_TIMEOUT_DEFAULT 3000 |
anonymous enum |
Definition at line 374 of file res_smdi.c.
00374 { 00375 OPT_SEARCH_TERMINAL = (1 << 0), 00376 OPT_SEARCH_NUMBER = (1 << 1), 00377 };
enum smdi_message_type |
static void __reg_module | ( | void | ) | [static] |
Definition at line 1416 of file res_smdi.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1416 of file res_smdi.c.
static struct ast_smdi_interface* alloc_smdi_interface | ( | void | ) | [static] |
Definition at line 834 of file res_smdi.c.
References ast_calloc, ast_cond_init(), ast_mutex_init(), ASTOBJ_CONTAINER_INIT, and ASTOBJ_INIT.
00835 { 00836 struct ast_smdi_interface *iface; 00837 00838 if (!(iface = ast_calloc(1, sizeof(*iface)))) 00839 return NULL; 00840 00841 ASTOBJ_INIT(iface); 00842 ASTOBJ_CONTAINER_INIT(&iface->md_q); 00843 ASTOBJ_CONTAINER_INIT(&iface->mwi_q); 00844 00845 ast_mutex_init(&iface->md_q_lock); 00846 ast_cond_init(&iface->md_q_cond, NULL); 00847 00848 ast_mutex_init(&iface->mwi_q_lock); 00849 ast_cond_init(&iface->mwi_q_cond, NULL); 00850 00851 return iface; 00852 }
static void append_mailbox_mapping | ( | struct ast_variable * | var, | |
struct ast_smdi_interface * | iface | |||
) | [static] |
Definition at line 755 of file res_smdi.c.
References ast_calloc, AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ASTOBJ_REF, context, mailbox_mapping::entry, free, mailbox_mapping::iface, mailbox, mwi_monitor, mailbox_mapping::smdi, and var.
00756 { 00757 struct mailbox_mapping *mm; 00758 char *mailbox, *context; 00759 00760 if (!(mm = ast_calloc(1, sizeof(*mm)))) 00761 return; 00762 00763 if (ast_string_field_init(mm, 32)) { 00764 free(mm); 00765 return; 00766 } 00767 00768 ast_string_field_set(mm, smdi, var->name); 00769 00770 context = ast_strdupa(var->value); 00771 mailbox = strsep(&context, "@"); 00772 if (ast_strlen_zero(context)) 00773 context = "default"; 00774 00775 ast_string_field_set(mm, mailbox, mailbox); 00776 ast_string_field_set(mm, context, context); 00777 00778 mm->iface = ASTOBJ_REF(iface); 00779 00780 ast_mutex_lock(&mwi_monitor.lock); 00781 AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry); 00782 ast_mutex_unlock(&mwi_monitor.lock); 00783 }
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 531 of file res_smdi.c.
References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.
Referenced by load_config(), and smdi_msg_retrieve_read().
00532 { 00533 return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name)); 00534 }
void ast_smdi_interface_unref | ( | struct ast_smdi_interface * | iface | ) |
Definition at line 160 of file res_smdi.c.
References ast_smdi_interface_destroy(), ASTOBJ_UNREF, and mailbox_mapping::iface.
Referenced by destroy_dahdi_pvt().
00161 { 00162 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00163 }
void ast_smdi_md_message_destroy | ( | struct ast_smdi_md_message * | msg | ) |
ast_smdi_md_message destructor.
Definition at line 728 of file res_smdi.c.
References free.
Referenced by ast_smdi_interface_destroy(), smdi_msg_datastore_destroy(), smdi_msg_retrieve_read(), and unref_msg().
00729 { 00730 free(msg); 00731 }
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 502 of file res_smdi.c.
References SMDI_MD, and smdi_msg_pop().
00503 { 00504 return smdi_msg_pop(iface, SMDI_MD); 00505 }
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 507 of file res_smdi.c.
References SMDI_MD, and smdi_message_wait().
Referenced by ss_thread().
00508 { 00509 struct ast_flags options = { 0 }; 00510 return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options); 00511 }
void ast_smdi_mwi_message_destroy | ( | struct ast_smdi_mwi_message * | msg | ) |
ast_smdi_mwi_message destructor.
Definition at line 733 of file res_smdi.c.
References free.
Referenced by ast_smdi_interface_destroy(), run_externnotify(), and unref_msg().
00734 { 00735 free(msg); 00736 }
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 513 of file res_smdi.c.
References smdi_msg_pop(), and SMDI_MWI.
00514 { 00515 return smdi_msg_pop(iface, SMDI_MWI); 00516 }
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 518 of file res_smdi.c.
References smdi_message_wait(), and SMDI_MWI.
00519 { 00520 struct ast_flags options = { 0 }; 00521 return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options); 00522 }
struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait_station | ( | struct ast_smdi_interface * | iface, | |
int | timeout, | |||
const char * | station | |||
) |
Definition at line 524 of file res_smdi.c.
References smdi_message_wait(), and SMDI_MWI.
Referenced by run_externnotify().
00526 { 00527 struct ast_flags options = { 0 }; 00528 return smdi_message_wait(iface, timeout, SMDI_MWI, station, options); 00529 }
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 745 of file res_smdi.c.
References AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), destroy_mailbox_mapping(), mailbox_mapping::entry, and mwi_monitor.
Referenced by unload_module().
00746 { 00747 struct mailbox_mapping *mm; 00748 00749 ast_mutex_lock(&mwi_monitor.lock); 00750 while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry))) 00751 destroy_mailbox_mapping(mm); 00752 ast_mutex_unlock(&mwi_monitor.lock); 00753 }
static void destroy_mailbox_mapping | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 738 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().
00739 { 00740 ast_string_field_free_memory(mm); 00741 ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy); 00742 free(mm); 00743 }
static int load_module | ( | void | ) | [static] |
Definition at line 1344 of file res_smdi.c.
References ast_cond_init(), ast_custom_function_register(), ast_log(), AST_MODULE_LOAD_SUCCESS, ast_mutex_init(), ASTOBJ_CONTAINER_INIT, LOG_WARNING, mwi_monitor, smdi_ifaces, smdi_load(), smdi_msg_function, smdi_msg_retrieve_function, and unload_module().
01345 { 01346 int res; 01347 01348 /* initialize our containers */ 01349 memset(&smdi_ifaces, 0, sizeof(smdi_ifaces)); 01350 ASTOBJ_CONTAINER_INIT(&smdi_ifaces); 01351 01352 ast_mutex_init(&mwi_monitor.lock); 01353 ast_cond_init(&mwi_monitor.cond, NULL); 01354 01355 ast_custom_function_register(&smdi_msg_retrieve_function); 01356 ast_custom_function_register(&smdi_msg_function); 01357 01358 /* load the config and start the listener threads*/ 01359 res = smdi_load(0); 01360 if (res < 0) { 01361 unload_module(); 01362 return res; 01363 } else if (res == 1) { 01364 ast_log(LOG_WARNING, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n"); 01365 /*! \note Since chan_dahdi depends on this module, we need to load the module in inactive state 01366 instead of AST_MODULE_LOAD_DECLINE. This is fixed in later releases of Asterisk. 01367 */ 01368 return AST_MODULE_LOAD_SUCCESS; 01369 } 01370 01371 return 0; 01372 }
static int lock_msg_q | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [inline, static] |
Definition at line 253 of file res_smdi.c.
References ast_mutex_lock(), mailbox_mapping::iface, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_lock, SMDI_MD, and SMDI_MWI.
Referenced by purge_old_messages(), smdi_message_wait(), and smdi_msg_pop().
00254 { 00255 switch (type) { 00256 case SMDI_MWI: 00257 return ast_mutex_lock(&iface->mwi_q_lock); 00258 case SMDI_MD: 00259 return ast_mutex_lock(&iface->md_q_lock); 00260 } 00261 00262 return -1; 00263 }
static struct timeval msg_timestamp | ( | void * | msg, | |
enum smdi_message_type | type | |||
) | [inline, static] |
Definition at line 289 of file res_smdi.c.
References ast_tv(), SMDI_MD, SMDI_MWI, ast_smdi_mwi_message::timestamp, and type.
Referenced by purge_old_messages().
00290 { 00291 struct ast_smdi_md_message *md_msg = msg; 00292 struct ast_smdi_mwi_message *mwi_msg = msg; 00293 00294 switch (type) { 00295 case SMDI_MWI: 00296 return mwi_msg->timestamp; 00297 case SMDI_MD: 00298 return md_msg->timestamp; 00299 } 00300 00301 return ast_tv(0, 0); 00302 }
static void* mwi_monitor_handler | ( | void * | data | ) | [static] |
Definition at line 807 of file res_smdi.c.
References ast_cond_timedwait(), AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_tv(), ast_tvadd(), ast_tvnow(), mailbox_mapping::entry, mwi_monitor, and poll_mailbox().
00808 { 00809 while (!mwi_monitor.stop) { 00810 struct timespec ts = { 0, }; 00811 struct timeval tv; 00812 struct mailbox_mapping *mm; 00813 00814 ast_mutex_lock(&mwi_monitor.lock); 00815 00816 mwi_monitor.last_poll = ast_tvnow(); 00817 00818 AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry) 00819 poll_mailbox(mm); 00820 00821 /* Sleep up to the configured polling interval. Allow unload_module() 00822 * to signal us to wake up and exit. */ 00823 tv = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0)); 00824 ts.tv_sec = tv.tv_sec; 00825 ts.tv_nsec = tv.tv_usec * 1000; 00826 ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts); 00827 00828 ast_mutex_unlock(&mwi_monitor.lock); 00829 } 00830 00831 return NULL; 00832 }
static void poll_mailbox | ( | struct mailbox_mapping * | mm | ) | [static] |
Definition at line 788 of file res_smdi.c.
References ast_app_has_voicemail(), ast_smdi_mwi_set(), ast_smdi_mwi_unset(), mailbox_mapping::context, mailbox_mapping::cur_state, mailbox_mapping::iface, mailbox_mapping::mailbox, and mailbox_mapping::smdi.
Referenced by mwi_monitor_handler().
00789 { 00790 char buf[1024]; 00791 unsigned int state; 00792 00793 snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context); 00794 00795 state = !!ast_app_has_voicemail(mm->mailbox, NULL); 00796 00797 if (state != mm->cur_state) { 00798 if (state) 00799 ast_smdi_mwi_set(mm->iface, mm->smdi); 00800 else 00801 ast_smdi_mwi_unset(mm->iface, mm->smdi); 00802 00803 mm->cur_state = state; 00804 } 00805 }
static void purge_old_messages | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [static] |
Definition at line 319 of file res_smdi.c.
References ast_log(), ast_smdi_md_message_push(), ast_smdi_mwi_message_push(), ast_tvdiff_ms(), ast_tvnow(), mailbox_mapping::iface, lock_msg_q(), LOG_NOTICE, ast_smdi_interface::msg_expiry, msg_timestamp(), ast_smdi_interface::name, SMDI_MD, SMDI_MWI, unlink_from_msg_q(), unlock_msg_q(), and unref_msg().
Referenced by smdi_msg_find(), and smdi_msg_pop().
00320 { 00321 struct timeval now; 00322 long elapsed = 0; 00323 void *msg; 00324 00325 lock_msg_q(iface, type); 00326 msg = unlink_from_msg_q(iface, type); 00327 unlock_msg_q(iface, type); 00328 00329 /* purge old messages */ 00330 now = ast_tvnow(); 00331 while (msg) { 00332 elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type)); 00333 00334 if (elapsed > iface->msg_expiry) { 00335 /* found an expired message */ 00336 unref_msg(msg, type); 00337 ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue. " 00338 "Message was %ld milliseconds too old.\n", 00339 iface->name, (type == SMDI_MD) ? "MD" : "MWI", 00340 elapsed - iface->msg_expiry); 00341 00342 lock_msg_q(iface, type); 00343 msg = unlink_from_msg_q(iface, type); 00344 unlock_msg_q(iface, type); 00345 } else { 00346 /* good message, put it back and return */ 00347 switch (type) { 00348 case SMDI_MD: 00349 ast_smdi_md_message_push(iface, msg); 00350 break; 00351 case SMDI_MWI: 00352 ast_smdi_mwi_message_push(iface, msg); 00353 break; 00354 } 00355 unref_msg(msg, type); 00356 break; 00357 } 00358 } 00359 }
static int reload | ( | void | ) | [static] |
Definition at line 1397 of file res_smdi.c.
References ast_log(), LOG_WARNING, and smdi_load().
01398 { 01399 int res; 01400 01401 res = smdi_load(1); 01402 01403 if (res < 0) { 01404 return res; 01405 } else if (res == 1) { 01406 ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n"); 01407 return 0; 01408 } else 01409 return 0; 01410 }
static int smdi_load | ( | int | reload | ) | [static] |
Definition at line 864 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().
00865 { 00866 struct ast_config *conf; 00867 struct ast_variable *v; 00868 struct ast_smdi_interface *iface = NULL; 00869 int res = 0; 00870 00871 /* Config options */ 00872 speed_t baud_rate = B9600; /* 9600 baud rate */ 00873 tcflag_t paritybit = PARENB; /* even parity checking */ 00874 tcflag_t charsize = CS7; /* seven bit characters */ 00875 int stopbits = 0; /* One stop bit */ 00876 00877 int msdstrip = 0; /* strip zero digits */ 00878 long msg_expiry = SMDI_MSG_EXPIRY_TIME; 00879 00880 conf = ast_config_load(config_file); 00881 00882 if (!conf) { 00883 if (reload) 00884 ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file); 00885 else 00886 ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file); 00887 return 1; 00888 } 00889 00890 /* Mark all interfaces that we are listening on. We will unmark them 00891 * as we find them in the config file, this way we know any interfaces 00892 * still marked after we have finished parsing the config file should 00893 * be stopped. 00894 */ 00895 if (reload) 00896 ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces); 00897 00898 for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) { 00899 if (!strcasecmp(v->name, "baudrate")) { 00900 if (!strcasecmp(v->value, "9600")) 00901 baud_rate = B9600; 00902 else if (!strcasecmp(v->value, "4800")) 00903 baud_rate = B4800; 00904 else if (!strcasecmp(v->value, "2400")) 00905 baud_rate = B2400; 00906 else if (!strcasecmp(v->value, "1200")) 00907 baud_rate = B1200; 00908 else { 00909 ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno); 00910 baud_rate = B9600; 00911 } 00912 } else if (!strcasecmp(v->name, "msdstrip")) { 00913 if (!sscanf(v->value, "%30d", &msdstrip)) { 00914 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); 00915 msdstrip = 0; 00916 } else if (0 > msdstrip || msdstrip > 9) { 00917 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); 00918 msdstrip = 0; 00919 } 00920 } else if (!strcasecmp(v->name, "msgexpirytime")) { 00921 if (!sscanf(v->value, "%30ld", &msg_expiry)) { 00922 ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno); 00923 msg_expiry = SMDI_MSG_EXPIRY_TIME; 00924 } 00925 } else if (!strcasecmp(v->name, "paritybit")) { 00926 if (!strcasecmp(v->value, "even")) 00927 paritybit = PARENB; 00928 else if (!strcasecmp(v->value, "odd")) 00929 paritybit = PARENB | PARODD; 00930 else if (!strcasecmp(v->value, "none")) 00931 paritybit = ~PARENB; 00932 else { 00933 ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno); 00934 paritybit = PARENB; 00935 } 00936 } else if (!strcasecmp(v->name, "charsize")) { 00937 if (!strcasecmp(v->value, "7")) 00938 charsize = CS7; 00939 else if (!strcasecmp(v->value, "8")) 00940 charsize = CS8; 00941 else { 00942 ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno); 00943 charsize = CS7; 00944 } 00945 } else if (!strcasecmp(v->name, "twostopbits")) { 00946 stopbits = ast_true(v->name); 00947 } else if (!strcasecmp(v->name, "smdiport")) { 00948 if (reload) { 00949 /* we are reloading, check if we are already 00950 * monitoring this interface, if we are we do 00951 * not want to start it again. This also has 00952 * the side effect of not updating different 00953 * setting for the serial port, but it should 00954 * be trivial to rewrite this section so that 00955 * options on the port are changed without 00956 * restarting the interface. Or the interface 00957 * could be restarted with out emptying the 00958 * queue. */ 00959 if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { 00960 ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name); 00961 ASTOBJ_UNMARK(iface); 00962 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00963 continue; 00964 } 00965 } 00966 00967 if (!(iface = alloc_smdi_interface())) 00968 continue; 00969 00970 ast_copy_string(iface->name, v->value, sizeof(iface->name)); 00971 00972 iface->thread = AST_PTHREADT_NULL; 00973 00974 if (!(iface->file = fopen(iface->name, "r"))) { 00975 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno)); 00976 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00977 continue; 00978 } 00979 00980 iface->fd = fileno(iface->file); 00981 00982 /* Set the proper attributes for our serial port. */ 00983 00984 /* get the current attributes from the port */ 00985 if (tcgetattr(iface->fd, &iface->mode)) { 00986 ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno)); 00987 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00988 continue; 00989 } 00990 00991 /* set the desired speed */ 00992 if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) { 00993 ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno)); 00994 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00995 continue; 00996 } 00997 00998 /* set the stop bits */ 00999 if (stopbits) 01000 iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */ 01001 else 01002 iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */ 01003 01004 /* set the parity */ 01005 iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit; 01006 01007 /* set the character size */ 01008 iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize; 01009 01010 /* commit the desired attributes */ 01011 if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) { 01012 ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno)); 01013 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01014 continue; 01015 } 01016 01017 /* set the msdstrip */ 01018 iface->msdstrip = msdstrip; 01019 01020 /* set the message expiry time */ 01021 iface->msg_expiry = msg_expiry; 01022 01023 /* start the listener thread */ 01024 if (option_verbose > 2) 01025 ast_verbose(VERBOSE_PREFIX_3 "Starting SMDI monitor thread for %s\n", iface->name); 01026 if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) { 01027 ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name); 01028 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01029 continue; 01030 } 01031 01032 ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface); 01033 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01034 ast_module_ref(ast_module_info->self); 01035 } else { 01036 ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file); 01037 } 01038 } 01039 01040 destroy_all_mailbox_mappings(); 01041 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL; 01042 01043 iface = NULL; 01044 01045 for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) { 01046 if (!strcasecmp(v->name, "smdiport")) { 01047 if (iface) 01048 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01049 01050 if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { 01051 ast_log(LOG_NOTICE, "SMDI interface %s not found\n", v->value); 01052 continue; 01053 } 01054 } else if (!strcasecmp(v->name, "pollinginterval")) { 01055 if (sscanf(v->value, "%30u", &mwi_monitor.polling_interval) != 1) { 01056 ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value); 01057 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL; 01058 } 01059 } else { 01060 if (!iface) { 01061 ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n"); 01062 continue; 01063 } 01064 append_mailbox_mapping(v, iface); 01065 } 01066 } 01067 01068 if (iface) 01069 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01070 01071 ast_config_destroy(conf); 01072 01073 if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL 01074 && ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) { 01075 ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n"); 01076 return AST_MODULE_LOAD_FAILURE; 01077 } 01078 01079 /* Prune any interfaces we should no longer monitor. */ 01080 if (reload) 01081 ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy); 01082 01083 ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces); 01084 /* TODO: this is bad, we need an ASTOBJ method for this! */ 01085 if (!smdi_ifaces.head) 01086 res = 1; 01087 ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces); 01088 01089 return res; 01090 }
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 447 of file res_smdi.c.
References ast_cond_timedwait(), ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), cond, lock, lock_msg_q(), ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_cond, ast_smdi_interface::mwi_q_lock, SMDI_MD, smdi_msg_find(), SMDI_MWI, and unlock_msg_q().
Referenced by ast_smdi_md_message_wait(), ast_smdi_mwi_message_wait(), ast_smdi_mwi_message_wait_station(), and smdi_msg_retrieve_read().
00449 { 00450 struct timeval start; 00451 long diff = 0; 00452 void *msg; 00453 ast_cond_t *cond = NULL; 00454 ast_mutex_t *lock = NULL; 00455 00456 switch (type) { 00457 case SMDI_MWI: 00458 cond = &iface->mwi_q_cond; 00459 lock = &iface->mwi_q_lock; 00460 break; 00461 case SMDI_MD: 00462 cond = &iface->md_q_cond; 00463 lock = &iface->md_q_lock; 00464 break; 00465 } 00466 00467 start = ast_tvnow(); 00468 while (diff < timeout) { 00469 struct timespec ts = { 0, }; 00470 struct timeval tv; 00471 00472 lock_msg_q(iface, type); 00473 00474 if ((msg = smdi_msg_find(iface, type, search_key, options))) { 00475 unlock_msg_q(iface, type); 00476 return msg; 00477 } 00478 00479 tv = ast_tvadd(start, ast_tv(0, timeout)); 00480 ts.tv_sec = tv.tv_sec; 00481 ts.tv_nsec = tv.tv_usec * 1000; 00482 00483 /* If there were no messages in the queue, then go to sleep until one 00484 * arrives. */ 00485 00486 ast_cond_timedwait(cond, lock, &ts); 00487 00488 if ((msg = smdi_msg_find(iface, type, search_key, options))) { 00489 unlock_msg_q(iface, type); 00490 return msg; 00491 } 00492 00493 unlock_msg_q(iface, type); 00494 00495 /* check timeout */ 00496 diff = ast_tvdiff_ms(ast_tvnow(), start); 00497 } 00498 00499 return NULL; 00500 }
static void smdi_msg_datastore_destroy | ( | void * | data | ) | [static] |
Definition at line 1098 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().
01099 { 01100 struct smdi_msg_datastore *smd = data; 01101 01102 if (smd->iface) 01103 ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy); 01104 01105 if (smd->md_msg) 01106 ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy); 01107 01108 free(smd); 01109 }
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 379 of file res_smdi.c.
References ast_strlen_zero(), ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_REF, mailbox_mapping::iface, ast_smdi_interface::md_q, OPT_SEARCH_TERMINAL, purge_old_messages(), and SMDI_MD.
Referenced by smdi_message_wait().
00381 { 00382 void *msg = NULL; 00383 00384 purge_old_messages(iface, type); 00385 00386 switch (type) { 00387 case SMDI_MD: 00388 if (ast_strlen_zero(search_key)) { 00389 struct ast_smdi_md_message *md_msg = NULL; 00390 00391 /* No search key provided (the code from chan_dahdi does this). 00392 * Just pop the top message off of the queue. */ 00393 00394 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do { 00395 md_msg = ASTOBJ_REF(iterator); 00396 } while (0); ); 00397 00398 msg = md_msg; 00399 } else if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) { 00400 struct ast_smdi_md_message *md_msg = NULL; 00401 00402 /* Searching by the message desk terminal */ 00403 00404 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do { 00405 if (!strcasecmp(iterator->mesg_desk_term, search_key)) 00406 md_msg = ASTOBJ_REF(iterator); 00407 } while (0); ); 00408 00409 msg = md_msg; 00410 } else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) { 00411 struct ast_smdi_md_message *md_msg = NULL; 00412 00413 /* Searching by the message desk number */ 00414 00415 ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do { 00416 if (!strcasecmp(iterator->mesg_desk_num, search_key)) 00417 md_msg = ASTOBJ_REF(iterator); 00418 } while (0); ); 00419 00420 msg = md_msg; 00421 } else { 00422 /* Searching by the forwarding station */ 00423 msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, search_key); 00424 } 00425 break; 00426 case SMDI_MWI: 00427 if (ast_strlen_zero(search_key)) { 00428 struct ast_smdi_mwi_message *mwi_msg = NULL; 00429 00430 /* No search key provided (the code from chan_dahdi does this). 00431 * Just pop the top message off of the queue. */ 00432 00433 ASTOBJ_CONTAINER_TRAVERSE(&iface->mwi_q, !mwi_msg, do { 00434 mwi_msg = ASTOBJ_REF(iterator); 00435 } while (0); ); 00436 00437 msg = mwi_msg; 00438 } else { 00439 msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, search_key); 00440 } 00441 break; 00442 } 00443 00444 return msg; 00445 }
static void* smdi_msg_pop | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [static] |
Definition at line 361 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().
00362 { 00363 void *msg; 00364 00365 purge_old_messages(iface, type); 00366 00367 lock_msg_q(iface, type); 00368 msg = unlink_from_msg_q(iface, type); 00369 unlock_msg_q(iface, type); 00370 00371 return msg; 00372 }
static int smdi_msg_read | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1225 of file res_smdi.c.
References AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_smdi_md_message::calling_st, ast_datastore::data, ast_smdi_md_message::fwd_st, LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, parse(), smdi_msg_datastore_info, and ast_smdi_md_message::type.
01226 { 01227 struct ast_module_user *u; 01228 int res = -1; 01229 AST_DECLARE_APP_ARGS(args, 01230 AST_APP_ARG(id); 01231 AST_APP_ARG(component); 01232 ); 01233 char *parse; 01234 struct ast_datastore *datastore = NULL; 01235 struct smdi_msg_datastore *smd = NULL; 01236 01237 u = ast_module_user_add(chan); 01238 01239 if (!chan) { 01240 ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n"); 01241 goto return_error; 01242 } 01243 01244 if (ast_strlen_zero(data)) { 01245 ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n"); 01246 goto return_error; 01247 } 01248 01249 parse = ast_strdupa(data); 01250 AST_STANDARD_APP_ARGS(args, parse); 01251 01252 if (ast_strlen_zero(args.id)) { 01253 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n"); 01254 goto return_error; 01255 } 01256 01257 if (ast_strlen_zero(args.component)) { 01258 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n"); 01259 goto return_error; 01260 } 01261 01262 ast_channel_lock(chan); 01263 datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id); 01264 ast_channel_unlock(chan); 01265 01266 if (!datastore) { 01267 ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id); 01268 goto return_error; 01269 } 01270 01271 smd = datastore->data; 01272 01273 if (!strcasecmp(args.component, "number")) { 01274 ast_copy_string(buf, smd->md_msg->mesg_desk_num, len); 01275 } else if (!strcasecmp(args.component, "terminal")) { 01276 ast_copy_string(buf, smd->md_msg->mesg_desk_term, len); 01277 } else if (!strcasecmp(args.component, "station")) { 01278 ast_copy_string(buf, smd->md_msg->fwd_st, len); 01279 } else if (!strcasecmp(args.component, "callerid")) { 01280 ast_copy_string(buf, smd->md_msg->calling_st, len); 01281 } else if (!strcasecmp(args.component, "type")) { 01282 snprintf(buf, len, "%c", smd->md_msg->type); 01283 } else { 01284 ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n", 01285 args.component); 01286 goto return_error; 01287 } 01288 01289 res = 0; 01290 01291 return_error: 01292 ast_module_user_remove(u); 01293 01294 return res; 01295 }
static int smdi_msg_retrieve_read | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1126 of file res_smdi.c.
References AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, ast_smdi_interface_destroy(), ast_smdi_interface_find(), ast_smdi_md_message_destroy(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_REF, ASTOBJ_UNREF, ast_datastore::data, LOG_ERROR, LOG_WARNING, parse(), SMDI_MD, smdi_message_wait(), smdi_msg_datastore_destroy(), smdi_msg_datastore_info, smdi_msg_ret_options, and SMDI_RETRIEVE_TIMEOUT_DEFAULT.
01127 { 01128 struct ast_module_user *u; 01129 AST_DECLARE_APP_ARGS(args, 01130 AST_APP_ARG(port); 01131 AST_APP_ARG(search_key); 01132 AST_APP_ARG(timeout); 01133 AST_APP_ARG(options); 01134 ); 01135 struct ast_flags options = { 0 }; 01136 unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT; 01137 int res = -1; 01138 char *parse = NULL; 01139 struct smdi_msg_datastore *smd = NULL; 01140 struct ast_datastore *datastore = NULL; 01141 struct ast_smdi_interface *iface = NULL; 01142 struct ast_smdi_md_message *md_msg = NULL; 01143 01144 u = ast_module_user_add(chan); 01145 01146 if (ast_strlen_zero(data)) { 01147 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n"); 01148 goto return_error; 01149 } 01150 01151 if (!chan) { 01152 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n"); 01153 goto return_error; 01154 } 01155 01156 ast_autoservice_start(chan); 01157 01158 parse = ast_strdupa(data); 01159 AST_STANDARD_APP_ARGS(args, parse); 01160 01161 if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) { 01162 ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n"); 01163 goto return_error; 01164 } 01165 01166 if (!(iface = ast_smdi_interface_find(args.port))) { 01167 ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port); 01168 goto return_error; 01169 } 01170 01171 if (!ast_strlen_zero(args.options)) { 01172 ast_app_parse_options(smdi_msg_ret_options, &options, NULL, args.options); 01173 } 01174 01175 if (!ast_strlen_zero(args.timeout)) { 01176 if (sscanf(args.timeout, "%30u", &timeout) != 1) { 01177 ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout); 01178 timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT; 01179 } 01180 } 01181 01182 if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) { 01183 ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after " 01184 "waiting %u ms.\n", args.search_key, timeout); 01185 goto return_error; 01186 } 01187 01188 if (!(smd = ast_calloc(1, sizeof(*smd)))) 01189 goto return_error; 01190 01191 smd->iface = ASTOBJ_REF(iface); 01192 smd->md_msg = ASTOBJ_REF(md_msg); 01193 smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1); 01194 snprintf(buf, len, "%u", smd->id); 01195 01196 if (!(datastore = ast_channel_datastore_alloc(&smdi_msg_datastore_info, buf))) 01197 goto return_error; 01198 01199 datastore->data = smd; 01200 01201 ast_channel_lock(chan); 01202 ast_channel_datastore_add(chan, datastore); 01203 ast_channel_unlock(chan); 01204 01205 res = 0; 01206 01207 return_error: 01208 if (iface) 01209 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 01210 01211 if (md_msg) 01212 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 01213 01214 if (smd && !datastore) 01215 smdi_msg_datastore_destroy(smd); 01216 01217 if (parse) 01218 ast_autoservice_stop(chan); 01219 01220 ast_module_user_remove(u); 01221 01222 return res; 01223 }
static void* smdi_read | ( | void * | iface_p | ) | [static] |
Definition at line 545 of file res_smdi.c.
References ast_calloc, ast_copy_string(), ast_log(), ast_smdi_interface_destroy(), ASTOBJ_INIT, ASTOBJ_UNREF, ast_smdi_md_message::calling_st, ast_smdi_interface::file, ast_smdi_md_message::fwd_st, LOG_DEBUG, ast_smdi_interface::msdstrip, and ast_smdi_md_message::name.
00546 { 00547 struct ast_smdi_interface *iface = iface_p; 00548 struct ast_smdi_md_message *md_msg; 00549 struct ast_smdi_mwi_message *mwi_msg; 00550 char c = '\0'; 00551 char *cp = NULL; 00552 int i; 00553 int start = 0; 00554 00555 /* read an smdi message */ 00556 while ((c = fgetc(iface->file))) { 00557 00558 /* check if this is the start of a message */ 00559 if (!start) { 00560 if (c == 'M') { 00561 ast_log(LOG_DEBUG, "Read an 'M' to start an SMDI message\n"); 00562 start = 1; 00563 } 00564 continue; 00565 } 00566 00567 if (c == 'D') { /* MD message */ 00568 start = 0; 00569 00570 ast_log(LOG_DEBUG, "Read a 'D' ... it's an MD message.\n"); 00571 00572 if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) { 00573 ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); 00574 return NULL; 00575 } 00576 00577 ASTOBJ_INIT(md_msg); 00578 00579 /* read the message desk number */ 00580 for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) { 00581 md_msg->mesg_desk_num[i] = fgetc(iface->file); 00582 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_num[i]); 00583 } 00584 00585 md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0'; 00586 00587 ast_log(LOG_DEBUG, "The message desk number is '%s'\n", md_msg->mesg_desk_num); 00588 00589 /* read the message desk terminal number */ 00590 for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) { 00591 md_msg->mesg_desk_term[i] = fgetc(iface->file); 00592 ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_term[i]); 00593 } 00594 00595 md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0'; 00596 00597 ast_log(LOG_DEBUG, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term); 00598 00599 /* read the message type */ 00600 md_msg->type = fgetc(iface->file); 00601 00602 ast_log(LOG_DEBUG, "Message type is '%c'\n", md_msg->type); 00603 00604 /* read the forwarding station number (may be blank) */ 00605 cp = &md_msg->fwd_st[0]; 00606 for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) { 00607 if ((c = fgetc(iface->file)) == ' ') { 00608 *cp = '\0'; 00609 ast_log(LOG_DEBUG, "Read a space, done looking for the forwarding station\n"); 00610 break; 00611 } 00612 00613 /* store c in md_msg->fwd_st */ 00614 if (i >= iface->msdstrip) { 00615 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the forwarding station buffer\n", c); 00616 *cp++ = c; 00617 } else { 00618 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); 00619 } 00620 } 00621 00622 /* make sure the value is null terminated, even if this truncates it */ 00623 md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0'; 00624 cp = NULL; 00625 00626 ast_log(LOG_DEBUG, "The forwarding station is '%s'\n", md_msg->fwd_st); 00627 00628 /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look 00629 * up a message on this field */ 00630 ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name)); 00631 00632 /* read the calling station number (may be blank) */ 00633 cp = &md_msg->calling_st[0]; 00634 for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) { 00635 if (!isdigit((c = fgetc(iface->file)))) { 00636 *cp = '\0'; 00637 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); 00638 if (c == ' ') { 00639 /* Don't break on a space. We may read the space before the calling station 00640 * here if the forwarding station buffer filled up. */ 00641 i--; /* We're still on the same character */ 00642 continue; 00643 } 00644 break; 00645 } 00646 00647 /* store c in md_msg->calling_st */ 00648 if (i >= iface->msdstrip) { 00649 ast_log(LOG_DEBUG, "Read a '%c' and stored it in the calling station buffer\n", c); 00650 *cp++ = c; 00651 } else { 00652 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); 00653 } 00654 } 00655 00656 /* make sure the value is null terminated, even if this truncates it */ 00657 md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0'; 00658 cp = NULL; 00659 00660 ast_log(LOG_DEBUG, "The calling station is '%s'\n", md_msg->calling_st); 00661 00662 /* add the message to the message queue */ 00663 md_msg->timestamp = ast_tvnow(); 00664 ast_smdi_md_message_push(iface, md_msg); 00665 ast_log(LOG_DEBUG, "Received SMDI MD message on %s\n", iface->name); 00666 00667 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 00668 00669 } else if (c == 'W') { /* MWI message */ 00670 start = 0; 00671 00672 ast_log(LOG_DEBUG, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n"); 00673 00674 if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) { 00675 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy); 00676 return NULL; 00677 } 00678 00679 ASTOBJ_INIT(mwi_msg); 00680 00681 /* discard the 'I' (from 'MWI') */ 00682 fgetc(iface->file); 00683 00684 /* read the forwarding station number (may be blank) */ 00685 cp = &mwi_msg->fwd_st[0]; 00686 for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) { 00687 if ((c = fgetc(iface->file)) == ' ') { 00688 *cp = '\0'; 00689 break; 00690 } 00691 00692 /* store c in md_msg->fwd_st */ 00693 if (i >= iface->msdstrip) 00694 *cp++ = c; 00695 } 00696 00697 /* make sure the station number is null terminated, even if this will truncate it */ 00698 mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0'; 00699 cp = NULL; 00700 00701 /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look 00702 * up a message on this field */ 00703 ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name)); 00704 00705 /* read the mwi failure cause */ 00706 for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) 00707 mwi_msg->cause[i] = fgetc(iface->file); 00708 00709 mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0'; 00710 00711 /* add the message to the message queue */ 00712 mwi_msg->timestamp = ast_tvnow(); 00713 ast_smdi_mwi_message_push(iface, mwi_msg); 00714 ast_log(LOG_DEBUG, "Received SMDI MWI message on %s\n", iface->name); 00715 00716 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); 00717 } else { 00718 ast_log(LOG_ERROR, "Unknown SMDI message type received on %s (M%c).\n", iface->name, c); 00719 start = 0; 00720 } 00721 } 00722 00723 ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name); 00724 ASTOBJ_UNREF(iface,ast_smdi_interface_destroy); 00725 return NULL; 00726 }
static int smdi_toggle_mwi | ( | struct ast_smdi_interface * | iface, | |
const char * | mailbox, | |||
int | on | |||
) | [static] |
Definition at line 193 of file res_smdi.c.
References ast_log(), ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, errno, mailbox_mapping::iface, LOG_DEBUG, LOG_ERROR, ast_smdi_interface::msdstrip, and ast_smdi_interface::name.
Referenced by ast_smdi_mwi_set(), and ast_smdi_mwi_unset().
00194 { 00195 FILE *file; 00196 int i; 00197 00198 if (!(file = fopen(iface->name, "w"))) { 00199 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno)); 00200 return 1; 00201 } 00202 00203 ASTOBJ_WRLOCK(iface); 00204 00205 fprintf(file, "%s:MWI ", on ? "OP" : "RMV"); 00206 00207 for (i = 0; i < iface->msdstrip; i++) 00208 fprintf(file, "0"); 00209 00210 fprintf(file, "%s!\x04", mailbox); 00211 00212 fclose(file); 00213 00214 ASTOBJ_UNLOCK(iface); 00215 00216 ast_log(LOG_DEBUG, "Sent MWI %s message for %s on %s\n", on ? "set" : "unset", 00217 mailbox, iface->name); 00218 00219 return 0; 00220 }
static void* unlink_from_msg_q | ( | struct ast_smdi_interface * | iface, | |
enum smdi_message_type | type | |||
) | [inline, static] |
Definition at line 277 of file res_smdi.c.
References ASTOBJ_CONTAINER_UNLINK_START, mailbox_mapping::iface, ast_smdi_interface::md_q, ast_smdi_interface::mwi_q, SMDI_MD, and SMDI_MWI.
Referenced by purge_old_messages(), and smdi_msg_pop().
00278 { 00279 switch (type) { 00280 case SMDI_MWI: 00281 return ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q); 00282 case SMDI_MD: 00283 return ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q); 00284 } 00285 00286 return NULL; 00287 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1374 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.
01375 { 01376 /* this destructor stops any running smdi_read threads */ 01377 ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy); 01378 ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces); 01379 01380 destroy_all_mailbox_mappings(); 01381 01382 ast_mutex_lock(&mwi_monitor.lock); 01383 mwi_monitor.stop = 1; 01384 ast_cond_signal(&mwi_monitor.cond); 01385 ast_mutex_unlock(&mwi_monitor.lock); 01386 01387 if (mwi_monitor.thread != AST_PTHREADT_NULL) { 01388 pthread_join(mwi_monitor.thread, NULL); 01389 } 01390 01391 ast_custom_function_unregister(&smdi_msg_retrieve_function); 01392 ast_custom_function_unregister(&smdi_msg_function); 01393 01394 return 0; 01395 }
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 break; 00313 case SMDI_MD: 00314 ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy); 00315 break; 00316 } 00317 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Simplified Message Desk Interface (SMDI) Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1416 of file res_smdi.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1416 of file res_smdi.c.
Definition at line 119 of file res_smdi.c.
const char config_file[] = "smdi.conf" [static] |
Definition at line 60 of file res_smdi.c.
struct mailbox_mapping* first |
Definition at line 121 of file res_smdi.c.
struct mailbox_mapping* last |
Definition at line 121 of file res_smdi.c.
struct timeval last_poll |
The time that the last poll began
Definition at line 127 of file res_smdi.c.
Definition at line 118 of file res_smdi.c.
struct { ... } mailbox_mappings |
A list of mailboxes that need to be monitored
struct { ... } mwi_monitor [static] |
Data that gets used by the SMDI MWI monitoring thread.
Referenced by append_mailbox_mapping(), destroy_all_mailbox_mappings(), load_module(), mwi_monitor_handler(), and unload_module().
unsigned int polling_interval |
Polling Interval for checking mailbox status
Definition at line 123 of file res_smdi.c.
SMDI interface container.
Referenced by ast_smdi_interface_find(), load_module(), smdi_load(), and unload_module().
struct ast_datastore_info smdi_msg_datastore_info [static] |
Initial value:
{ .type = "SMDIMSG", .destroy = smdi_msg_datastore_destroy, }
Definition at line 1111 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 1116 of file res_smdi.c.
struct ast_app_option smdi_msg_ret_options[128] = { [ 't' ] = { .flag = OPT_SEARCH_TERMINAL }, [ 'n' ] = { .flag = OPT_SEARCH_NUMBER }, } [static] |
struct ast_custom_function smdi_msg_retrieve_function [static] |
unsigned int stop |
Set to 1 to tell the polling thread to stop
Definition at line 125 of file res_smdi.c.
pthread_t thread |
The thread ID
Definition at line 117 of file res_smdi.c.