Fri Jul 24 00:41:57 2009

Asterisk developer's documentation


res_smdi.c File Reference

SMDI support for Asterisk. More...

#include "asterisk.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/stringfields.h"
#include "asterisk/linkedlists.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.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, const char *cmd, char *data, char *buf, size_t len)
static int smdi_msg_retrieve_read (struct ast_channel *chan, const 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 , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, }
static 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

Todo:
This module currently has its own mailbox monitoring thread. This should be converted to MWI subscriptions and just let the optional global voicemail polling thread handle it.

Definition in file res_smdi.c.


Define Documentation

#define DEFAULT_POLLING_INTERVAL   10

10 seconds

Definition at line 111 of file res_smdi.c.

#define SMDI_MSG_EXPIRY_TIME   30000

Definition at line 57 of file res_smdi.c.

Referenced by smdi_load().

#define SMDI_RETRIEVE_TIMEOUT_DEFAULT   3000

In milliseconds

Definition at line 1088 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 367 of file res_smdi.c.

00367      {
00368    OPT_SEARCH_TERMINAL = (1 << 0),
00369    OPT_SEARCH_NUMBER   = (1 << 1),
00370 };

enum smdi_message_type

Enumerator:
SMDI_MWI 
SMDI_MD 

Definition at line 245 of file res_smdi.c.

00245                        {
00246    SMDI_MWI,
00247    SMDI_MD,
00248 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1379 of file res_smdi.c.

static void __unreg_module ( void   )  [static]

Definition at line 1379 of file res_smdi.c.

static struct ast_smdi_interface* alloc_smdi_interface ( void   )  [static]

Definition at line 804 of file res_smdi.c.

References ast_calloc, ast_cond_init(), ast_mutex_init(), ASTOBJ_CONTAINER_INIT, and ASTOBJ_INIT.

00805 {
00806    struct ast_smdi_interface *iface;
00807 
00808    if (!(iface = ast_calloc(1, sizeof(*iface))))
00809       return NULL;
00810 
00811    ASTOBJ_INIT(iface);
00812    ASTOBJ_CONTAINER_INIT(&iface->md_q);
00813    ASTOBJ_CONTAINER_INIT(&iface->mwi_q);
00814 
00815    ast_mutex_init(&iface->md_q_lock);
00816    ast_cond_init(&iface->md_q_cond, NULL);
00817 
00818    ast_mutex_init(&iface->mwi_q_lock);
00819    ast_cond_init(&iface->mwi_q_cond, NULL);
00820 
00821    return iface;
00822 }

static void append_mailbox_mapping ( struct ast_variable var,
struct ast_smdi_interface iface 
) [static]

Definition at line 725 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, strsep(), and var.

00726 {
00727    struct mailbox_mapping *mm;
00728    char *mailbox, *context;
00729 
00730    if (!(mm = ast_calloc(1, sizeof(*mm))))
00731       return;
00732    
00733    if (ast_string_field_init(mm, 32)) {
00734       free(mm);
00735       return;
00736    }
00737 
00738    ast_string_field_set(mm, smdi, var->name);
00739 
00740    context = ast_strdupa(var->value);
00741    mailbox = strsep(&context, "@");
00742    if (ast_strlen_zero(context))
00743       context = "default";
00744 
00745    ast_string_field_set(mm, mailbox, mailbox);
00746    ast_string_field_set(mm, context, context);
00747 
00748    mm->iface = ASTOBJ_REF(iface);
00749 
00750    ast_mutex_lock(&mwi_monitor.lock);
00751    AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry);
00752    ast_mutex_unlock(&mwi_monitor.lock);
00753 }

static void ast_smdi_interface_destroy ( struct ast_smdi_interface iface  )  [static]

Definition at line 131 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().

00132 {
00133    if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
00134       pthread_cancel(iface->thread);
00135       pthread_join(iface->thread, NULL);
00136    }
00137    
00138    iface->thread = AST_PTHREADT_STOP;
00139    
00140    if (iface->file) 
00141       fclose(iface->file);
00142    
00143    ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy);
00144    ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy);
00145    ASTOBJ_CONTAINER_DESTROY(&iface->md_q);
00146    ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q);
00147 
00148    ast_mutex_destroy(&iface->md_q_lock);
00149    ast_cond_destroy(&iface->md_q_cond);
00150 
00151    ast_mutex_destroy(&iface->mwi_q_lock);
00152    ast_cond_destroy(&iface->mwi_q_cond);
00153 
00154    free(iface);
00155 
00156    ast_module_unref(ast_module_info->self);
00157 }

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 501 of file res_smdi.c.

References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.

Referenced by load_config(), and smdi_msg_retrieve_read().

00502 {
00503    return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
00504 }

void ast_smdi_interface_unref ( struct ast_smdi_interface iface  ) 

Definition at line 159 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 698 of file res_smdi.c.

References ast_free, and msg.

Referenced by ast_smdi_interface_destroy(), smdi_msg_datastore_destroy(), smdi_msg_retrieve_read(), and unref_msg().

00699 {
00700    ast_free(msg);
00701 }

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 472 of file res_smdi.c.

References SMDI_MD, and smdi_msg_pop().

00473 {
00474    return smdi_msg_pop(iface, SMDI_MD);
00475 }

