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/io.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"

Include dependency graph for res_smdi.c:

Go to the source code of this file.

Data Structures

struct  ast_smdi_interface
struct  mailbox_mapping
 A mapping between an SMDI mailbox ID and an Asterisk mailbox. More...
struct  smdi_msg_datastore

Defines

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

Enumerations

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int _unload_module (int fromload)
static struct ast_smdi_interfacealloc_smdi_interface (void)
static AO2_GLOBAL_OBJ_STATIC (smdi_ifaces)
static void append_mailbox_mapping (struct ast_variable *var, struct ast_smdi_interface *iface)
struct ast_smdi_interface
*AST_OPTIONAL_API_NAME() 
ast_smdi_interface_find (const char *iface_name)
 Find an SMDI interface with the specified name.
struct ast_smdi_md_message
*AST_OPTIONAL_API_NAME() 
ast_smdi_md_message_pop (struct ast_smdi_interface *iface)
 Get the next SMDI message from the queue.
static void ast_smdi_md_message_push (struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
struct ast_smdi_md_message
*AST_OPTIONAL_API_NAME() 
ast_smdi_md_message_wait (struct ast_smdi_interface *iface, int timeout)
 Get the next SMDI message from the queue.
struct ast_smdi_mwi_message
*AST_OPTIONAL_API_NAME() 
ast_smdi_mwi_message_pop (struct ast_smdi_interface *iface)
 Get the next SMDI message from the queue.
static void ast_smdi_mwi_message_push (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
struct ast_smdi_mwi_message
*AST_OPTIONAL_API_NAME() 
ast_smdi_mwi_message_wait (struct ast_smdi_interface *iface, int timeout)
 Get the next SMDI message from the queue.
struct ast_smdi_mwi_message
*AST_OPTIONAL_API_NAME() 
ast_smdi_mwi_message_wait_station (struct ast_smdi_interface *iface, int timeout, const char *station)
int AST_OPTIONAL_API_NAME() ast_smdi_mwi_set (struct ast_smdi_interface *iface, const char *mailbox)
 Set the MWI indicator for a mailbox.
int AST_OPTIONAL_API_NAME() 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)
 Load the module.
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_ifaces_cmp_fn (void *obj, void *data, int flags)
static void smdi_interface_destroy (void *obj)
static int smdi_load (int reload)
static int smdi_md_q_cmp_fn (void *obj, void *arg, int flags)
static void * smdi_message_wait (struct ast_smdi_interface *iface, int timeout, enum smdi_message_type type, const char *search_key, struct ast_flags options)
static void smdi_msg_datastore_destroy (void *data)
static void * smdi_msg_find (struct ast_smdi_interface *iface, enum smdi_message_type type, const char *search_key, struct ast_flags options)
static void * smdi_msg_pop (struct ast_smdi_interface *iface, enum smdi_message_type type)
static int smdi_msg_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int smdi_msg_retrieve_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int smdi_mwi_q_cmp_fn (void *obj, void *data, int flags)
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)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static struct ast_module_infoast_module_info = &__mod_info
static const char config_file [] = "smdi.conf"
struct {
   ast_cond_t   cond
   struct timeval   last_poll
   ast_mutex_t   lock
   struct {
      struct mailbox_mapping *   first
      struct 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.
static int smdi_loaded
static struct ast_datastore_info smdi_msg_datastore_info
static struct ast_custom_function smdi_msg_function
static int smdi_msg_id
static struct ast_app_option smdi_msg_ret_options [128] = { [ 't' ] = { .flag = OPT_SEARCH_TERMINAL }, [ 'n' ] = { .flag = OPT_SEARCH_NUMBER }, }
static struct ast_custom_function smdi_msg_retrieve_function


Detailed Description

SMDI support for Asterisk.

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

Russell Bryant <russell@digium.com>

Here is a useful mailing list post that describes SMDI protocol details: http://lists.digium.com/pipermail/asterisk-dev/2003-June/000884.html

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

Definition in file res_smdi.c.


Define Documentation

#define AST_API_MODULE

Definition at line 59 of file res_smdi.c.

#define DEFAULT_POLLING_INTERVAL   10

10 seconds

Definition at line 206 of file res_smdi.c.

Referenced by smdi_load().

#define SMDI_MSG_EXPIRY_TIME   30000

Definition at line 70 of file res_smdi.c.

Referenced by smdi_load().

#define SMDI_RETRIEVE_TIMEOUT_DEFAULT   3000

In milliseconds

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

00429      {
00430    OPT_SEARCH_TERMINAL = (1 << 0),
00431    OPT_SEARCH_NUMBER   = (1 << 1),
00432 };

Enumerator:
SMDI_MWI 
SMDI_MD 

Definition at line 319 of file res_smdi.c.

00319                        {
00320    SMDI_MWI,
00321    SMDI_MD,
00322 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1441 of file res_smdi.c.

static void __unreg_module ( void   )  [static]

Definition at line 1441 of file res_smdi.c.

static int _unload_module ( int  fromload  )  [static]

Definition at line 1387 of file res_smdi.c.

References ao2_global_obj_release, ast_cond_signal, ast_custom_function_unregister(), ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, destroy_all_mailbox_mappings(), mwi_monitor, NULL, smdi_msg_function, and smdi_msg_retrieve_function.

Referenced by load_module(), and unload_module().

01388 {
01389    if (!smdi_loaded) {
01390       return 0;
01391    }
01392 
01393    ao2_global_obj_release(smdi_ifaces);
01394 
01395    destroy_all_mailbox_mappings();
01396 
01397    ast_mutex_lock(&mwi_monitor.lock);
01398    mwi_monitor.stop = 1;
01399    ast_cond_signal(&mwi_monitor.cond);
01400    ast_mutex_unlock(&mwi_monitor.lock);
01401 
01402    if (mwi_monitor.thread != AST_PTHREADT_NULL) {
01403       pthread_join(mwi_monitor.thread, NULL);
01404    }
01405 
01406    if (!fromload) {
01407       ast_custom_function_unregister(&smdi_msg_retrieve_function);
01408       ast_custom_function_unregister(&smdi_msg_function);
01409    }
01410 
01411    smdi_loaded = 0;
01412    return 0;
01413 }

static struct ast_smdi_interface* alloc_smdi_interface ( void   )  [static, read]

static AO2_GLOBAL_OBJ_STATIC ( smdi_ifaces   )  [static]

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

Definition at line 786 of file res_smdi.c.

References ao2_bump, ast_calloc_with_stringfields, AST_LIST_INSERT_TAIL, ast_mutex_lock, ast_mutex_unlock, ast_strdupa, ast_string_field_set, ast_strlen_zero, mailbox_mapping::context, mailbox_mapping::iface, mailbox_mapping::mailbox, mwi_monitor, ast_variable::name, mailbox_mapping::smdi, strsep(), and ast_variable::value.

Referenced by smdi_load().

00787 {
00788    struct mailbox_mapping *mm;
00789    char *mailbox, *context;
00790 
00791    if (!(mm = ast_calloc_with_stringfields(1, struct mailbox_mapping, 32)))
00792       return;
00793 
00794    ast_string_field_set(mm, smdi, var->name);
00795 
00796    context = ast_strdupa(var->value);
00797    mailbox = strsep(&context, "@");
00798    if (ast_strlen_zero(context))
00799       context = "default";
00800 
00801    ast_string_field_set(mm, mailbox, mailbox);
00802    ast_string_field_set(mm, context, context);
00803 
00804    mm->iface = ao2_bump(iface);
00805 
00806    ast_mutex_lock(&mwi_monitor.lock);
00807    AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry);
00808    ast_mutex_unlock(&mwi_monitor.lock);
00809 }

struct ast_smdi_interface* AST_OPTIONAL_API_NAME() 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:
an ao2 reference to the interface located or NULL if none was found.

Definition at line 563 of file res_smdi.c.

References ao2_find, ao2_global_obj_ref, ao2_ref, c, mailbox_mapping::iface, NULL, and OBJ_SEARCH_KEY.

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

00564 {
00565    struct ao2_container *c;
00566    struct ast_smdi_interface *iface = NULL;
00567 
00568    c = ao2_global_obj_ref(smdi_ifaces);
00569    if (c) {
00570       iface = ao2_find(c, iface_name, OBJ_SEARCH_KEY);
00571       ao2_ref(c, -1);
00572    }
00573 
00574    return iface;
00575 }

struct ast_smdi_md_message* AST_OPTIONAL_API_NAME() 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 534 of file res_smdi.c.

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

00535 {
00536    return smdi_msg_pop(iface, SMDI_MD);
00537 }

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

struct ast_smdi_md_message* AST_OPTIONAL_API_NAME() 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 539 of file res_smdi.c.

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

Referenced by __analog_ss_thread(), and analog_ss_thread().

00540 {
00541    struct ast_flags options = { 0 };
00542    return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
00543 }

struct ast_smdi_mwi_message* AST_OPTIONAL_API_NAME() 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 545 of file res_smdi.c.

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

00546 {
00547    return smdi_msg_pop(iface, SMDI_MWI);
00548 }

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

struct ast_smdi_mwi_message* AST_OPTIONAL_API_NAME() 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 550 of file res_smdi.c.

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

00551 {
00552    struct ast_flags options = { 0 };
00553    return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
00554 }

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

Definition at line 556 of file res_smdi.c.

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

Referenced by run_externnotify().

00558 {
00559    struct ast_flags options = { 0 };
00560    return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
00561 }

int AST_OPTIONAL_API_NAME() 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 309 of file res_smdi.c.

References mailbox_mapping::iface, mailbox_mapping::mailbox, and smdi_toggle_mwi().

Referenced by poll_mailbox(), and run_externnotify().

00310 {
00311    return smdi_toggle_mwi(iface, mailbox, 1);
00312 }

int AST_OPTIONAL_API_NAME() 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 314 of file res_smdi.c.

References mailbox_mapping::iface, mailbox_mapping::mailbox, and smdi_toggle_mwi().

Referenced by poll_mailbox(), and run_externnotify().

00315 {
00316    return smdi_toggle_mwi(iface, mailbox, 0);
00317 }

static void destroy_all_mailbox_mappings ( void   )  [static]

Definition at line 776 of file res_smdi.c.

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

Referenced by _unload_module(), and smdi_load().

00777 {
00778    struct mailbox_mapping *mm;
00779 
00780    ast_mutex_lock(&mwi_monitor.lock);
00781    while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry)))
00782       destroy_mailbox_mapping(mm);
00783    ast_mutex_unlock(&mwi_monitor.lock);
00784 }

