Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 210 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 1201 of file res_smdi.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
OPT_SEARCH_TERMINAL 
OPT_SEARCH_NUMBER 

Definition at line 435 of file res_smdi.c.

435 {
436 OPT_SEARCH_TERMINAL = (1 << 0),
437 OPT_SEARCH_NUMBER = (1 << 1),
438};
@ OPT_SEARCH_NUMBER
Definition: res_smdi.c:437
@ OPT_SEARCH_TERMINAL
Definition: res_smdi.c:436

◆ smdi_message_type

Enumerator
SMDI_MWI 
SMDI_MD 

Definition at line 325 of file res_smdi.c.

325 {
326 SMDI_MWI,
327 SMDI_MD,
328};
@ SMDI_MWI
Definition: res_smdi.c:326
@ SMDI_MD
Definition: res_smdi.c:327

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1458 of file res_smdi.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1458 of file res_smdi.c.

◆ alloc_smdi_interface()

static struct ast_smdi_interface * alloc_smdi_interface ( void  )
static

Definition at line 920 of file res_smdi.c.

921{
922 struct ast_smdi_interface *iface;
923
924 if (!(iface = ao2_alloc(sizeof(*iface), smdi_interface_destroy))) {
925 return NULL;
926 }
927
930
931 ast_mutex_init(&iface->md_q_lock);
932 ast_cond_init(&iface->md_q_cond, NULL);
933
934 ast_mutex_init(&iface->mwi_q_lock);
935 ast_cond_init(&iface->mwi_q_cond, NULL);
936
937 return iface;
938}
@ 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:208
#define ast_mutex_init(pmutex)
Definition: lock.h:193
static int smdi_md_q_cmp_fn(void *obj, void *arg, int flags)
Definition: res_smdi.c:892
static void smdi_interface_destroy(void *obj)
Definition: res_smdi.c:230
static int smdi_mwi_q_cmp_fn(void *obj, void *data, int flags)
Definition: res_smdi.c:885
#define NULL
Definition: resample.c:96
ast_mutex_t md_q_lock
Definition: res_smdi.c:176
ast_mutex_t mwi_q_lock
Definition: res_smdi.c:179
ast_cond_t md_q_cond
Definition: res_smdi.c:177
struct ao2_container * mwi_q
Definition: res_smdi.c:178
ast_cond_t mwi_q_cond
Definition: res_smdi.c:180
struct ao2_container * md_q
Definition: res_smdi.c:175

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

812{
813 struct mailbox_mapping *mm;
814 char *mailbox, *context;
815
816 if (!(mm = ast_calloc_with_stringfields(1, struct mailbox_mapping, 32)))
817 return;
818
819 ast_string_field_set(mm, smdi, var->name);
820
821 context = ast_strdupa(var->value);
822 mailbox = strsep(&context, "@");
824 context = "default";
825
828
829 mm->iface = ao2_bump(iface);
830
832 AST_LIST_INSERT_TAIL(&mwi_monitor.mailbox_mappings, mm, entry);
834}
#define var
Definition: ast_expr2f.c:605
char * strsep(char **str, const char *delims)
#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
#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:197
#define ast_mutex_lock(a)
Definition: lock.h:196
static struct @478 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
A mapping between an SMDI mailbox ID and an Asterisk mailbox.
Definition: res_smdi.c:192
struct ast_smdi_interface * iface
Definition: res_smdi.c:197
const ast_string_field smdi
Definition: res_smdi.c:205
struct mailbox_mapping::@480 entry

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::entry, 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 1458 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 569 of file res_smdi.c.

570{
571 struct ao2_container *c;
572 struct ast_smdi_interface *iface = NULL;
573
574 c = ao2_global_obj_ref(smdi_ifaces);
575 if (c) {
576 iface = ao2_find(c, iface_name, OBJ_SEARCH_KEY);
577 ao2_ref(c, -1);
578 }
579
580 return iface;
581}
#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 540 of file res_smdi.c.