static void ast_smdi_md_message_push ( struct ast_smdi_interface iface,
struct ast_smdi_md_message md_msg 
) [static]

Definition at line 170 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 229 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 477 of file res_smdi.c.

References SMDI_MD, and smdi_message_wait().

Referenced by ss_thread().

00478 {
00479    struct ast_flags options = { 0 };
00480    return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
00481 }

void ast_smdi_mwi_message_destroy ( struct ast_smdi_mwi_message msg  ) 

ast_smdi_mwi_message destructor.

Definition at line 703 of file res_smdi.c.

References ast_free, and msg.

Referenced by ast_smdi_interface_destroy(), run_externnotify(), and unref_msg().

00704 {
00705    ast_free(msg);
00706 }

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 483 of file res_smdi.c.

References smdi_msg_pop(), and SMDI_MWI.

00484 {
00485    return smdi_msg_pop(iface, SMDI_MWI);
00486 }

static void ast_smdi_mwi_message_push ( struct ast_smdi_interface iface,
struct ast_smdi_mwi_message mwi_msg 
) [static]

Definition at line 184 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().

00185 {
00186    ast_mutex_lock(&iface->mwi_q_lock);
00187    ASTOBJ_CONTAINER_LINK_END(&iface->mwi_q, mwi_msg);
00188    ast_cond_broadcast(&iface->mwi_q_cond);
00189    ast_mutex_unlock(&iface->mwi_q_lock);
00190 }

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 237 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.

00238 {
00239    ast_mutex_lock(&iface->mwi_q_lock);
00240    ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
00241    ast_cond_broadcast(&iface->mwi_q_cond);
00242    ast_mutex_unlock(&iface->mwi_q_lock);
00243 }

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 488 of file res_smdi.c.

References smdi_message_wait(), and SMDI_MWI.

00489 {
00490    struct ast_flags options = { 0 };
00491    return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
00492 }

struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait_station ( struct ast_smdi_interface iface,
int  timeout,
const char *  station 
)

Definition at line 494 of file res_smdi.c.

References smdi_message_wait(), and SMDI_MWI.

Referenced by run_externnotify().

00496 {
00497    struct ast_flags options = { 0 };
00498    return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
00499 }

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 219 of file res_smdi.c.

References mailbox_mapping::iface, and smdi_toggle_mwi().

Referenced by poll_mailbox(), and run_externnotify().

00220 {
00221    return smdi_toggle_mwi(iface, mailbox, 1);
00222 }

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 224 of file res_smdi.c.

References mailbox_mapping::iface, and smdi_toggle_mwi().

Referenced by poll_mailbox(), and run_externnotify().

00225 {
00226    return smdi_toggle_mwi(iface, mailbox, 0);
00227 }

static void destroy_all_mailbox_mappings ( void   )  [static]

Definition at line 715 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().

00716 {
00717    struct mailbox_mapping *mm;
00718 
00719    ast_mutex_lock(&mwi_monitor.lock);
00720    while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry)))
00721       destroy_mailbox_mapping(mm);
00722    ast_mutex_unlock(&mwi_monitor.lock);
00723 }

static void destroy_mailbox_mapping ( struct mailbox_mapping mm  )  [static]

Definition at line 708 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().

00709 {
00710    ast_string_field_free_memory(mm);
00711    ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy);
00712    free(mm);
00713 }

static int load_module ( void   )  [static]

Definition at line 1311 of file res_smdi.c.

References ast_cond_init(), ast_custom_function_register, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_mutex_init(), ASTOBJ_CONTAINER_INIT, LOG_NOTICE, mwi_monitor, smdi_ifaces, smdi_load(), smdi_msg_function, and smdi_msg_retrieve_function.

01312 {
01313    int res;
01314    
01315    /* initialize our containers */
01316    memset(&smdi_ifaces, 0, sizeof(smdi_ifaces));
01317    ASTOBJ_CONTAINER_INIT(&smdi_ifaces);
01318    
01319    ast_mutex_init(&mwi_monitor.lock);
01320    ast_cond_init(&mwi_monitor.cond, NULL);
01321 
01322    ast_custom_function_register(&smdi_msg_retrieve_function);
01323    ast_custom_function_register(&smdi_msg_function);
01324 
01325    /* load the config and start the listener threads*/
01326    res = smdi_load(0);
01327    if (res < 0) {
01328       return res;
01329    } else if (res == 1) {
01330       ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
01331       return AST_MODULE_LOAD_DECLINE;
01332    }
01333    
01334    return AST_MODULE_LOAD_SUCCESS;
01335 }

static int lock_msg_q ( struct ast_smdi_interface iface,
enum smdi_message_type  type 
) [inline, static]

Definition at line 250 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().

00251 {
00252    switch (type) {
00253    case SMDI_MWI:
00254       return ast_mutex_lock(&iface->mwi_q_lock);
00255    case SMDI_MD:  
00256       return ast_mutex_lock(&iface->md_q_lock);
00257    }
00258    
00259    return -1;
00260 }

static struct timeval msg_timestamp ( void *  msg,
enum smdi_message_type  type 
) [inline, static]

Definition at line 285 of file res_smdi.c.

