Thu Jul 9 13:41:31 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  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 *station)
static void smdi_msg_datastore_destroy (void *data)
static void * smdi_msg_find (struct ast_smdi_interface *iface, enum smdi_message_type type, const char *station)
static void * smdi_msg_pop (struct ast_smdi_interface *iface, enum smdi_message_type type)
static int smdi_msg_read (struct ast_channel *chan, 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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, }
static const struct ast_module_infoast_module_info = &__mod_info
static const char config_file [] = "smdi.conf"
struct {
   ast_cond_t   cond
   timeval   last_poll
   ast_mutex_t   lock
   struct {
      mailbox_mapping *   first
      mailbox_mapping *   last
   }   mailbox_mappings
   unsigned int   polling_interval
   unsigned int   stop:1
   pthread_t   thread
mwi_monitor
 Data that gets used by the SMDI MWI monitoring thread.
ast_smdi_interface_container smdi_ifaces
 SMDI interface container.
static struct ast_datastore_info smdi_msg_datastore_info
static struct ast_custom_function smdi_msg_function
static int smdi_msg_id
static struct ast_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 1057 of file res_smdi.c.

Referenced by smdi_msg_retrieve_read().


Enumeration Type Documentation

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

static void __unreg_module ( void   )  [static]

Definition at line 1327 of file res_smdi.c.

static struct ast_smdi_interface* alloc_smdi_interface ( void   )  [static]

Definition at line 773 of file res_smdi.c.

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

00774 {
00775    struct ast_smdi_interface *iface;
00776 
00777    if (!(iface = ast_calloc(1, sizeof(*iface))))
00778       return NULL;
00779 
00780    ASTOBJ_INIT(iface);
00781    ASTOBJ_CONTAINER_INIT(&iface->md_q);
00782    ASTOBJ_CONTAINER_INIT(&iface->mwi_q);
00783 
00784    ast_mutex_init(&iface->md_q_lock);
00785    ast_cond_init(&iface->md_q_cond, NULL);
00786 
00787    ast_mutex_init(&iface->mwi_q_lock);
00788    ast_cond_init(&iface->mwi_q_cond, NULL);
00789 
00790    return iface;
00791 }

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

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

00695 {
00696    struct mailbox_mapping *mm;
00697    char *mailbox, *context;
00698 
00699    if (!(mm = ast_calloc(1, sizeof(*mm))))
00700       return;
00701    
00702    if (ast_string_field_init(mm, 32)) {
00703       free(mm);
00704       return;
00705    }
00706 
00707    ast_string_field_set(mm, smdi, var->name);
00708 
00709    context = ast_strdupa(var->value);
00710    mailbox = strsep(&context, "@");
00711    if (ast_strlen_zero(context))
00712       context = "default";
00713 
00714    ast_string_field_set(mm, mailbox, mailbox);
00715    ast_string_field_set(mm, context, context);
00716 
00717    mm->iface = ASTOBJ_REF(iface);
00718 
00719    ast_mutex_lock(&mwi_monitor.lock);
00720    AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry);
00721    ast_mutex_unlock(&mwi_monitor.lock);
00722 }

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

References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.

Referenced by load_config(), and smdi_msg_retrieve_read().

00471 {
00472    return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
00473 }

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

00668 {
00669    ast_free(msg);
00670 }

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

References mailbox_mapping::iface, SMDI_MD, and smdi_msg_pop().

00445 {
00446    return smdi_msg_pop(iface, SMDI_MD);
00447 }

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

References mailbox_mapping::iface, SMDI_MD, and smdi_message_wait().

Referenced by ss_thread().

00450 {
00451    return smdi_message_wait(iface, timeout, SMDI_MD, NULL);
00452 }

void ast_smdi_mwi_message_destroy ( struct ast_smdi_mwi_message msg  ) 

ast_smdi_mwi_message destructor.

Definition at line 672 of file res_smdi.c.

References ast_free, and msg.

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

00673 {
00674    ast_free(msg);
00675 }

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

References mailbox_mapping::iface, smdi_msg_pop(), and SMDI_MWI.

00455 {
00456    return smdi_msg_pop(iface, SMDI_MWI);
00457 }

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

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.

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

References mailbox_mapping::iface, smdi_message_wait(), and SMDI_MWI.

00460 {
00461    return smdi_message_wait(iface, timeout, SMDI_MWI, NULL);
00462 }

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