541{
542 return smdi_msg_pop(iface, SMDI_MD);
543}
static void * smdi_msg_pop(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:422

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

267{
268 ast_mutex_lock(&iface->md_q_lock);
269 ao2_link(iface->md_q, md_msg);
272}
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ast_cond_broadcast(cond)
Definition: lock.h:211

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

546{
547 struct ast_flags options = { 0 };
548 return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
549}
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:484
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 551 of file res_smdi.c.

552{
553 return smdi_msg_pop(iface, SMDI_MWI);
554}

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

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

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

564{
565 struct ast_flags options = { 0 };
566 return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
567}

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

316{
317 return smdi_toggle_mwi(iface, mailbox, 1);
318}
static int smdi_toggle_mwi(struct ast_smdi_interface *iface, const char *mailbox, int on)
Definition: res_smdi.c:288

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

321{
322 return smdi_toggle_mwi(iface, mailbox, 0);
323}

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

802{
803 struct mailbox_mapping *mm;
804
806 while ((mm = AST_LIST_REMOVE_HEAD(&mwi_monitor.mailbox_mappings, entry)))
809}
#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:794

References AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, destroy_mailbox_mapping(), mailbox_mapping::entry, 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 794 of file res_smdi.c.

795{
797 ao2_ref(mm->iface, -1);
798 ast_free(mm);
799}
#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 1417 of file res_smdi.c.

1418{
1419 int res;
1420
1423
1424 /* load the config and start the listener threads*/
1425 res = smdi_load(0);
1426 if (res < 0) {
1427 unload_module();
1429 } else if (res == 1) {
1430 ast_log(LOG_NOTICE, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
1431 }
1432
1435
1437}
#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:1559
static struct ast_custom_function smdi_msg_function
Definition: res_smdi.c:1381
static int unload_module(void)
Definition: res_smdi.c:1386
static struct ast_custom_function smdi_msg_retrieve_function
Definition: res_smdi.c:1376
static int smdi_load(int reload)
Definition: res_smdi.c:958

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

331{
332 switch (type) {
333 case SMDI_MWI:
334 return ast_mutex_lock(&iface->mwi_q_lock);
335 case SMDI_MD:
336 return ast_mutex_lock(&iface->md_q_lock);
337 }
338
339 return -1;
340}
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 366 of file res_smdi.c.

367{
368 struct ast_smdi_md_message *md_msg = msg;
369 struct ast_smdi_mwi_message *mwi_msg = msg;
370
371 switch (type) {
372 case SMDI_MWI:
373 return mwi_msg->timestamp;
374 case SMDI_MD:
375 return md_msg->timestamp;
376 }
377
378 return ast_tv(0, 0);
379}
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 ari_websocket_send_event(), and purge_old_messages().

◆ mwi_monitor_handler()

static void * mwi_monitor_handler ( void *  data)
static

Definition at line 858 of file res_smdi.c.

859{
860 while (!mwi_monitor.stop) {
861 struct timespec ts = { 0, };
862 struct timeval polltime;
863 struct mailbox_mapping *mm;
864
866
867 mwi_monitor.last_poll = ast_tvnow();
868
869 AST_LIST_TRAVERSE(&mwi_monitor.mailbox_mappings, mm, entry)
870 poll_mailbox(mm);
871
872 /* Sleep up to the configured polling interval. Allow unload_module()
873 * to signal us to wake up and exit. */
874 polltime = ast_tvadd(mwi_monitor.last_poll, ast_tv(mwi_monitor.polling_interval, 0));
875 ts.tv_sec = polltime.tv_sec;
876 ts.tv_nsec = polltime.tv_usec * 1000;
877 ast_cond_timedwait(&mwi_monitor.cond, &mwi_monitor.lock, &ts);
878
880 }
881
882 return NULL;
883}
#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:213
static void poll_mailbox(struct mailbox_mapping *mm)
Definition: res_smdi.c:839
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(), mailbox_mapping::entry, 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 839 of file res_smdi.c.

840{
841 char buf[1024];
842 unsigned int state;
843
844 snprintf(buf, sizeof(buf), "%s@%s", mm->mailbox, mm->context);
845
847
848 if (state != mm->cur_state) {
849 if (state)
850 ast_smdi_mwi_set(mm->iface, mm->smdi);
851 else
852 ast_smdi_mwi_unset(mm->iface, mm->smdi);
853
854 mm->cur_state = state;
855 }
856}
enum cc_state state
Definition: ccss.c:399
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:320
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:315
unsigned int cur_state
Definition: res_smdi.c:195
const ast_string_field context
Definition: res_smdi.c:205
const ast_string_field mailbox
Definition: res_smdi.c:205

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

382{
383 struct timeval now = ast_tvnow();
384 long elapsed = 0;
385 void *msg;
386
387 lock_msg_q(iface, type);
388 msg = unlink_from_msg_q(iface, type);
389 unlock_msg_q(iface, type);
390
391 /* purge old messages */
392 while (msg) {
393 elapsed = ast_tvdiff_ms(now, msg_timestamp(msg, type));
394
395 if (elapsed > iface->msg_expiry) {
396 /* found an expired message */
397 ao2_ref(msg, -1);
398 ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue. "
399 "Message was %ld milliseconds too old.\n",
400 iface->name, (type == SMDI_MD) ? "MD" : "MWI",
401 elapsed - iface->msg_expiry);
402
403 lock_msg_q(iface, type);
404 msg = unlink_from_msg_q(iface, type);
405 unlock_msg_q(iface, type);
406 } else {
407 /* good message, put it back and return */
408 switch (type) {
409 case SMDI_MD:
410 ast_smdi_md_message_push(iface, msg);
411 break;
412 case SMDI_MWI:
413 ast_smdi_mwi_message_push(iface, msg);
414 break;
415 }
416 ao2_ref(msg, -1);
417 break;
418 }
419 }
420}
static struct timeval msg_timestamp(void *msg, enum smdi_message_type type)
Definition: res_smdi.c:366
static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
Definition: res_smdi.c:266
static void ast_smdi_mwi_message_push(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
Definition: res_smdi.c:280
static int lock_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:330
static void * unlink_from_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:354
static int unlock_msg_q(struct ast_smdi_interface *iface, enum smdi_message_type type)
Definition: res_smdi.c:342
char name[SMDI_MAX_FILENAME_LEN]
Definition: res_smdi.c:174
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 1439 of file res_smdi.c.

1440{
1441 int res;
1442
1443 res = smdi_load(1);
1444 if (res < 0) {
1445 return res;
1446 } else if (res == 1) {
1447 ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
1448 }
1449 return 0;
1450}
#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 940 of file res_smdi.c.

941{
942 struct ast_smdi_interface *iface = obj;
943
944 char *str = data;
945 return !strcmp(iface->name, str) ? CMP_MATCH | CMP_STOP : 0;
946}
const char * str
Definition: app_jack.c:150
@ 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 230 of file res_smdi.c.

231{
232 struct ast_smdi_interface *iface = obj;
233 int mod_unref_defer = 0;
234
235 if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
236 pthread_cancel(iface->thread);
237 pthread_join(iface->thread, NULL);
238 mod_unref_defer = 1;
239 }
240
241 iface->thread = AST_PTHREADT_STOP;
242
243 if (iface->file) {
244 fclose(iface->file);
245 }
246
247 ao2_cleanup(iface->md_q);
250
251 ao2_cleanup(iface->mwi_q);
254
255 if (mod_unref_defer) {
257 }
258}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ast_cond_destroy(cond)
Definition: lock.h:209
#define AST_PTHREADT_NULL
Definition: lock.h:73
#define AST_PTHREADT_STOP
Definition: lock.h:74
#define ast_mutex_destroy(a)
Definition: lock.h:195
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483
struct ast_module * self
Definition: module.h:356
pthread_t thread
Definition: res_smdi.c:183

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

959{
960 struct ast_config *conf;
961 struct ast_variable *v;
962 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
963 int res = 0;
964 RAII_VAR(struct ao2_container *, new_ifaces, NULL, ao2_cleanup);
965 RAII_VAR(struct ao2_container *, old_ifaces, ao2_global_obj_ref(smdi_ifaces), ao2_cleanup);
966 struct ast_smdi_interface *mailbox_iface = NULL;
967
968 /* Config options */
969 speed_t baud_rate = B9600; /* 9600 baud rate */
970 tcflag_t paritybit = PARENB; /* even parity checking */
971 tcflag_t charsize = CS7; /* seven bit characters */
972 int stopbits = 0; /* One stop bit */
973
974 int msdstrip = 0; /* strip zero digits */
976
977 if (!(conf = ast_config_load(config_file, config_flags)) || conf == CONFIG_STATUS_FILEINVALID) {
978 if (reload)
979 ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
980 else
981 ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file);
982 return 1;
983 } else if (conf == CONFIG_STATUS_FILEUNCHANGED)
984 return 0;
985
987 if (!new_ifaces) {
989 return -1;
990 }
991
992 for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
993 RAII_VAR(struct ast_smdi_interface *, iface, NULL, ao2_cleanup);
994
995 if (!strcasecmp(v->name, "baudrate")) {
996 if (!strcasecmp(v->value, "9600"))
997 baud_rate = B9600;
998 else if (!strcasecmp(v->value, "4800"))
999 baud_rate = B4800;
1000 else if (!strcasecmp(v->value, "2400"))
1001 baud_rate = B2400;
1002 else if (!strcasecmp(v->value, "1200"))
1003 baud_rate = B1200;
1004 else {
1005 ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno);
1006 baud_rate = B9600;
1007 }
1008 } else if (!strcasecmp(v->name, "msdstrip")) {
1009 if (!sscanf(v->value, "%30d", &msdstrip)) {
1010 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
1011 msdstrip = 0;
1012 } else if (0 > msdstrip || msdstrip > 9) {
1013 ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
1014 msdstrip = 0;
1015 }
1016 } else if (!strcasecmp(v->name, "msgexpirytime")) {
1017 if (!sscanf(v->value, "%30ld", &msg_expiry)) {
1018 ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno);
1020 }
1021 } else if (!strcasecmp(v->name, "paritybit")) {
1022 if (!strcasecmp(v->value, "even"))
1023 paritybit = PARENB;
1024 else if (!strcasecmp(v->value, "odd"))
1025 paritybit = PARENB | PARODD;
1026 else if (!strcasecmp(v->value, "none"))
1027 paritybit = ~PARENB;
1028 else {
1029 ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno);
1030 paritybit = PARENB;
1031 }
1032 } else if (!strcasecmp(v->name, "charsize")) {
1033 if (!strcasecmp(v->value, "7"))
1034 charsize = CS7;
1035 else if (!strcasecmp(v->value, "8"))
1036 charsize = CS8;
1037 else {
1038 ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno);
1039 charsize = CS7;
1040 }
1041 } else if (!strcasecmp(v->name, "twostopbits")) {
1042 stopbits = ast_true(v->name);
1043 } else if (!strcasecmp(v->name, "smdiport")) {
1044 if (reload && old_ifaces) {
1045 /* we are reloading, check if we are already
1046 * monitoring this interface, if we are we do
1047 * not want to start it again. This also has
1048 * the side effect of not updating different
1049 * setting for the serial port, but it should
1050 * be trivial to rewrite this section so that
1051 * options on the port are changed without
1052 * restarting the interface. Or the interface
1053 * could be restarted with out emptying the
1054 * queue. */
1055 if ((iface = ao2_find(old_ifaces, v->value, OBJ_SEARCH_KEY))) {
1056 ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
1057 ao2_link(new_ifaces, iface);
1058 continue;
1059 }
1060 }
1061
1062 if (!(iface = alloc_smdi_interface()))
1063 continue;
1064
1065 ast_copy_string(iface->name, v->value, sizeof(iface->name));
1066
1067 iface->thread = AST_PTHREADT_NULL;
1068
1069 if (!(iface->file = fopen(iface->name, "r"))) {
1070 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
1071 continue;
1072 }
1073
1074 iface->fd = fileno(iface->file);
1075
1076 /* Set the proper attributes for our serial port. */
1077
1078 /* get the current attributes from the port */
1079 if (tcgetattr(iface->fd, &iface->mode)) {
1080 ast_log(LOG_ERROR, "Error getting attributes of %s (%s)\n", iface->name, strerror(errno));
1081 continue;
1082 }
1083
1084 /* set the desired speed */
1085 if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
1086 ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
1087 continue;
1088 }
1089
1090 /* set the stop bits */
1091 if (stopbits)
1092 iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */
1093 else
1094 iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */
1095
1096 /* set the parity */
1097 iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit;
1098
1099 /* set the character size */
1100 iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize;
1101
1102 /* commit the desired attributes */
1103 if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
1104 ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
1105 continue;
1106 }
1107
1108 /* set the msdstrip */
1109 iface->msdstrip = msdstrip;
1110
1111 /* set the message expiry time */
1112 iface->msg_expiry = msg_expiry;
1113
1114 /*
1115 * start the listener thread
1116 *
1117 * The listener thread does not actually hold a ref to iface. When all
1118 * external refs go away, the destructor will stop the listener thread
1119 * before actually destroying the iface object.
1120 */
1121 ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name);
1122 if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
1123 ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
1124 continue;
1125 }
1126
1127 ao2_link(new_ifaces, iface);
1129 } else {
1130 ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
1131 }
1132 }
1133
1135 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
1136
1137 for (v = ast_variable_browse(conf, "mailboxes"); v; v = v->next) {
1138 if (!strcasecmp(v->name, "smdiport")) {
1139 ao2_cleanup(mailbox_iface);
1140
1141 if (!(mailbox_iface = ao2_find(new_ifaces, v->value, OBJ_SEARCH_KEY))) {
1142 ast_log(LOG_NOTICE, "SMDI interface %s not found\n", v->value);
1143 continue;
1144 }
1145 } else if (!strcasecmp(v->name, "pollinginterval")) {
1146 if (sscanf(v->value, "%30u", &mwi_monitor.polling_interval) != 1) {
1147 ast_log(LOG_ERROR, "Invalid value for pollinginterval: %s\n", v->value);
1148 mwi_monitor.polling_interval = DEFAULT_POLLING_INTERVAL;
1149 }
1150 } else {
1151 if (!mailbox_iface) {
1152 ast_log(LOG_ERROR, "Mailbox mapping ignored, no valid SMDI interface specified in mailboxes section\n");
1153 continue;
1154 }
1155 append_mailbox_mapping(v, mailbox_iface);
1156 }
1157 }
1158 ao2_cleanup(mailbox_iface);
1159
1161
1162 ao2_global_obj_replace_unref(smdi_ifaces, new_ifaces);
1163
1164 if (!AST_LIST_EMPTY(&mwi_monitor.mailbox_mappings) && mwi_monitor.thread == AST_PTHREADT_NULL
1166 ast_log(LOG_ERROR, "Failed to start MWI monitoring thread. This module will not operate.\n");
1167 return -1;
1168 }
1169
1170 if (!ao2_container_count(new_ifaces)) {
1171 res = 1;
1172 }
1173
1174 return res;
1175}
@ 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.
@ CONFIG_FLAG_FILEUNCHANGED
#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
#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:457
#define SMDI_MSG_EXPIRY_TIME
Definition: res_smdi.c:69
static struct ast_smdi_interface * alloc_smdi_interface(void)
Definition: res_smdi.c:920
static int smdi_ifaces_cmp_fn(void *obj, void *data, int flags)
Definition: res_smdi.c:940
#define DEFAULT_POLLING_INTERVAL
Definition: res_smdi.c:210
static void * smdi_read(void *iface_p)
Definition: res_smdi.c:592
static void destroy_all_mailbox_mappings(void)
Definition: res_smdi.c:801
static void * mwi_monitor_handler(void *data)
Definition: res_smdi.c:858
static const char config_file[]
Definition: res_smdi.c:171
static int reload(void)
Definition: res_smdi.c:1439
static void append_mailbox_mapping(struct ast_variable *var, struct ast_smdi_interface *iface)
Definition: res_smdi.c:811
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 892 of file res_smdi.c.