References ast_tv(), msg, SMDI_MD, SMDI_MWI, ast_smdi_mwi_message::timestamp, and type.

Referenced by purge_old_messages().

00286 {
00287    struct ast_smdi_md_message *md_msg = msg;
00288    struct ast_smdi_mwi_message *mwi_msg = msg;
00289 
00290    switch (type) {
00291    case SMDI_MWI:
00292       return mwi_msg->timestamp;
00293    case SMDI_MD:
00294       return md_msg->timestamp;
00295    }
00296 
00297    return ast_tv(0, 0);
00298 }

static void* mwi_monitor_handler ( void *  data  )  [static]

Definition at line 777 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().

00778 {
00779    while (!mwi_monitor.stop) {
00780       struct timespec ts = { 0, };
00781       struct timeval polltime;
00782       struct mailbox_mapping *mm;
00783 
00784       ast_mutex_lock(&mwi_monitor.lock);
00785 
00786       mwi_monitor.last_poll = ast_tvnow();
00787 
00788       AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry)
00789          poll_mailbox(mm);
00790 
00791       /* Sleep up to the configured polling interval.  Allow unload_module()
00792        * to signal us to wake up and exit. */
00793       polltime = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0));
00794       ts.tv_sec = polltime.tv_sec;
00795       ts.tv_nsec = polltime.tv_usec * 1000;
00796       ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts);
00797 
00798       ast_mutex_unlock(&mwi_monitor.lock);
00799    }
00800 
00801    return NULL;
00802 }

static void poll_mailbox ( struct mailbox_mapping mm  )  [static]

Note:
Called with the mwi_monitor.lock locked

Definition at line 758 of file res_smdi.c.

References ast_app_has_voicemail(), ast_smdi_mwi_set(), ast_smdi_mwi_unset(), buf, mailbox_mapping::context, mailbox_mapping::cur_state, mailbox_mapping::iface, mailbox_mapping::mailbox, and mailbox_mapping::smdi.

Referenced by mwi_monitor_handler().

00759 {
00760    char buf[1024];
00761    unsigned int state;
00762 
00763    snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context);
00764 
00765    state = !!ast_app_has_voicemail(mm->mailbox, NULL);
00766 
00767    if (state != mm->cur_state) {
00768       if (state)
00769          ast_smdi_mwi_set(mm->iface, mm->smdi);
00770       else
00771          ast_smdi_mwi_unset(mm->iface, mm->smdi);
00772 
00773       mm->cur_state = state;
00774    }
00775 }

static void purge_old_messages ( struct ast_smdi_interface iface,
enum smdi_message_type  type 
) [static]

Definition at line 313 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, msg, 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().

00314 {
00315    struct timeval now = ast_tvnow();
00316    long elapsed = 0;
00317    void *msg;
00318    
00319    lock_msg_q(iface, type);
00320    msg = unlink_from_msg_q(iface, type);
00321    unlock_msg_q(iface, type);
00322 
00323    /* purge old messages */
00324    while (msg) {
00325       elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type));
00326 
00327       if (elapsed > iface->msg_expiry) {
00328          /* found an expired message */
00329          unref_msg(msg, type);
00330          ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue.  "
00331             "Message was %ld milliseconds too old.\n",
00332             iface->name, (type == SMDI_MD) ? "MD" : "MWI", 
00333             elapsed - iface->msg_expiry);
00334 
00335          lock_msg_q(iface, type);
00336          msg = unlink_from_msg_q(iface, type);
00337          unlock_msg_q(iface, type);
00338       } else {
00339          /* good message, put it back and return */
00340          switch (type) {
00341          case SMDI_MD:
00342             ast_smdi_md_message_push(iface, msg);
00343             break;
00344          case SMDI_MWI:
00345             ast_smdi_mwi_message_push(iface, msg);
00346             break;
00347          }
00348          unref_msg(msg, type);
00349          break;
00350       }
00351    }
00352 }

static int reload ( void   )  [static]

Definition at line 1360 of file res_smdi.c.

References ast_log(), LOG_WARNING, and smdi_load().

01361 {
01362    int res;
01363 
01364    res = smdi_load(1);
01365 
01366    if (res < 0) {
01367       return res;
01368    } else if (res == 1) {
01369       ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
01370       return 0;
01371    } else
01372       return 0;
01373 }

static int smdi_load ( int  reload  )  [static]

Definition at line 834 of file res_smdi.c.

References ast_config_load, ast_log(), ast_variable_browse(), ASTOBJ_CONTAINER_MARKALL, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEUNCHANGED, ast_variable::lineno, LOG_NOTICE, ast_variable::name, ast_variable::next, smdi_ifaces, SMDI_MSG_EXPIRY_TIME, and ast_variable::value.

Referenced by load_module(), and reload().

