Asterisk - The Open Source Telephony Project GIT-master-2de1a68
Data Structures | Macros | Enumerations | Functions | Variables
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/mwi.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
 

Macros

#define AST_API_MODULE
 
#define DEFAULT_POLLING_INTERVAL   10
 
#define SMDI_MSG_EXPIRY_TIME   30000 /* 30 seconds */
 
#define SMDI_RETRIEVE_TIMEOUT_DEFAULT   3000
 

Enumerations

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

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static struct ast_smdi_interfacealloc_smdi_interface (void)
 
static AO2_GLOBAL_OBJ_STATIC (smdi_ifaces)
 
static void append_mailbox_mapping (struct ast_variable *var, struct ast_smdi_interface *iface)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
struct ast_smdi_interface *AST_OPTIONAL_API_NAME() ast_smdi_interface_find (const char *iface_name)
 Find an SMDI interface with the specified name. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
int AST_OPTIONAL_API_NAME() ast_smdi_mwi_unset (struct ast_smdi_interface *iface, const char *mailbox)
 Unset the MWI indicator for a mailbox. More...
 
static void destroy_all_mailbox_mappings (void)
 
static void destroy_mailbox_mapping (struct mailbox_mapping *mm)
 
static int load_module (void)
 Load the module. More...
 
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_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
 
static const 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. More...
 
static const struct ast_datastore_info smdi_msg_datastore_info
 
static struct ast_custom_function smdi_msg_function
 
static int smdi_msg_id
 
static const 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 mnich.nosp@m.olso.nosp@m.n@dig.nosp@m.ium..nosp@m.com
Russell Bryant russe.nosp@m.ll@d.nosp@m.igium.nosp@m..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.

Macro Definition Documentation

◆ AST_API_MODULE

#define AST_API_MODULE

Definition at line 57 of file res_smdi.c.

◆ DEFAULT_POLLING_INTERVAL

#define DEFAULT_POLLING_INTERVAL   10

10 seconds

Definition at line 204 of file res_smdi.c.

◆ SMDI_MSG_EXPIRY_TIME

#define SMDI_MSG_EXPIRY_TIME   30000 /* 30 seconds */

Definition at line 69 of file res_smdi.c.

◆ SMDI_RETRIEVE_TIMEOUT_DEFAULT

#define SMDI_RETRIEVE_TIMEOUT_DEFAULT   3000

In milliseconds

Definition at line 1195 of file res_smdi.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
OPT_SEARCH_TERMINAL 
OPT_SEARCH_NUMBER 

Definition at line 429 of file res_smdi.c.

429 {
430 OPT_SEARCH_TERMINAL = (1 << 0),
431 OPT_SEARCH_NUMBER = (1 << 1),
432};
@ OPT_SEARCH_NUMBER
Definition: res_smdi.c:431
@ OPT_SEARCH_TERMINAL
Definition: res_smdi.c:430

◆ smdi_message_type

Enumerator
SMDI_MWI 
SMDI_MD 

Definition at line 319 of file res_smdi.c.

319 {
320 SMDI_MWI,
321 SMDI_MD,
322};
@ SMDI_MWI
Definition: res_smdi.c:320
@ SMDI_MD
Definition: res_smdi.c:321

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1452 of file res_smdi.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1452 of file res_smdi.c.

◆ alloc_smdi_interface()

static struct ast_smdi_interface * alloc_smdi_interface ( void  )
static

Definition at line 914 of file res_smdi.c.

915{
916 struct ast_smdi_interface *iface;
917
918 if (!(iface = ao2_alloc(sizeof(*iface), smdi_interface_destroy))) {
919 return NULL;
920 }
921
924
925 ast_mutex_init(&iface->md_q_lock);
926 ast_cond_init(&iface->md_q_cond, NULL);
927
928 ast_mutex_init(&iface->mwi_q_lock);
929 ast_cond_init(&iface->mwi_q_cond, NULL);
930
931 return iface;
932}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_mutex_init(pmutex)
Definition: lock.h:186
static int smdi_md_q_cmp_fn(void *obj, void *arg, int flags)
Definition: res_smdi.c:886
static void smdi_interface_destroy(void *obj)
Definition: res_smdi.c:224
static int smdi_mwi_q_cmp_fn(void *obj, void *data, int flags)
Definition: res_smdi.c:879
#define NULL
Definition: resample.c:96
ast_mutex_t md_q_lock
Definition: res_smdi.c:170
ast_mutex_t mwi_q_lock
Definition: res_smdi.c:173
ast_cond_t md_q_cond
Definition: res_smdi.c:171
struct ao2_container * mwi_q
Definition: res_smdi.c:172
ast_cond_t mwi_q_cond
Definition: res_smdi.c:174
struct ao2_container * md_q
Definition: res_smdi.c:169

References ao2_alloc, AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_list, ast_cond_init, ast_mutex_init, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q, ast_smdi_interface::mwi_q_cond, ast_smdi_interface::mwi_q_lock, NULL, smdi_interface_destroy(), smdi_md_q_cmp_fn(), and smdi_mwi_q_cmp_fn().

Referenced by smdi_load().

◆ AO2_GLOBAL_OBJ_STATIC()

static AO2_GLOBAL_OBJ_STATIC ( smdi_ifaces  )
static

◆ append_mailbox_mapping()

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

Definition at line 805 of file res_smdi.c.

806{
807 struct mailbox_mapping *mm;
808 char *mailbox, *context;
809
810 if (!(mm = ast_calloc_with_stringfields(1, struct mailbox_mapping, 32)))
811 return;
812
813 ast_string_field_set(mm, smdi, var->name);
814
815 context = ast_strdupa(var->value);
816 mailbox = strsep(&context, "@");
818 context = "default";
819
822
823 mm->iface = ao2_bump(iface);
824
826 AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry);
828}
#define var
Definition: ast_expr2f.c:605
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
char * strsep(char **str, const char *delims)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
static struct @475 mwi_monitor
Data that gets used by the SMDI MWI monitoring thread.
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:432
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Definition: search.h:40
A mapping between an SMDI mailbox ID and an Asterisk mailbox.
Definition: res_smdi.c:186
struct ast_smdi_interface * iface
Definition: res_smdi.c:191
const ast_string_field smdi
Definition: res_smdi.c:199

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(), voicemailpwcheck::context, mailbox_mapping::iface, voicemailpwcheck::mailbox, mwi_monitor, mailbox_mapping::smdi, strsep(), and var.

Referenced by smdi_load().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1452 of file res_smdi.c.

◆ ast_smdi_interface_find()