893{
894 const struct ast_smdi_md_message *msg = obj;
895 const struct ast_smdi_md_message *search_msg = arg;
896 const char *search_key = arg;
897 int cmp = 0;
898
899 switch (flags & OBJ_SEARCH_MASK) {
901 if (!ast_strlen_zero(search_msg->mesg_desk_num)) {
902 cmp = strcmp(msg->mesg_desk_num, search_msg->mesg_desk_num);
903 }
904 if (!ast_strlen_zero(search_msg->mesg_desk_term)) {
905 cmp |= strcmp(msg->mesg_desk_term, search_msg->mesg_desk_term);
906 }
907 break;
908 case OBJ_SEARCH_KEY:
909 cmp = strcmp(msg->name, search_key);
910 break;
911 }
912
913 if (cmp) {
914 return 0;
915 }
916
917 return CMP_MATCH;
918}
@ 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 484 of file res_smdi.c.

486{
487 struct timeval start;
488 long diff = 0;
489 void *msg;
492
493 switch (type) {
494 case SMDI_MWI:
495 cond = &iface->mwi_q_cond;
496 lock = &iface->mwi_q_lock;
497 break;
498 case SMDI_MD:
499 cond = &iface->md_q_cond;
500 lock = &iface->md_q_lock;
501 break;
502 }
503
504 start = ast_tvnow();
505
506 while (diff < timeout) {
507 struct timespec ts = { 0, };
508 struct timeval wait;
509
510 lock_msg_q(iface, type);
511
512 if ((msg = smdi_msg_find(iface, type, search_key, options))) {
513 unlock_msg_q(iface, type);
514 return msg;
515 }
516
517 wait = ast_tvadd(start, ast_tv(0, timeout));
518 ts.tv_sec = wait.tv_sec;
519 ts.tv_nsec = wait.tv_usec * 1000;
520
521 /* If there were no messages in the queue, then go to sleep until one
522 * arrives. */
523
525
526 if ((msg = smdi_msg_find(iface, type, search_key, options))) {
527 unlock_msg_q(iface, type);
528 return msg;
529 }
530
531 unlock_msg_q(iface, type);
532
533 /* check timeout */
534 diff = ast_tvdiff_ms(ast_tvnow(), start);
535 }
536
537 return NULL;
538}
pthread_cond_t ast_cond_t
Definition: lock.h:185
ast_cond_t cond
Definition: res_smdi.c:217
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:440
ast_mutex_t lock
Definition: res_smdi.c:216
Structure for mutex and tracking information.
Definition: lock.h:142

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