static void destroy_mailbox_mapping ( struct mailbox_mapping mm  )  [static]

Definition at line 769 of file res_smdi.c.

References ao2_ref, ast_free, ast_string_field_free_memory, and mailbox_mapping::iface.

Referenced by destroy_all_mailbox_mappings().

00770 {
00771    ast_string_field_free_memory(mm);
00772    ao2_ref(mm->iface, -1);
00773    ast_free(mm);
00774 }

static int load_module ( void   )  [static]

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 1362 of file res_smdi.c.

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

01363 {
01364    int res;
01365    smdi_loaded = 1;
01366 
01367    ast_mutex_init(&mwi_monitor.lock);
01368    ast_cond_init(&mwi_monitor.cond, NULL);
01369 
01370    /* load the config and start the listener threads*/
01371    res = smdi_load(0);
01372    if (res < 0) {
01373       _unload_module(1);
01374       return res;
01375    } else if (res == 1) {
01376       _unload_module(1);
01377       ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
01378       return AST_MODULE_LOAD_DECLINE;
01379    }
01380 
01381    ast_custom_function_register(&smdi_msg_retrieve_function);
01382    ast_custom_function_register(&smdi_msg_function);
01383 
01384    return AST_MODULE_LOAD_SUCCESS;
01385 }

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

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

00325 {
00326    switch (type) {
00327    case SMDI_MWI:
00328       return ast_mutex_lock(&iface->mwi_q_lock);
00329    case SMDI_MD:  
00330       return ast_mutex_lock(&iface->md_q_lock);
00331    }
00332    
00333    return -1;
00334 }

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

Definition at line 360 of file res_smdi.c.

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

Referenced by purge_old_messages().

