Sat Aug 6 00:40:04 2011

Asterisk developer's documentation


res_smdi.c File Reference

SMDI support for Asterisk. More...

#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_interfacealloc_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_interfaceast_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_messageast_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_messageast_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_messageast_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_messageast_smdi_mwi_message_wait (struct ast_smdi_interface *iface, int timeout)
 Get the next SMDI message from the queue.
ast_smdi_mwi_messageast_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_infoast_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


Detailed Description

SMDI support for Asterisk.

Author:
Matthew A. Nicholson <mnicholson@digium.com>

Russell Bryant <russell@digium.com>

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 Documentation

#define DEFAULT_POLLING_INTERVAL   10

10 seconds

Definition at line 112 of file res_smdi.c.

#define SMDI_MSG_EXPIRY_TIME   30000

Definition at line 58 of file res_smdi.c.

Referenced by smdi_load().

#define SMDI_RETRIEVE_TIMEOUT_DEFAULT   3000

In milliseconds

Definition at line 1119 of file res_smdi.c.

Referenced by smdi_msg_retrieve_read().


Enumeration Type Documentation

anonymous enum

Enumerator:
OPT_SEARCH_TERMINAL 
OPT_SEARCH_NUMBER 

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

Enumerator:
SMDI_MWI 
SMDI_MD 

Definition at line 248 of file res_smdi.c.

00248                        {
00249    SMDI_MWI,
00250    SMDI_MD,
00251 };


Function Documentation

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.

Parameters:
iface_name the name/port of the interface to search for.
Returns:
a pointer to the interface located or NULL if none was found. This actually returns an ASTOBJ reference and should be released using ASTOBJ_UNREF(iface, ast_smdi_interface_destroy).

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().

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.

Parameters:
iface a pointer to the interface to use.
This function pulls the first unexpired message from the SMDI message queue on the specified interface. It will purge all expired SMDI messages before returning.

Returns:
the next SMDI message, or NULL if there were no pending messages.

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().

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.

Parameters:
iface a pointer to the interface to use.
md_msg a pointer to the message to use.
This function puts a message back in the front of the specified queue. It should be used if a message was popped but is not going to be processed for some reason, and the message needs to be returned to the queue.

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.

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.

Parameters:
iface a pointer to the interface to use.
timeout the time to wait before returning in milliseconds.
This function pulls a message from the SMDI message queue on the specified interface. If no message is available this function will wait the specified amount of time before returning.

Returns:
the next SMDI message, or NULL if there were no pending messages and the timeout has expired.

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.

Parameters:
iface a pointer to the interface to use.
This function pulls the first unexpired message from the SMDI message queue on the specified interface. It will purge all expired SMDI messages before returning.

Returns:
the next SMDI message, or NULL if there were no pending messages.

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.

Parameters:
iface a pointer to the interface to use.
mwi_msg a pointer to the message to use.
This function puts a message back in the front of the specified queue. It should be used if a message was popped but is not going to be processed for some reason, and the message needs to be returned to the queue.

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.

Parameters:
iface a pointer to the interface to use.
timeout the time to wait before returning in milliseconds.
This function pulls a message from the SMDI message queue on the specified interface. If no message is available this function will wait the specified amount of time before returning.

Returns:
the next SMDI message, or NULL if there were no pending messages and the timeout has expired.

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.

Parameters:
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.

Parameters:
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]

Note:
Called with the mwi_monitor.lock locked

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 }


Variable Documentation

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.

ast_cond_t cond

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.

ast_mutex_t lock

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.

struct ast_smdi_interface_container smdi_ifaces

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]

Definition at line 1321 of file res_smdi.c.

Referenced by load_module(), and unload_module().

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]

Definition at line 1124 of file res_smdi.c.

Referenced by smdi_msg_retrieve_read().

struct ast_custom_function smdi_msg_retrieve_function [static]

Definition at line 1297 of file res_smdi.c.

Referenced by load_module(), and unload_module().

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.


Generated on Sat Aug 6 00:40:04 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7