Thu Oct 8 21:56:33 2009

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"

Include dependency graph for res_smdi.c:

Go to the source code of this file.

Data Structures

struct  ast_smdi_interface
struct  ast_smdi_interface_container
 SMDI interface container. More...
struct  ast_smdi_md_queue
 SMDI message desk message queue. More...
struct  ast_smdi_mwi_queue
 SMDI message waiting indicator message queue. More...
struct  mailbox_mapping
 A mapping between an SMDI mailbox ID and an Asterisk mailbox. More...
struct  smdi_msg_datastore

Defines

#define DEFAULT_POLLING_INTERVAL   10
#define SMDI_MSG_EXPIRY_TIME   30000
#define SMDI_RETRIEVE_TIMEOUT_DEFAULT   3000

Enumerations

enum  { OPT_SEARCH_TERMINAL = (1 << 0), OPT_SEARCH_NUMBER = (1 << 1) }
enum  smdi_message_type { SMDI_MWI, SMDI_MD }

Functions

static struct ast_smdi_interfacealloc_smdi_interface (void)
static void append_mailbox_mapping (struct ast_variable *var, struct ast_smdi_interface *iface)
 AST_APP_OPTIONS (smdi_msg_ret_options, BEGIN_OPTIONS AST_APP_OPTION('t', OPT_SEARCH_TERMINAL), AST_APP_OPTION('n', OPT_SEARCH_NUMBER), END_OPTIONS)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Simplified Message Desk Interface (SMDI) Resource",.load=load_module,.unload=unload_module,.reload=reload,)
static void ast_smdi_interface_destroy (struct ast_smdi_interface *iface)
struct ast_smdi_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.
struct 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.
struct 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.
struct 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.
struct ast_smdi_mwi_messageast_smdi_mwi_message_wait (struct ast_smdi_interface *iface, int timeout)
 Get the next SMDI message from the queue.