00361 {
00362    struct ast_smdi_md_message *md_msg = msg;
00363    struct ast_smdi_mwi_message *mwi_msg = msg;
00364 
00365    switch (type) {
00366    case SMDI_MWI:
00367       return mwi_msg->timestamp;
00368    case SMDI_MD:
00369       return md_msg->timestamp;
00370    }
00371 
00372    return ast_tv(0, 0);
00373 }

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

Definition at line 833 of file res_smdi.c.

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

Referenced by smdi_load().

00834 {
00835    while (!mwi_monitor.stop) {
00836       struct timespec ts = { 0, };
00837       struct timeval polltime;
00838       struct mailbox_mapping *mm;
00839 
00840       ast_mutex_lock(&mwi_monitor.lock);
00841 
00842       mwi_monitor.last_poll = ast_tvnow();
00843 
00844       AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry)
00845          poll_mailbox(mm);
00846 
00847       /* Sleep up to the configured polling interval.  Allow unload_module()
00848        * to signal us to wake up and exit. */
00849       polltime = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0));
00850       ts.tv_sec = polltime.tv_sec;
00851       ts.tv_nsec = polltime.tv_usec * 1000;
00852       ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts);
00853 
00854       ast_mutex_unlock(&mwi_monitor.lock);
00855    }
00856 
00857    return NULL;
00858 }

static void poll_mailbox ( struct mailbox_mapping mm  )  [static]

Note:
Called with the mwi_monitor.lock locked

Definition at line 814 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, NULL, and mailbox_mapping::smdi.

Referenced by mwi_monitor_handler().

00815 {
00816    char buf[1024];
00817    unsigned int state;
00818 
00819    snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context);
00820 
00821    state = !!ast_app_has_voicemail(mm->mailbox, NULL);
00822 
00823    if (state != mm->cur_state) {
00824       if (state)
00825          ast_smdi_mwi_set(mm->iface, mm->smdi);
00826       else
00827          ast_smdi_mwi_unset(mm->iface, mm->smdi);
00828 
00829       mm->cur_state = state;
00830    }
00831 }

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

Definition at line 375 of file res_smdi.c.

References ao2_ref, ast_log, ast_smdi_md_message_push(), ast_smdi_mwi_message_push(), ast_tvdiff_ms(), ast_tvnow(), lock_msg_q(), LOG_NOTICE, ast_smdi_interface::msg_expiry, msg_timestamp(), ast_smdi_interface::name, SMDI_MD, SMDI_MWI, unlink_from_msg_q(), and unlock_msg_q().

Referenced by smdi_msg_find(), and smdi_msg_pop().

00376 {
00377    struct timeval now = ast_tvnow();
00378    long elapsed = 0;
00379    void *msg;
00380    
00381    lock_msg_q(iface, type);
00382    msg = unlink_from_msg_q(iface, type);
00383    unlock_msg_q(iface, type);
00384 
00385    /* purge old messages */
00386    while (msg) {
00387       elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type));
00388 
00389       if (elapsed > iface->msg_expiry) {
00390          /* found an expired message */
00391          ao2_ref(msg, -1);
00392          ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue.  "
00393             "Message was %ld milliseconds too old.\n",
00394             iface->name, (type == SMDI_MD) ? "MD" : "MWI", 
00395             elapsed - iface->msg_expiry);
00396 
00397          lock_msg_q(iface, type);
00398          msg = unlink_from_msg_q(iface, type);
00399          unlock_msg_q(iface, type);
00400       } else {
00401          /* good message, put it back and return */
00402          switch (type) {
00403          case SMDI_MD:
00404             ast_smdi_md_message_push(iface, msg);
00405             break;
00406          case SMDI_MWI:
00407             ast_smdi_mwi_message_push(iface, msg);
00408             break;
00409          }
00410          ao2_ref(msg, -1);
00411          break;
00412       }
00413    }
00414 }

static int reload ( void   )  [static]

Definition at line 1420 of file res_smdi.c.

References ast_log, LOG_WARNING, and smdi_load().

01421 {
01422    int res;
01423 
01424    res = smdi_load(1);
01425 
01426    if (res < 0) {
01427       return res;
01428    } else if (res == 1) {
01429       ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
01430       return 0;
01431    } else
01432       return 0;
01433 }

static int smdi_ifaces_cmp_fn ( void *  obj,
void *  data,
int  flags 
) [static]

Definition at line 915 of file res_smdi.c.

References CMP_MATCH, CMP_STOP, mailbox_mapping::iface, ast_smdi_interface::name, and str.

Referenced by smdi_load().

00916 {
00917    struct ast_smdi_interface *iface = obj;
00918 
00919    char *str = data;
00920    return !strcmp(iface->name, str) ? CMP_MATCH | CMP_STOP : 0;
00921 }

static void smdi_interface_destroy ( void *  obj  )  [static]

Definition at line 226 of file res_smdi.c.

References ao2_cleanup, ast_cond_destroy, ast_free, ast_module_unref, ast_mutex_destroy, AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_smdi_interface::file, 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, NULL, and ast_smdi_interface::thread.

Referenced by alloc_smdi_interface().

00227 {
00228    struct ast_smdi_interface *iface = obj;
00229 
00230    if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
00231       pthread_cancel(iface->thread);
00232       pthread_join(iface->thread, NULL);
00233    }
00234 
00235    iface->thread = AST_PTHREADT_STOP;
00236 
00237    if (iface->file) {
00238       fclose(iface->file);
00239    }
00240 
00241    ao2_cleanup(iface->md_q);
00242    ast_mutex_destroy(&iface->md_q_lock);
00243    ast_cond_destroy(&iface->md_q_cond);
00244 
00245    ao2_cleanup(iface->mwi_q);
00246    ast_mutex_destroy(&iface->mwi_q_lock);
00247    ast_cond_destroy(&iface->mwi_q_cond);
00248 
00249    ast_free(iface);
00250 
00251    ast_module_unref(ast_module_info->self);
00252 }

static int smdi_load ( int  reload  )  [static]

Definition at line 933 of file res_smdi.c.