struct ast_smdi_interface *AST_OPTIONAL_API_NAME() ast_smdi_interface_find ( const char *  iface_name)

Find an SMDI interface with the specified name.

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

564{
565 struct ao2_container *c;
566 struct ast_smdi_interface *iface = NULL;
567
568 c = ao2_global_obj_ref(smdi_ifaces);
569 if (c) {
570 iface = ao2_find(c, iface_name, OBJ_SEARCH_KEY);
571 ao2_ref(c, -1);
572 }
573
574 return iface;
575}
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
Generic container type.
static struct test_val c

References ao2_find, ao2_global_obj_ref, ao2_ref, c, NULL, and OBJ_SEARCH_KEY.

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

◆ ast_smdi_md_message_pop()

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.

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

535{
536 return smdi_msg_pop(iface, SMDI_MD);
537}
static void * smdi_msg_pop(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:416

References SMDI_MD, and smdi_msg_pop().

◆ ast_smdi_md_message_push()

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

Definition at line 260 of file res_smdi.c.

261{
262 ast_mutex_lock(&iface->md_q_lock);
263 ao2_link(iface->md_q, md_msg);
266}
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ast_cond_broadcast(cond)
Definition: lock.h:204

References ao2_link, ast_cond_broadcast, ast_mutex_lock, ast_mutex_unlock, ast_smdi_interface::md_q, ast_smdi_interface::md_q_cond, and ast_smdi_interface::md_q_lock.

Referenced by purge_old_messages(), and smdi_read().

◆ ast_smdi_md_message_wait()

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.

Parameters
ifacea pointer to the interface to use.
timeoutthe 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.

540{
541 struct ast_flags options = { 0 };
542 return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
543}
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)
Definition: res_smdi.c:478
Structure used to handle boolean flags.
Definition: utils.h:199
static struct test_options options

References NULL, options, SMDI_MD, and smdi_message_wait().

Referenced by __analog_ss_thread(), and analog_ss_thread().

◆ ast_smdi_mwi_message_pop()

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.

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

546{
547 return smdi_msg_pop(iface, SMDI_MWI);
548}

References smdi_msg_pop(), and SMDI_MWI.

◆ ast_smdi_mwi_message_push()

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

◆ ast_smdi_mwi_message_wait()

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.

Parameters
ifacea pointer to the interface to use.
timeoutthe 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.

551{
552 struct ast_flags options = { 0 };
553 return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
554}

References NULL, options, smdi_message_wait(), and SMDI_MWI.

◆ ast_smdi_mwi_message_wait_station()

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 
)

Definition at line 556 of file res_smdi.c.

558{
559 struct ast_flags options = { 0 };
560 return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
561}

References options, smdi_message_wait(), and SMDI_MWI.

Referenced by run_externnotify().

◆ ast_smdi_mwi_set()

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
ifacethe interface to use.
mailboxthe mailbox to use.

Definition at line 309 of file res_smdi.c.

310{
311 return smdi_toggle_mwi(iface, mailbox, 1);
312}
static int smdi_toggle_mwi(struct ast_smdi_interface *iface, const char *mailbox, int on)
Definition: res_smdi.c:282

References voicemailpwcheck::mailbox, and smdi_toggle_mwi().

Referenced by poll_mailbox(), and run_externnotify().

◆ ast_smdi_mwi_unset()

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
ifacethe interface to use.
mailboxthe mailbox to use.

Definition at line 314 of file res_smdi.c.

315{
316 return smdi_toggle_mwi(iface, mailbox, 0);
317}

References voicemailpwcheck::mailbox, and smdi_toggle_mwi().

Referenced by poll_mailbox(), and run_externnotify().

◆ destroy_all_mailbox_mappings()

static void destroy_all_mailbox_mappings ( void  )
static

Definition at line 795 of file res_smdi.c.

796{
797 struct mailbox_mapping *mm;
798
800 while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry)))
803}
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
static void destroy_mailbox_mapping(struct mailbox_mapping *mm)
Definition: res_smdi.c:788

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

Referenced by smdi_load(), and unload_module().

◆ destroy_mailbox_mapping()

static void destroy_mailbox_mapping ( struct mailbox_mapping mm)
static

Definition at line 788 of file res_smdi.c.

789{
791 ao2_ref(mm->iface, -1);
792 ast_free(mm);
793}
#define ast_free(a)
Definition: astmm.h:180
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374

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

Referenced by destroy_all_mailbox_mappings().

◆ load_module()

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

1412{
1413 int res;
1414
1417
1418 /* load the config and start the listener threads*/
1419 res = smdi_load(0);
1420 if (res < 0) {
1421 unload_module();
1423 } else if (res == 1) {
1424 ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
1425 }
1426
1429
1431}
#define ast_log
Definition: astobj2.c:42
#define LOG_NOTICE
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
static struct ast_custom_function smdi_msg_function
Definition: res_smdi.c:1375
static int unload_module(void)
Definition: res_smdi.c:1380
static struct ast_custom_function smdi_msg_retrieve_function
Definition: res_smdi.c:1370
static int smdi_load(int reload)
Definition: res_smdi.c:952

References 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, smdi_msg_retrieve_function, and unload_module().

◆ lock_msg_q()

static int lock_msg_q ( struct ast_smdi_interface iface,
enum smdi_message_type  type 
)
inlinestatic

Definition at line 324 of file res_smdi.c.

325{
326 switch (type) {
327 case SMDI_MWI:
328 return ast_mutex_lock(&iface->mwi_q_lock);
329 case SMDI_MD:
330 return ast_mutex_lock(&iface->md_q_lock);
331 }
332
333 return -1;
334}
static const char type[]
Definition: chan_ooh323.c:109

References ast_mutex_lock, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_lock, SMDI_MD, SMDI_MWI, and type.

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

◆ msg_timestamp()

static struct timeval msg_timestamp ( void *  msg,
enum smdi_message_type  type 
)
inlinestatic

Definition at line 360 of file res_smdi.c.

361{
362 struct ast_smdi_md_message *md_msg = msg;
363 struct ast_smdi_mwi_message *mwi_msg = msg;
364
365 switch (type) {
366 case SMDI_MWI:
367 return mwi_msg->timestamp;
368 case SMDI_MD:
369 return md_msg->timestamp;
370 }
371
372 return ast_tv(0, 0);
373}
An SMDI message desk message.
Definition: smdi.h:65
struct timeval timestamp
Definition: smdi.h:72
An SMDI message waiting indicator message.
Definition: smdi.h:51
struct timeval timestamp
Definition: smdi.h:55
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235

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

Referenced by purge_old_messages().

◆ mwi_monitor_handler()