1184{
1185 struct smdi_msg_datastore *smd = data;
1186
1187 ao2_cleanup(smd->iface);
1188 ao2_cleanup(smd->md_msg);
1189
1190 ast_free(smd);
1191}
struct ast_smdi_interface * iface
Definition: res_smdi.c:1179
struct ast_smdi_md_message * md_msg
Definition: res_smdi.c:1180

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

442{
443 void *msg = NULL;
444
445 purge_old_messages(iface, type);
446
447 switch (type) {
448 case SMDI_MD:
449 if (ast_strlen_zero(search_key)) {
450 /* No search key provided (the code from chan_dahdi does this).
451 * Just pop the top message off of the queue. */
452
453 msg = ao2_callback(iface->md_q, 0, NULL, NULL);
455 /* Searching by the message desk terminal */
456 struct ast_smdi_md_message md_msg = { .name = "" };
457 strncpy(md_msg.mesg_desk_term, search_key, SMDI_MESG_DESK_TERM_LEN);
458 msg = ao2_find(iface->md_q, &md_msg, OBJ_SEARCH_OBJECT);
460 /* Searching by the message desk number */
461 struct ast_smdi_md_message md_msg = { .name = "" };
462 strncpy(md_msg.mesg_desk_num, search_key, SMDI_MESG_DESK_NUM_LEN);
463 msg = ao2_find(iface->md_q, &md_msg, OBJ_SEARCH_OBJECT);
464 } else {
465 /* Searching by the forwarding station */
466 msg = ao2_find(iface->md_q, search_key, OBJ_SEARCH_KEY);
467 }
468 break;
469 case SMDI_MWI:
470 if (ast_strlen_zero(search_key)) {
471 /* No search key provided (the code from chan_dahdi does this).
472 * Just pop the top message off of the queue. */
473
474 msg = ao2_callback(iface->mwi_q, 0, NULL, NULL);
475 } else {
476 msg = ao2_find(iface->mwi_q, search_key, OBJ_SEARCH_KEY);
477 }
478 break;
479 }
480
481 return msg;
482}
#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:381
#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 422 of file res_smdi.c.