References alloc_smdi_interface(), AO2_ALLOC_OPT_LOCK_MUTEX, ao2_cleanup, ao2_container_alloc_list, ao2_container_count(), ao2_find, ao2_global_obj_ref, ao2_global_obj_replace_unref, ao2_link, append_mailbox_mapping(), ast_config_destroy(), ast_config_load, ast_copy_string(), AST_LIST_EMPTY, ast_log, AST_MODULE_LOAD_FAILURE, ast_module_ref, ast_pthread_create_background, AST_PTHREADT_NULL, ast_true(), ast_variable_browse(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_POLLING_INTERVAL, destroy_all_mailbox_mappings(), errno, ast_smdi_interface::fd, ast_smdi_interface::file, mailbox_mapping::iface, 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_smdi_interface::name, ast_variable::name, ast_variable::next, NULL, OBJ_SEARCH_KEY, PARENB, RAII_VAR, smdi_ifaces_cmp_fn(), SMDI_MSG_EXPIRY_TIME, smdi_read(), ast_smdi_interface::thread, and ast_variable::value.

Referenced by load_module(), and reload().

00934 {
00935    struct ast_config *conf;
00936    struct ast_variable *v;
00937    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00938    int res = 0;
00939    RAII_VAR(struct ao2_container *, new_ifaces, NULL, ao2_cleanup);
00940    RAII_VAR(struct ao2_container *, old_ifaces, ao2_global_obj_ref(smdi_ifaces), ao2_cleanup);
00941    struct ast_smdi_interface *mailbox_iface = NULL;
00942 
00943    /* Config options */
00944    speed_t baud_rate = B9600;     /* 9600 baud rate */
00945    tcflag_t paritybit = PARENB;   /* even parity checking */
00946    tcflag_t charsize = CS7;       /* seven bit characters */
00947    int stopbits = 0;              /* One stop bit */
00948    
00949    int msdstrip = 0;              /* strip zero digits */
00950    long msg_expiry = SMDI_MSG_EXPIRY_TIME;
00951 
00952    if (!(conf = ast_config_load(config_file, config_flags)) || conf == CONFIG_STATUS_FILEINVALID) {
00953       if (reload)
00954          ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
00955       else
00956          ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file);
00957       return 1;
00958    } else if (conf == CONFIG_STATUS_FILEUNCHANGED)
00959       return 0;
00960 
00961    new_ifaces = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, smdi_ifaces_cmp_fn);
00962    for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
00963       RAII_VAR(struct ast_smdi_interface *, iface, NULL, ao2_cleanup);
00964 
00965       if (!strcasecmp(v->name, "baudrate")) {
00966          if (!strcasecmp(v->value, "9600"))
00967             baud_rate = B9600;
00968          else if (!strcasecmp(v->value, "4800"))
00969             baud_rate = B4800;
00970          else if (!strcasecmp(v->value, "2400"))
00971             baud_rate = B2400;
00972          else if (!strcasecmp(v->value, "1200"))
00973             baud_rate = B1200;
00974          else {
00975             ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno);
00976             baud_rate = B9600;
00977          }
00978       } else if (!strcasecmp(v->name, "msdstrip")) {
00979          if (!sscanf(v->value, "%30d", &msdstrip)) {
00980             ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00981             msdstrip = 0;
00982          } else if (0 > msdstrip || msdstrip > 9) {
00983             ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00984             msdstrip = 0;
00985          }
00986       } else if (!strcasecmp(v->name, "msgexpirytime")) {
00987          if (!sscanf(v->value, "%30ld", &msg_expiry)) {
00988             ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno);
00989             msg_expiry = SMDI_MSG_EXPIRY_TIME;
00990          }
00991       } else if (!strcasecmp(v->name, "paritybit")) {
00992          if (!strcasecmp(v->value, "even"))
00993             paritybit = PARENB;
00994          else if (!strcasecmp(v->value, "odd"))
00995             paritybit = PARENB | PARODD;
00996          else if (!strcasecmp(v->value, "none"))
00997             paritybit = ~PARENB;
00998          else {
00999             ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno);
01000             paritybit = PARENB;
01001          }
01002       } else if (!strcasecmp(v->name, "charsize")) {
01003          if (!strcasecmp(v->value, "7"))
01004             charsize = CS7;
01005          else if (!strcasecmp(v->value, "8"))
01006             charsize = CS8;
01007          else {
01008             ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno);
01009             charsize = CS7;
01010          }
01011       } else if (!strcasecmp(v->name, "twostopbits")) {
01012          stopbits = ast_true(v->name);
01013       } else if (!strcasecmp(v->name, "smdiport")) {
01014          if (reload) {
01015             /* we are reloading, check if we are already
01016              * monitoring this interface, if we are we do
01017              * not want to start it again.  This also has
01018              * the side effect of not updating different
01019              * setting for the serial port, but it should
01020              * be trivial to rewrite this section so that
01021              * options on the port are changed without
01022              * restarting the interface.  Or the interface
01023              * could be restarted with out emptying the
01024              * queue. */
01025             if ((iface = ao2_find(old_ifaces, v->value, OBJ_SEARCH_KEY))) {
01026                ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
01027                ao2_link(new_ifaces, iface);
01028                continue;
01029             }
01030          }
01031          
01032          if (!(iface = alloc_smdi_interface()))
01033             continue;
01034 
01035          ast_copy_string(iface->name, v->value, sizeof(iface->name));
01036 
01037          iface->thread = AST_PTHREADT_NULL;
01038 
01039          if (!(iface->file = fopen(iface->name, "r"))) {
01040             ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
01041             continue;
01042          }
01043 
01044          iface->fd = fileno(iface->file);
01045 
01046          /* Set the proper attributes for our serial port. */
01047 
01048          /* get the current attributes from the port */
01049          if (tcgetattr(iface->fd, &iface->mode)) {
01050             ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno));
01051             continue;
01052          }
01053 
01054          /* set the desired speed */
01055          if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
01056             ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
01057             continue;
01058          }
01059          
01060          /* set the stop bits */
01061          if (stopbits)
01062             iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB;   /* set two stop bits */
01063          else
01064             iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB;  /* set one stop bit */
01065          
01066          /* set the parity */
01067          iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit;
01068          
01069          /* set the character size */
01070          iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize;
01071          
01072          /* commit the desired attributes */
01073          if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
01074             ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
01075             continue;
01076          }
01077 
01078          /* set the msdstrip */
01079          iface->msdstrip = msdstrip;
01080 
01081          /* set the message expiry time */
01082          iface->msg_expiry = msg_expiry;
01083 
01084          /* start the listener thread */
01085          ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name);
01086          if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
01087             ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
01088             continue;
01089          }
01090 
01091          ao2_link(new_ifaces, iface);
01092          ast_module_ref(ast_module_info->self);
01093       } else {
01094          ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
01095       }
01096    }
01097 
01098    destroy_all_mailbox_mappings();
01099    mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
01100 
01101    for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) {
01102       if (!strcasecmp(v->name, "smdiport")) {
01103          ao2_cleanup(mailbox_iface);
01104 
01105          if (!(mailbox_iface = ao2_find(new_ifaces, v->value, OBJ_SEARCH_KEY))) {
01106             ast_log(LOG_NOTICE, "SMDI interface %s not found\n", v->value);
01107             continue;
01108          }
01109       } else if (!strcasecmp(v->name, "pollinginterval")) {
01110          if (sscanf(v->value, "%30u", &mwi_monitor.polling_interval) != 1) {
01111             ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value);
01112             mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
01113          }
01114       } else {
01115          if (!mailbox_iface) {
01116             ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n");
01117             continue;
01118          }
01119          append_mailbox_mapping(v, mailbox_iface);
01120       }
01121    }
01122    ao2_cleanup(mailbox_iface);
01123 
01124    ast_config_destroy(conf);
01125 
01126    ao2_global_obj_replace_unref(smdi_ifaces, new_ifaces);
01127 
01128    if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL
01129       && ast_pthread_create_background(&mwi_monitor.thread, NULL, mwi_monitor_handler, NULL)) {
01130       ast_log(LOG_ERROR, "Failed to start MWI monitoring thread.  This module will not operate.\n");
01131       return AST_MODULE_LOAD_FAILURE;
01132    }
01133 
01134    if (ao2_container_count(new_ifaces)) {
01135       res = 1;
01136    }
01137    
01138    return res;
01139 }