static void * mwi_monitor_handler ( void *  data)
static

Definition at line 852 of file res_smdi.c.

853{
854 while (!mwi_monitor.stop) {
855 struct timespec ts = { 0, };
856 struct timeval polltime;
857 struct mailbox_mapping *mm;
858
860
861 mwi_monitor.last_poll = ast_tvnow();
862
863 AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry)
864 poll_mailbox(mm);
865
866 /* Sleep up to the configured polling interval. Allow unload_module()
867 * to signal us to wake up and exit. */
868 polltime = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0));
869 ts.tv_sec = polltime.tv_sec;
870 ts.tv_nsec = polltime.tv_usec * 1000;
871 ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts);
872
874 }
875
876 return NULL;
877}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
static void poll_mailbox(struct mailbox_mapping *mm)
Definition: res_smdi.c:833
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

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

◆ poll_mailbox()

static void poll_mailbox ( struct mailbox_mapping mm)
static
Note
Called with the mwi_monitor.lock locked

Definition at line 833 of file res_smdi.c.

834{
835 char buf[1024];
836 unsigned int state;
837
838 snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context);
839
841
842 if (state != mm->cur_state) {
843 if (state)
844 ast_smdi_mwi_set(mm->iface, mm->smdi);
845 else
846 ast_smdi_mwi_unset(mm->iface, mm->smdi);
847
848 mm->cur_state = state;
849 }
850}
enum cc_state state
Definition: ccss.c:393
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX"....
Definition: main/app.c:582
int AST_OPTIONAL_API_NAME() ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
Unset the MWI indicator for a mailbox.
Definition: res_smdi.c:314
int AST_OPTIONAL_API_NAME() ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
Set the MWI indicator for a mailbox.
Definition: res_smdi.c:309
unsigned int cur_state
Definition: res_smdi.c:189
const ast_string_field context
Definition: res_smdi.c:199
const ast_string_field mailbox
Definition: res_smdi.c:199

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, mailbox_mapping::smdi, and state.

Referenced by mwi_monitor_handler().

◆ purge_old_messages()

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.

376{
377 struct timeval now = ast_tvnow();
378 long elapsed = 0;
379 void *msg;
380
381 lock_msg_q(iface, type);
382 msg = unlink_from_msg_q(iface, type);
383 unlock_msg_q(iface, type);
384
385 /* purge old messages */
386 while (msg) {
387 elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type));
388
389 if (elapsed > iface->msg_expiry) {
390 /* found an expired message */
391 ao2_ref(msg, -1);
392 ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue. "
393 "Message was %ld milliseconds too old.\n",
394 iface->name, (type == SMDI_MD) ? "MD" : "MWI",
395 elapsed - iface->msg_expiry);
396
397 lock_msg_q(iface, type);
398 msg = unlink_from_msg_q(iface, type);
399 unlock_msg_q(iface, type);
400 } else {
401 /* good message, put it back and return */
402 switch (type) {
403 case SMDI_MD:
404 ast_smdi_md_message_push(iface, msg);
405 break;
406 case SMDI_MWI:
407 ast_smdi_mwi_message_push(iface, msg);
408 break;
409 }
410 ao2_ref(msg, -1);
411 break;
412 }
413 }
414}
static struct timeval msg_timestamp(void *msg, enum smdi_message_type type)
Definition: res_smdi.c:360
static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
Definition: res_smdi.c:260
static void ast_smdi_mwi_message_push(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
Definition: res_smdi.c:274
static int lock_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:324
static void * unlink_from_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:348
static int unlock_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:336
char name[SMDI_MAX_FILENAME_LEN]
Definition: res_smdi.c:168
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107

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, type, unlink_from_msg_q(), and unlock_msg_q().

Referenced by smdi_msg_find(), and smdi_msg_pop().

◆ reload()

static int reload ( void  )
static

Definition at line 1433 of file res_smdi.c.

1434{
1435 int res;
1436
1437 res = smdi_load(1);
1438 if (res < 0) {
1439 return res;
1440 } else if (res == 1) {
1441 ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
1442 }
1443 return 0;
1444}
#define LOG_WARNING

References ast_log, LOG_WARNING, and smdi_load().

Referenced by smdi_load().

◆ smdi_ifaces_cmp_fn()

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

Definition at line 934 of file res_smdi.c.

935{
936 struct ast_smdi_interface *iface = obj;
937
938 char *str = data;
939 return !strcmp(iface->name, str) ? CMP_MATCH | CMP_STOP : 0;
940}
const char * str
Definition: app_jack.c:147
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028

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

Referenced by smdi_load().

◆ smdi_interface_destroy()

static void smdi_interface_destroy ( void *  obj)
static

Definition at line 224 of file res_smdi.c.

225{
226 struct ast_smdi_interface *iface = obj;
227 int mod_unref_defer = 0;
228
229 if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
230 pthread_cancel(iface->thread);
231 pthread_join(iface->thread, NULL);
232 mod_unref_defer = 1;
233 }
234
235 iface->thread = AST_PTHREADT_STOP;
236
237 if (iface->file) {
238 fclose(iface->file);
239 }
240
241 ao2_cleanup(iface->md_q);
244
245 ao2_cleanup(iface->mwi_q);
248
249 if (mod_unref_defer) {
251 }
252}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ast_cond_destroy(cond)
Definition: lock.h:202
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define AST_PTHREADT_STOP
Definition: lock.h:67
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
struct ast_module * self
Definition: module.h:342
pthread_t thread
Definition: res_smdi.c:177

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

Referenced by alloc_smdi_interface().

◆ smdi_load()

static int smdi_load ( int  reload)
static

Definition at line 952 of file res_smdi.c.