423{
424 void *msg;
425
426 purge_old_messages(iface, type);
427
428 lock_msg_q(iface, type);
429 msg = unlink_from_msg_q(iface, type);
430 unlock_msg_q(iface, type);
431
432 return msg;
433}

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

1305{
1306 struct ast_module_user *u;
1307 int res = -1;
1309 AST_APP_ARG(id);
1310 AST_APP_ARG(component);
1311 );
1312 char *parse;
1313 struct ast_datastore *datastore = NULL;
1314 struct smdi_msg_datastore *smd = NULL;
1315
1316 u = ast_module_user_add(chan);
1317
1318 if (!chan) {
1319 ast_log(LOG_ERROR, "SMDI_MSG can not be called without a channel\n");
1320 goto return_error;
1321 }
1322
1323 if (ast_strlen_zero(data)) {
1324 ast_log(LOG_WARNING, "SMDI_MSG requires an argument\n");
1325 goto return_error;
1326 }
1327
1328 parse = ast_strdupa(data);
1330
1331 if (ast_strlen_zero(args.id)) {
1332 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
1333 goto return_error;
1334 }
1335
1336 if (ast_strlen_zero(args.component)) {
1337 ast_log(LOG_WARNING, "ID must be supplied to SMDI_MSG\n");
1338 goto return_error;
1339 }
1340
1341 ast_channel_lock(chan);
1343 ast_channel_unlock(chan);
1344
1345 if (!datastore) {
1346 ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id);
1347 goto return_error;
1348 }
1349
1350 smd = datastore->data;
1351
1352 if (!strcasecmp(args.component, "number")) {
1354 } else if (!strcasecmp(args.component, "terminal")) {
1356 } else if (!strcasecmp(args.component, "station")) {
1358 } else if (!strcasecmp(args.component, "callerid")) {
1360 } else if (!strcasecmp(args.component, "type")) {
1361 snprintf(buf, len, "%c", smd->md_msg->type);
1362 } else {
1363 ast_log(LOG_ERROR, "'%s' is not a valid message component for SMDI_MSG\n",
1364 args.component);
1365 goto return_error;
1366 }
1367
1368 res = 0;
1369
1370return_error:
1372
1373 return res;
1374}
#define ast_channel_lock(chan)
Definition: channel.h:2972
#define ast_channel_unlock(chan)
Definition: channel.h:2973
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:2368
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:441
#define ast_module_user_add(chan)
Definition: module.h:440
static const struct ast_datastore_info smdi_msg_datastore_info
Definition: res_smdi.c:1193
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 1208 of file res_smdi.c.