00835 {
00836    struct ast_config *conf;
00837    struct ast_variable *v;
00838    struct ast_smdi_interface *iface = NULL;
00839    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00840    int res = 0;
00841 
00842    /* Config options */
00843    speed_t baud_rate = B9600;     /* 9600 baud rate */
00844    tcflag_t paritybit = PARENB;   /* even parity checking */
00845    tcflag_t charsize = CS7;       /* seven bit characters */
00846    int stopbits = 0;              /* One stop bit */
00847    
00848    int msdstrip = 0;              /* strip zero digits */
00849    long msg_expiry = SMDI_MSG_EXPIRY_TIME;
00850 
00851    if (!(conf = ast_config_load(config_file, config_flags))) {
00852       if (reload)
00853          ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
00854       else
00855          ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file);
00856       return 1;
00857    } else if (conf == CONFIG_STATUS_FILEUNCHANGED)
00858       return 0;
00859 
00860    /* Mark all interfaces that we are listening on.  We will unmark them
00861     * as we find them in the config file, this way we know any interfaces
00862     * still marked after we have finished parsing the config file should
00863     * be stopped.
00864     */
00865    if (reload)
00866       ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces);
00867 
00868    for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
00869       if (!strcasecmp(v->name, "baudrate")) {
00870          if (!strcasecmp(v->value, "9600"))
00871             baud_rate = B9600;
00872          else if (!strcasecmp(v->value, "4800"))
00873             baud_rate = B4800;
00874          else if (!strcasecmp(v->value, "2400"))
00875             baud_rate = B2400;
00876          else if (!strcasecmp(v->value, "1200"))
00877             baud_rate = B1200;
00878          else {
00879             ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno);
00880             baud_rate = B9600;
00881          }
00882       } else if (!strcasecmp(v->name, "msdstrip")) {
00883          if (!sscanf(v->value, "%d", &msdstrip)) {
00884             ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00885             msdstrip = 0;
00886          } else if (0 > msdstrip || msdstrip > 9) {
00887             ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00888             msdstrip = 0;
00889          }
00890       } else if (!strcasecmp(v->name, "msgexpirytime")) {
00891          if (!sscanf(v->value, "%ld", &msg_expiry)) {
00892             ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno);
00893             msg_expiry = SMDI_MSG_EXPIRY_TIME;
00894          }
00895       } else if (!strcasecmp(v->name, "paritybit")) {
00896          if (!strcasecmp(v->value, "even"))
00897             paritybit = PARENB;
00898          else if (!strcasecmp(v->value, "odd"))
00899             paritybit = PARENB | PARODD;
00900          else if (!strcasecmp(v->value, "none"))
00901             paritybit = ~PARENB;
00902          else {
00903             ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno);
00904             paritybit = PARENB;
00905          }
00906       } else if (!strcasecmp(v->name, "charsize")) {
00907          if (!strcasecmp(v->value, "7"))
00908             charsize = CS7;
00909          else if (!strcasecmp(v->value, "8"))
00910             charsize = CS8;
00911          else {
00912             ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno);
00913             charsize = CS7;
00914          }
00915       } else if (!strcasecmp(v->name, "twostopbits")) {
00916          stopbits = ast_true(v->name);
00917       } else if (!strcasecmp(v->name, "smdiport")) {
00918          if (reload) {
00919             /* we are reloading, check if we are already
00920              * monitoring this interface, if we are we do
00921              * not want to start it again.  This also has
00922              * the side effect of not updating different
00923              * setting for the serial port, but it should
00924              * be trivial to rewrite this section so that
00925              * options on the port are changed without
00926              * restarting the interface.  Or the interface
00927              * could be restarted with out emptying the
00928              * queue. */
00929             if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
00930                ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
00931                ASTOBJ_UNMARK(iface);
00932                ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00933                continue;
00934             }
00935          }
00936          
00937          if (!(iface = alloc_smdi_interface()))
00938             continue;
00939 
00940          ast_copy_string(iface->name, v->value, sizeof(iface->name));
00941 
00942          iface->thread = AST_PTHREADT_NULL;
00943 
00944          if (!(iface->file = fopen(iface->name, "r"))) {
00945             ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
00946             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00947             continue;
00948          }
00949 
00950          iface->fd = fileno(iface->file);
00951 
00952          /* Set the proper attributes for our serial port. */
00953 
00954          /* get the current attributes from the port */
00955          if (tcgetattr(iface->fd, &iface->mode)) {
00956             ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno));
00957             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00958             continue;
00959          }
00960 
00961          /* set the desired speed */
00962          if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
00963             ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
00964             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00965             continue;
00966          }
00967          
00968          /* set the stop bits */
00969          if (stopbits)
00970             iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB;   /* set two stop bits */
00971          else
00972             iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB;  /* set one stop bit */
00973          
00974          /* set the parity */
00975          iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit;
00976          
00977          /* set the character size */
00978          iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize;
00979          
00980          /* commit the desired attributes */
00981          if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
00982             ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
00983             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00984             continue;
00985          }
00986 
00987          /* set the msdstrip */
00988          iface->msdstrip = msdstrip;
00989 
00990          /* set the message expiry time */
00991          iface->msg_expiry = msg_expiry;
00992 
00993          /* start the listener thread */
00994          ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name);
00995          if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
00996             ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
00997             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00998             continue;
00999          }
01000 
01001          ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface);
01002          ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01003          ast_module_ref(ast_module_info->self);
01004       } else {
01005          ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
01006       }
01007    }
01008 
01009    destroy_all_mailbox_mappings();
01010    mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
01011    
01012    iface = NULL;
01013 
01014    for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) {
01015       if (!strcasecmp(v->name, "smdiport")) {
01016          if (iface)
01017             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01018 
01019          if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
01020             ast_log(LOG_NOTICE, "SMDI interface %s not found\n", iface->name);
01021             continue;
01022          }
01023       } else if (!strcasecmp(v->name, "pollinginterval")) {
01024          if (sscanf(v->value, "%u", &mwi_monitor.polling_interval) != 1) {
01025             ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value);
01026             mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
01027          }
01028       } else {
01029          if (!iface) {
01030             ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n");
01031             continue;
01032          }
01033          append_mailbox_mapping(v, iface);
01034       }
01035    }
01036 
01037    if (iface)
01038       ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01039 
01040    ast_config_destroy(conf);
01041    
01042    if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL
01043       && ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) {
01044       ast_log(LOG_ERROR, "Failed to start MWI monitoring thread.  This module will not operate.\n");
01045       return AST_MODULE_LOAD_FAILURE;
01046    }
01047 
01048    /* Prune any interfaces we should no longer monitor. */
01049    if (reload)
01050       ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy);
01051    
01052    ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces);
01053    /* TODO: this is bad, we need an ASTOBJ method for this! */
01054    if (!smdi_ifaces.head)
01055       res = 1;
01056    ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces);
01057    
01058    return res;
01059 }

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 416 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, msg, 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().