953{
954 struct ast_config *conf;
955 struct ast_variable *v;
956 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
957 int res = 0;
958 RAII_VAR(struct ao2_container *, new_ifaces, NULL, ao2_cleanup);
959 RAII_VAR(struct ao2_container *, old_ifaces, ao2_global_obj_ref(smdi_ifaces), ao2_cleanup);
960 struct ast_smdi_interface *mailbox_iface = NULL;
961
962 /* Config options */
963 speed_t baud_rate = B9600; /* 9600 baud rate */
964 tcflag_t paritybit = PARENB; /* even parity checking */
965 tcflag_t charsize = CS7; /* seven bit characters */
966 int stopbits = 0; /* One stop bit */
967
968 int msdstrip = 0; /* strip zero digits */
970
971 if (!(conf = ast_config_load(config_file, config_flags)) || conf == CONFIG_STATUS_FILEINVALID) {
972 if (reload)
973 ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
974 else
975 ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file);
976 return 1;
977 } else if (conf == CONFIG_STATUS_FILEUNCHANGED)
978 return 0;
979
981 if (!new_ifaces) {
983 return -1;
984 }
985
986 for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
987 RAII_VAR(struct ast_smdi_interface *, iface, NULL, ao2_cleanup);
988
989 if (!strcasecmp(v->name, "baudrate")) {
990 if (!strcasecmp(v->value, "9600"))
991 baud_rate = B9600;
992 else if (!strcasecmp(v->value, "4800"))
993 baud_rate = B4800;
994 else if (!strcasecmp(v->value, "2400"))
995 baud_rate = B2400;
996 else if (!strcasecmp(v->value, "1200"))
997 baud_rate = B1200;
998 else {
999 ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno);
1000 baud_rate = B9600;
1001 }
1002 } else if (!strcasecmp(v->name, "msdstrip")) {
1003 if (!sscanf(v->value, "%30d", &msdstrip)) {
1004 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
1005 msdstrip = 0;
1006 } else if (0 > msdstrip || msdstrip > 9) {
1007 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
1008 msdstrip = 0;
1009 }
1010 } else if (!strcasecmp(v->name, "msgexpirytime")) {
1011 if (!sscanf(v->value, "%30ld", &msg_expiry)) {
1012 ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno);
1014 }
1015 } else if (!strcasecmp(v->name, "paritybit")) {
1016 if (!strcasecmp(v->value, "even"))
1017 paritybit = PARENB;
1018 else if (!strcasecmp(v->value, "odd"))
1019 paritybit = PARENB | PARODD;
1020 else if (!strcasecmp(v->value, "none"))
1021 paritybit = ~PARENB;
1022 else {
1023 ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno);
1024 paritybit = PARENB;
1025 }
1026 } else if (!strcasecmp(v->name, "charsize")) {
1027 if (!strcasecmp(v->value, "7"))
1028 charsize = CS7;
1029 else if (!strcasecmp(v->value, "8"))
1030 charsize = CS8;
1031 else {
1032 ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno);
1033 charsize = CS7;
1034 }
1035 } else if (!strcasecmp(v->name, "twostopbits")) {
1036 stopbits = ast_true(v->name);
1037 } else if (!strcasecmp(v->name, "smdiport")) {
1038 if (reload && old_ifaces) {
1039 /* we are reloading, check if we are already
1040 * monitoring this interface, if we are we do
1041 * not want to start it again. This also has
1042 * the side effect of not updating different
1043 * setting for the serial port, but it should
1044 * be trivial to rewrite this section so that
1045 * options on the port are changed without
1046 * restarting the interface. Or the interface
1047 * could be restarted with out emptying the
1048 * queue. */
1049 if ((iface = ao2_find(old_ifaces, v->value, OBJ_SEARCH_KEY))) {
1050 ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
1051 ao2_link(new_ifaces, iface);
1052 continue;
1053 }
1054 }
1055
1056 if (!(iface = alloc_smdi_interface()))
1057 continue;
1058
1059 ast_copy_string(iface->name, v->value, sizeof(iface->name));
1060
1061 iface->thread = AST_PTHREADT_NULL;
1062
1063 if (!(iface->file = fopen(iface->name, "r"))) {
1064 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
1065 continue;
1066 }
1067
1068 iface->fd = fileno(iface->file);
1069
1070 /* Set the proper attributes for our serial port. */
1071
1072 /* get the current attributes from the port */
1073 if (tcgetattr(iface->fd, &iface->mode)) {
1074 ast_log(LOG_ERROR, "Error getting attributes of %s (%s)\n", iface->name, strerror(errno));
1075 continue;
1076 }
1077
1078 /* set the desired speed */
1079 if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
1080 ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
1081 continue;
1082 }
1083
1084 /* set the stop bits */
1085 if (stopbits)
1086 iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */
1087 else
1088 iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */
1089
1090 /* set the parity */
1091 iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit;
1092
1093 /* set the character size */
1094 iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize;
1095
1096 /* commit the desired attributes */
1097 if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
1098 ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
1099 continue;
1100 }
1101
1102 /* set the msdstrip */
1103 iface->msdstrip = msdstrip;
1104
1105 /* set the message expiry time */
1106 iface->msg_expiry = msg_expiry;
1107
1108 /*
1109 * start the listener thread
1110 *
1111 * The listener thread does not actually hold a ref to iface. When all
1112 * external refs go away, the destructor will stop the listener thread
1113 * before actually destroying the iface object.
1114 */
1115 ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name);
1116 if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
1117 ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
1118 continue;
1119 }
1120
1121 ao2_link(new_ifaces, iface);
1123 } else {
1124 ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
1125 }
1126 }
1127
1129 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
1130
1131 for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) {
1132 if (!strcasecmp(v->name, "smdiport")) {
1133 ao2_cleanup(mailbox_iface);
1134
1135 if (!(mailbox_iface = ao2_find(new_ifaces, v->value, OBJ_SEARCH_KEY))) {
1136 ast_log(LOG_NOTICE, "SMDI interface %s not found\n", v->value);
1137 continue;
1138 }
1139 } else if (!strcasecmp(v->name, "pollinginterval")) {
1140 if (sscanf(v->value, "%30u", &mwi_monitor.polling_interval) != 1) {
1141 ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value);
1142 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
1143 }
1144 } else {
1145 if (!mailbox_iface) {
1146 ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n");
1147 continue;
1148 }
1149 append_mailbox_mapping(v, mailbox_iface);
1150 }
1151 }
1152 ao2_cleanup(mailbox_iface);
1153
1155
1156 ao2_global_obj_replace_unref(smdi_ifaces, new_ifaces);
1157
1158 if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL
1160 ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n");
1161 return -1;
1162 }
1163
1164 if (!ao2_container_count(new_ifaces)) {
1165 res = 1;
1166 }
1167
1168 return res;
1169}
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED
#define LOG_ERROR
#define ast_verb(level,...)
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
int errno
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443
#define SMDI_MSG_EXPIRY_TIME
Definition: res_smdi.c:69
static struct ast_smdi_interface * alloc_smdi_interface(void)
Definition: res_smdi.c:914
static int smdi_ifaces_cmp_fn(void *obj, void *data, int flags)
Definition: res_smdi.c:934
#define DEFAULT_POLLING_INTERVAL
Definition: res_smdi.c:204
static void * smdi_read(void *iface_p)
Definition: res_smdi.c:586
static void destroy_all_mailbox_mappings(void)
Definition: res_smdi.c:795
static void * mwi_monitor_handler(void *data)
Definition: res_smdi.c:852
static const char config_file[]
Definition: res_smdi.c:165
static int reload(void)
Definition: res_smdi.c:1433
static void append_mailbox_mapping(struct ast_variable *var, struct ast_smdi_interface *iface)
Definition: res_smdi.c:805
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
All configuration options for http media cache.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592

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_ref, ast_pthread_create_background, AST_PTHREADT_NULL, ast_true(), ast_variable_browse(), ast_verb, config_file, 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, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, ast_smdi_interface::mode, ast_smdi_interface::msdstrip, ast_smdi_interface::msg_expiry, mwi_monitor, mwi_monitor_handler(), ast_variable::name, ast_smdi_interface::name, ast_variable::next, NULL, OBJ_SEARCH_KEY, RAII_VAR, reload(), ast_module_info::self, smdi_ifaces_cmp_fn(), SMDI_MSG_EXPIRY_TIME, smdi_read(), ast_smdi_interface::thread, and ast_variable::value.