1209{
1210 struct ast_module_user *u;
1212 AST_APP_ARG(port);
1213 AST_APP_ARG(search_key);
1214 AST_APP_ARG(timeout);
1216 );
1217 struct ast_flags options = { 0 };
1218 unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
1219 int res = -1;
1220 char *parse = NULL;
1221 struct smdi_msg_datastore *smd = NULL;
1222 struct ast_datastore *datastore = NULL;
1223 struct ast_smdi_interface *iface = NULL;
1224 struct ast_smdi_md_message *md_msg = NULL;
1225
1226 u = ast_module_user_add(chan);
1227
1228 if (ast_strlen_zero(data)) {
1229 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE requires an argument\n");
1230 goto return_error;
1231 }
1232
1233 if (!chan) {
1234 ast_log(LOG_ERROR, "SMDI_MSG_RETRIEVE must be used with a channel\n");
1235 goto return_error;
1236 }
1237
1239
1240 parse = ast_strdupa(data);
1242
1243 if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) {
1244 ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n");
1245 goto return_error;
1246 }
1247
1248 if (!(iface = ast_smdi_interface_find(args.port))) {
1249 ast_log(LOG_ERROR, "SMDI port '%s' not found\n", args.port);
1250 goto return_error;
1251 }
1252
1253 if (!ast_strlen_zero(args.options)) {
1255 }
1256
1257 if (!ast_strlen_zero(args.timeout)) {
1258 if (sscanf(args.timeout, "%30u", &timeout) != 1) {
1259 ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
1261 }
1262 }
1263
1264 if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) {
1265 ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after "
1266 "waiting %u ms.\n", args.search_key, timeout);
1267 goto return_error;
1268 }
1269
1270 if (!(smd = ast_calloc(1, sizeof(*smd))))
1271 goto return_error;
1272
1273 smd->iface = ao2_bump(iface);
1274 smd->md_msg = ao2_bump(md_msg);
1275 smd->id = ast_atomic_fetchadd_int((int *) &smdi_msg_id, 1);
1276 snprintf(buf, len, "%u", smd->id);
1277
1278 if (!(datastore = ast_datastore_alloc(&smdi_msg_datastore_info, buf)))
1279 goto return_error;
1280
1281 datastore->data = smd;
1282
1283 ast_channel_lock(chan);
1284 ast_channel_datastore_add(chan, datastore);
1285 ast_channel_unlock(chan);
1286
1287 res = 0;
1288
1289return_error:
1290 ao2_cleanup(iface);
1291 ao2_cleanup(md_msg);
1292
1293 if (smd && !datastore)
1295
1296 if (parse)
1298
1300
1301 return res;
1302}
#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:2354
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:3066
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:764
static const struct ast_app_option smdi_msg_ret_options[128]
Definition: res_smdi.c:1206
#define SMDI_RETRIEVE_TIMEOUT_DEFAULT
Definition: res_smdi.c:1201
static void smdi_msg_datastore_destroy(void *data)
Definition: res_smdi.c:1183
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:569
static int smdi_msg_id
Definition: res_smdi.c:1198
unsigned int id
Definition: res_smdi.c:1178

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