00418 {
00419    struct timeval start;
00420    long diff = 0;
00421    void *msg;
00422    ast_cond_t *cond = NULL;
00423    ast_mutex_t *lock = NULL;
00424 
00425    switch (type) {
00426    case SMDI_MWI:
00427       cond = &iface->mwi_q_cond;
00428       lock = &iface->mwi_q_lock;
00429       break;
00430    case SMDI_MD:
00431       cond = &iface->md_q_cond;
00432       lock = &iface->md_q_lock;
00433       break;
00434    }
00435 
00436    start = ast_tvnow();
00437 
00438    while (diff < timeout) {
00439       struct timespec ts = { 0, };
00440       struct timeval wait;
00441 
00442       lock_msg_q(iface, type);
00443 
00444       if ((msg = smdi_msg_find(iface, type, search_key, options))) {
00445          unlock_msg_q(iface, type);
00446          return msg;
00447       }
00448 
00449       wait = ast_tvadd(start, ast_tv(0, timeout));
00450       ts.tv_sec = wait.tv_sec;
00451       ts.tv_nsec = wait.tv_usec * 1000;
00452 
00453       /* If there were no messages in the queue, then go to sleep until one
00454        * arrives. */
00455 
00456       ast_cond_timedwait(cond, lock, &ts);
00457 
00458       if ((msg = smdi_msg_find(iface, type, search_key, options))) {
00459          unlock_msg_q(iface, type);
00460          return msg;
00461       }
00462 
00463       unlock_msg_q(iface, type);
00464 
00465       /* check timeout */
00466       diff = ast_tvdiff_ms(ast_tvnow(), start);
00467    }
00468 
00469    return NULL;
00470 }

static void smdi_msg_datastore_destroy ( void *  data  )  [static]

Definition at line 1067 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().

01068 {
01069    struct smdi_msg_datastore *smd = data;
01070 
01071    if (smd->iface)
01072       ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy);
01073 
01074    if (smd->md_msg)
01075       ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy);
01076 
01077    free(smd);
01078 }

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 372 of file res_smdi.c.

References ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_REF, mailbox_mapping::iface, ast_smdi_interface::md_q, msg, OPT_SEARCH_NUMBER, OPT_SEARCH_TERMINAL, purge_old_messages(), and SMDI_MD.

Referenced by smdi_message_wait().

00374 {
00375    void *msg = NULL;
00376 
00377    purge_old_messages(iface, type);
00378 
00379    switch (type) {
00380    case SMDI_MD:
00381       if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) {
00382          struct ast_smdi_md_message *md_msg = NULL;
00383 
00384          /* Searching by the message desk terminal */
00385 
00386          ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
00387             if (!strcasecmp(iterator->mesg_desk_term, search_key))
00388                md_msg = ASTOBJ_REF(iterator);
00389          } while (0); );
00390 
00391          msg = md_msg;
00392       } else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) {
00393          struct ast_smdi_md_message *md_msg = NULL;
00394 
00395          /* Searching by the message desk number */
00396 
00397          ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
00398             if (!strcasecmp(iterator->mesg_desk_num, search_key))
00399                md_msg = ASTOBJ_REF(iterator);
00400          } while (0); );
00401 
00402          msg = md_msg;
00403       } else {
00404          /* Searching by the forwarding station */
00405          msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, search_key);
00406       }
00407       break;
00408    case SMDI_MWI:
00409       msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, search_key);
00410       break;
00411    }
00412 
00413    return msg;
00414 }

static void* smdi_msg_pop ( struct ast_smdi_interface iface,
enum smdi_message_type  type 
) [static]

Definition at line 354 of file res_smdi.c.

References mailbox_mapping::iface, lock_msg_q(), msg, purge_old_messages(), unlink_from_msg_q(), and unlock_msg_q().

Referenced by ast_smdi_md_message_pop(), and ast_smdi_mwi_message_pop().

00355 {
00356    void *msg;
00357 
00358    purge_old_messages(iface, type);
00359 
00360    lock_msg_q(iface, type);
00361    msg = unlink_from_msg_q(iface, type);
00362    unlock_msg_q(iface, type);
00363 
00364    return msg;
00365 }