struct 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 const char config_file [] = "smdi.conf"
struct {
   ast_cond_t   cond
   ast_mutex_t   lock
   pthread_t   thread
mwi_monitor
 Data that gets used by the SMDI MWI monitoring thread.
struct ast_smdi_interface_container smdi_ifaces
 SMDI interface container.
static struct ast_datastore_info smdi_msg_datastore_info
static struct ast_custom_function smdi_msg_function
static int smdi_msg_id
static struct ast_custom_function smdi_msg_retrieve_function


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.

Referenced by smdi_load().

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

00372      {
00373    OPT_SEARCH_TERMINAL = (1 << 0),
00374    OPT_SEARCH_NUMBER   = (1 << 1),
00375 };

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 struct ast_smdi_interface* alloc_smdi_interface ( void   )  [static, read]

Definition at line 808 of file res_smdi.c.

References ast_calloc, ast_cond_init(), ast_mutex_init(), ASTOBJ_CONTAINER_INIT, ASTOBJ_INIT, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, and ast_smdi_interface::mwi_q_lock.

Referenced by smdi_load().

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

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

Definition at line 729 of file res_smdi.c.

References ast_calloc, AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ASTOBJ_REF, context, free, mailbox_mapping::iface, mailbox, mwi_monitor, ast_variable::name, strsep(), and ast_variable::value.

Referenced by smdi_load().

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

AST_APP_OPTIONS ( smdi_msg_ret_options  ,
BEGIN_OPTIONS   AST_APP_OPTION't', OPT_SEARCH_TERMINAL,
AST_APP_OPTION('n', OPT_SEARCH_NUMBER)  ,
END_OPTIONS   
)

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_GLOBAL_SYMBOLS  ,
"Simplified Message Desk Interface (SMDI) Resource"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

static void ast_smdi_interface_destroy ( struct ast_smdi_interface iface  )  [static]

Definition at line 132 of file res_smdi.c.

References ast_cond_destroy(), ast_module_unref(), ast_mutex_destroy(), AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_smdi_md_message_destroy(), ast_smdi_mwi_message_destroy(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ast_smdi_interface::file, free, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, ast_smdi_interface::mwi_q_lock, and ast_smdi_interface::thread.

Referenced by ast_smdi_interface_unref(), destroy_mailbox_mapping(), smdi_load(), smdi_msg_datastore_destroy(), smdi_msg_retrieve_read(), smdi_read(), and unload_module().

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

struct ast_smdi_interface* ast_smdi_interface_find ( const char *  iface_name  )  [read]

Find an SMDI interface with the specified name.

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

References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.

Referenced by load_config(), mkintf(), and smdi_msg_retrieve_read().

00506 {
00507    return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
00508 }

void ast_smdi_interface_unref ( struct ast_smdi_interface iface  ) 

Definition at line 160 of file res_smdi.c.

References ast_smdi_interface_destroy(), and ASTOBJ_UNREF.

Referenced by destroy_zt_pvt().

00161 {
00162    ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00163 }

void ast_smdi_md_message_destroy ( struct ast_smdi_md_message msg  ) 

ast_smdi_md_message destructor.

Definition at line 702 of file res_smdi.c.

References free.

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

00703 {
00704    free(msg);
00705 }

struct ast_smdi_md_message* ast_smdi_md_message_pop ( struct ast_smdi_interface iface  )  [read]

Get the next SMDI message from the queue.

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

References SMDI_MD, and smdi_msg_pop().

00477 {
00478    return smdi_msg_pop(iface, SMDI_MD);
00479 }

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

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, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, and ast_smdi_interface::md_q_lock.

00233 {
00234    ast_mutex_lock(&iface->md_q_lock);
00235    ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg);
00236    ast_cond_broadcast(&iface->md_q_cond);
00237    ast_mutex_unlock(&iface->md_q_lock);
00238 }

struct ast_smdi_md_message* ast_smdi_md_message_wait ( struct ast_smdi_interface iface,
int  timeout 
) [read]

Get the next SMDI message from the queue.

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

References SMDI_MD, and smdi_message_wait().

Referenced by ss_thread().

00482 {
00483    struct ast_flags options = { 0 };
00484    return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
00485 }

void ast_smdi_mwi_message_destroy ( struct ast_smdi_mwi_message msg  ) 

ast_smdi_mwi_message destructor.

Definition at line 707 of file res_smdi.c.

References free.

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

00708 {
00709    free(msg);
00710 }

struct ast_smdi_mwi_message* ast_smdi_mwi_message_pop ( struct ast_smdi_interface iface  )  [read]

Get the next SMDI message from the queue.

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

References smdi_msg_pop(), and SMDI_MWI.

00488 {
00489    return smdi_msg_pop(iface, SMDI_MWI);
00490 }

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

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, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, and ast_smdi_interface::mwi_q_lock.

00241 {
00242    ast_mutex_lock(&iface->mwi_q_lock);
00243    ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
00244    ast_cond_broadcast(&iface->mwi_q_cond);
00245    ast_mutex_unlock(&iface->mwi_q_lock);
00246 }

struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait ( struct ast_smdi_interface iface,
int  timeout 
) [read]

Get the next SMDI message from the queue.

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

References smdi_message_wait(), and SMDI_MWI.

00493 {
00494    struct ast_flags options = { 0 };
00495    return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
00496 }

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

Definition at line 498 of file res_smdi.c.

References smdi_message_wait(), and SMDI_MWI.

Referenced by run_externnotify().

00500 {
00501    struct ast_flags options = { 0 };
00502    return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
00503 }

int ast_smdi_mwi_set ( struct ast_smdi_interface iface,
const char *  mailbox 
)

Set the MWI indicator for a mailbox.

Parameters:
iface the interface to use.
mailbox the mailbox to use.

Definition at line 222 of file res_smdi.c.

References smdi_toggle_mwi().

Referenced by poll_mailbox(), and run_externnotify().

00223 {
00224    return smdi_toggle_mwi(iface, mailbox, 1);
00225 }

int ast_smdi_mwi_unset ( struct ast_smdi_interface iface,
const char *  mailbox 
)

Unset the MWI indicator for a mailbox.

Parameters:
iface the interface to use.
mailbox the mailbox to use.

Definition at line 227 of file res_smdi.c.

References smdi_toggle_mwi().

Referenced by poll_mailbox(), and run_externnotify().

00228 {
00229    return smdi_toggle_mwi(iface, mailbox, 0);
00230 }

static void destroy_all_mailbox_mappings ( void   )  [static]

Definition at line 719 of file res_smdi.c.

References AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), destroy_mailbox_mapping(), and mwi_monitor.

Referenced by smdi_load(), and unload_module().

00720 {
00721    struct mailbox_mapping *mm;
00722 
00723    ast_mutex_lock(&mwi_monitor.lock);
00724    while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry)))
00725       destroy_mailbox_mapping(mm);
00726    ast_mutex_unlock(&mwi_monitor.lock);
00727 }

static void destroy_mailbox_mapping ( struct mailbox_mapping mm  )  [static]

static int load_module ( void   )  [static]

Definition at line 1316 of file res_smdi.c.

References ast_cond_init(), ast_custom_function_register(), ast_log(), AST_MODULE_LOAD_DECLINE, ast_mutex_init(), ASTOBJ_CONTAINER_INIT, LOG_WARNING, mwi_monitor, smdi_ifaces, and smdi_load().

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

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