Referenced by load_module(), and reload().

◆ smdi_md_q_cmp_fn()

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

Definition at line 886 of file res_smdi.c.

887{
888 const struct ast_smdi_md_message *msg = obj;
889 const struct ast_smdi_md_message *search_msg = arg;
890 const char *search_key = arg;
891 int cmp = 0;
892
893 switch (flags & OBJ_SEARCH_MASK) {
895 if (!ast_strlen_zero(search_msg->mesg_desk_num)) {
896 cmp = strcmp(msg->mesg_desk_num, search_msg->mesg_desk_num);
897 }
898 if (!ast_strlen_zero(search_msg->mesg_desk_term)) {
899 cmp |= strcmp(msg->mesg_desk_term, search_msg->mesg_desk_term);
900 }
901 break;
902 case OBJ_SEARCH_KEY:
903 cmp = strcmp(msg->name, search_key);
904 break;
905 }
906
907 if (cmp) {
908 return 0;
909 }
910
911 return CMP_MATCH;
912}
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
char mesg_desk_term[SMDI_MESG_DESK_TERM_LEN+1]
Definition: smdi.h:68
char name[SMDI_MESG_NAME_LEN]
Definition: smdi.h:66
char mesg_desk_num[SMDI_MESG_DESK_NUM_LEN+1]
Definition: smdi.h:67

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

◆ smdi_message_wait()

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.

480{
481 struct timeval start;
482 long diff = 0;
483 void *msg;
486
487 switch (type) {
488 case SMDI_MWI:
489 cond = &iface->mwi_q_cond;
490 lock = &iface->mwi_q_lock;
491 break;
492 case SMDI_MD:
493 cond = &iface->md_q_cond;
494 lock = &iface->md_q_lock;
495 break;
496 }
497
498 start = ast_tvnow();
499
500 while (diff < timeout) {
501 struct timespec ts = { 0, };
502 struct timeval wait;
503
504 lock_msg_q(iface, type);
505
506 if ((msg = smdi_msg_find(iface, type, search_key, options))) {
507 unlock_msg_q(iface, type);
508 return msg;
509 }
510
511 wait = ast_tvadd(start, ast_tv(0, timeout));
512 ts.tv_sec = wait.tv_sec;
513 ts.tv_nsec = wait.tv_usec * 1000;
514
515 /* If there were no messages in the queue, then go to sleep until one
516 * arrives. */
517
519
520 if ((msg = smdi_msg_find(iface, type, search_key, options))) {
521 unlock_msg_q(iface, type);
522 return msg;
523 }
524
525 unlock_msg_q(iface, type);
526
527 /* check timeout */
528 diff = ast_tvdiff_ms(ast_tvnow(), start);
529 }
530
531 return NULL;
532}
pthread_cond_t ast_cond_t
Definition: lock.h:178
ast_cond_t cond
Definition: res_smdi.c:211
static void * smdi_msg_find(struct ast_smdi_interface *iface, enum smdi_message_type type, const char *search_key, struct ast_flags options)
Definition: res_smdi.c:434
ast_mutex_t lock
Definition: res_smdi.c:210
Structure for mutex and tracking information.
Definition: lock.h:135

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, options, SMDI_MD, smdi_msg_find(), SMDI_MWI, type, 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().

◆ smdi_msg_datastore_destroy()

static void smdi_msg_datastore_destroy ( void *  data)
static

Definition at line 1177 of file res_smdi.c.

1178{
1179 struct smdi_msg_datastore *smd = data;
1180
1181 ao2_cleanup(smd->iface);
1182 ao2_cleanup(smd->md_msg);
1183
1184 ast_free(smd);
1185}
struct ast_smdi_interface * iface
Definition: res_smdi.c:1173
struct ast_smdi_md_message * md_msg
Definition: res_smdi.c:1174

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

Referenced by smdi_msg_retrieve_read().

◆ smdi_msg_find()

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.