static int smdi_md_q_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 867 of file res_smdi.c.

References ast_strlen_zero, CMP_MATCH, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, ast_smdi_md_message::name, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, and OBJ_SEARCH_OBJECT.

Referenced by alloc_smdi_interface().

00868 {
00869    const struct ast_smdi_md_message *msg = obj;
00870    const struct ast_smdi_md_message *search_msg = arg;
00871    const char *search_key = arg;
00872    int cmp = 0;
00873 
00874    switch (flags & OBJ_SEARCH_MASK) {
00875    case OBJ_SEARCH_OBJECT:
00876       if (!ast_strlen_zero(search_msg->mesg_desk_num)) {
00877          cmp = strcmp(msg->mesg_desk_num, search_msg->mesg_desk_num);
00878       }
00879       if (!ast_strlen_zero(search_msg->mesg_desk_term)) {
00880          cmp |= strcmp(msg->mesg_desk_term, search_msg->mesg_desk_term);
00881       }
00882       break;
00883    case OBJ_SEARCH_KEY:
00884       cmp = strcmp(msg->name, search_key);
00885       break;
00886    }
00887 
00888    if (cmp) {
00889       return 0;
00890    }
00891 
00892    return CMP_MATCH;
00893 }

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

References ast_cond_timedwait, ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), cond, lock, lock_msg_q(), ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_cond, ast_smdi_interface::mwi_q_lock, NULL, 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().

00480 {
00481    struct timeval start;
00482    long diff = 0;
00483    void *msg;
00484    ast_cond_t *cond = NULL;
00485    ast_mutex_t *lock = NULL;
00486 
00487    switch (type) {
00488    case SMDI_MWI:
00489       cond = &iface->mwi_q_cond;
00490       lock = &iface->mwi_q_lock;
00491       break;
00492    case SMDI_MD:
00493       cond = &iface->md_q_cond;
00494       lock = &iface->md_q_lock;
00495       break;
00496    }
00497 
00498    start = ast_tvnow();
00499 
00500    while (diff < timeout) {
00501       struct timespec ts = { 0, };
00502       struct timeval wait;
00503 
00504       lock_msg_q(iface, type);
00505 
00506       if ((msg = smdi_msg_find(iface, type, search_key, options))) {
00507          unlock_msg_q(iface, type);
00508          return msg;
00509       }
00510 
00511       wait = ast_tvadd(start, ast_tv(0, timeout));
00512       ts.tv_sec = wait.tv_sec;
00513       ts.tv_nsec = wait.tv_usec * 1000;
00514 
00515       /* If there were no messages in the queue, then go to sleep until one
00516        * arrives. */
00517 
00518       ast_cond_timedwait(cond, lock, &ts);
00519 
00520       if ((msg = smdi_msg_find(iface, type, search_key, options))) {
00521          unlock_msg_q(iface, type);
00522          return msg;
00523       }
00524 
00525       unlock_msg_q(iface, type);
00526 
00527       /* check timeout */
00528       diff = ast_tvdiff_ms(ast_tvnow(), start);
00529    }
00530 
00531    return NULL;
00532 }

static void smdi_msg_datastore_destroy ( void *  data  )  [static]

Definition at line 1147 of file res_smdi.c.

References ao2_cleanup, ast_free, smdi_msg_datastore::iface, and smdi_msg_datastore::md_msg.

Referenced by smdi_msg_retrieve_read().

01148 {
01149    struct smdi_msg_datastore *smd = data;
01150 
01151    ao2_cleanup(smd->iface);
01152    ao2_cleanup(smd->md_msg);
01153 
01154    ast_free(smd);
01155 }

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

References ao2_callback, ao2_find, ast_strlen_zero, ast_test_flag, ast_smdi_interface::md_q, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, ast_smdi_interface::mwi_q, ast_smdi_md_message::name, NULL, OBJ_SEARCH_KEY, OBJ_SEARCH_OBJECT, OPT_SEARCH_NUMBER, OPT_SEARCH_TERMINAL, purge_old_messages(), SMDI_MD, SMDI_MESG_DESK_NUM_LEN, SMDI_MESG_DESK_TERM_LEN, and SMDI_MWI.

Referenced by smdi_message_wait().