static int smdi_msg_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 1194 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, chan, 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.

01195 {
01196    struct ast_module_user *u;
01197    int res = -1;
01198    AST_DECLARE_APP_ARGS(args,
01199       AST_APP_ARG(id);
01200       AST_APP_ARG(component);
01201    );
01202    char *parse;
01203    struct ast_datastore *datastore = NULL;
01204    struct smdi_msg_datastore *smd = NULL;
01205 
01206    u = ast_module_user_add(chan);
01207 
01208    if (!chan) {
01209       ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n");
01210       goto return_error;
01211    }
01212 
01213    if (ast_strlen_zero(data)) {
01214       ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n");
01215       goto return_error;
01216    }
01217 
01218    parse = ast_strdupa(data);
01219    AST_STANDARD_APP_ARGS(args, parse);
01220 
01221    if (ast_strlen_zero(args.id)) {
01222       ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
01223       goto return_error;
01224    }
01225 
01226    if (ast_strlen_zero(args.component)) {
01227       ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
01228       goto return_error;
01229    }
01230 
01231    ast_channel_lock(chan);
01232    datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id);
01233    ast_channel_unlock(chan);
01234    
01235    if (!datastore) {
01236       ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id);
01237       goto return_error;
01238    }
01239 
01240    smd = datastore->data;
01241 
01242    if (!strcasecmp(args.component, "number")) {
01243       ast_copy_string(buf, smd->md_msg->mesg_desk_num, len);
01244    } else if (!strcasecmp(args.component, "terminal")) {
01245       ast_copy_string(buf, smd->md_msg->mesg_desk_term, len);
01246    } else if (!strcasecmp(args.component, "station")) {
01247       ast_copy_string(buf, smd->md_msg->fwd_st, len);
01248    } else if (!strcasecmp(args.component, "callerid")) {
01249       ast_copy_string(buf, smd->md_msg->calling_st, len);
01250    } else if (!strcasecmp(args.component, "type")) {
01251       snprintf(buf, len, "%c", smd->md_msg->type);
01252    } else {
01253       ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n",
01254          args.component);
01255       goto return_error;
01256    }
01257 
01258    res = 0;
01259 
01260 return_error:
01261    ast_module_user_remove(u);
01262 
01263    return res;
01264 }

static int smdi_msg_retrieve_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 1095 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_lock, ast_channel_unlock, ast_datastore_alloc(), 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, chan, 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.

01096 {
01097    struct ast_module_user *u;
01098    AST_DECLARE_APP_ARGS(args,
01099       AST_APP_ARG(port);
01100       AST_APP_ARG(search_key);
01101       AST_APP_ARG(timeout);
01102       AST_APP_ARG(options);
01103    );
01104    struct ast_flags options = { 0 };
01105    unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
01106    int res = -1;
01107    char *parse = NULL;
01108    struct smdi_msg_datastore *smd = NULL;
01109    struct ast_datastore *datastore = NULL;
01110    struct ast_smdi_interface *iface = NULL;
01111    struct ast_smdi_md_message *md_msg = NULL;
01112 
01113    u = ast_module_user_add(chan);
01114 
01115    if (ast_strlen_zero(data)) {
01116       ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n");
01117       goto return_error;
01118    }
01119 
01120    if (!chan) {
01121       ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n");
01122       goto return_error;
01123    }
01124 
01125    ast_autoservice_start(chan);
01126 
01127    parse = ast_strdupa(data);
01128    AST_STANDARD_APP_ARGS(args, parse);
01129 
01130    if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) {
01131       ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n");
01132       goto return_error;
01133    }
01134 
01135    if (!(iface = ast_smdi_interface_find(args.port))) {
01136       ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port);
01137       goto return_error;
01138    }
01139 
01140    if (!ast_strlen_zero(args.options)) {
01141       ast_app_parse_options(smdi_msg_ret_options, &options, NULL, args.options);
01142    }
01143 
01144    if (!ast_strlen_zero(args.timeout)) {
01145       if (sscanf(args.timeout, "%u", &timeout) != 1) {
01146          ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
01147          timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
01148       }
01149    }
01150 
01151    if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) {
01152       ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after "
01153          "waiting %u ms.\n", args.search_key, timeout);
01154       goto return_error;
01155    }
01156 
01157    if (!(smd = ast_calloc(1, sizeof(*smd))))
01158       goto return_error;
01159 
01160    smd->iface = ASTOBJ_REF(iface);
01161    smd->md_msg = ASTOBJ_REF(md_msg);
01162    smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
01163    snprintf(buf, len, "%u", smd->id);
01164 
01165    if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf)))
01166       goto return_error;
01167 
01168    datastore->data = smd;
01169 
01170    ast_channel_lock(chan);
01171    ast_channel_datastore_add(chan, datastore);
01172    ast_channel_unlock(chan);
01173 
01174    res = 0;
01175 
01176 return_error:
01177    if (iface)
01178       ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01179 
01180    if (md_msg)
01181       ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
01182 
01183    if (smd && !datastore)
01184       smdi_msg_datastore_destroy(smd);
01185 
01186    if (parse)
01187       ast_autoservice_stop(chan);
01188 
01189    ast_module_user_remove(u);
01190 
01191    return res;
01192 }