436{
437 void *msg = NULL;
438
439 purge_old_messages(iface, type);
440
441 switch (type) {
442 case SMDI_MD:
443 if (ast_strlen_zero(search_key)) {
444 /* No search key provided (the code from chan_dahdi does this).
445 * Just pop the top message off of the queue. */
446
447 msg = ao2_callback(iface->md_q, 0, NULL, NULL);
449 /* Searching by the message desk terminal */
450 struct ast_smdi_md_message md_msg = { .name = "" };
451 strncpy(md_msg.mesg_desk_term, search_key, SMDI_MESG_DESK_TERM_LEN);
452 msg = ao2_find(iface->md_q, &md_msg, OBJ_SEARCH_OBJECT);
454 /* Searching by the message desk number */
455 struct ast_smdi_md_message md_msg = { .name = "" };
456 strncpy(md_msg.mesg_desk_num, search_key, SMDI_MESG_DESK_NUM_LEN);
457 msg = ao2_find(iface->md_q, &md_msg, OBJ_SEARCH_OBJECT);
458 } else {
459 /* Searching by the forwarding station */
460 msg = ao2_find(iface->md_q, search_key, OBJ_SEARCH_KEY);
461 }
462 break;
463 case SMDI_MWI:
464 if (ast_strlen_zero(search_key)) {
465 /* No search key provided (the code from chan_dahdi does this).
466 * Just pop the top message off of the queue. */
467
468 msg = ao2_callback(iface->mwi_q, 0, NULL, NULL);
469 } else {
470 msg = ao2_find(iface->mwi_q, search_key, OBJ_SEARCH_KEY);
471 }
472 break;
473 }
474
475 return msg;
476}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
static void purge_old_messages(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:375
#define SMDI_MESG_DESK_TERM_LEN
Definition: smdi.h:39
#define SMDI_MESG_DESK_NUM_LEN
Definition: smdi.h:38
#define ast_test_flag(p, flag)
Definition: utils.h:63

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, options, purge_old_messages(), SMDI_MD, SMDI_MESG_DESK_NUM_LEN, SMDI_MESG_DESK_TERM_LEN, SMDI_MWI, and type.

Referenced by smdi_message_wait().

◆ smdi_msg_pop()

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.

417{
418 void *msg;
419
420 purge_old_messages(iface, type);
421
422 lock_msg_q(iface, type);
423 msg = unlink_from_msg_q(iface, type);
424 unlock_msg_q(iface, type);
425
426 return msg;
427}

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

Referenced by ast_smdi_md_message_pop(), and ast_smdi_mwi_message_pop().

◆ smdi_msg_read()

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

Definition at line 1298 of file res_smdi.c.

1299{
1300 struct ast_module_user *u;
1301 int res = -1;
1303 AST_APP_ARG(id);
1304 AST_APP_ARG(component);
1305 );
1306 char *parse;
1307 struct ast_datastore *datastore = NULL;
1308 struct smdi_msg_datastore *smd = NULL;
1309
1310 u = ast_module_user_add(chan);
1311
1312 if (!chan) {
1313 ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n");
1314 goto return_error;
1315 }
1316
1317 if (ast_strlen_zero(data)) {
1318 ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n");
1319 goto return_error;
1320 }
1321
1322 parse = ast_strdupa(data);
1324
1325 if (ast_strlen_zero(args.id)) {
1326 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
1327 goto return_error;
1328 }
1329
1330 if (ast_strlen_zero(args.component)) {
1331 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
1332 goto return_error;
1333 }
1334
1335 ast_channel_lock(chan);
1337 ast_channel_unlock(chan);
1338
1339 if (!datastore) {
1340 ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id);
1341 goto return_error;
1342 }
1343
1344 smd = datastore->data;
1345
1346 if (!strcasecmp(args.component, "number")) {
1348 } else if (!strcasecmp(args.component, "terminal")) {
1350 } else if (!strcasecmp(args.component, "station")) {
1352 } else if (!strcasecmp(args.component, "callerid")) {
1354 } else if (!strcasecmp(args.component, "type")) {
1355 snprintf(buf, len, "%c", smd->md_msg->type);
1356 } else {
1357 ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n",
1358 args.component);
1359 goto return_error;
1360 }
1361
1362 res = 0;
1363
1364return_error:
1366
1367 return res;
1368}
#define ast_channel_lock(chan)
Definition: channel.h:2922
#define ast_channel_unlock(chan)
Definition: channel.h:2923
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define ast_module_user_remove(user)
Definition: module.h:427
#define ast_module_user_add(chan)
Definition: module.h:426
static const struct ast_datastore_info smdi_msg_datastore_info
Definition: res_smdi.c:1187
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
char calling_st[SMDI_MAX_STATION_NUM_LEN+1]
Definition: smdi.h:70
char fwd_st[SMDI_MAX_STATION_NUM_LEN+1]
Definition: smdi.h:69
const char * args

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(), buf, ast_smdi_md_message::calling_st, ast_datastore::data, ast_smdi_md_message::fwd_st, len(), LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, NULL, smdi_msg_datastore_info, and ast_smdi_md_message::type.

◆ smdi_msg_retrieve_read()

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

Definition at line 1202 of file res_smdi.c.

1203{
1204 struct ast_module_user *u;
1206 AST_APP_ARG(port);
1207 AST_APP_ARG(search_key);
1208 AST_APP_ARG(timeout);
1210 );
1211 struct ast_flags options = { 0 };
1212 unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
1213 int res = -1;
1214 char *parse = NULL;
1215 struct smdi_msg_datastore *smd = NULL;
1216 struct ast_datastore *datastore = NULL;
1217 struct ast_smdi_interface *iface = NULL;
1218 struct ast_smdi_md_message *md_msg = NULL;
1219
1220 u = ast_module_user_add(chan);
1221
1222 if (ast_strlen_zero(data)) {
1223 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n");
1224 goto return_error;
1225 }
1226
1227 if (!chan) {
1228 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n");
1229 goto return_error;
1230 }
1231
1233
1234 parse = ast_strdupa(data);
1236
1237 if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) {
1238 ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n");
1239 goto return_error;
1240 }
1241
1242 if (!(iface = ast_smdi_interface_find(args.port))) {
1243 ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port);
1244 goto return_error;
1245 }
1246
1247 if (!ast_strlen_zero(args.options)) {
1249 }
1250
1251 if (!ast_strlen_zero(args.timeout)) {
1252 if (sscanf(args.timeout, "%30u", &timeout) != 1) {
1253 ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
1255 }
1256 }
1257
1258 if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) {
1259 ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after "
1260 "waiting %u ms.\n", args.search_key, timeout);
1261 goto return_error;
1262 }
1263
1264 if (!(smd = ast_calloc(1, sizeof(*smd))))
1265 goto return_error;
1266
1267 smd->iface = ao2_bump(iface);
1268 smd->md_msg = ao2_bump(md_msg);
1269 smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
1270 snprintf(buf, len, "%u", smd->id);
1271
1272 if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf)))
1273 goto return_error;
1274
1275 datastore->data = smd;
1276
1277 ast_channel_lock(chan);
1278 ast_channel_datastore_add(chan, datastore);
1279 ast_channel_unlock(chan);
1280
1281 res = 0;
1282
1283return_error:
1284 ao2_cleanup(iface);
1285 ao2_cleanup(md_msg);
1286
1287 if (smd && !datastore)
1289
1290 if (parse)
1292
1294
1295 return res;
1296}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3056
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
static const struct ast_app_option smdi_msg_ret_options[128]
Definition: res_smdi.c:1200
#define SMDI_RETRIEVE_TIMEOUT_DEFAULT
Definition: res_smdi.c:1195
static void smdi_msg_datastore_destroy(void *data)
Definition: res_smdi.c:1177
struct ast_smdi_interface *AST_OPTIONAL_API_NAME() ast_smdi_interface_find(const char *iface_name)
Find an SMDI interface with the specified name.
Definition: res_smdi.c:563
static int smdi_msg_id
Definition: res_smdi.c:1192
unsigned int id
Definition: res_smdi.c:1172

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(), buf, ast_datastore::data, smdi_msg_datastore::id, smdi_msg_datastore::iface, len(), LOG_ERROR, LOG_WARNING, smdi_msg_datastore::md_msg, NULL, options, SMDI_MD, smdi_message_wait(), smdi_msg_datastore_destroy(), smdi_msg_datastore_info, smdi_msg_id, smdi_msg_ret_options, and SMDI_RETRIEVE_TIMEOUT_DEFAULT.