Definition at line 253 of file res_smdi.c.

References ast_mutex_lock(), ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_lock, SMDI_MD, and SMDI_MWI.

Referenced by purge_old_messages(), smdi_message_wait(), and smdi_msg_pop().

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

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

Definition at line 289 of file res_smdi.c.

References SMDI_MD, SMDI_MWI, ast_smdi_md_message::timestamp, ast_smdi_mwi_message::timestamp, and type.

Referenced by purge_old_messages().

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

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

Definition at line 781 of file res_smdi.c.

References ast_cond_timedwait(), AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_tvadd(), mwi_monitor, and poll_mailbox().

Referenced by smdi_load().

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

static void poll_mailbox ( struct mailbox_mapping mm  )  [static]

Note:
Called with the mwi_monitor.lock locked

Definition at line 762 of file res_smdi.c.

References ast_app_has_voicemail(), ast_smdi_mwi_set(), ast_smdi_mwi_unset(), mailbox_mapping::cur_state, and mailbox_mapping::iface.

Referenced by mwi_monitor_handler().

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

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

Definition at line 317 of file res_smdi.c.

References ast_log(), ast_smdi_md_message_push(), ast_smdi_mwi_message_push(), lock_msg_q(), LOG_NOTICE, ast_smdi_interface::msg_expiry, msg_timestamp(), SMDI_MD, SMDI_MWI, unlink_from_msg_q(), unlock_msg_q(), and unref_msg().

Referenced by smdi_msg_find(), and smdi_msg_pop().

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

static int reload ( void   )  [static]

Definition at line 1365 of file res_smdi.c.

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

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

static int smdi_load ( int  reload  )  [static]

Definition at line 838 of file res_smdi.c.

References alloc_smdi_interface(), append_mailbox_mapping(), ast_config_destroy(), ast_config_load(), AST_LIST_EMPTY, ast_log(), AST_MODULE_LOAD_FAILURE, ast_module_ref(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_smdi_interface_destroy(), ast_true(), ast_variable_browse(), ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_CONTAINER_PRUNE_MARKED, ASTOBJ_CONTAINER_RDLOCK, ASTOBJ_CONTAINER_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, DEFAULT_POLLING_INTERVAL, destroy_all_mailbox_mappings(), errno, ast_smdi_interface::fd, ast_smdi_interface::file, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, ast_smdi_interface::mode, ast_smdi_interface::msdstrip, ast_smdi_interface::msg_expiry, mwi_monitor, mwi_monitor_handler(), ast_variable::name, ast_variable::next, option_verbose, smdi_ifaces, SMDI_MSG_EXPIRY_TIME, smdi_read(), ast_smdi_interface::thread, ast_variable::value, and VERBOSE_PREFIX_3.

Referenced by load_module(), and reload().

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

static void* smdi_message_wait ( struct ast_smdi_interface iface,
int  timeout,
enum smdi_message_type  type,
const char *  search_key,
struct ast_flags  options 
) [static]

Definition at line 421 of file res_smdi.c.

References ast_cond_timedwait(), ast_tvadd(), cond, lock, lock_msg_q(), ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_cond, ast_smdi_interface::mwi_q_lock, SMDI_MD, smdi_msg_find(), SMDI_MWI, and unlock_msg_q().

Referenced by ast_smdi_md_message_wait(), ast_smdi_mwi_message_wait(), ast_smdi_mwi_message_wait_station(), and smdi_msg_retrieve_read().

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

static void smdi_msg_datastore_destroy ( void *  data  )  [static]

Definition at line 1072 of file res_smdi.c.

References ast_smdi_interface_destroy(), ast_smdi_md_message_destroy(), ASTOBJ_UNREF, free, smdi_msg_datastore::iface, and smdi_msg_datastore::md_msg.

Referenced by smdi_msg_retrieve_read().

01073 {
01074    struct smdi_msg_datastore *smd = data;
01075 
01076    if (smd->iface)
01077       ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy);
01078 
01079    if (smd->md_msg)
01080       ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy);
01081 
01082    free(smd);
01083 }

static void* smdi_msg_find ( struct ast_smdi_interface iface,
enum smdi_message_type  type,
const char *  search_key,
struct ast_flags  options 
) [static]

Definition at line 377 of file res_smdi.c.

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

Referenced by smdi_message_wait().

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

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

Definition at line 359 of file res_smdi.c.

References lock_msg_q(), purge_old_messages(), unlink_from_msg_q(), and unlock_msg_q().