886{
887 struct ast_smdi_mwi_message *msg = obj;
888 char *str = data;
889 return !strcmp(msg->name, str) ? CMP_MATCH | CMP_STOP : 0;
890}
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 592 of file res_smdi.c.

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

289{
290 FILE *file;
291 int i;
292
293 if (!(file = fopen(iface->name, "w"))) {
294 ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
295 return 1;
296 }
297
298 ao2_wrlock(iface);
299
300 fprintf(file, "%s:MWI ", on ? "OP" : "RMV");
301
302 for (i = 0; i < iface->msdstrip; i++)
303 fprintf(file, "0");
304
305 fprintf(file, "%s!\x04", mailbox);
306
307 fclose(file);
308
309 ao2_unlock(iface);
310 ast_debug(1, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
311
312 return 0;
313}
#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 354 of file res_smdi.c.

355{
356 switch (type) {
357 case SMDI_MWI:
358 return ao2_callback(iface->mwi_q, OBJ_UNLINK, NULL, NULL);
359 case SMDI_MD:
360 return ao2_callback(iface->md_q, OBJ_UNLINK, NULL, NULL);
361 }
362
363 return NULL;
364}
@ 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 1386 of file res_smdi.c.

1387{
1388 ao2_global_obj_release(smdi_ifaces);
1389
1391
1393 mwi_monitor.stop = 1;
1396
1397 if (mwi_monitor.thread != AST_PTHREADT_NULL) {
1398 pthread_join(mwi_monitor.thread, NULL);
1399 }
1400
1403
1404 return 0;
1405}
#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:210
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 342 of file res_smdi.c.

343{
344 switch (type) {
345 case SMDI_MWI:
346 return ast_mutex_unlock(&iface->mwi_q_lock);
347 case SMDI_MD:
348 return ast_mutex_unlock(&iface->md_q_lock);
349 }
350
351 return -1;
352}

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

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1458 of file res_smdi.c.

◆ cond

ast_cond_t cond

Definition at line 217 of file res_smdi.c.

Referenced by smdi_message_wait().

◆ config_file

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

Definition at line 171 of file res_smdi.c.

Referenced by smdi_load().

◆ first

struct mailbox_mapping* first

Definition at line 219 of file res_smdi.c.

◆ last

struct mailbox_mapping* last

Definition at line 219 of file res_smdi.c.

◆ last_poll

struct timeval last_poll

The time that the last poll began

Definition at line 225 of file res_smdi.c.

◆ lock

Definition at line 216 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 221 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 1193 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:1304

Definition at line 1381 of file res_smdi.c.

Referenced by load_module(), and unload_module().

◆ smdi_msg_id

int smdi_msg_id
static

Definition at line 1198 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 1206 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:1208

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

◆ thread

pthread_t thread

The thread ID

Definition at line 215 of file res_smdi.c.