00436 {
00437    void *msg = NULL;
00438 
00439    purge_old_messages(iface, type);
00440 
00441    switch (type) {
00442    case SMDI_MD:
00443       if (ast_strlen_zero(search_key)) {
00444          /* No search key provided (the code from chan_dahdi does this).
00445           * Just pop the top message off of the queue. */
00446 
00447          msg = ao2_callback(iface->md_q, 0, NULL, NULL);
00448       } else if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) {
00449          /* Searching by the message desk terminal */
00450          struct ast_smdi_md_message md_msg = { .name = "" };
00451          strncpy(md_msg.mesg_desk_term, search_key, SMDI_MESG_DESK_TERM_LEN);
00452          msg = ao2_find(iface->md_q, &md_msg, OBJ_SEARCH_OBJECT);
00453       } else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) {
00454          /* Searching by the message desk number */
00455          struct ast_smdi_md_message md_msg = { .name = "" };
00456          strncpy(md_msg.mesg_desk_num, search_key, SMDI_MESG_DESK_NUM_LEN);
00457          msg = ao2_find(iface->md_q, &md_msg, OBJ_SEARCH_OBJECT);
00458       } else {
00459          /* Searching by the forwarding station */
00460          msg = ao2_find(iface->md_q, search_key, OBJ_SEARCH_KEY);
00461       }
00462       break;
00463    case SMDI_MWI:
00464       if (ast_strlen_zero(search_key)) {
00465          /* No search key provided (the code from chan_dahdi does this).
00466           * Just pop the top message off of the queue. */
00467 
00468          msg = ao2_callback(iface->mwi_q, 0, NULL, NULL);
00469       } else {
00470          msg = ao2_find(iface->mwi_q, search_key, OBJ_SEARCH_KEY);
00471       }
00472       break;
00473    }
00474 
00475    return msg;
00476 }

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

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

00417 {
00418    void *msg;
00419 
00420    purge_old_messages(iface, type);
00421 
00422    lock_msg_q(iface, type);
00423    msg = unlink_from_msg_q(iface, type);
00424    unlock_msg_q(iface, type);
00425 
00426    return msg;
00427 }

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

Definition at line 1268 of file res_smdi.c.

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

01269 {
01270    struct ast_module_user *u;
01271    int res = -1;
01272    AST_DECLARE_APP_ARGS(args,
01273       AST_APP_ARG(id);
01274       AST_APP_ARG(component);
01275    );
01276    char *parse;
01277    struct ast_datastore *datastore = NULL;
01278    struct smdi_msg_datastore *smd = NULL;
01279 
01280    u = ast_module_user_add(chan);
01281 
01282    if (!chan) {
01283       ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n");
01284       goto return_error;
01285    }
01286 
01287    if (ast_strlen_zero(data)) {
01288       ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n");
01289       goto return_error;
01290    }
01291 
01292    parse = ast_strdupa(data);
01293    AST_STANDARD_APP_ARGS(args, parse);
01294 
01295    if (ast_strlen_zero(args.id)) {
01296       ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
01297       goto return_error;
01298    }
01299 
01300    if (ast_strlen_zero(args.component)) {
01301       ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
01302       goto return_error;
01303    }
01304 
01305    ast_channel_lock(chan);
01306    datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id);
01307    ast_channel_unlock(chan);
01308    
01309    if (!datastore) {
01310       ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id);
01311       goto return_error;
01312    }
01313 
01314    smd = datastore->data;
01315 
01316    if (!strcasecmp(args.component, "number")) {
01317       ast_copy_string(buf, smd->md_msg->mesg_desk_num, len);
01318    } else if (!strcasecmp(args.component, "terminal")) {
01319       ast_copy_string(buf, smd->md_msg->mesg_desk_term, len);
01320    } else if (!strcasecmp(args.component, "station")) {
01321       ast_copy_string(buf, smd->md_msg->fwd_st, len);
01322    } else if (!strcasecmp(args.component, "callerid")) {
01323       ast_copy_string(buf, smd->md_msg->calling_st, len);
01324    } else if (!strcasecmp(args.component, "type")) {
01325       snprintf(buf, len, "%c", smd->md_msg->type);
01326    } else {
01327       ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n",
01328          args.component);
01329       goto return_error;
01330    }
01331 
01332    res = 0;
01333 
01334 return_error:
01335    ast_module_user_remove(u);
01336 
01337    return res;
01338 }

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

Definition at line 1172 of file res_smdi.c.

References ao2_bump, ao2_cleanup, args, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, AST_DECLARE_APP_ARGS, ast_log, ast_module_user_add, ast_module_user_remove, ast_smdi_interface_find(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_datastore::data, smdi_msg_datastore::id, smdi_msg_datastore::iface, mailbox_mapping::iface, LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, NULL, parse(), SMDI_MD, smdi_message_wait(), smdi_msg_datastore_destroy(), smdi_msg_datastore_info, smdi_msg_id, smdi_msg_ret_options, SMDI_RETRIEVE_TIMEOUT_DEFAULT, and timeout.

01173 {
01174    struct ast_module_user *u;
01175    AST_DECLARE_APP_ARGS(args,
01176       AST_APP_ARG(port);
01177       AST_APP_ARG(search_key);
01178       AST_APP_ARG(timeout);
01179       AST_APP_ARG(options);
01180    );
01181    struct ast_flags options = { 0 };
01182    unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
01183    int res = -1;
01184    char *parse = NULL;
01185    struct smdi_msg_datastore *smd = NULL;
01186    struct ast_datastore *datastore = NULL;
01187    struct ast_smdi_interface *iface = NULL;
01188    struct ast_smdi_md_message *md_msg = NULL;
01189 
01190    u = ast_module_user_add(chan);
01191 
01192    if (ast_strlen_zero(data)) {
01193       ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n");
01194       goto return_error;
01195    }
01196 
01197    if (!chan) {
01198       ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n");
01199       goto return_error;
01200    }
01201 
01202    ast_autoservice_start(chan);
01203 
01204    parse = ast_strdupa(data);
01205    AST_STANDARD_APP_ARGS(args, parse);
01206 
01207    if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) {
01208       ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n");
01209       goto return_error;
01210    }
01211 
01212    if (!(iface = ast_smdi_interface_find(args.port))) {
01213       ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port);
01214       goto return_error;
01215    }
01216 
01217    if (!ast_strlen_zero(args.options)) {
01218       ast_app_parse_options(smdi_msg_ret_options, &options, NULL, args.options);
01219    }
01220 
01221    if (!ast_strlen_zero(args.timeout)) {
01222       if (sscanf(args.timeout, "%30u", &timeout) != 1) {
01223          ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
01224          timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
01225       }
01226    }
01227 
01228    if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) {
01229       ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after "
01230          "waiting %u ms.\n", args.search_key, timeout);
01231       goto return_error;
01232    }
01233 
01234    if (!(smd = ast_calloc(1, sizeof(*smd))))
01235       goto return_error;
01236 
01237    smd->iface = ao2_bump(iface);
01238    smd->md_msg = ao2_bump(md_msg);
01239    smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
01240    snprintf(buf, len, "%u", smd->id);
01241 
01242    if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf)))
01243       goto return_error;
01244 
01245    datastore->data = smd;
01246 
01247    ast_channel_lock(chan);
01248    ast_channel_datastore_add(chan, datastore);
01249    ast_channel_unlock(chan);
01250 
01251    res = 0;
01252 
01253 return_error:
01254    ao2_cleanup(iface);
01255    ao2_cleanup(md_msg);
01256 
01257    if (smd && !datastore)
01258       smdi_msg_datastore_destroy(smd);
01259 
01260    if (parse)
01261       ast_autoservice_stop(chan);
01262 
01263    ast_module_user_remove(u);
01264 
01265    return res;
01266 }