Referenced by ast_smdi_md_message_pop(), and ast_smdi_mwi_message_pop().

00360 {
00361    void *msg;
00362 
00363    purge_old_messages(iface, type);
00364 
00365    lock_msg_q(iface, type);
00366    msg = unlink_from_msg_q(iface, type);
00367    unlock_msg_q(iface, type);
00368 
00369    return msg;
00370 }

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

Definition at line 1199 of file res_smdi.c.

References AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_smdi_md_message::calling_st, ast_datastore::data, ast_smdi_md_message::fwd_st, LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, parse(), and ast_smdi_md_message::type.

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

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

Definition at line 1100 of file res_smdi.c.

References AST_APP_ARG, ast_app_parse_options(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, ast_smdi_interface_destroy(), ast_smdi_interface_find(), ast_smdi_md_message_destroy(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_REF, ASTOBJ_UNREF, ast_datastore::data, smdi_msg_datastore::id, smdi_msg_datastore::iface, LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, parse(), SMDI_MD, smdi_message_wait(), smdi_msg_datastore_destroy(), and SMDI_RETRIEVE_TIMEOUT_DEFAULT.

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

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

Definition at line 519 of file res_smdi.c.

References ast_calloc, ast_log(), ast_smdi_interface_destroy(), ast_smdi_md_message_destroy(), ast_smdi_md_message_push(), ast_smdi_mwi_message_destroy(), ast_smdi_mwi_message_push(), ASTOBJ_INIT, ASTOBJ_UNREF, ast_smdi_md_message::calling_st, ast_smdi_mwi_message::cause, ast_smdi_interface::file, ast_smdi_mwi_message::fwd_st, ast_smdi_md_message::fwd_st, LOG_DEBUG, LOG_ERROR, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, ast_smdi_interface::msdstrip, ast_smdi_mwi_message::timestamp, ast_smdi_md_message::timestamp, and ast_smdi_md_message::type.

Referenced by smdi_load().

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

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

Definition at line 193 of file res_smdi.c.

References ast_log(), ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, errno, file, LOG_DEBUG, LOG_ERROR, and ast_smdi_interface::msdstrip.

Referenced by ast_smdi_mwi_set(), and ast_smdi_mwi_unset().

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

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

Definition at line 277 of file res_smdi.c.

References ASTOBJ_CONTAINER_UNLINK_START, ast_smdi_interface::md_q, ast_smdi_interface::mwi_q, SMDI_MD, and SMDI_MWI.

Referenced by purge_old_messages(), and smdi_msg_pop().

00278 {
00279    switch (type) {
00280    case SMDI_MWI:
00281       return ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
00282    case SMDI_MD:
00283       return ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
00284    }
00285 
00286    return NULL;
00287 }

static int unload_module ( void   )  [static]

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

Definition at line 265 of file res_smdi.c.

References ast_mutex_unlock(), ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_lock, SMDI_MD, and SMDI_MWI.

Referenced by purge_old_messages(), smdi_message_wait(), and smdi_msg_pop().

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

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

Definition at line 304 of file res_smdi.c.

References ast_smdi_md_message_destroy(), ast_smdi_mwi_message_destroy(), ASTOBJ_UNREF, SMDI_MD, and SMDI_MWI.

Referenced by purge_old_messages().

00305 {
00306    struct ast_smdi_md_message *md_msg = msg;
00307    struct ast_smdi_mwi_message *mwi_msg = msg;
00308 
00309    switch (type) {
00310    case SMDI_MWI:
00311       ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00312    case SMDI_MD:
00313       ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00314    }
00315 }


Variable Documentation

Definition at line 119 of file res_smdi.c.

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

Definition at line 60 of file res_smdi.c.

Definition at line 118 of file res_smdi.c.

struct { ... } mwi_monitor [static]

Data that gets used by the SMDI MWI monitoring thread.

Referenced by append_mailbox_mapping(), destroy_all_mailbox_mappings(), load_module(), mwi_monitor_handler(), smdi_load(), and unload_module().

SMDI interface container.

Referenced by ast_smdi_interface_find(), load_module(), smdi_load(), and unload_module().

Initial value:

 {
   .type = "SMDIMSG",
   .destroy = smdi_msg_datastore_destroy,
}

Definition at line 1085 of file res_smdi.c.

Definition at line 1295 of file res_smdi.c.

int smdi_msg_id [static]

Definition at line 1090 of file res_smdi.c.

Definition at line 1271 of file res_smdi.c.

pthread_t thread

The thread ID

Definition at line 117 of file res_smdi.c.


Generated on Thu Oct 8 21:56:33 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6