◆ smdi_mwi_q_cmp_fn()

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

Definition at line 879 of file res_smdi.c.

880{
881 struct ast_smdi_mwi_message *msg = obj;
882 char *str = data;
883 return !strcmp(msg->name, str) ? CMP_MATCH | CMP_STOP : 0;
884}
char name[SMDI_MESG_NAME_LEN]
Definition: smdi.h:52

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

Referenced by alloc_smdi_interface().

◆ smdi_read()

static void * smdi_read ( void *  iface_p)
static

Definition at line 586 of file res_smdi.c.

587{
588 struct ast_smdi_interface *iface = iface_p;
589 struct ast_smdi_md_message *md_msg;
590 struct ast_smdi_mwi_message *mwi_msg;
591 char *cp = NULL;
592 int i, c;
593 int start = 0;
594
595 /* read an smdi message */
596 while ((c = fgetc(iface->file))) {
597
598 /* check if this is the start of a message */
599 if (!start) {
600 if (c == 'M') {
601 ast_debug(1, "Read an 'M' to start an SMDI message\n");
602 start = 1;
603 }
604 continue;
605 }
606
607 if (c == 'D') { /* MD message */
608 start = 0;
609
610 ast_debug(1, "Read a 'D' ... it's an MD message.\n");
611
612 md_msg = ao2_alloc(sizeof(*md_msg), NULL);
613 if (!md_msg) {
614 return NULL;
615 }
616
617 /* read the message desk number */
618 for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) {
619 c = fgetc(iface->file);
620 if (c == EOF) {
621 ast_log(LOG_ERROR, "Unexpected EOF while reading MD message\n");
622 ao2_ref(md_msg, -1);
623 return NULL;
624 }
625 md_msg->mesg_desk_num[i] = (char) c;
626 ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_num[i]);
627 }
628
629 md_msg->mesg_desk_num[sizeof(md_msg->mesg_desk_num) - 1] = '\0';
630
631 ast_debug(1, "The message desk number is '%s'\n", md_msg->mesg_desk_num);
632
633 /* read the message desk terminal number */
634 for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) {
635 c = fgetc(iface->file);
636 if (c == EOF) {
637 ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n");
638 ao2_ref(md_msg, -1);
639 return NULL;
640 }
641 md_msg->mesg_desk_term[i] = (char) c;
642 ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_term[i]);
643 }
644
645 md_msg->mesg_desk_term[sizeof(md_msg->mesg_desk_term) - 1] = '\0';
646
647 ast_debug(1, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term);
648
649 /* read the message type */
650 c = fgetc(iface->file);
651 if (c == EOF) {
652 ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n");
653 ao2_ref(md_msg, -1);
654 return NULL;
655 }
656 md_msg->type = (char) c;
657
658 ast_debug(1, "Message type is '%c'\n", md_msg->type);
659
660 /* read the forwarding station number (may be blank) */
661 cp = &md_msg->fwd_st[0];
662 for (i = 0; i < sizeof(md_msg->fwd_st) - 1; i++) {
663 if ((c = fgetc(iface->file)) == ' ') {
664 *cp = '\0';
665 ast_debug(1, "Read a space, done looking for the forwarding station\n");
666 break;
667 }
668
669 /* store c in md_msg->fwd_st */
670 if (i >= iface->msdstrip) {
671 ast_debug(1, "Read a '%c' and stored it in the forwarding station buffer\n", c);
672 *cp++ = c;
673 } else {
674 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);
675 }
676 }
677
678 /* make sure the value is null terminated, even if this truncates it */
679 md_msg->fwd_st[sizeof(md_msg->fwd_st) - 1] = '\0';
680 cp = NULL;
681
682 ast_debug(1, "The forwarding station is '%s'\n", md_msg->fwd_st);
683
684 /* Put the fwd_st in the name field so that we can use ao2_find to look
685 * up a message on this field */
686 ast_copy_string(md_msg->name, md_msg->fwd_st, sizeof(md_msg->name));
687
688 /* read the calling station number (may be blank) */
689 cp = &md_msg->calling_st[0];
690 for (i = 0; i < sizeof(md_msg->calling_st) - 1; i++) {
691 if (!isdigit((c = fgetc(iface->file)))) {
692 *cp = '\0';
693 ast_debug(1, "Read a '%c', but didn't store it in the calling station buffer because it's not a digit\n", c);
694 if (c == ' ') {
695 /* Don't break on a space. We may read the space before the calling station
696 * here if the forwarding station buffer filled up. */
697 i--; /* We're still on the same character */
698 continue;
699 }
700 break;
701 }
702
703 /* store c in md_msg->calling_st */
704 if (i >= iface->msdstrip) {
705 ast_debug(1, "Read a '%c' and stored it in the calling station buffer\n", c);
706 *cp++ = c;
707 } else {
708 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);
709 }
710 }
711
712 /* make sure the value is null terminated, even if this truncates it */
713 md_msg->calling_st[sizeof(md_msg->calling_st) - 1] = '\0';
714 cp = NULL;
715
716 ast_debug(1, "The calling station is '%s'\n", md_msg->calling_st);
717
718 /* add the message to the message queue */
719 md_msg->timestamp = ast_tvnow();
720 ast_smdi_md_message_push(iface, md_msg);
721 ast_debug(1, "Received SMDI MD message on %s\n", iface->name);
722
723 ao2_ref(md_msg, -1);
724
725 } else if (c == 'W') { /* MWI message */
726 start = 0;
727
728 ast_debug(1, "Read a 'W', it's an MWI message. (No more debug coming for MWI messages)\n");
729
730 mwi_msg = ao2_alloc(sizeof(*mwi_msg), NULL);
731 if (!mwi_msg) {
732 return NULL;
733 }
734
735 /* discard the 'I' (from 'MWI') */
736 fgetc(iface->file);
737
738 /* read the forwarding station number (may be blank) */
739 cp = &mwi_msg->fwd_st[0];
740 for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) {
741 if ((c = fgetc(iface->file)) == ' ') {
742 *cp = '\0';
743 break;
744 }
745
746 /* store c in md_msg->fwd_st */
747 if (i >= iface->msdstrip)
748 *cp++ = c;
749 }
750
751 /* make sure the station number is null terminated, even if this will truncate it */
752 mwi_msg->fwd_st[sizeof(mwi_msg->fwd_st) - 1] = '\0';
753 cp = NULL;
754
755 /* Put the fwd_st in the name field so that we can use ao2_find to look
756 * up a message on this field */
757 ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name));
758
759 /* read the mwi failure cause */
760 for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) {
761 c = fgetc(iface->file);
762 if (c == EOF) {
763 ast_log(LOG_ERROR, "Unexpected EOF while reading MWI message\n");
764 ao2_ref(mwi_msg, -1);
765 return NULL;
766 }
767 mwi_msg->cause[i] = (char) c;
768 }
769
770 mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0';
771
772 /* add the message to the message queue */
773 mwi_msg->timestamp = ast_tvnow();
774 ast_smdi_mwi_message_push(iface, mwi_msg);
775 ast_debug(1, "Received SMDI MWI message on %s\n", iface->name);
776
777 ao2_ref(mwi_msg, -1);
778 } else {
779 ast_log(LOG_ERROR, "Unknown SMDI message type received on %s (M%c).\n", iface->name, c);
780 start = 0;
781 }
782 }
783
784 ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
785 return NULL;
786}
#define ast_debug(level,...)
Log a DEBUG message.
char cause[SMDI_MWI_FAIL_CAUSE_LEN+1]
Definition: smdi.h:54
char fwd_st[SMDI_MAX_STATION_NUM_LEN+1]
Definition: smdi.h:53