Definition at line 464 of file res_smdi.c.

References mailbox_mapping::iface, smdi_message_wait(), and SMDI_MWI.

Referenced by run_externnotify().

00466 {
00467    return smdi_message_wait(iface, timeout, SMDI_MWI, station);
00468 }

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

00685 {
00686    struct mailbox_mapping *mm;
00687 
00688    ast_mutex_lock(&mwi_monitor.lock);
00689    while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry)))
00690       destroy_mailbox_mapping(mm);
00691    ast_mutex_unlock(&mwi_monitor.lock);
00692 }

static void destroy_mailbox_mapping ( struct mailbox_mapping mm  )  [static]

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

00678 {
00679    ast_string_field_free_memory(mm);
00680    ASTOBJ_UNREF(mm->iface, ast_smdi_interface_destroy);
00681    free(mm);
00682 }

static int load_module ( void   )  [static]

Definition at line 1257 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, smdi_msg_retrieve_function, and unload_module().

01258 {
01259    int res;
01260    
01261    /* initialize our containers */
01262    memset(&smdi_ifaces, 0, sizeof(smdi_ifaces));
01263    ASTOBJ_CONTAINER_INIT(&smdi_ifaces);
01264    
01265    ast_mutex_init(&mwi_monitor.lock);
01266    ast_cond_init(&mwi_monitor.cond, NULL);
01267 
01268    ast_custom_function_register(&smdi_msg_retrieve_function);
01269    ast_custom_function_register(&smdi_msg_function);
01270 
01271    /* load the config and start the listener threads*/
01272    res = smdi_load(0);
01273    if (res < 0) {
01274       unload_module();
01275       return res;
01276    } else if (res == 1) {
01277       unload_module();
01278       ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
01279       return AST_MODULE_LOAD_DECLINE;
01280    }
01281    
01282    return AST_MODULE_LOAD_SUCCESS;
01283 }

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

00747 {
00748    while (!mwi_monitor.stop) {
00749       struct timespec ts = { 0, };
00750       struct timeval tv;
00751       struct mailbox_mapping *mm;
00752 
00753       ast_mutex_lock(&mwi_monitor.lock);
00754 
00755       mwi_monitor.last_poll = ast_tvnow();
00756 
00757       AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry)
00758          poll_mailbox(mm);
00759 
00760       /* Sleep up to the configured polling interval.  Allow unload_module()
00761        * to signal us to wake up and exit. */
00762       tv = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0));
00763       ts.tv_sec = tv.tv_sec;
00764       ts.tv_nsec = tv.tv_usec * 1000;
00765       ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts);
00766 
00767       ast_mutex_unlock(&mwi_monitor.lock);
00768    }
00769 
00770    return NULL;
00771 }

static void poll_mailbox ( struct mailbox_mapping mm  )  [static]

Note:
Called with the mwi_monitor.lock locked

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

00728 {
00729    char buf[1024];
00730    unsigned int state;
00731 
00732    snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context);
00733 
00734    state = !!ast_app_has_voicemail(mm->mailbox, NULL);
00735 
00736    if (state != mm->cur_state) {
00737       if (state)
00738          ast_smdi_mwi_set(mm->iface, mm->smdi);
00739       else
00740          ast_smdi_mwi_unset(mm->iface, mm->smdi);
00741 
00742       mm->cur_state = state;
00743    }
00744 }

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

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

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

static int reload ( void   )  [static]

Definition at line 1308 of file res_smdi.c.

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

01309 {
01310    int res;
01311 
01312    res = smdi_load(1);
01313 
01314    if (res < 0) {
01315       return res;
01316    } else if (res == 1) {
01317       ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
01318       return 0;
01319    } else
01320       return 0;
01321 }

static int smdi_load ( int  reload  )  [static]

Definition at line 803 of file res_smdi.c.

References ast_config_load, ast_log(), ast_variable_browse(), ASTOBJ_CONTAINER_MARKALL, CONFIG_FLAG_FILEUNCHANGED, 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().

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

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

Definition at line 388 of file res_smdi.c.

References ast_cond_timedwait(), ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), cond, mailbox_mapping::iface, 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().