static int smdi_mwi_q_cmp_fn ( void *  obj,
void *  data,
int  flags 
) [static]

Definition at line 860 of file res_smdi.c.

References CMP_MATCH, CMP_STOP, ast_smdi_mwi_message::name, and str.

Referenced by alloc_smdi_interface().

00861 {
00862    struct ast_smdi_mwi_message *msg = obj;
00863    char *str = data;
00864    return !strcmp(msg->name, str) ? CMP_MATCH | CMP_STOP : 0;
00865 }

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

Definition at line 586 of file res_smdi.c.

References ao2_alloc, ao2_ref, ast_calloc, ast_copy_string(), ast_debug, ast_log, ast_smdi_md_message_push(), ast_smdi_mwi_message_push(), ast_tvnow(), c, 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, mailbox_mapping::iface, LOG_ERROR, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, ast_smdi_interface::msdstrip, ast_smdi_mwi_message::name, ast_smdi_interface::name, ast_smdi_md_message::name, NULL, ast_smdi_mwi_message::timestamp, ast_smdi_md_message::timestamp, and ast_smdi_md_message::type.

Referenced by smdi_load().

00587 {
00588    struct ast_smdi_interface *iface = iface_p;
00589    struct ast_smdi_md_message *md_msg;
00590    struct ast_smdi_mwi_message *mwi_msg;
00591    char c = '\0';
00592    char *cp = NULL;
00593    int i;
00594    int start = 0;
00595 
00596    /* read an smdi message */
00597    while ((c = fgetc(iface->file))) {
00598 
00599       /* check if this is the start of a message */
00600       if (!start) {
00601          if (c == 'M') {
00602             ast_debug(1, "Read an 'M' to start an SMDI message\n");
00603             start = 1;
00604          }
00605          continue;
00606       }
00607 
00608       if (c == 'D') { /* MD message */
00609          start = 0;
00610 
00611          ast_debug(1, "Read a 'D' ... it's an MD message.\n");
00612 
00613          if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) {
00614             ao2_ref(iface, -1);
00615             return NULL;
00616          }
00617 
00618          md_msg = ao2_alloc(sizeof(*md_msg), NULL);
00619 
00620          /* read the message desk number */
00621          for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) {
00622             md_msg->mesg_desk_num[i] = fgetc(iface->file);
00623             ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_num[i]);
00624          }
00625 
00626          md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0';
00627 
00628          ast_debug(1, "The message desk number is '%s'\n", md_msg->mesg_desk_num);
00629 
00630          /* read the message desk terminal number */
00631          for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) {
00632             md_msg->mesg_desk_term[i] = fgetc(iface->file);
00633             ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_term[i]);
00634          }
00635 
00636          md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0';
00637 
00638          ast_debug(1, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term);
00639 
00640          /* read the message type */
00641          md_msg->type = fgetc(iface->file);
00642 
00643          ast_debug(1, "Message type is '%c'\n", md_msg->type);
00644 
00645          /* read the forwarding station number (may be blank) */
00646          cp = &md_msg->fwd_st[0];
00647          for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) {
00648             if ((c = fgetc(iface->file)) == ' ') {
00649                *cp = '\0';
00650                ast_debug(1, "Read a space, done looking for the forwarding station\n");
00651                break;
00652             }
00653 
00654             /* store c in md_msg->fwd_st */
00655             if (i >= iface->msdstrip) {
00656                ast_debug(1, "Read a '%c' and stored it in the forwarding station buffer\n", c);
00657                *cp++ = c;
00658             } else {
00659                ast_debug(1, "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);
00660             }
00661          }
00662 
00663          /* make sure the value is null terminated, even if this truncates it */
00664          md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0';
00665          cp = NULL;
00666 
00667          ast_debug(1, "The forwarding station is '%s'\n", md_msg->fwd_st);
00668 
00669          /* Put the fwd_st in the name field so that we can use ao2_find to look
00670           * up a message on this field */
00671          ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name));
00672 
00673          /* read the calling station number (may be blank) */
00674          cp = &md_msg->calling_st[0];
00675          for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) {
00676             if (!isdigit((c = fgetc(iface->file)))) {
00677                *cp = '\0';
00678                ast_debug(1, "Read a '%c', but didn't store it in the calling station buffer because it's not a digit\n", c);
00679                if (c == ' ') {
00680                   /* Don't break on a space.  We may read the space before the calling station
00681                    * here if the forwarding station buffer filled up. */
00682                   i--; /* We're still on the same character */
00683                   continue;
00684                }
00685                break;
00686             }
00687 
00688             /* store c in md_msg->calling_st */
00689             if (i >= iface->msdstrip) {
00690                ast_debug(1, "Read a '%c' and stored it in the calling station buffer\n", c);
00691                *cp++ = c;
00692             } else {
00693                ast_debug(1, "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);
00694             }
00695          }
00696 
00697          /* make sure the value is null terminated, even if this truncates it */
00698          md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0';
00699          cp = NULL;
00700 
00701          ast_debug(1, "The calling station is '%s'\n", md_msg->calling_st);
00702 
00703          /* add the message to the message queue */
00704          md_msg->timestamp = ast_tvnow();
00705          ast_smdi_md_message_push(iface, md_msg);
00706          ast_debug(1, "Received SMDI MD message on %s\n", iface->name);
00707 
00708          ao2_ref(md_msg, -1);
00709 
00710       } else if (c == 'W') { /* MWI message */
00711          start = 0;
00712 
00713          ast_debug(1, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n");
00714 
00715          if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) {
00716             ao2_ref(iface, -1);
00717             return NULL;
00718          }
00719 
00720          mwi_msg = ao2_alloc(sizeof(*mwi_msg), NULL);
00721 
00722          /* discard the 'I' (from 'MWI') */
00723          fgetc(iface->file);
00724          
00725          /* read the forwarding station number (may be blank) */
00726          cp = &mwi_msg->fwd_st[0];
00727          for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) {
00728             if ((c = fgetc(iface->file)) == ' ') {
00729                *cp = '\0';
00730                break;
00731             }
00732 
00733             /* store c in md_msg->fwd_st */
00734             if (i >= iface->msdstrip)
00735                *cp++ = c;
00736          }
00737 
00738          /* make sure the station number is null terminated, even if this will truncate it */
00739          mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0';
00740          cp = NULL;
00741 
00742          /* Put the fwd_st in the name field so that we can use ao2_find to look
00743           * up a message on this field */
00744          ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name));
00745 
00746          /* read the mwi failure cause */
00747          for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++)
00748             mwi_msg->cause[i] = fgetc(iface->file);
00749 
00750          mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0';
00751 
00752          /* add the message to the message queue */
00753          mwi_msg->timestamp = ast_tvnow();
00754          ast_smdi_mwi_message_push(iface, mwi_msg);
00755          ast_debug(1, "Received SMDI MWI message on %s\n", iface->name);
00756 
00757          ao2_ref(mwi_msg, -1);
00758       } else {
00759          ast_log(LOG_ERROR, "Unknown SMDI message type received on %s (M%c).\n", iface->name, c);
00760          start = 0;
00761       }
00762    }
00763 
00764    ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
00765    ao2_ref(iface, -1);
00766    return NULL;
00767 }

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