References ao2_alloc, ao2_ref, 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, LOG_ERROR, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, ast_smdi_interface::msdstrip, ast_smdi_interface::name, ast_smdi_mwi_message::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().

◆ smdi_toggle_mwi()

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.

283{
284 FILE *file;
285 int i;
286
287 if (!(file = fopen(iface->name, "w"))) {
288 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
289 return 1;
290 }
291
292 ao2_wrlock(iface);
293
294 fprintf(file, "%s:MWI ", on ? "OP" : "RMV");
295
296 for (i = 0; i < iface->msdstrip; i++)
297 fprintf(file, "0");
298
299 fprintf(file, "%s!\x04", mailbox);
300
301 fclose(file);
302
303 ao2_unlock(iface);
304 ast_debug(1, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
305
306 return 0;
307}
#define ao2_wrlock(a)
Definition: astobj2.h:719
#define ao2_unlock(a)
Definition: astobj2.h:729

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

Referenced by ast_smdi_mwi_set(), and ast_smdi_mwi_unset().

◆ unlink_from_msg_q()

static void * unlink_from_msg_q ( struct ast_smdi_interface iface,
enum smdi_message_type  type 
)
inlinestatic

Definition at line 348 of file res_smdi.c.

349{
350 switch (type) {
351 case SMDI_MWI:
352 return ao2_callback(iface->mwi_q, OBJ_UNLINK, NULL, NULL);
353 case SMDI_MD:
354 return ao2_callback(iface->md_q, OBJ_UNLINK, NULL, NULL);
355 }
356
357 return NULL;
358}
@ OBJ_UNLINK
Definition: astobj2.h:1039

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

Referenced by purge_old_messages(), and smdi_msg_pop().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1380 of file res_smdi.c.

1381{
1382 ao2_global_obj_release(smdi_ifaces);
1383
1385
1387 mwi_monitor.stop = 1;
1390
1391 if (mwi_monitor.thread != AST_PTHREADT_NULL) {
1392 pthread_join(mwi_monitor.thread, NULL);
1393 }
1394
1397
1398 return 0;
1399}
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
#define ast_cond_signal(cond)
Definition: lock.h:203
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

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

◆ unlock_msg_q()

static int unlock_msg_q ( struct ast_smdi_interface iface,
enum smdi_message_type  type 
)
inlinestatic

Definition at line 336 of file res_smdi.c.

337{
338 switch (type) {
339 case SMDI_MWI:
340 return ast_mutex_unlock(&iface->mwi_q_lock);
341 case SMDI_MD:
342 return ast_mutex_unlock(&iface->md_q_lock);
343 }
344
345 return -1;
346}

References ast_mutex_unlock, ast_smdi_interface::md_q_lock, ast_smdi_interface::mwi_q_lock, SMDI_MD, SMDI_MWI, and type.

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

Variable Documentation

◆ __mod_info

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_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static

Definition at line 1452 of file res_smdi.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1452 of file res_smdi.c.

◆ cond

ast_cond_t cond

Definition at line 211 of file res_smdi.c.

Referenced by smdi_message_wait().

◆ config_file

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

Definition at line 165 of file res_smdi.c.

Referenced by smdi_load().

◆ first

struct mailbox_mapping* first

Definition at line 213 of file res_smdi.c.

◆ last

struct mailbox_mapping* last

Definition at line 213 of file res_smdi.c.

◆ last_poll

struct timeval last_poll

The time that the last poll began

Definition at line 219 of file res_smdi.c.

◆ lock

Definition at line 210 of file res_smdi.c.

Referenced by smdi_message_wait().

◆ 

struct { ... } mailbox_mappings

A list of mailboxes that need to be monitored

◆ 

struct { ... } mwi_monitor
Initial value:
= {
.thread = AST_PTHREADT_NULL,
}

Data that gets used by the SMDI MWI monitoring thread.

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

◆ polling_interval

unsigned int polling_interval

Polling Interval for checking mailbox status

Definition at line 215 of file res_smdi.c.

◆ smdi_msg_datastore_info

const struct ast_datastore_info smdi_msg_datastore_info
static
Initial value:
= {
.type = "SMDIMSG",
}

Definition at line 1187 of file res_smdi.c.

Referenced by smdi_msg_read(), and smdi_msg_retrieve_read().

◆ smdi_msg_function

struct ast_custom_function smdi_msg_function
static
Initial value:
= {
.name = "SMDI_MSG",
.read = smdi_msg_read,
}
static int smdi_msg_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: res_smdi.c:1298

Definition at line 1375 of file res_smdi.c.

Referenced by load_module(), and unload_module().

◆ smdi_msg_id

int smdi_msg_id
static

Definition at line 1192 of file res_smdi.c.

Referenced by smdi_msg_retrieve_read().

◆ smdi_msg_ret_options

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

Definition at line 1200 of file res_smdi.c.

Referenced by smdi_msg_retrieve_read().

◆ smdi_msg_retrieve_function

struct ast_custom_function smdi_msg_retrieve_function
static
Initial value:
= {
.name = "SMDI_MSG_RETRIEVE",
}
static int smdi_msg_retrieve_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: res_smdi.c:1202

Definition at line 1370 of file res_smdi.c.

Referenced by load_module(), and unload_module().

◆ stop

unsigned int stop

Set to 1 to tell the polling thread to stop

Definition at line 217 of file res_smdi.c.

◆ thread

pthread_t thread

The thread ID

Definition at line 209 of file res_smdi.c.