static void* smdi_read ( void *  iface_p  )  [static]

Definition at line 515 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.

00516 {
00517    struct ast_smdi_interface *iface = iface_p;
00518    struct ast_smdi_md_message *md_msg;
00519    struct ast_smdi_mwi_message *mwi_msg;
00520    char c = '\0';
00521    char *cp = NULL;
00522    int i;
00523    int start = 0;
00524       
00525    /* read an smdi message */
00526    while ((c = fgetc(iface->file))) {
00527 
00528       /* check if this is the start of a message */
00529       if (!start) {
00530          if (c == 'M') {
00531             ast_log(LOG_DEBUG, "Read an 'M' to start an SMDI message\n");
00532             start = 1;
00533          }
00534          continue;
00535       }
00536       
00537       if (c == 'D') { /* MD message */
00538          start = 0;
00539 
00540          ast_log(LOG_DEBUG, "Read a 'D' ... it's an MD message.\n");
00541 
00542          if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) {
00543             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00544             return NULL;
00545          }
00546          
00547          ASTOBJ_INIT(md_msg);
00548 
00549          /* read the message desk number */
00550          for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) {
00551             md_msg->mesg_desk_num[i] = fgetc(iface->file);
00552             ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_num[i]);
00553          }
00554 
00555          md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0';
00556          
00557          ast_log(LOG_DEBUG, "The message desk number is '%s'\n", md_msg->mesg_desk_num);
00558 
00559          /* read the message desk terminal number */
00560          for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) {
00561             md_msg->mesg_desk_term[i] = fgetc(iface->file);
00562             ast_log(LOG_DEBUG, "Read a '%c'\n", md_msg->mesg_desk_term[i]);
00563          }
00564 
00565          md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0';
00566 
00567          ast_log(LOG_DEBUG, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term);
00568 
00569          /* read the message type */
00570          md_msg->type = fgetc(iface->file);
00571        
00572          ast_log(LOG_DEBUG, "Message type is '%c'\n", md_msg->type);
00573 
00574          /* read the forwarding station number (may be blank) */
00575          cp = &md_msg->fwd_st[0];
00576          for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) {
00577             if ((c = fgetc(iface->file)) == ' ') {
00578                *cp = '\0';
00579                ast_log(LOG_DEBUG, "Read a space, done looking for the forwarding station\n");
00580                break;
00581             }
00582 
00583             /* store c in md_msg->fwd_st */
00584             if (i >= iface->msdstrip) {
00585                ast_log(LOG_DEBUG, "Read a '%c' and stored it in the forwarding station buffer\n", c);
00586                *cp++ = c;
00587             } else {
00588                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);
00589             }
00590          }
00591 
00592          /* make sure the value is null terminated, even if this truncates it */
00593          md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0';
00594          cp = NULL;
00595 
00596          ast_log(LOG_DEBUG, "The forwarding station is '%s'\n", md_msg->fwd_st);
00597 
00598          /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look
00599           * up a message on this field */
00600          ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name));
00601 
00602          /* read the calling station number (may be blank) */
00603          cp = &md_msg->calling_st[0];
00604          for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) {
00605             if (!isdigit((c = fgetc(iface->file)))) {
00606                *cp = '\0';
00607                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);
00608                if (c == ' ') {
00609                   /* Don't break on a space.  We may read the space before the calling station
00610                    * here if the forwarding station buffer filled up. */
00611                   i--; /* We're still on the same character */
00612                   continue;
00613                }
00614                break;
00615             }
00616 
00617             /* store c in md_msg->calling_st */
00618             if (i >= iface->msdstrip) {
00619                ast_log(LOG_DEBUG, "Read a '%c' and stored it in the calling station buffer\n", c);
00620                *cp++ = c;
00621             } else {
00622                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);
00623             }
00624          }
00625 
00626          /* make sure the value is null terminated, even if this truncates it */
00627          md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0';
00628          cp = NULL;
00629 
00630          ast_log(LOG_DEBUG, "The calling station is '%s'\n", md_msg->calling_st);
00631 
00632          /* add the message to the message queue */
00633          md_msg->timestamp = ast_tvnow();
00634          ast_smdi_md_message_push(iface, md_msg);
00635          ast_log(LOG_DEBUG, "Recieved SMDI MD message on %s\n", iface->name);
00636          
00637          ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00638 
00639       } else if (c == 'W') { /* MWI message */
00640          start = 0;
00641 
00642          ast_log(LOG_DEBUG, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n");
00643 
00644          if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) {
00645             ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00646             return NULL;
00647          }
00648 
00649          ASTOBJ_INIT(mwi_msg);
00650 
00651          /* discard the 'I' (from 'MWI') */
00652          fgetc(iface->file);
00653          
00654          /* read the forwarding station number (may be blank) */
00655          cp = &mwi_msg->fwd_st[0];
00656          for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) {
00657             if ((c = fgetc(iface->file)) == ' ') {
00658                *cp = '\0';
00659                break;
00660             }
00661 
00662             /* store c in md_msg->fwd_st */
00663             if (i >= iface->msdstrip)
00664                *cp++ = c;
00665          }
00666 
00667          /* make sure the station number is null terminated, even if this will truncate it */
00668          mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0';
00669          cp = NULL;
00670          
00671          /* Put the fwd_st in the name field so that we can use ASTOBJ_FIND to look
00672           * up a message on this field */
00673          ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name));
00674 
00675          /* read the mwi failure cause */
00676          for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++)
00677             mwi_msg->cause[i] = fgetc(iface->file);
00678 
00679          mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0';
00680 
00681          /* add the message to the message queue */
00682          mwi_msg->timestamp = ast_tvnow();
00683          ast_smdi_mwi_message_push(iface, mwi_msg);
00684          ast_log(LOG_DEBUG, "Recieved SMDI MWI message on %s\n", iface->name);
00685          
00686          ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00687       } else {
00688          ast_log(LOG_ERROR, "Unknown SMDI message type recieved on %s (M%c).\n", iface->name, c);
00689          start = 0;
00690       }
00691    }
00692 
00693    ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
00694    ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00695    return NULL;
00696 }