Definition at line 282 of file res_smdi.c.

References ao2_unlock, ao2_wrlock, ast_debug, ast_log, errno, ast_smdi_interface::file, LOG_ERROR, ast_smdi_interface::msdstrip, and ast_smdi_interface::name.

Referenced by ast_smdi_mwi_set(), and ast_smdi_mwi_unset().

00283 {
00284    FILE *file;
00285    int i;
00286 
00287    if (!(file = fopen(iface->name, "w"))) {
00288       ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
00289       return 1;
00290    }
00291 
00292    ao2_wrlock(iface);
00293 
00294    fprintf(file, "%s:MWI ", on ? "OP" : "RMV");
00295 
00296    for (i = 0; i < iface->msdstrip; i++)
00297       fprintf(file, "0");
00298 
00299    fprintf(file, "%s!\x04", mailbox);
00300 
00301    fclose(file);
00302 
00303    ao2_unlock(iface);
00304    ast_debug(1, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
00305 
00306    return 0;
00307 }

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

Definition at line 348 of file res_smdi.c.

References ao2_callback, ast_smdi_interface::md_q, ast_smdi_interface::mwi_q, NULL, OBJ_UNLINK, SMDI_MD, and SMDI_MWI.

Referenced by purge_old_messages(), and smdi_msg_pop().

00349 {
00350    switch (type) {
00351    case SMDI_MWI:
00352       return ao2_callback(iface->mwi_q, OBJ_UNLINK, NULL, NULL);
00353    case SMDI_MD:
00354       return ao2_callback(iface->md_q, OBJ_UNLINK, NULL, NULL);
00355    }
00356 
00357    return NULL;
00358 }

static int unload_module ( void   )  [static]

Definition at line 1415 of file res_smdi.c.

References _unload_module().

01416 {
01417    return _unload_module(0);
01418 }

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

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

00337 {
00338    switch (type) {
00339    case SMDI_MWI:
00340       return ast_mutex_unlock(&iface->mwi_q_lock);
00341    case SMDI_MD:
00342       return ast_mutex_unlock(&iface->md_q_lock);
00343    }
00344 
00345    return -1;
00346 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static]

Definition at line 1441 of file res_smdi.c.

Definition at line 1441 of file res_smdi.c.

Definition at line 213 of file res_smdi.c.

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

Definition at line 166 of file res_smdi.c.

Definition at line 215 of file res_smdi.c.

Definition at line 215 of file res_smdi.c.

struct timeval last_poll

The time that the last poll began

Definition at line 221 of file res_smdi.c.

Definition at line 212 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 _unload_module(), append_mailbox_mapping(), destroy_all_mailbox_mappings(), load_module(), mwi_monitor_handler(), and smdi_load().

unsigned int polling_interval

Polling Interval for checking mailbox status

Definition at line 217 of file res_smdi.c.

int smdi_loaded [static]

Definition at line 167 of file res_smdi.c.

Initial value:

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

Definition at line 1157 of file res_smdi.c.

Referenced by smdi_msg_read(), and smdi_msg_retrieve_read().

Initial value:

 {
   .name = "SMDI_MSG",
   .read = smdi_msg_read,
}

Definition at line 1345 of file res_smdi.c.

Referenced by _unload_module(), and load_module().

int smdi_msg_id [static]

Definition at line 1162 of file res_smdi.c.

Referenced by smdi_msg_retrieve_read().

struct ast_app_option smdi_msg_ret_options[128] = { [ 't' ] = { .flag = OPT_SEARCH_TERMINAL }, [ 'n' ] = { .flag = OPT_SEARCH_NUMBER }, } [static]

Definition at line 1170 of file res_smdi.c.

Referenced by smdi_msg_retrieve_read().

Initial value:

 {
   .name = "SMDI_MSG_RETRIEVE",
   .read = smdi_msg_retrieve_read,
}

Definition at line 1340 of file res_smdi.c.

Referenced by _unload_module(), and load_module().

unsigned int stop

Set to 1 to tell the polling thread to stop

Definition at line 219 of file res_smdi.c.

pthread_t thread

The thread ID

Definition at line 211 of file res_smdi.c.


Generated on Thu Apr 16 06:33:22 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6