00390 {
00391    struct timeval start;
00392    long diff = 0;
00393    void *msg;
00394    ast_cond_t *cond = NULL;
00395    ast_mutex_t *lock = NULL;
00396 
00397    switch (type) {
00398    case SMDI_MWI:
00399       cond = &iface->mwi_q_cond;
00400       lock = &iface->mwi_q_lock;
00401       break;
00402    case SMDI_MD:
00403       cond = &iface->md_q_cond;
00404       lock = &iface->md_q_lock;
00405       break;
00406    }
00407 
00408    start = ast_tvnow();
00409 
00410    while (diff < timeout) {
00411       struct timespec ts = { 0, };
00412       struct timeval tv;
00413 
00414       lock_msg_q(iface, type);
00415 
00416       if ((msg = smdi_msg_find(iface, type, station))) {
00417          unlock_msg_q(iface, type);
00418          return msg;
00419       }
00420 
00421       tv = ast_tvadd(start, ast_tv(0, timeout));
00422       ts.tv_sec = tv.tv_sec;
00423       ts.tv_nsec = tv.tv_usec * 1000;
00424 
00425       /* If there were no messages in the queue, then go to sleep until one
00426        * arrives. */
00427 
00428       ast_cond_timedwait(cond, lock, &ts);
00429 
00430       if ((msg = smdi_msg_find(iface, type, station))) {
00431          unlock_msg_q(iface, type);
00432          return msg;
00433       }
00434 
00435       unlock_msg_q(iface, type);
00436 
00437       /* check timeout */
00438       diff = ast_tvdiff_ms(ast_tvnow(), start);
00439    }
00440 
00441    return NULL;
00442 }

static void smdi_msg_datastore_destroy ( void *  data  )  [static]

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

01037 {
01038    struct smdi_msg_datastore *smd = data;
01039 
01040    if (smd->iface)
01041       ASTOBJ_UNREF(smd->iface, ast_smdi_interface_destroy);
01042 
01043    if (smd->md_msg)
01044       ASTOBJ_UNREF(smd->md_msg, ast_smdi_md_message_destroy);
01045 
01046    free(smd);
01047 }

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

Definition at line 369 of file res_smdi.c.

References ASTOBJ_CONTAINER_FIND, mailbox_mapping::iface, ast_smdi_interface::md_q, msg, ast_smdi_interface::mwi_q, purge_old_messages(), SMDI_MD, and SMDI_MWI.

Referenced by smdi_message_wait().

00371 {
00372    void *msg = NULL;
00373 
00374    purge_old_messages(iface, type);
00375 
00376    switch (type) {
00377    case SMDI_MD:
00378       msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, station);
00379       break;
00380    case SMDI_MWI:
00381       msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, station);
00382       break;
00383    }
00384 
00385    return msg;
00386 }

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

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

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

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

Definition at line 1152 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, parse(), smdi_msg_datastore_info, and ast_smdi_md_message::type.

01153 {
01154    struct ast_module_user *u;
01155    int res = -1;
01156    AST_DECLARE_APP_ARGS(args,
01157       AST_APP_ARG(id);
01158       AST_APP_ARG(component);
01159    );
01160    char *parse;
01161    struct ast_datastore *datastore = NULL;
01162    struct smdi_msg_datastore *smd = NULL;
01163 
01164    u = ast_module_user_add(chan);
01165 
01166    if (!chan) {
01167       ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n");
01168       goto return_error;
01169    }
01170 
01171    if (ast_strlen_zero(data)) {
01172       ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n");
01173       goto return_error;
01174    }
01175 
01176    parse = ast_strdupa(data);
01177    AST_STANDARD_APP_ARGS(args, parse);
01178 
01179    if (ast_strlen_zero(args.id)) {
01180       ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
01181       goto return_error;
01182    }
01183 
01184    if (ast_strlen_zero(args.component)) {
01185       ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
01186       goto return_error;
01187    }
01188 
01189    ast_channel_lock(chan);
01190    datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id);
01191    ast_channel_unlock(chan);
01192    
01193    if (!datastore) {
01194       ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id);
01195       goto return_error;
01196    }
01197 
01198    smd = datastore->data;
01199 
01200    if (!strcasecmp(args.component, "station")) {
01201       ast_copy_string(buf, smd->md_msg->fwd_st, len);
01202    } else if (!strcasecmp(args.component, "callerid")) {
01203       ast_copy_string(buf, smd->md_msg->calling_st, len);
01204    } else if (!strcasecmp(args.component, "type")) {
01205       snprintf(buf, len, "%c", smd->md_msg->type);
01206    } else {
01207       ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n",
01208          args.component);
01209       goto return_error;
01210    }
01211 
01212    res = 0;
01213 
01214 return_error:
01215    ast_module_user_remove(u);
01216 
01217    return 0;
01218 }

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