static int smdi_toggle_mwi ( struct ast_smdi_interface iface,
const char *  mailbox,
int  on 
) [static]

Definition at line 192 of file res_smdi.c.

References ast_debug, ast_log(), ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, errno, mailbox_mapping::iface, LOG_ERROR, ast_smdi_interface::msdstrip, and ast_smdi_interface::name.

Referenced by ast_smdi_mwi_set(), and ast_smdi_mwi_unset().

00193 {
00194    FILE *file;
00195    int i;
00196    
00197    if (!(file = fopen(iface->name, "w"))) {
00198       ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
00199       return 1;
00200    }  
00201    
00202    ASTOBJ_WRLOCK(iface);
00203    
00204    fprintf(file, "%s:MWI ", on ? "OP" : "RMV");
00205    
00206    for (i = 0; i < iface->msdstrip; i++)
00207       fprintf(file, "0");
00208 
00209    fprintf(file, "%s!\x04", mailbox);
00210 
00211    fclose(file);
00212 
00213    ASTOBJ_UNLOCK(iface);
00214    ast_debug(1, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
00215 
00216    return 0;
00217 }

static void* unlink_from_msg_q ( struct ast_smdi_interface iface,
enum smdi_message_type  type 
) [inline, static]

Definition at line 274 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().

00275 {
00276    switch (type) {
00277    case SMDI_MWI:
00278       return ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
00279    case SMDI_MD:
00280       return ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
00281    }
00282    return NULL;
00283 }

static int unload_module ( void   )  [static]

Definition at line 1337 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.

01338 {
01339    /* this destructor stops any running smdi_read threads */
01340    ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy);
01341    ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces);
01342 
01343    destroy_all_mailbox_mappings();
01344 
01345    ast_mutex_lock(&mwi_monitor.lock);
01346    mwi_monitor.stop = 1;
01347    ast_cond_signal(&mwi_monitor.cond);
01348    ast_mutex_unlock(&mwi_monitor.lock);
01349 
01350    if (mwi_monitor.thread != AST_PTHREADT_NULL) {
01351       pthread_join(mwi_monitor.thread, NULL);
01352    }
01353 
01354    ast_custom_function_unregister(&smdi_msg_retrieve_function);
01355    ast_custom_function_unregister(&smdi_msg_function);
01356 
01357    return 0;
01358 }

static int unlock_msg_q ( struct ast_smdi_interface iface,
enum smdi_message_type  type 
) [inline, static]

Definition at line 262 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().

00263 {
00264    switch (type) {
00265    case SMDI_MWI:
00266       return ast_mutex_unlock(&iface->mwi_q_lock);
00267    case SMDI_MD:
00268       return ast_mutex_unlock(&iface->md_q_lock);
00269    }
00270 
00271    return -1;
00272 }

static void unref_msg ( void *  msg,
enum smdi_message_type  type 
) [inline, static]

Definition at line 300 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().

00301 {
00302    struct ast_smdi_md_message *md_msg = msg;
00303    struct ast_smdi_mwi_message *mwi_msg = msg;
00304 
00305    switch (type) {
00306    case SMDI_MWI:
00307       ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00308    case SMDI_MD:
00309       ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00310    }
00311 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1379 of file res_smdi.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1379 of file res_smdi.c.

ast_cond_t cond

Definition at line 118 of file res_smdi.c.

const char config_file[] = "smdi.conf" [static]

Definition at line 59 of file res_smdi.c.

struct mailbox_mapping* first

Definition at line 120 of file res_smdi.c.

struct mailbox_mapping* last

Definition at line 120 of file res_smdi.c.

struct timeval last_poll

The time that the last poll began

Definition at line 126 of file res_smdi.c.

ast_mutex_t lock

Definition at line 117 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 122 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 1080 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 1290 of file res_smdi.c.

Referenced by load_module(), and unload_module().

int smdi_msg_id [static]

Definition at line 1085 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 1093 of file res_smdi.c.

Referenced by smdi_msg_retrieve_read().

struct ast_custom_function smdi_msg_retrieve_function [static]

Definition at line 1266 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 124 of file res_smdi.c.

pthread_t thread

The thread ID

Definition at line 116 of file res_smdi.c.


Generated on Fri Jul 24 00:41:57 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7