Definition at line 1059 of file res_smdi.c.

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

01060 {
01061    struct ast_module_user *u;
01062    AST_DECLARE_APP_ARGS(args,
01063       AST_APP_ARG(port);
01064       AST_APP_ARG(station);
01065       AST_APP_ARG(timeout);
01066    );
01067    unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
01068    int res = -1;
01069    char *parse = NULL;
01070    struct smdi_msg_datastore *smd = NULL;
01071    struct ast_datastore *datastore = NULL;
01072    struct ast_smdi_interface *iface = NULL;
01073    struct ast_smdi_md_message *md_msg = NULL;
01074 
01075    u = ast_module_user_add(chan);
01076 
01077    if (ast_strlen_zero(data)) {
01078       ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n");
01079       goto return_error;
01080    }
01081 
01082    if (!chan) {
01083       ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n");
01084       goto return_error;
01085    }
01086 
01087    ast_autoservice_start(chan);
01088 
01089    parse = ast_strdupa(data);
01090    AST_STANDARD_APP_ARGS(args, parse);
01091 
01092    if (ast_strlen_zero(args.port) || ast_strlen_zero(args.station)) {
01093       ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n");
01094       goto return_error;
01095    }
01096 
01097    if (!(iface = ast_smdi_interface_find(args.port))) {
01098       ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port);
01099       goto return_error;
01100    }
01101 
01102    if (!ast_strlen_zero(args.timeout)) {
01103       if (sscanf(args.timeout, "%u", &timeout) != 1) {
01104          ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
01105          timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
01106       }
01107    }
01108 
01109    if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.station))) {
01110       ast_log(LOG_WARNING, "No SMDI message retrieved for station '%s' after "
01111          "waiting %u ms.\n", args.station, timeout);
01112       goto return_error;
01113    }
01114 
01115    if (!(smd = ast_calloc(1, sizeof(*smd))))
01116       goto return_error;
01117 
01118    smd->iface = ASTOBJ_REF(iface);
01119    smd->md_msg = ASTOBJ_REF(md_msg);
01120    smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
01121    snprintf(buf, len, "%u", smd->id);
01122 
01123    if (!(datastore = ast_channel_datastore_alloc(&smdi_msg_datastore_info, buf)))
01124       goto return_error;
01125 
01126    datastore->data = smd;
01127 
01128    ast_channel_lock(chan);
01129    ast_channel_datastore_add(chan, datastore);
01130    ast_channel_unlock(chan);
01131 
01132    res = 0;
01133 
01134 return_error:
01135    if (iface)
01136       ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
01137 
01138    if (md_msg)
01139       ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
01140 
01141    if (smd && !datastore)
01142       smdi_msg_datastore_destroy(smd);
01143 
01144    if (parse)
01145       ast_autoservice_stop(chan);
01146 
01147    ast_module_user_remove(u);
01148 
01149    return res;
01150 }

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

Definition at line 484 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, mailbox_mapping::iface, LOG_DEBUG, ast_smdi_interface::msdstrip, and ast_smdi_md_message::name.

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

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

01286 {
01287    /* this destructor stops any running smdi_read threads */
01288    ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy);
01289    ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces);
01290 
01291    destroy_all_mailbox_mappings();
01292 
01293    ast_mutex_lock(&mwi_monitor.lock);
01294    mwi_monitor.stop = 1;
01295    ast_cond_signal(&mwi_monitor.cond);
01296    ast_mutex_unlock(&mwi_monitor.lock);
01297 
01298    if (mwi_monitor.thread != AST_PTHREADT_NULL) {
01299       pthread_join(mwi_monitor.thread, NULL);
01300    }
01301 
01302    ast_custom_function_unregister(&smdi_msg_retrieve_function);
01303    ast_custom_function_unregister(&smdi_msg_function);
01304 
01305    return 0;
01306 }

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       break;
00309    case SMDI_MD:
00310       ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00311       break;
00312    }
00313 }


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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1327 of file res_smdi.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1327 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 1049 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 1236 of file res_smdi.c.

Referenced by load_module(), and unload_module().

int smdi_msg_id [static]

Definition at line 1054 of file res_smdi.c.

struct ast_custom_function smdi_msg_retrieve_function [static]

Definition at line 1220 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 Thu Jul 9 13:41:31 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7