/*** MODULEINFO
<depend>res_adsi</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>dahdi</depend>
<support_level>deprecated</support_level>
+ <defaultenabled>no</defaultenabled>
<replacement>app_chanspy</replacement>
***/
/*** MODULEINFO
<depend>dahdi</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
<depend>jack</depend>
<depend>resample</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
+#include "asterisk/stringfields.h"
#include "asterisk/file.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/autochan.h"
#include "asterisk/manager.h"
+#include "asterisk/callerid.h"
/*** DOCUMENTATION
<application name="MixMonitor" language="en_US">
of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
<argument name="x" required="true" />
</option>
+ <option name="m">
+ <argument name="mailbox" required="true" />
+ <para>Create a copy of the recording as a voicemail in each indicated <emphasis>mailbox</emphasis>
+ separated by commas eg. m(1111@default,2222@default,...). Folders can be optionally specified using
+ the syntax: mailbox@context/folder</para>
+ <note><para>The recording will be deleted once all the copies are made.</para></note>
+ </option>
</optionlist>
</parameter>
<parameter name="command">
<para>This action may be used to mute a MixMonitor recording.</para>
</description>
</manager>
+ <manager name="MixMonitor" language="en_US">
+ <synopsis>
+ Record a call and mix the audio during the recording. Use of StopMixMonitor is required
+ to guarantee the audio file is available for processing during dialplan execution.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="Channel" required="true">
+ <para>Used to specify the channel to record.</para>
+ </parameter>
+ <parameter name="File">
+ <para>Is the name of the file created in the monitor spool directory.
+ Defaults to the same name as the channel (with slashes replaced with dashes).
+ This argument is optional if you specify to record unidirectional audio with
+ either the r(filename) or t(filename) options in the options field. If
+ neither MIXMONITOR_FILENAME or this parameter is set, the mixed stream won't
+ be recorded.</para>
+ </parameter>
+ <parameter name="options">
+ <para>Options that apply to the MixMonitor in the same way as they
+ would apply if invoked from the MixMonitor application. For a list of
+ available options, see the documentation for the mixmonitor application. </para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>This action records the audio on the current channel to the specified file.</para>
+ <variablelist>
+ <variable name="MIXMONITOR_FILENAME">
+ <para>Will contain the filename used to record the mixed stream.</para>
+ </variable>
+ </variablelist>
+ </description>
+ </manager>
+ <manager name="StopMixMonitor" language="en_US">
+ <synopsis>
+ Stop recording a call through MixMonitor, and free the recording's file handle.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="Channel" required="true">
+ <para>The name of the channel monitored.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>This action stops the audio recording that was started with the <literal>MixMonitor</literal>
+ action on the current channel.</para>
+ </description>
+ </manager>
***/
static const char * const mixmonitor_spy_type = "MixMonitor";
+/*!
+ * \internal
+ * \brief This struct is a list item holds data needed to find a vm_recipient within voicemail
+ */
+struct vm_recipient {
+ char mailbox[AST_MAX_CONTEXT];
+ char context[AST_MAX_EXTENSION];
+ char folder[80];
+ AST_LIST_ENTRY(vm_recipient) list;
+};
+
struct mixmonitor {
struct ast_audiohook audiohook;
char *filename;
unsigned int flags;
struct ast_autochan *autochan;
struct mixmonitor_ds *mixmonitor_ds;
+
+ /* the below string fields describe data used for creating voicemails from the recording */
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(call_context);
+ AST_STRING_FIELD(call_macrocontext);
+ AST_STRING_FIELD(call_extension);
+ AST_STRING_FIELD(call_callerchan);
+ AST_STRING_FIELD(call_callerid);
+ );
+ int call_priority;
+
+ /* FUTURE DEVELOPMENT NOTICE
+ * recipient_list will need locks if we make it editable after the monitor is started */
+ AST_LIST_HEAD_NOLOCK(, vm_recipient) recipient_list;
};
enum mixmonitor_flags {
MUXFLAG_VOLUME = (1 << 3),
MUXFLAG_READVOLUME = (1 << 4),
MUXFLAG_WRITEVOLUME = (1 << 5),
+ MUXFLAG_VMRECIPIENTS = (1 << 6),
};
enum mixmonitor_args {
OPT_ARG_READVOLUME = 0,
OPT_ARG_WRITEVOLUME,
OPT_ARG_VOLUME,
+ OPT_ARG_VMRECIPIENTS,
OPT_ARG_ARRAY_SIZE,
};
AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
+ AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS),
});
struct mixmonitor_ds {
return res;
}
+/*!
+ * \internal
+ * \brief adds recipients to a mixmonitor's recipient list
+ * \param mixmonitor mixmonitor being affected
+ * \param vm_recipients string containing the desired recipients to add
+ */
+static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
+{
+ /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
+ char *cur_mailbox = ast_strdupa(vm_recipients);
+ char *cur_context;
+ char *cur_folder;
+ char *next;
+ int elements_processed = 0;
+
+ while (!ast_strlen_zero(cur_mailbox)) {
+ ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
+ if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
+ *(next++) = '\0';
+ }
+
+ if ((cur_folder = strchr(cur_mailbox, '/'))) {
+ *(cur_folder++) = '\0';
+ } else {
+ cur_folder = "INBOX";
+ }
+
+ if ((cur_context = strchr(cur_mailbox, '@'))) {
+ *(cur_context++) = '\0';
+ } else {
+ cur_context = "default";
+ }
+
+ if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
+ struct vm_recipient *recipient;
+ if (!(recipient = ast_malloc(sizeof(*recipient)))) {
+ ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
+ return;
+ }
+ ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
+ ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
+ ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
+
+ /* Add to list */
+ ast_verb(5, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
+ AST_LIST_INSERT_HEAD(&mixmonitor->recipient_list, recipient, list);
+ } else {
+ ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
+ }
+
+ cur_mailbox = next;
+ elements_processed++;
+ }
+}
+
+static void clear_mixmonitor_recipient_list(struct mixmonitor *mixmonitor)
+{
+ struct vm_recipient *current;
+ while ((current = AST_LIST_REMOVE_HEAD(&mixmonitor->recipient_list, list))) {
+ /* Clear list element data */
+ ast_free(current);
+ }
+}
+
#define SAMPLES_PER_FRAME 160
static void mixmonitor_free(struct mixmonitor *mixmonitor)
ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
ast_free(mixmonitor->mixmonitor_ds);
}
+
+ /* Free everything in the recipient list */
+ clear_mixmonitor_recipient_list(mixmonitor);
+
+ /* clean stringfields */
+ ast_string_field_free_memory(mixmonitor);
+
ast_free(mixmonitor);
}
}
+
+/*!
+ * \internal
+ * \brief Copies the mixmonitor to all voicemail recipients
+ * \param mixmonitor The mixmonitor that needs to forward its file to recipients
+ * \param ext Format of the file that was saved
+ */
+static void copy_to_voicemail(struct mixmonitor *mixmonitor, char *ext)
+{
+ struct vm_recipient *recipient = NULL;
+ struct ast_vm_recording_data recording_data;
+ char filename[PATH_MAX];
+
+ if (ast_string_field_init(&recording_data, 512)) {
+ ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
+ return;
+ }
+
+ /* Copy strings to stringfields that will be used for all recipients */
+ ast_string_field_set(&recording_data, recording_file, mixmonitor->filename);
+ ast_string_field_set(&recording_data, recording_ext, ext);
+ ast_string_field_set(&recording_data, call_context, mixmonitor->call_context);
+ ast_string_field_set(&recording_data, call_macrocontext, mixmonitor->call_macrocontext);
+ ast_string_field_set(&recording_data, call_extension, mixmonitor->call_extension);
+ ast_string_field_set(&recording_data, call_callerchan, mixmonitor->call_callerchan);
+ ast_string_field_set(&recording_data, call_callerid, mixmonitor->call_callerid);
+ /* and call_priority gets copied too */
+ recording_data.call_priority = mixmonitor->call_priority;
+
+ AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
+ /* context, mailbox, and folder need to be set per recipient */
+ ast_string_field_set(&recording_data, context, recipient->context);
+ ast_string_field_set(&recording_data, mailbox, recipient->mailbox);
+ ast_string_field_set(&recording_data, folder, recipient->folder);
+
+ ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
+ recording_data.context);
+ ast_app_copy_recording_to_vm(&recording_data);
+ }
+
+ /* Delete the source file */
+ snprintf(filename, sizeof(filename), "%s.%s", mixmonitor->filename, ext);
+ if (remove(filename)) {
+ ast_log(LOG_ERROR, "Failed to delete recording source file %s\n", filename);
+ }
+
+ /* Free the string fields for recording_data before exiting the function. */
+ ast_string_field_free_memory(&recording_data);
+}
+
static void *mixmonitor_thread(void *obj)
{
struct mixmonitor *mixmonitor = obj;
struct ast_filestream **fs = NULL;
unsigned int oflags;
- char *ext;
+ char *ext = "";
char *last_slash;
int errflag = 0;
}
ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
+
+ if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) {
+ if (ast_strlen_zero(ext)) {
+ ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
+ mixmonitor -> name);
+ } else {
+ ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
+ copy_to_voicemail(mixmonitor, ext);
+ }
+ } else {
+ ast_debug(3, "No recipients to forward monitor to, moving on.\n");
+ }
+
mixmonitor_free(mixmonitor);
return NULL;
}
}
static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
- int readvol, int writevol, const char *post_process)
+ int readvol, int writevol, const char *post_process, const char *recipients)
{
pthread_t thread;
struct mixmonitor *mixmonitor;
return;
}
+ /* Now that the struct has been calloced, go ahead and initialize the string fields. */
+ if (ast_string_field_init(mixmonitor, 512)) {
+ mixmonitor_free(mixmonitor);
+ return;
+ }
+
/* Setup the actual spy before creating our thread */
if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
mixmonitor_free(mixmonitor);
strcpy(mixmonitor->post_process, postprocess2);
}
+ if (!ast_strlen_zero(recipients)) {
+ char callerid[256];
+
+ ast_channel_lock(chan);
+
+ /* We use the connected line of the invoking channel for caller ID. */
+ ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", chan->connected.id.name.valid,
+ chan->connected.id.name.str, chan->connected.id.number.valid,
+ chan->connected.id.number.str);
+ ast_callerid_merge(callerid, sizeof(callerid),
+ S_COR(chan->connected.id.name.valid, chan->connected.id.name.str, NULL),
+ S_COR(chan->connected.id.number.valid, chan->connected.id.number.str, NULL),
+ "Unknown");
+
+ ast_string_field_set(mixmonitor, call_context, chan->context);
+ ast_string_field_set(mixmonitor, call_macrocontext, chan->macrocontext);
+ ast_string_field_set(mixmonitor, call_extension, chan->exten);
+ ast_string_field_set(mixmonitor, call_callerchan, chan->name);
+ ast_string_field_set(mixmonitor, call_callerid, callerid);
+ mixmonitor->call_priority = chan->priority;
+
+ ast_channel_unlock(chan);
+
+ add_vm_recipients_from_string(mixmonitor, recipients);
+ }
+
mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
strcpy(mixmonitor->filename, filename);
{
int x, readvol = 0, writevol = 0;
struct ast_flags flags = {0};
+ char *recipients = NULL;
char *parse, *tmp, *slash;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filename);
readvol = writevol = get_volfactor(x);
}
}
+
+ if (ast_test_flag(&flags, MUXFLAG_VMRECIPIENTS)) {
+ if (ast_strlen_zero(opts[OPT_ARG_VMRECIPIENTS])) {
+ ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
+ } else {
+ recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
+ }
+ }
}
/* if not provided an absolute path, use the system-configured monitoring directory */
ast_mkdir(tmp, 0777);
pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
- launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
+ launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process, recipients);
return 0;
}
return AMI_SUCCESS;
}
+static int manager_mixmonitor(struct mansession *s, const struct message *m)
+{
+ struct ast_channel *c = NULL;
+
+ const char *name = astman_get_header(m, "Channel");
+ const char *id = astman_get_header(m, "ActionID");
+ const char *file = astman_get_header(m, "File");
+ const char *options = astman_get_header(m, "Options");
+
+ int res;
+ char args[PATH_MAX] = "";
+ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "No channel specified");
+ return AMI_SUCCESS;
+ }
+
+ c = ast_channel_get_by_name(name);
+
+ if (!c) {
+ astman_send_error(s, m, "No such channel");
+ return AMI_SUCCESS;
+ }
+
+ strcpy(args, file);
+ strcat(args, ",");
+ strcat(args, options);
+
+ ast_channel_lock(c);
+ res = mixmonitor_exec(c, args);
+ ast_channel_unlock(c);
+
+ if (res) {
+ astman_send_error(s, m, "Could not start monitoring channel");
+ return AMI_SUCCESS;
+ }
+
+ astman_append(s, "Response: Success\r\n");
+
+ if (!ast_strlen_zero(id)) {
+ astman_append(s, "ActionID: %s\r\n", id);
+ }
+
+ astman_append(s, "\r\n");
+
+ c = ast_channel_unref(c);
+
+ return AMI_SUCCESS;
+}
+
+static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
+{
+ struct ast_channel *c = NULL;
+
+ const char *name = astman_get_header(m, "Channel");
+ const char *id = astman_get_header(m, "ActionID");
+
+ int res;
+ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "No channel specified");
+ return AMI_SUCCESS;
+ }
+
+ c = ast_channel_get_by_name(name);
+
+ if (!c) {
+ astman_send_error(s, m, "No such channel");
+ return AMI_SUCCESS;
+ }
+
+ res = stop_mixmonitor_exec(c, NULL);
+
+ if (res) {
+ astman_send_error(s, m, "Could not stop monitoring channel");
+ return AMI_SUCCESS;
+ }
+
+ astman_append(s, "Response: Success\r\n");
+
+ if (!ast_strlen_zero(id)) {
+ astman_append(s, "ActionID: %s\r\n", id);
+ }
+
+ astman_append(s, "\r\n");
+
+ c = ast_channel_unref(c);
+
+ return AMI_SUCCESS;
+}
+
static struct ast_cli_entry cli_mixmonitor[] = {
AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
};
res = ast_unregister_application(stop_app);
res |= ast_unregister_application(app);
res |= ast_manager_unregister("MixMonitorMute");
+ res |= ast_manager_unregister("MixMonitor");
+ res |= ast_manager_unregister("StopMixMonitor");
return res;
}
res = ast_register_application_xml(app, mixmonitor_exec);
res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
+ res |= ast_manager_register_xml("MixMonitor", 0, manager_mixmonitor);
+ res |= ast_manager_register_xml("StopMixMonitor", 0, manager_stop_mixmonitor);
return res;
}
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
<depend>osptk</depend>
<depend>openssl</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
return state;
}
-static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
+static int extension_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
{
struct ao2_iterator miter, qiter;
struct member *m;
struct call_queue *q;
+ int state = info->exten_state;
int found = 0, device_state = extensionstate2devicestate(state);
+ /* only interested in extension state updates involving device states */
+ if (info->reason != AST_HINT_UPDATE_DEVICE) {
+ return 0;
+ }
+
qiter = ao2_iterator_init(queues, 0);
while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
ao2_lock(q);
/*** MODULEINFO
<support_level>deprecated</support_level>
+ <defaultenabled>no</defaultenabled>
<replacement>func_env (FILE())</replacement>
***/
/*** MODULEINFO
<support_level>deprecated</support_level>
+ <defaultenabled>no</defaultenabled>
<replacement>func_callerid</replacement>
***/
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/stringfields.h"
+#include "asterisk/strings.h"
#include "asterisk/smdi.h"
#include "asterisk/astobj2.h"
#include "asterisk/event.h"
</enumlist>
</description>
</application>
+ <application name="VoiceMailPlayMsg" language="en_US">
+ <synopsis>
+ Play a single voice mail msg from a mailbox by msg id.
+ </synopsis>
+ <syntax>
+ <parameter name="mailbox" required="true" argsep="@">
+ <argument name="mailbox" />
+ <argument name="context" />
+ </parameter>
+ <parameter name="msg_id" required="true">
+ <para>The msg id of the msg to play back. </para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>This application sets the following channel variable upon completion:</para>
+ <variablelist>
+ <variable name="VOICEMAIL_PLAYBACKSTATUS">
+ <para>The status of the playback attempt as a text string.</para>
+ <value name="SUCCESS"/>
+ <value name="FAILED"/>
+ </variable>
+ </variablelist>
+ </description>
+ </application>
<application name="VMSayName" language="en_US">
<synopsis>
Play the name of a voicemail user
#define ERROR_LOCK_PATH -100
#define OPERATOR_EXIT 300
-
enum vm_box {
NEW_FOLDER,
OLD_FOLDER,
AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
});
+static const char * const mailbox_folders[] = {
+#ifdef IMAP_STORAGE
+ imapfolder,
+#else
+ "INBOX",
+#endif
+ "Old",
+ "Work",
+ "Family",
+ "Friends",
+ "Cust1",
+ "Cust2",
+ "Cust3",
+ "Cust4",
+ "Cust5",
+ "Deleted",
+ "Urgent",
+};
+
static int load_config(int reload);
#ifdef TEST_FRAMEWORK
static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
static char *app3 = "MailboxExists";
static char *app4 = "VMAuthenticate";
+static char *playmsg_app = "VoiceMailPlayMsg";
+
static char *sayname_app = "VMSayName";
static AST_LIST_HEAD_STATIC(users, ast_vm_user);
static const char *substitute_escapes(const char *value);
static void free_user(struct ast_vm_user *vmu);
+static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD);
+static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot);
+
+static int vm_msg_forward(const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, int *msg_ids, int delete_old);
+static int vm_msg_move(const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, int *old_msg_nums, const char *newfolder, int *new_msg_nums);
+static int vm_msg_remove(const char *mailbox, const char *context, size_t num_msgs, const char *folder, int *msgs);
+static int vm_msg_play(struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb cb);
+
+#ifdef TEST_FRAMEWORK
+static int vm_test_destroy_user(const char *context, const char *mailbox);
+static int vm_test_create_user(const char *context, const char *mailbox);
+#endif
+
struct ao2_container *inprocess_container;
struct inprocess {
return 0;
}
-static const char * const mailbox_folders[] = {
-#ifdef IMAP_STORAGE
- imapfolder,
-#else
- "INBOX",
-#endif
- "Old",
- "Work",
- "Family",
- "Friends",
- "Cust1",
- "Cust2",
- "Cust3",
- "Cust4",
- "Cust5",
- "Deleted",
- "Urgent",
-};
-
static const char *mbox(struct ast_vm_user *vmu, int id)
{
#ifdef IMAP_STORAGE
return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
}
+static const char *vm_index_to_foldername(int id)
+{
+ return mbox(NULL, id);
+}
+
+
static int get_folder_by_name(const char *name)
{
size_t i;
check_quota(vms, vmu->imapfolder);
if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
- ast_play_and_wait(chan, "vm-mailboxfull");
+ if (chan) {
+ ast_play_and_wait(chan, "vm-mailboxfull");
+ }
return -1;
}
ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
- ast_play_and_wait(chan, "vm-mailboxfull");
- pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
+ if (chan) {
+ ast_play_and_wait(chan, "vm-mailboxfull");
+ pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
+ }
return -1;
}
}
make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
- S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
- S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
+ chan ? S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL) : NULL,
+ chan ? S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL) : NULL,
fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
/* read mail file to memory */
len = ftell(p);
*
* \return zero on success, -1 on error.
*/
-static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, char *flag)
+static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, char *flag, const char *dest_folder)
{
struct vm_state *sendvms = NULL, *destvms = NULL;
char messagestring[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/
}
snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
ast_mutex_lock(&sendvms->lock);
- if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
+ if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, dest_folder)) == T)) {
ast_mutex_unlock(&sendvms->lock);
return 0;
}
#endif
/* flag added for Urgent */
fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
- fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
- fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
+ fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan ? chan->priority : 0);
+ fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan ? chan->name : "");
fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
*
* \return zero on success, -1 on error.
*/
-static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, const char *flag)
+static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, const char *flag, const char *dest_folder)
{
char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
const char *frombox = mbox(vmu, imbox);
if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) { /* If urgent, copy to Urgent folder */
userfolder = "Urgent";
+ } else if (!ast_strlen_zero(dest_folder)) {
+ userfolder = dest_folder;
} else {
userfolder = "INBOX";
}
if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
make_file(topath, sizeof(topath), todir, recipmsgnum);
#ifndef ODBC_STORAGE
- if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
+ if (EXISTS(fromdir, msgnum, frompath, chan ? chan->language : "")) {
COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
} else {
#endif
res = -1;
}
ast_unlock_path(todir);
- notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
- S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
- S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
- flag);
-
+ if (chan) {
+ notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
+ S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
+ S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
+ flag);
+ }
return res;
}
#endif
char *exitcontext;
};
+/*!
+ * \internal
+ * \brief Creates a voicemail based on a specified file to a mailbox.
+ * \param recdata A vm_recording_data containing filename and voicemail txt info.
+ * \retval -1 failure
+ * \retval 0 success
+ *
+ * This is installed to the app.h voicemail functions and accommodates all voicemail
+ * storage methods. It should probably be broken out along with leave_voicemail at
+ * some point in the future.
+ *
+ * This function currently only works for a single recipient and only uses the format
+ * specified in recording_ext.
+ */
+static int msg_create_from_file(struct ast_vm_recording_data *recdata)
+{
+ /* voicemail recipient structure */
+ struct ast_vm_user *recipient; /* points to svm once it's been created */
+ struct ast_vm_user svm; /* struct storing the voicemail recipient */
+
+ /* File paths */
+ char tmpdir[PATH_MAX]; /* directory temp files are stored in */
+ char tmptxtfile[PATH_MAX]; /* tmp file for voicemail txt file */
+ char desttxtfile[PATH_MAX]; /* final destination for txt file */
+ char tmpaudiofile[PATH_MAX]; /* tmp file where audio is stored */
+ char dir[PATH_MAX]; /* destination for tmp files on completion */
+ char destination[PATH_MAX]; /* destination with msgXXXX. Basically <dir>/msgXXXX */
+
+ /* stuff that only seems to be needed for IMAP */
+ #ifdef IMAP_STORAGE
+ struct vm_state *vms = NULL;
+ char ext_context[256] = "";
+ char *fmt = ast_strdupa(recdata->recording_ext);
+ int newmsgs = 0;
+ int oldmsgs = 0;
+ #endif
+
+ /* miscellaneous operational variables */
+ int res = 0; /* Used to store error codes from functions */
+ int txtdes /* File descriptor for the text file used to write the voicemail info */;
+ FILE *txt; /* FILE pointer to text file used to write the voicemail info */
+ char date[256]; /* string used to hold date of the voicemail (only used for ODBC) */
+ int msgnum; /* the 4 digit number designated to the voicemail */
+ int duration = 0; /* Length of the audio being recorded in seconds */
+ struct ast_filestream *recording_fs; /*used to read the recording to get duration data */
+
+ /* We aren't currently doing anything with category, since it comes from a channel variable and
+ * this function doesn't use channels, but this function could add that as an argument later. */
+ const char *category = NULL; /* pointless for now */
+
+ /* Start by checking to see if the file actually exists... */
+ if (!(ast_fileexists(recdata->recording_file, recdata->recording_ext, NULL))) {
+ ast_log(LOG_ERROR, "File: %s not found.\n", recdata->recording_file);
+ return -1;
+ }
+
+ if (!(recipient = find_user(&svm, recdata->context, recdata->mailbox))) {
+ ast_log(LOG_ERROR, "No entry in voicemail config file for '%s@%s'\n", recdata->mailbox, recdata->context);
+ return -1;
+ }
+
+ /* determine duration in seconds */
+ if ((recording_fs = ast_readfile(recdata->recording_file, recdata->recording_ext, NULL, 0, 0, VOICEMAIL_DIR_MODE))) {
+ if (!ast_seekstream(recording_fs, 0, SEEK_END)) {
+ long framelength = ast_tellstream(recording_fs);
+ duration = (int) (framelength / ast_format_rate(ast_getformatbyname(recdata->recording_ext)));
+ }
+ }
+
+ /* If the duration was below the minimum duration for the user, let's just drop the whole thing now */
+ if (duration < recipient->minsecs) {
+ ast_log(LOG_NOTICE, "Copying recording to voicemail %s@%s skipped because duration was shorter than "
+ "minmessage of recipient\n", recdata->mailbox, recdata->context);
+ return -1;
+ }
+
+ /* Note that this number must be dropped back to a net sum of zero before returning from this function */
+
+ if ((res = create_dirpath(tmpdir, sizeof(tmpdir), recipient->context, recdata->mailbox, "tmp"))) {
+ ast_log(LOG_ERROR, "Failed to make directory.\n");
+ }
+
+ snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
+ txtdes = mkstemp(tmptxtfile);
+ if (txtdes < 0) {
+ chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
+ /* Something screwed up. Abort. */
+ ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
+ free_user(recipient);
+ return -1;
+ }
+
+ /* Store information */
+ txt = fdopen(txtdes, "w+");
+ if (txt) {
+ char msg_id[256];
+ char msg_id_hash[256];
+
+ /* Every voicemail msg gets its own unique msg id. The msg id is the originate time
+ * plus a hash of the extension, context, and callerid of the channel leaving the msg */
+
+ snprintf(msg_id_hash, sizeof(msg_id_hash), "%s%s%s", recdata->call_extension,
+ recdata->call_context, recdata->call_callerid);
+ snprintf(msg_id, sizeof(msg_id), "%ld-%d", (long) time(NULL), ast_str_hash(msg_id_hash));
+
+ get_date(date, sizeof(date));
+ fprintf(txt,
+ ";\n"
+ "; Message Information file\n"
+ ";\n"
+ "[message]\n"
+ "origmailbox=%s\n"
+ "context=%s\n"
+ "macrocontext=%s\n"
+ "exten=%s\n"
+ "rdnis=Unknown\n"
+ "priority=%d\n"
+ "callerchan=%s\n"
+ "callerid=%s\n"
+ "origdate=%s\n"
+ "origtime=%ld\n"
+ "category=%s\n"
+ "msg_id=%s\n"
+ "flag=\n" /* flags not supported in copy from file yet */
+ "duration=%d\n", /* Don't have any reliable way to get duration of file. */
+
+ recdata->mailbox,
+ S_OR(recdata->call_context, ""),
+ S_OR(recdata->call_macrocontext, ""),
+ S_OR(recdata->call_extension, ""),
+ recdata->call_priority,
+ S_OR(recdata->call_callerchan, "Unknown"),
+ S_OR(recdata->call_callerid, "Unknown"),
+ date, (long) time(NULL),
+ S_OR(category, ""),
+ msg_id,
+ duration);
+
+ /* Since we are recording from a file, we shouldn't need to do anything else with
+ * this txt file */
+ fclose(txt);
+
+ } else {
+ ast_log(LOG_WARNING, "Error opening text file for output\n");
+ if (ast_check_realtime("voicemail_data")) {
+ ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
+ }
+ free_user(recipient);
+ return -1;
+ }
+
+ /* At this point, the actual creation of a voicemail message should be finished.
+ * Now we just need to copy the files being recorded into the receiving folder. */
+
+ create_dirpath(dir, sizeof(dir), recipient->context, recipient->mailbox, recdata->folder);
+
+#ifdef IMAP_STORAGE
+ /* make recipient info into an inboxcount friendly string */
+ snprintf(ext_context, sizeof(ext_context), "%s@%s", recipient->mailbox, recipient->context);
+
+ /* Is ext a mailbox? */
+ /* must open stream for this user to get info! */
+ res = inboxcount(ext_context, &newmsgs, &oldmsgs);
+ if (res < 0) {
+ ast_log(LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
+ free_user(recipient);
+ unlink(tmptxtfile);
+ return -1;
+ }
+ if (!(vms = get_vm_state_by_mailbox(recipient->mailbox, recipient->context, 0))) {
+ /* It is possible under certain circumstances that inboxcount did not
+ * create a vm_state when it was needed. This is a catchall which will
+ * rarely be used.
+ */
+ if (!(vms = create_vm_state_from_user(recipient))) {
+ ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
+ free_user(recipient);
+ unlink(tmptxtfile);
+ return -1;
+ }
+ }
+ vms->newmessages++;
+
+ /* here is a big difference! We add one to it later */
+ msgnum = newmsgs + oldmsgs;
+ ast_debug(3, "Messagecount set to %d\n", msgnum);
+ snprintf(destination, sizeof(destination), "%simap/msg%s%04d", VM_SPOOL_DIR, recipient->mailbox, msgnum);
+
+ /* Check to see if we have enough room in the mailbox. If not, spit out an error and end
+ * Note that imap_check_limits raises inprocess_count if successful */
+ if ((res = imap_check_limits(NULL, vms, recipient, msgnum))) {
+ ast_log(LOG_NOTICE, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
+ inprocess_count(recipient->mailbox, recipient->context, -1);
+ free_user(recipient);
+ unlink(tmptxtfile);
+ return -1;
+ }
+
+#else
+
+ /* Check to see if the mailbox is full for ODBC/File storage */
+ ast_debug(3, "mailbox = %d : inprocess = %d\n", count_messages(recipient, dir),
+ inprocess_count(recipient->mailbox, recipient->context, 0));
+ if (count_messages(recipient, dir) > recipient->maxmsg - inprocess_count(recipient->mailbox, recipient->context, +1)) {
+ ast_log(AST_LOG_WARNING, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
+ inprocess_count(recipient->mailbox, recipient->context, -1);
+ free_user(recipient);
+ unlink(tmptxtfile);
+ return -1;
+ }
+
+ msgnum = last_message_index(recipient, dir) + 1;
+#endif
+
+ /* Lock the directory receiving the voicemail since we want it to still exist when we attempt to copy the voicemail.
+ * We need to unlock it before we return. */
+ if (vm_lock_path(dir)) {
+ ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
+ /* Delete files */
+ ast_filedelete(tmptxtfile, NULL);
+ unlink(tmptxtfile);
+ free_user(recipient);
+ return -1;
+ }
+
+ make_file(destination, sizeof(destination), dir, msgnum);
+
+ make_file(tmpaudiofile, sizeof(tmpaudiofile), tmpdir, msgnum);
+
+ if (ast_filecopy(recdata->recording_file, tmpaudiofile, recdata->recording_ext)) {
+ ast_log(LOG_ERROR, "Audio file failed to copy to tmp dir. Probably low disk space.\n");
+
+ inprocess_count(recipient->mailbox, recipient->context, -1);
+ ast_unlock_path(dir);
+ free_user(recipient);
+ unlink(tmptxtfile);
+ return -1;
+ }
+
+ /* Alright, try to copy to the destination folder now. */
+ if (ast_filerename(tmpaudiofile, destination, recdata->recording_ext)) {
+ ast_log(LOG_ERROR, "Audio file failed to move to destination directory. Permissions/Overlap?\n");
+ inprocess_count(recipient->mailbox, recipient->context, -1);
+ ast_unlock_path(dir);
+ free_user(recipient);
+ unlink(tmptxtfile);
+ return -1;
+ }
+
+ snprintf(desttxtfile, sizeof(desttxtfile), "%s.txt", destination);
+ rename(tmptxtfile, desttxtfile);
+
+ if (chmod(desttxtfile, VOICEMAIL_FILE_MODE) < 0) {
+ ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", desttxtfile, strerror(errno));
+ }
+
+
+ ast_unlock_path(dir);
+ inprocess_count(recipient->mailbox, recipient->context, -1);
+
+ /* If we copied something, we should store it either to ODBC or IMAP if we are using those. The STORE macro allows us
+ * to do both with one line and is also safe to use with file storage mode. Also, if we are using ODBC, now is a good
+ * time to create the voicemail database entry. */
+ if (ast_fileexists(destination, NULL, NULL) > 0) {
+ if (ast_check_realtime("voicemail_data")) {
+ get_date(date, sizeof(date));
+ ast_store_realtime("voicemail_data",
+ "origmailbox", recdata->mailbox,
+ "context", S_OR(recdata->context, ""),
+ "macrocontext", S_OR(recdata->call_macrocontext, ""),
+ "exten", S_OR(recdata->call_extension, ""),
+ "priority", recdata->call_priority,
+ "callerchan", S_OR(recdata->call_callerchan, "Unknown"),
+ "callerid", S_OR(recdata->call_callerid, "Unknown"),
+ "origdate", date,
+ "origtime", time(NULL),
+ "category", S_OR(category, ""),
+ "filename", tmptxtfile,
+ "duration", duration,
+ SENTINEL);
+ }
+
+ STORE(dir, recipient->mailbox, recipient->context, msgnum, NULL, recipient, fmt, 0, vms, "");
+ }
+
+ free_user(recipient);
+ unlink(tmptxtfile);
+ return 0;
+}
+
/*!
* \brief Prompts the user and records a voicemail to a mailbox.
* \param chan
if (ast_exists_extension(chan, vmu->exit, "o", 1,
S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
- ouseexten = 1;
+ ouseexten = 1;
}
} else if (ast_exists_extension(chan, chan->context, "o", 1,
S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
/* Store information */
txt = fdopen(txtdes, "w+");
if (txt) {
+ char msg_id[256] = "";
+ char msg_id_hash[256] = "";
+
+ /* Every voicemail msg gets its own unique msg id. The msg id is the originate time
+ * plus a hash of the extension, context, and callerid of the channel leaving the msg */
+ snprintf(msg_id_hash, sizeof(msg_id_hash), "%s%s%s", chan->exten, chan->context, callerid);
+ snprintf(msg_id, sizeof(msg_id), "%ld-%d", (long) time(NULL), ast_str_hash(msg_id_hash));
+
get_date(date, sizeof(date));
ast_callerid_merge(callerid, sizeof(callerid),
S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
"callerid=%s\n"
"origdate=%s\n"
"origtime=%ld\n"
- "category=%s\n",
+ "category=%s\n"
+ "msg_id=%s\n",
ext,
chan->context,
chan->macrocontext,
chan->name,
callerid,
date, (long) time(NULL),
- category ? category : "");
+ category ? category : "",
+ msg_id);
} else {
ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
inprocess_count(vmu->mailbox, vmu->context, -1);
cntx++;
}
if ((recip = find_user(&recipu, cntx, exten))) {
- copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
+ copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag, NULL);
free_user(recip);
}
}
return d;
}
-static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
+static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg)
{
#ifdef IMAP_STORAGE
/* we must use mbox(x) folder names, and copy the message there */
COPY(dir, msg, ddir, x, username, context, sfn, dfn);
}
ast_unlock_path(ddir);
+
+ if (newmsg) {
+ *newmsg = x;
+ }
#endif
return 0;
}
vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
NULL, urgent_str);
#else
- copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
+ copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str, NULL);
#endif
saved_messages++;
AST_LIST_REMOVE_CURRENT(list);
/* traverses directory using readdir (or select query for ODBC) */
count_msg = count_messages(vmu, vms->curdir);
+
if (count_msg < 0) {
return count_msg;
} else {
}
} else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
/* Move to old folder before deleting */
- res = save_to_folder(vmu, vms, x, 1);
+ res = save_to_folder(vmu, vms, x, 1, NULL);
if (res == ERROR_LOCK_PATH) {
/* If save failed do not delete the message */
ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
}
} else if (vms->deleted[x] && vmu->maxdeletedmsg) {
/* Move to deleted folder */
- res = save_to_folder(vmu, vms, x, 10);
+ res = save_to_folder(vmu, vms, x, 10, NULL);
if (res == ERROR_LOCK_PATH) {
/* If save failed do not delete the message */
vms->deleted[x] = 0;
return 0;
}
-static int vm_execmain(struct ast_channel *chan, const char *data)
+static int play_message_by_id_helper(struct ast_channel *chan,
+ struct ast_vm_user *vmu,
+ struct vm_state *vms,
+ const char *msg_id)
+{
+ struct ast_config *msg_cfg;
+ struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
+ char filename[256];
+ const char *other_msg_id;
+ int found = 0;
+
+ for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg && !found; vms->curmsg++) {
+ /* Find the msg */
+ make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
+ snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
+ RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
+ msg_cfg = ast_config_load(filename, config_flags);
+ if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
+ DISPOSE(vms->curdir, vms->curmsg);
+ continue;
+ }
+
+ other_msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
+
+ if (!ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
+ /* Found the msg, so play it back */
+
+ make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
+ make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
+ found = 1;
+
+#ifdef IMAP_STORAGE
+ /*IMAP storage stores any prepended message from a forward
+ * as a separate file from the rest of the message
+ */
+ if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
+ wait_file(chan, vms, vms->introfn);
+ }
+#endif
+ if ((wait_file(chan, vms, vms->fn)) < 0) {
+ ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
+ } else {
+ vms->heard[vms->curmsg] = 1;
+ }
+ }
+
+ /* cleanup configs and msg */
+ ast_config_destroy(msg_cfg);
+ DISPOSE(vms->curdir, vms->curmsg);
+ }
+
+ return found ? 0 : -1;
+}
+
+/*!
+ * \brief Finds a message in a specific mailbox by msg_id and plays it to the channel
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+static int play_message_by_id(struct ast_channel *chan, const char *mailbox, const char *context, const char *msg_id)
{
- /* XXX This is, admittedly, some pretty horrendous code. For some
- reason it just seemed a lot easier to do with GOTO's. I feel
- like I'm back in my GWBASIC days. XXX */
- int res = -1;
- int cmd = 0;
- int valid = 0;
- char prefixstr[80] ="";
- char ext_context[256]="";
- int box;
- int useadsi = 0;
- int skipuser = 0;
struct vm_state vms;
struct ast_vm_user *vmu = NULL, vmus;
- char *context = NULL;
- int silentexit = 0;
- struct ast_flags flags = { 0 };
- signed char record_gain = 0;
- int play_auto = 0;
- int play_folder = 0;
- int in_urgent = 0;
+ int res = 0;
+ int open = 0;
+ int played = 0;
+ int i;
+
+ memset(&vmus, 0, sizeof(vmus));
+ memset(&vms, 0, sizeof(vms));
+
+ if (!(vmu = find_user(&vmus, context, mailbox))) {
+ goto play_msg_cleanup;
+ }
+
+ /* Iterate through every folder, find the msg, and play it */
+ for (i = 0; i < ARRAY_LEN(mailbox_folders) && !played; i++) {
+ ast_copy_string(vms.username, mailbox, sizeof(vms.username));
+ vms.lastmsg = -1;
+
+ /* open the mailbox state */
+ if ((res = open_mailbox(&vms, vmu, i)) < 0) {
+ ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
+ res = -1;
+ goto play_msg_cleanup;
+ }
+ open = 1;
+
+ /* play msg if it exists in this mailbox */
+ if ((vms.lastmsg != -1) && !(play_message_by_id_helper(chan, vmu, &vms, msg_id))) {
+ played = 1;
+ }
+
+ /* close mailbox */
+ if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
+ res = -1;
+ goto play_msg_cleanup;
+ }
+ open = 0;
+ }
+
+play_msg_cleanup:
+ if (!played) {
+ res = -1;
+ }
+
+ if (vmu && open) {
+ close_mailbox(&vms, vmu);
+ }
+
#ifdef IMAP_STORAGE
- int deleted = 0;
+ if (vmu) {
+ vmstate_delete(&vms);
+ }
#endif
- /* Add the vm_state to the active list and keep it active */
- memset(&vms, 0, sizeof(vms));
+ return res;
+}
- vms.lastmsg = -1;
+static int vm_playmsgexec(struct ast_channel *chan, const char *data)
+{
+ char *parse;
+ char *mailbox = NULL;
+ char *context = NULL;
+ int res;
- memset(&vmus, 0, sizeof(vmus));
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(mailbox);
+ AST_APP_ARG(msg_id);
+ );
- ast_test_suite_event_notify("START", "Message: vm_execmain started");
if (chan->_state != AST_STATE_UP) {
ast_debug(1, "Before ast_answer\n");
ast_answer(chan);
}
- if (!ast_strlen_zero(data)) {
- char *opts[OPT_ARG_ARRAY_SIZE];
- char *parse;
+ if (ast_strlen_zero(data)) {
+ return -1;
+ }
+
+ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (ast_strlen_zero(args.mailbox) || ast_strlen_zero(args.msg_id)) {
+ return -1;
+ }
+
+ if ((context = strchr(args.mailbox, '@'))) {
+ *context++ = '\0';
+ }
+ mailbox = args.mailbox;
+
+ res = play_message_by_id(chan, mailbox, context, args.msg_id);
+ pbx_builtin_setvar_helper(chan, "VOICEMAIL_PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
+
+ return 0;
+}
+
+static int vm_execmain(struct ast_channel *chan, const char *data)
+{
+ /* XXX This is, admittedly, some pretty horrendous code. For some
+ reason it just seemed a lot easier to do with GOTO's. I feel
+ like I'm back in my GWBASIC days. XXX */
+ int res = -1;
+ int cmd = 0;
+ int valid = 0;
+ char prefixstr[80] ="";
+ char ext_context[256]="";
+ int box;
+ int useadsi = 0;
+ int skipuser = 0;
+ struct vm_state vms;
+ struct ast_vm_user *vmu = NULL, vmus;
+ char *context = NULL;
+ int silentexit = 0;
+ struct ast_flags flags = { 0 };
+ signed char record_gain = 0;
+ int play_auto = 0;
+ int play_folder = 0;
+ int in_urgent = 0;
+#ifdef IMAP_STORAGE
+ int deleted = 0;
+#endif
+
+ /* Add the vm_state to the active list and keep it active */
+ memset(&vms, 0, sizeof(vms));
+
+ vms.lastmsg = -1;
+
+ memset(&vmus, 0, sizeof(vmus));
+
+ ast_test_suite_event_notify("START", "Message: vm_execmain started");
+ if (chan->_state != AST_STATE_UP) {
+ ast_debug(1, "Before ast_answer\n");
+ ast_answer(chan);
+ }
+
+ if (!ast_strlen_zero(data)) {
+ char *opts[OPT_ARG_ARRAY_SIZE];
+ char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(argv0);
AST_APP_ARG(argv1);
break;
} else if (cmd > 0) {
box = cmd = cmd - '0';
- cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
+ cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd, NULL);
if (cmd == ERROR_LOCK_PATH) {
res = cmd;
goto out;
res |= ast_unregister_application(app2);
res |= ast_unregister_application(app3);
res |= ast_unregister_application(app4);
+ res |= ast_unregister_application(playmsg_app);
res |= ast_unregister_application(sayname_app);
res |= ast_custom_function_unregister(&mailbox_exists_acf);
res |= ast_manager_unregister("VoicemailUsersList");
#endif
ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
ast_uninstall_vm_functions();
+#ifdef TEST_FRAMEWORK
+ ast_uninstall_vm_test_functions();
+#endif
ao2_ref(inprocess_container, -1);
if (poll_thread != AST_PTHREADT_NULL)
res |= ast_register_application_xml(app2, vm_execmain);
res |= ast_register_application_xml(app3, vm_box_exists);
res |= ast_register_application_xml(app4, vmauthenticate);
+ res |= ast_register_application_xml(playmsg_app, vm_playmsgexec);
res |= ast_register_application_xml(sayname_app, vmsayname_exec);
res |= ast_custom_function_register(&mailbox_exists_acf);
res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
- ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
+ ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname, msg_create_from_file,
+ vm_index_to_foldername,
+ vm_mailbox_snapshot_create, vm_mailbox_snapshot_destroy,
+ vm_msg_move, vm_msg_remove, vm_msg_forward, vm_msg_play);
+
+#ifdef TEST_FRAMEWORK
+ ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
+#endif
+
ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
return cmd;
}
+static struct ast_vm_msg_snapshot *vm_msg_snapshot_alloc(void)
+{
+ struct ast_vm_msg_snapshot *msg_snapshot;
+
+ if (!(msg_snapshot = ast_calloc(1, sizeof(*msg_snapshot)))) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(msg_snapshot, 512)) {
+ ast_free(msg_snapshot);
+ return NULL;
+ }
+
+ return msg_snapshot;
+}
+
+static struct ast_vm_msg_snapshot *vm_msg_snapshot_destroy(struct ast_vm_msg_snapshot *msg_snapshot)
+{
+ ast_string_field_free_memory(msg_snapshot);
+ ast_free(msg_snapshot);
+
+ return NULL;
+}
+
+#ifdef TEST_FRAMEWORK
+
+static int vm_test_destroy_user(const char *context, const char *mailbox)
+{
+ struct ast_vm_user *vmu;
+
+ AST_LIST_LOCK(&users);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&users, vmu, list) {
+ if (!strncmp(context, vmu->context, sizeof(context))
+ && !strncmp(mailbox, vmu->mailbox, sizeof(mailbox))) {
+ AST_LIST_REMOVE_CURRENT(list);
+ ast_free(vmu);
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END
+ AST_LIST_UNLOCK(&users);
+ return 0;
+}
+
+static int vm_test_create_user(const char *context, const char *mailbox)
+{
+ struct ast_vm_user *vmu;
+
+ if (!(vmu = find_or_create(context, mailbox))) {
+ return -1;
+ }
+ populate_defaults(vmu);
+ return 0;
+}
+
+#endif
+
+/*!
+ * \brief Create and store off all the msgs in an open mailbox
+ *
+ * \note TODO XXX This function should work properly for all
+ * voicemail storage options, but is far more expensive for
+ * ODBC at the moment. This is because the RETRIEVE macro
+ * not only pulls out the message's meta data file from the
+ * database, but also the actual audio for each message, temporarily
+ * writing it to the file system. This is an area that needs
+ * to be made more efficient.
+ */
+static int vm_msg_snapshot_create(struct ast_vm_user *vmu,
+ struct vm_state *vms,
+ struct ast_vm_mailbox_snapshot *mailbox_snapshot,
+ int snapshot_index,
+ int mailbox_index,
+ int descending,
+ enum ast_vm_snapshot_sort_val sort_val)
+{
+ struct ast_vm_msg_snapshot *msg_snapshot;
+ struct ast_vm_msg_snapshot *msg_snapshot_tmp;
+ struct ast_config *msg_cfg;
+ struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
+ char filename[PATH_MAX];
+ const char *value;
+
+ for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
+ int inserted = 0;
+ /* Find the msg */
+ make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
+ snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
+ RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
+ msg_cfg = ast_config_load(filename, config_flags);
+ if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
+ DISPOSE(vms->curdir, vms->curmsg);
+ continue;
+ }
+
+ /* Create the snapshot object */
+ if (!(msg_snapshot = vm_msg_snapshot_alloc())) {
+ ast_config_destroy(msg_cfg);
+ return -1;
+ }
+
+ /* Fill in the snapshot object */
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "msg_id"))) {
+ ast_string_field_set(msg_snapshot, msg_id, value);
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
+ ast_string_field_set(msg_snapshot, callerid, value);
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "callerchan"))) {
+ ast_string_field_set(msg_snapshot, callerchan, value);
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "exten"))) {
+ ast_string_field_set(msg_snapshot, exten, value);
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "origdate"))) {
+ ast_string_field_set(msg_snapshot, origdate, value);
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
+ ast_string_field_set(msg_snapshot, origtime, value);
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
+ ast_string_field_set(msg_snapshot, duration, value);
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "flag"))) {
+ ast_string_field_set(msg_snapshot, flag, value);
+ }
+ msg_snapshot->msg_number = vms->curmsg;
+ ast_string_field_set(msg_snapshot, folder_name, mailbox_folders[mailbox_index]);
+
+ /* store msg snapshot in mailbox snapshot */
+ switch (sort_val) {
+ default:
+ case AST_VM_SNAPSHOT_SORT_BY_ID:
+ if (descending) {
+ AST_LIST_INSERT_HEAD(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
+ } else {
+ AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
+ }
+ inserted = 1;
+ break;
+ case AST_VM_SNAPSHOT_SORT_BY_TIME:
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot_tmp, msg) {
+ int val = strcmp(msg_snapshot->origtime, msg_snapshot_tmp->origtime);
+ if (descending && val >= 0) {
+ AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
+ inserted = 1;
+ break;
+ } else if (!descending && val <= 0) {
+ AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
+ inserted = 1;
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ break;
+ }
+
+ if (!inserted) {
+ AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
+ }
+
+ mailbox_snapshot->total_msg_num++;
+
+ /* cleanup configs and msg */
+ ast_config_destroy(msg_cfg);
+ DISPOSE(vms->curdir, vms->curmsg);
+ }
+
+ return 0;
+}
+
+static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *mailbox,
+ const char *context,
+ const char *folder,
+ int descending,
+ enum ast_vm_snapshot_sort_val sort_val,
+ int combine_INBOX_and_OLD)
+{
+ struct ast_vm_mailbox_snapshot *mailbox_snapshot;
+ struct vm_state vms;
+ struct ast_vm_user *vmu = NULL, vmus;
+ int res;
+ int i;
+ int this_index_only = -1;
+ int open = 0;
+ int inbox_index = 0;
+ int old_index = 1;
+
+ if (ast_strlen_zero(mailbox)) {
+ ast_log(LOG_WARNING, "Cannot create a mailbox snapshot since no mailbox was specified\n");
+ return NULL;
+ }
+
+ memset(&vmus, 0, sizeof(vmus));
+
+ if (!(ast_strlen_zero(folder))) {
+ /* find the folder index */
+ for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
+ if (!strcasecmp(mailbox_folders[i], folder)) {
+ this_index_only = i;
+ break;
+ }
+ }
+ if (this_index_only == -1) {
+ /* Folder was specified and it did not match any folder in our list */
+ return NULL;
+ }
+ }
+
+ if (!(vmu = find_user(&vmus, context, mailbox))) {
+ return NULL;
+ }
+
+ if (!(mailbox_snapshot = ast_calloc(1, sizeof(*mailbox_snapshot)))) {
+ return NULL;
+ }
+
+ if (!(mailbox_snapshot->snapshots = ast_calloc(ARRAY_LEN(mailbox_folders), sizeof(*mailbox_snapshot->snapshots)))) {
+ ast_free(mailbox_snapshot);
+ return NULL;
+ }
+
+ mailbox_snapshot->folders = ARRAY_LEN(mailbox_folders);
+
+ for (i = 0; i < mailbox_snapshot->folders; i++) {
+ int combining_old = 0;
+ if ((i == old_index) && (combine_INBOX_and_OLD)) {
+ combining_old = 1;
+ }
+
+ /* This if statement is confusing looking. Here is what it means in english.
+ * - If a folder is given to the function and that folder's index is not the one we are iterating over, skip it...
+ * - Unless the folder provided is the INBOX folder and the current index is the OLD folder and we are combining OLD and INBOX msgs.
+ */
+ if ((this_index_only != -1) && (this_index_only != i) && !(combining_old && i == old_index && this_index_only == inbox_index)) {
+ continue;
+ }
+
+ memset(&vms, 0, sizeof(vms));
+ ast_copy_string(vms.username, mailbox, sizeof(vms.username));
+ vms.lastmsg = -1;
+ open = 0;
+
+ /* open the mailbox state */
+ if ((res = open_mailbox(&vms, vmu, i)) < 0) {
+ ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
+ goto snapshot_cleanup;
+ }
+ open = 1;
+
+ /* Iterate through each msg, storing off info */
+ if (vms.lastmsg != -1) {
+ if ((vm_msg_snapshot_create(vmu, &vms, mailbox_snapshot, combining_old ? inbox_index : i, i, descending, sort_val))) {
+ ast_log(LOG_WARNING, "Failed to create msg snapshots for %s@%s\n", mailbox, context);
+ goto snapshot_cleanup;
+ }
+ }
+
+ /* close mailbox */
+ if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
+ goto snapshot_cleanup;
+ }
+ open = 0;
+ }
+
+snapshot_cleanup:
+ if (vmu && open) {
+ close_mailbox(&vms, vmu);
+ }
+
+#ifdef IMAP_STORAGE
+ if (vmu) {
+ vmstate_delete(&vms);
+ }
+#endif
+
+ return mailbox_snapshot;
+}
+
+static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
+{
+ int i;
+ struct ast_vm_msg_snapshot *msg_snapshot;
+
+ for (i = 0; i < mailbox_snapshot->folders; i++) {
+ while ((msg_snapshot = AST_LIST_REMOVE_HEAD(&mailbox_snapshot->snapshots[i], msg))) {
+ msg_snapshot = vm_msg_snapshot_destroy(msg_snapshot);
+ }
+ }
+ ast_free(mailbox_snapshot->snapshots);
+ ast_free(mailbox_snapshot);
+ return NULL;
+}
+
+/*!
+ * \brief common bounds checking and existence check for Voicemail API functions.
+ *
+ * \details
+ * This is called by vm_msg_move, vm_msg_remove, and vm_msg_forward to
+ * ensure that data passed in are valid. This tests the following:
+ *
+ * 1. No negative indexes are given.
+ * 2. No index greater than the highest message index for the folder is given.
+ * 3. All message indexes given point to messages that exist.
+ *
+ * \param vms The voicemail state corresponding to an open mailbox
+ * \param msg_ids An array of message identifiers
+ * \param num_msgs The number of identifiers in msg_ids
+ *
+ * \retval -1 Failure
+ * \retval 0 Success
+ */
+static int message_range_and_existence_check(struct vm_state *vms, int *msg_ids, size_t num_msgs)
+{
+ int i;
+ int res = 0;
+ for (i = 0; i < num_msgs; ++i) {
+ int cur_msg = msg_ids[i];
+ if (cur_msg < 0) {
+ ast_log(LOG_WARNING, "Message has negative index\n");
+ res = -1;
+ break;
+ }
+ if (vms->lastmsg < cur_msg) {
+ ast_log(LOG_WARNING, "Message %d is out of range. Last message is %d\n", cur_msg, vms->lastmsg);
+ res = -1;
+ break;
+ }
+ make_file(vms->fn, sizeof(vms->fn), vms->curdir, cur_msg);
+ if (!EXISTS(vms->curdir, cur_msg, vms->fn, NULL)) {
+ ast_log(LOG_WARNING, "Message %d does not exist.\n", cur_msg);
+ res = -1;
+ break;
+ }
+ }
+
+ return res;
+}
+
+static void notify_new_state(struct ast_vm_user *vmu)
+{
+ int new = 0, old = 0, urgent = 0;
+ char ext_context[1024];
+
+ snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
+ run_externnotify(vmu->context, vmu->mailbox, NULL);
+ ast_app_inboxcount2(ext_context, &urgent, &new, &old);
+ queue_mwi_event(ext_context, urgent, new, old);
+}
+
+static int vm_msg_forward(const char *from_mailbox,
+ const char *from_context,
+ const char *from_folder,
+ const char *to_mailbox,
+ const char *to_context,
+ const char *to_folder,
+ size_t num_msgs,
+ int *msg_ids,
+ int delete_old)
+{
+ struct vm_state from_vms;
+ struct ast_vm_user *vmu = NULL, vmus;
+ struct ast_vm_user *to_vmu = NULL, to_vmus;
+ struct ast_config *msg_cfg;
+ struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
+ char filename[PATH_MAX];
+ int from_folder_index;
+ int open = 0;
+ int res = 0;
+ int i;
+
+ if (ast_strlen_zero(from_mailbox) || ast_strlen_zero(to_mailbox)) {
+ ast_log(LOG_WARNING, "Cannot forward message because either the from or to mailbox was not specified\n");
+ return -1;
+ }
+
+ if (!num_msgs) {
+ ast_log(LOG_WARNING, "Invalid number of messages specified to forward: %zu\n", num_msgs);
+ return -1;
+ }
+
+ if (ast_strlen_zero(from_folder) || ast_strlen_zero(to_folder)) {
+ ast_log(LOG_WARNING, "Cannot forward message because the from_folder or to_folder was not specified\n");
+ return -1;
+ }
+
+ memset(&vmus, 0, sizeof(vmus));
+ memset(&to_vmus, 0, sizeof(to_vmus));
+ memset(&from_vms, 0, sizeof(from_vms));
+
+ from_folder_index = get_folder_by_name(from_folder);
+ if (from_folder_index == -1) {
+ return -1;
+ }
+
+ if (get_folder_by_name(to_folder) == -1) {
+ return -1;
+ }
+
+ if (!(vmu = find_user(&vmus, from_context, from_mailbox))) {
+ ast_log(LOG_WARNING, "Can't find voicemail user to forward from (%s@%s)\n", from_mailbox, from_context);
+ return -1;
+ }
+
+ if (!(to_vmu = find_user(&to_vmus, to_context, to_mailbox))) {
+ ast_log(LOG_WARNING, "Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context);
+ return -1;
+ }
+
+ ast_copy_string(from_vms.username, from_mailbox, sizeof(from_vms.username));
+ from_vms.lastmsg = -1;
+ open = 0;
+
+ /* open the mailbox state */
+ if ((res = open_mailbox(&from_vms, vmu, from_folder_index)) < 0) {
+ ast_log(LOG_WARNING, "Could not open mailbox %s\n", from_mailbox);
+ res = -1;
+ goto vm_forward_cleanup;
+ }
+
+ open = 1;
+
+ if ((from_vms.lastmsg + 1) < num_msgs) {
+ ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", from_folder, num_msgs);
+ res = -1;
+ goto vm_forward_cleanup;
+ }
+
+ if ((res = message_range_and_existence_check(&from_vms, msg_ids, num_msgs) < 0)) {
+ goto vm_forward_cleanup;
+ }
+
+ /* Now we actually forward the messages */
+ for (i = 0; i < num_msgs; i++) {
+ int cur_msg = msg_ids[i];
+ int duration = 0;
+ const char *value;
+
+ make_file(from_vms.fn, sizeof(from_vms.fn), from_vms.curdir, cur_msg);
+ snprintf(filename, sizeof(filename), "%s.txt", from_vms.fn);
+ RETRIEVE(from_vms.curdir, cur_msg, vmu->mailbox, vmu->context);
+ msg_cfg = ast_config_load(filename, config_flags);
+ /* XXX This likely will not fail since we previously ensured that the
+ * message we are looking for exists. However, there still could be some
+ * circumstance where this fails, so atomicity is not guaranteed.
+ */
+ if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
+ DISPOSE(from_vms.curdir, cur_msg);
+ continue;
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
+ duration = atoi(value);
+ }
+
+ copy_message(NULL, vmu, from_folder_index, cur_msg, duration, to_vmu, vmfmts, from_vms.curdir, "", to_folder);
+
+ if (delete_old) {
+ from_vms.deleted[cur_msg] = 1;
+ }
+ ast_config_destroy(msg_cfg);
+ DISPOSE(from_vms.curdir, cur_msg);
+ }
+
+ /* close mailbox */
+ if ((res = close_mailbox(&from_vms, vmu) == ERROR_LOCK_PATH)) {
+ res = -1;
+ goto vm_forward_cleanup;
+ }
+ open = 0;
+
+vm_forward_cleanup:
+ if (vmu && open) {
+ close_mailbox(&from_vms, vmu);
+ }
+#ifdef IMAP_STORAGE
+ if (vmu) {
+ vmstate_delete(&from_vms);
+ }
+#endif
+
+ if (!res) {
+ notify_new_state(to_vmu);
+ }
+
+ return res;
+}
+
+static int vm_msg_move(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *oldfolder,
+ int *old_msg_nums,
+ const char *newfolder,
+ int *new_msg_nums)
+{
+ struct vm_state vms;
+ struct ast_vm_user *vmu = NULL, vmus;
+ int old_folder_index;
+ int new_folder_index;
+ int open = 0;
+ int res = 0;
+ int i;
+
+ if (ast_strlen_zero(mailbox)) {
+ ast_log(LOG_WARNING, "Cannot move message because no mailbox was specified\n");
+ return -1;
+ }
+
+ if (!num_msgs) {
+ ast_log(LOG_WARNING, "Invalid number of messages specified to move: %zu\n", num_msgs);
+ return -1;
+ }
+
+ if (ast_strlen_zero(oldfolder) || ast_strlen_zero(newfolder)) {
+ ast_log(LOG_WARNING, "Cannot move message because either oldfolder or newfolder was not specified\n");
+ return -1;
+ }
+
+ old_folder_index = get_folder_by_name(oldfolder);
+ new_folder_index = get_folder_by_name(newfolder);
+
+ memset(&vmus, 0, sizeof(vmus));
+ memset(&vms, 0, sizeof(vms));
+
+ if (old_folder_index == -1 || new_folder_index == -1) {
+ return -1;
+ }
+
+ if (!(vmu = find_user(&vmus, context, mailbox))) {
+ return -1;
+ }
+
+ ast_copy_string(vms.username, mailbox, sizeof(vms.username));
+ vms.lastmsg = -1;
+ open = 0;
+
+ /* open the mailbox state */
+ if ((res = open_mailbox(&vms, vmu, old_folder_index)) < 0) {
+ ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
+ res = -1;
+ goto vm_move_cleanup;
+ }
+
+ open = 1;
+
+ if ((res = message_range_and_existence_check(&vms, old_msg_nums, num_msgs)) < 0) {
+ goto vm_move_cleanup;
+ }
+
+ /* Now actually move the message */
+ for (i = 0; i < num_msgs; ++i) {
+ if (save_to_folder(vmu, &vms, old_msg_nums[i], new_folder_index, new_msg_nums ? (new_msg_nums + i) : NULL)) {
+ res = -1;
+ goto vm_move_cleanup;
+ }
+ vms.deleted[old_msg_nums[i]] = 1;
+ }
+
+ /* close mailbox */
+ if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
+ res = -1;
+ goto vm_move_cleanup;
+ }
+ open = 0;
+
+vm_move_cleanup:
+ if (vmu && open) {
+ close_mailbox(&vms, vmu);
+ }
+#ifdef IMAP_STORAGE
+ if (vmu) {
+ vmstate_delete(&vms);
+ }
+#endif
+
+ if (!res) {
+ notify_new_state(vmu);
+ }
+
+ return res;
+}
+
+static int vm_msg_remove(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *folder,
+ int *msgs)
+{
+ struct vm_state vms;
+ struct ast_vm_user *vmu = NULL, vmus;
+ int folder_index;
+ int open = 0;
+ int res = 0;
+ int i;
+
+ if (ast_strlen_zero(mailbox)) {
+ ast_log(LOG_WARNING, "Cannot remove message because no mailbox was specified\n");
+ return -1;
+ }
+
+ if (!num_msgs) {
+ ast_log(LOG_WARNING, "Invalid number of messages specified to remove: %zu\n", num_msgs);
+ return -1;
+ }
+
+ if (ast_strlen_zero(folder)) {
+ ast_log(LOG_WARNING, "Cannot remove message because no folder was specified\n");
+ return -1;
+ }
+
+ memset(&vmus, 0, sizeof(vmus));
+ memset(&vms, 0, sizeof(vms));
+
+ folder_index = get_folder_by_name(folder);
+ if (folder_index == -1) {
+ ast_log(LOG_WARNING, "Could not remove msgs from unknown folder %s\n", folder);
+ return -1;
+ }
+
+ if (!(vmu = find_user(&vmus, context, mailbox))) {
+ ast_log(LOG_WARNING, "Can't find voicemail user to remove msg from (%s@%s)\n", mailbox, context);
+ return -1;
+ }
+
+ ast_copy_string(vms.username, mailbox, sizeof(vms.username));
+ vms.lastmsg = -1;
+ open = 0;
+
+ /* open the mailbox state */
+ if ((res = open_mailbox(&vms, vmu, folder_index)) < 0) {
+ ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
+ res = -1;
+ goto vm_remove_cleanup;
+ }
+
+ open = 1;
+
+ if ((vms.lastmsg + 1) < num_msgs) {
+ ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", folder, num_msgs);
+ res = -1;
+ goto vm_remove_cleanup;
+ }
+
+ if ((res = message_range_and_existence_check(&vms, msgs, num_msgs)) < 0) {
+ goto vm_remove_cleanup;
+ }
+
+ for (i = 0; i < num_msgs; i++) {
+ vms.deleted[msgs[i]] = 1;
+ }
+
+ /* close mailbox */
+ if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
+ res = -1;
+ ast_log(AST_LOG_ERROR, "Failed to close mailbox folder %s while removing msgs\n", folder);
+ goto vm_remove_cleanup;
+ }
+ open = 0;
+
+vm_remove_cleanup:
+ if (vmu && open) {
+ close_mailbox(&vms, vmu);
+ }
+#ifdef IMAP_STORAGE
+ if (vmu) {
+ vmstate_delete(&vms);
+ }
+#endif
+
+ if (!res) {
+ notify_new_state(vmu);
+ }
+
+ return res;
+}
+
+static int vm_msg_play(struct ast_channel *chan,
+ const char *mailbox,
+ const char *context,
+ const char *folder,
+ const char *msg_num,
+ ast_vm_msg_play_cb cb)
+{
+ struct vm_state vms;
+ struct ast_vm_user *vmu = NULL, vmus;
+ int res = 0;
+ int open = 0;
+ int i;
+ char filename[PATH_MAX];
+ struct ast_config *msg_cfg;
+ struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
+ int duration = 0;
+ const char *value;
+
+ if (ast_strlen_zero(mailbox)) {
+ ast_log(LOG_WARNING, "Cannot play message because no mailbox was specified\n");
+ return -1;
+ }
+
+ if (ast_strlen_zero(folder)) {
+ ast_log(LOG_WARNING, "Cannot play message because no folder was specified\n");
+ return -1;
+ }
+
+ if (ast_strlen_zero(msg_num)) {
+ ast_log(LOG_WARNING, "Cannot play message because no message number was specified\n");
+ return -1;
+ }
+
+ memset(&vmus, 0, sizeof(vmus));
+ memset(&vms, 0, sizeof(vms));
+
+ if (ast_strlen_zero(context)) {
+ context = "default";
+ }
+
+ if (!(vmu = find_user(&vmus, context, mailbox))) {
+ return -1;
+ }
+
+ i = get_folder_by_name(folder);
+ ast_copy_string(vms.username, mailbox, sizeof(vms.username));
+ vms.lastmsg = -1;
+ if ((res = open_mailbox(&vms, vmu, i)) < 0) {
+ ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
+ goto play2_msg_cleanup;
+ }
+ open = 1;
+
+ vms.curmsg = atoi(msg_num);
+ if (vms.curmsg > vms.lastmsg || vms.curmsg < 0) {
+ res = -1;
+ goto play2_msg_cleanup;
+ }
+
+ /* Find the msg */
+ make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
+ snprintf(filename, sizeof(filename), "%s.txt", vms.fn);
+ RETRIEVE(vms.curdir, vms.curmsg, vmu->mailbox, vmu->context);
+
+ msg_cfg = ast_config_load(filename, config_flags);
+ if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
+ DISPOSE(vms.curdir, vms.curmsg);
+ res = -1;
+ goto play2_msg_cleanup;
+ }
+ if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
+ duration = atoi(value);
+ }
+ ast_config_destroy(msg_cfg);
+
+#ifdef IMAP_STORAGE
+ /*IMAP storage stores any prepended message from a forward
+ * as a separate file from the rest of the message
+ */
+ if (!ast_strlen_zero(vms.introfn) && ast_fileexists(vms.introfn, NULL, NULL) > 0) {
+ wait_file(chan, &vms, vms.introfn);
+ }
+#endif
+ if (cb) {
+ cb(chan, vms.fn, duration);
+ } else if ((wait_file(chan, &vms, vms.fn)) < 0) {
+ ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms.fn);
+ } else {
+ res = 0;
+ }
+
+ vms.heard[vms.curmsg] = 1;
+
+ /* cleanup configs and msg */
+ DISPOSE(vms.curdir, vms.curmsg);
+
+play2_msg_cleanup:
+ if (vmu && open) {
+ close_mailbox(&vms, vmu);
+ }
+
+#ifdef IMAP_STORAGE
+ if (vmu) {
+ vmstate_delete(&vms);
+ }
+#endif
+
+ if (!res) {
+ notify_new_state(vmu);
+ }
+
+ return res;
+}
+
/* This is a workaround so that menuselect displays a proper description
* AST_MODULE_INFO(, , "Comedian Mail (Voicemail System)"
*/
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>res_odbc</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>pgsql</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>radius</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>sqlite</depend>
<support_level>deprecated</support_level>
+ <defaultenabled>no</defaultenabled>
<replacement>sqlite3_custom</replacement>
***/
/*** MODULEINFO
<depend>sqlite3</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>freetds</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>pgsql</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>radius</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>sqlite3</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>freetds</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>alsa</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>portaudio</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
<depend>res_jabber</depend>
<use>openssl</use>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
/*** MODULEINFO
<depend>openh323</depend>
- <defaultenabled>yes</defaultenabled>
+ <defaultenabled>no</defaultenabled>
<support_level>deprecated</support_level>
<replacement>chan_ooh323</replacement>
***/
<depend>res_jabber</depend>
<use>openssl</use>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<use>res_pktccops</use>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
<depend>misdn</depend>
<depend>suppserv</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>nbs</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>oss</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>ixjuser</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
#include "asterisk/cel.h"
#include "asterisk/data.h"
#include "asterisk/aoc.h"
+#include "asterisk/custom_control_frame.h"
+#include "asterisk/message.h"
#include "sip/include/sip.h"
#include "sip/include/globals.h"
#include "sip/include/config_parser.h"
<para>Always returns <literal>0</literal>.</para>
</description>
</application>
+ <application name="SIPSendCustomINFO" language="en_US">
+ <synopsis>
+ Send a custom INFO frame on specified channels.
+ </synopsis>
+ <syntax>
+ <parameter name="Data" required="true" />
+ <parameter name="UserAgent" required="false" />
+ </syntax>
+ <description>
+ <para>SIPSendCustomINFO() allows you to send a custom INFO message on all
+ active SIP channels or on channels with the specified User Agent. This
+ application is only available if TEST_FRAMEWORK is defined.</para>
+ </description>
+ </application>
<function name="SIP_HEADER" language="en_US">
<synopsis>
Gets the specified SIP header from an incoming INVITE message.
{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
{ AST_REDIRECTING_REASON_AWAY, "away" },
- { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"}
+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"},
+ { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm"},
};
}
}
+struct state_notify_data {
+ int state;
+ int presence_state;
+ const char *presence_subtype;
+ const char *presence_message;
+};
+
/*!
* \details
* This container holds the dialogs that will be destroyed immediately.
static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *decoded);
static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
static int transmit_info_with_vidupdate(struct sip_pvt *p);
-static int transmit_message_with_text(struct sip_pvt *p, const char *text);
+static int transmit_message_with_text(struct sip_pvt *p, const char *text, int init, int auth);
+static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *msg);
static int transmit_refer(struct sip_pvt *p, const char *dest);
static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten);
static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, uint32_t seqno);
static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, uint32_t seqno);
static void copy_request(struct sip_request *dst, const struct sip_request *src);
-static void receive_message(struct sip_pvt *p, struct sip_request *req);
+static void receive_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward);
static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only);
static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
/*--- Device monitoring and Device/extension state/event handling */
-static int cb_extensionstate(char *context, char* exten, int state, void *data);
+static int extensionstate_update(char *context, char *exten, struct state_notify_data *data, struct sip_pvt *p);
+static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, void *data);
static int sip_devicestate(void *data);
static int sip_poke_noanswer(const void *data);
static int sip_poke_peer(struct sip_peer *peer, int force);
static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
static int get_msg_text(char *buf, int len, struct sip_request *req);
-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
+static int transmit_state_notify(struct sip_pvt *p, struct state_notify_data *data, int full, int timeout);
static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen);
static int get_domain(const char *str, char *domain, int len);
static int handle_request_bye(struct sip_pvt *p, struct sip_request *req);
static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *sin, const char *e);
static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req);
-static int handle_request_message(struct sip_pvt *p, struct sip_request *req);
+static int handle_request_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, uint32_t seqno, const char *e);
static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
static int handle_request_options(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
/* If this is a subscription, tell the phone that we got a timeout */
if (p->subscribed && p->subscribed != MWI_NOTIFICATION && p->subscribed != CALL_COMPLETION) {
- transmit_state_notify(p, AST_EXTENSION_DEACTIVATED, 1, TRUE); /* Send last notification */
+ struct state_notify_data data = { 0, };
+ data.state = AST_EXTENSION_DEACTIVATED;
+
+ transmit_state_notify(p, &data, 1, TRUE); /* Send last notification */
p->subscribed = NONE;
append_history(p, "Subscribestatus", "timeout");
ast_debug(3, "Re-scheduled destruction of SIP subscription %s\n", p->callid ? p->callid : "<unknown>");
ast_verbose("Sending text %s on %s\n", text, ast->name);
}
- transmit_message_with_text(dialog, text);
+ transmit_message_with_text(dialog, text, 0, 0);
return 0;
}
return 0;
}
+/*!
+ * \brief Sends AST_CUSTOM_FRAME of type sip info.
+ *
+ * \note pvt is expected to be locked before entering this function.
+ */
+static int sip_handle_custom_info(struct sip_pvt *pvt, struct ast_custom_payload *pl)
+{
+ struct ast_variable *headers = NULL;
+ char *content_type = NULL;
+ char *content = NULL;
+ char *useragent_filter = NULL;
+ struct ast_variable *var;
+ struct sip_request req;
+ int res = -1;
+
+ if (ast_custom_payload_sipinfo_decode(pl, &headers, &content_type, &content, &useragent_filter)) {
+ goto custom_info_cleanup;
+ }
+
+ if (!(ast_strlen_zero(useragent_filter))) {
+ int match = (strstr(pvt->useragent, useragent_filter)) ? 1 : 0;
+ if (!match) {
+ goto custom_info_cleanup;
+ }
+ }
+
+ reqprep(&req, pvt, SIP_INFO, 0, 1);
+ for (var = headers; var; var = var->next) {
+ add_header(&req, var->name, var->value);
+ }
+ if (!ast_strlen_zero(content) && !ast_strlen_zero(content_type)) {
+ add_header(&req, "Content-Type", content_type);
+ add_content(&req, content);
+ }
+
+ res = send_request(pvt, &req, XMIT_RELIABLE, pvt->ocseq);
+
+custom_info_cleanup:
+
+ ast_free(content);
+ ast_free(content_type);
+ ast_free(useragent_filter);
+ ast_variables_destroy(headers);
+
+ return res;
+}
+
+
/*! \brief Play indication to user
* With SIP a lot of indications is sent as messages, letting the device play
the indication - busy signal, congestion etc
case AST_CONTROL_REDIRECTING:
update_redirecting(p, data, datalen);
break;
+ case AST_CONTROL_CUSTOM:
+ if (datalen && ast_custom_payload_type((struct ast_custom_payload *) data) == AST_CUSTOM_SIP_INFO) {
+ sip_handle_custom_info(p, (struct ast_custom_payload *) data);
+ }
+ break;
case AST_CONTROL_AOC:
{
struct ast_aoc_decoded *decoded = ast_aoc_decode((struct ast_aoc_encoded *) data, datalen, ast);
return res ? CMP_MATCH | CMP_STOP : 0;
}
+static int allow_notify_user_presence(struct sip_pvt *p)
+{
+ return (strstr(p->useragent, "Digium")) ? 1 : 0;
+}
+
/*! \brief Builds XML portion of NOTIFY messages for presence or dialog updates */
-static void state_notify_build_xml(int state, int full, const char *exten, const char *context, struct ast_str **tmp, struct sip_pvt *p, int subscribed, const char *mfrom, const char *mto)
+static void state_notify_build_xml(struct state_notify_data *data, int full, const char *exten, const char *context, struct ast_str **tmp, struct sip_pvt *p, int subscribed, const char *mfrom, const char *mto)
{
enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN;
const char *statestring = "terminated";
const char *pidfnote= "Ready";
char hint[AST_MAX_EXTENSION];
- switch (state) {
+ switch (data->state) {
case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE):
statestring = (sip_cfg.notifyringing) ? "early" : "confirmed";
local_state = NOTIFY_INUSE;
/* Check which device/devices we are watching and if they are registered */
if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten)) {
- char *hint2 = hint, *individual_hint = NULL;
+ char *hint2;
+ char *individual_hint = NULL;
int hint_count = 0, unavailable_count = 0;
+ /* strip off any possible PRESENCE providers from hint */
+ if ((hint2 = strrchr(hint, ','))) {
+ *hint2 = '\0';
+ }
+ hint2 = hint;
+
while ((individual_hint = strsep(&hint2, "&"))) {
hint_count++;
ast_str_append(tmp, 0, "<status><basic>open</basic></status>\n");
else
ast_str_append(tmp, 0, "<status><basic>%s</basic></status>\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed");
+
+ if (allow_notify_user_presence(p) && (data->presence_state > 0)) {
+ ast_str_append(tmp, 0, "</tuple>\n");
+ ast_str_append(tmp, 0, "<tuple id=\"digium-presence\">\n");
+ ast_str_append(tmp, 0, "<status>\n");
+ ast_str_append(tmp, 0, "<digium_presence type=\"%s\" subtype=\"%s\">%s</digium_presence>\n",
+ ast_presence_state2str(data->presence_state),
+ S_OR(data->presence_subtype, ""),
+ S_OR(data->presence_message, ""));
+ ast_str_append(tmp, 0, "</status>\n");
+ }
ast_str_append(tmp, 0, "</tuple>\n</presence>\n");
break;
case DIALOG_INFO_XML: /* SNOM subscribes in this format */
ast_str_append(tmp, 0, "<?xml version=\"1.0\"?>\n");
ast_str_append(tmp, 0, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%u\" state=\"%s\" entity=\"%s\">\n", p->dialogver, full ? "full" : "partial", mto);
- if ((state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) {
+ if ((data->state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) {
const char *local_display = exten;
char *local_target = ast_strdupa(mto);
const char *remote_display = exten;
ast_str_append(tmp, 0, "<dialog id=\"%s\">\n", exten);
}
ast_str_append(tmp, 0, "<state>%s</state>\n", statestring);
- if (state == AST_EXTENSION_ONHOLD) {
+ if (data->state == AST_EXTENSION_ONHOLD) {
ast_str_append(tmp, 0, "<local>\n<target uri=\"%s\">\n"
"<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n"
"</target>\n</local>\n", mto);
}
/*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */
-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
+static int transmit_state_notify(struct sip_pvt *p, struct state_notify_data *data, int full, int timeout)
{
struct ast_str *tmp = ast_str_alloca(4000);
char from[256], to[256];
reqprep(&req, p, SIP_NOTIFY, 0, 1);
- switch(state) {
+ switch(data->state) {
case AST_EXTENSION_DEACTIVATED:
if (timeout)
add_header(&req, "Subscription-State", "terminated;reason=timeout");
case XPIDF_XML:
case CPIM_PIDF_XML:
add_header(&req, "Event", subscriptiontype->event);
- state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+ state_notify_build_xml(data, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
add_header(&req, "Content-Type", subscriptiontype->mediatype);
p->dialogver++;
break;
case PIDF_XML: /* Eyebeam supports this format */
add_header(&req, "Event", subscriptiontype->event);
- state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+ state_notify_build_xml(data, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
add_header(&req, "Content-Type", subscriptiontype->mediatype);
p->dialogver++;
break;
case DIALOG_INFO_XML: /* SNOM subscribes in this format */
add_header(&req, "Event", subscriptiontype->event);
- state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+ state_notify_build_xml(data, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
add_header(&req, "Content-Type", subscriptiontype->mediatype);
p->dialogver++;
break;
return res;
}
-/*! \brief Transmit text with SIP MESSAGE method */
-static int transmit_message_with_text(struct sip_pvt *p, const char *text)
+/*! \brief Transmit text with SIP MESSAGE method based on an ast_msg */
+static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *msg)
{
struct sip_request req;
-
- reqprep(&req, p, SIP_MESSAGE, 0, 1);
- add_text(&req, text);
+ struct ast_msg_var_iterator *i;
+ const char *var, *val;
+
+ i = ast_msg_var_iterator_init(msg);
+ while (ast_msg_var_iterator_next(msg, i, &var, &val)) {
+ if (!strcasecmp(var, "Request-URI")) {
+ ast_string_field_set(p, fullcontact, val);
+ ast_msg_var_unref_current(i);
+ break;
+ }
+ ast_msg_var_unref_current(i);
+ }
+ ast_msg_var_iterator_destroy(i);
+
+ build_via(p);
+ initreqprep(&req, p, SIP_MESSAGE, NULL);
+ ast_string_field_set(p, msg_body, ast_msg_get_body(msg));
+ initialize_initreq(p, &req);
+
+ i = ast_msg_var_iterator_init(msg);
+ while (ast_msg_var_iterator_next(msg, i, &var, &val)) {
+ if (strcasecmp(var, "Request-URI")) {
+ add_header(&req, var, val);
+ }
+ ast_msg_var_unref_current(i);
+ }
+ ast_msg_var_iterator_destroy(i);
+
+ add_text(&req, ast_msg_get_body(msg));
+
return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
}
+/*! \brief Transmit text with SIP MESSAGE method */
+static int transmit_message_with_text(struct sip_pvt *p, const char *text, int init, int auth)
+{
+ struct sip_request req;
+
+ if (init) {
+ initreqprep(&req, p, SIP_MESSAGE, NULL);
+ ast_string_field_set(p, msg_body, text);
+ initialize_initreq(p, &req);
+ } else {
+ reqprep(&req, p, SIP_MESSAGE, 0, 1);
+ }
+ if (auth) {
+ return transmit_request_with_auth(p, SIP_MESSAGE, p->ocseq, XMIT_RELIABLE, 0);
+ } else {
+ add_text(&req, text);
+ return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
+ }
+}
+
/*! \brief Allocate SIP refer structure */
static int sip_refer_allocate(struct sip_pvt *p)
{
add_header(&resp, "X-Asterisk-HangupCauseCode", buf);
}
+ if (sipmethod == SIP_MESSAGE) {
+ add_text(&resp, p->msg_body);
+ }
+
return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
}
dialog_unref(p, "the extensionstate containing this dialog ptr was destroyed");
}
-/*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
-\note If you add an "hint" priority to the extension in the dial plan,
- you will get notifications on device state changes */
-static int cb_extensionstate(char *context, char* exten, int state, void *data)
+static int extensionstate_update(char *context, char *exten, struct state_notify_data *data, struct sip_pvt *p)
{
- struct sip_pvt *p = data;
-
sip_pvt_lock(p);
- switch(state) {
+ switch(data->state) {
case AST_EXTENSION_DEACTIVATED: /* Retry after a while */
case AST_EXTENSION_REMOVED: /* Extension is gone */
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); /* Delete subscription in 32 secs */
- ast_verb(2, "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
+ ast_verb(2, "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, data->state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
p->subscribed = NONE;
- append_history(p, "Subscribestatus", "%s", state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
+ append_history(p, "Subscribestatus", "%s", data->state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
break;
default: /* Tell user */
- p->laststate = state;
+ p->laststate = data->state;
+ p->last_presence_state = data->presence_state;
+ ast_string_field_set(p, last_presence_subtype, S_OR(data->presence_subtype, ""));
+ ast_string_field_set(p, last_presence_message, S_OR(data->presence_message, ""));
break;
}
if (p->subscribed != NONE) { /* Only send state NOTIFY if we know the format */
if (!p->pendinginvite) {
- transmit_state_notify(p, state, 1, FALSE);
+ transmit_state_notify(p, data, 1, FALSE);
} else {
/* We already have a NOTIFY sent that is not answered. Queue the state up.
if many state changes happen meanwhile, we will only send a notification of the last one */
ast_set_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
}
}
- ast_verb(2, "Extension Changed %s[%s] new state %s for Notify User %s %s\n", exten, context, ast_extension_state2str(state), p->username,
+ ast_verb(2, "Extension Changed %s[%s] new state %s for Notify User %s %s\n", exten, context, ast_extension_state2str(data->state), p->username,
ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE) ? "(queued)" : "");
sip_pvt_unlock(p);
return 0;
}
+/*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
+\note If you add an "hint" priority to the extension in the dial plan,
+ you will get notifications on device state changes */
+static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, void *data)
+{
+ struct sip_pvt *p = data;
+ struct state_notify_data notify_data = {
+ .state = info->exten_state,
+ .presence_state = info->presence_state,
+ .presence_subtype = info->presence_subtype,
+ .presence_message = info->presence_message,
+ };
+
+ if ((info->reason == AST_HINT_UPDATE_PRESENCE) && !(allow_notify_user_presence(p))) {
+ /* ignore a presence triggered update if we know the useragent doesn't care */
+ return 0;
+ }
+
+ return extensionstate_update(context, exten, ¬ify_data, p);
+}
+
/*! \brief Send a fake 401 Unauthorized response when the administrator
wants to hide the names of local devices from fishers
*/
if (!ast_strlen_zero(peer->context)) {
ast_string_field_set(p, context, peer->context);
}
+ if (!ast_strlen_zero(peer->messagecontext)) {
+ ast_string_field_set(p, messagecontext, peer->messagecontext);
+ }
if (!ast_strlen_zero(peer->mwi_from)) {
ast_string_field_set(p, mwi_from, peer->mwi_from);
}
return 0;
}
+static int get_msg_text2(struct ast_str **buf, struct sip_request *req)
+{
+ int i, res = 0;
+
+ ast_str_reset(*buf);
+
+ for (i = 0; res >= 0 && i < req->lines; i++) {
+ const char *line = REQ_OFFSET_TO_STR(req, line[i]);
+
+ res = ast_str_append(buf, 0, "%s\n", line);
+ }
+
+ return res < 0 ? -1 : 0;
+}
+
+static void set_message_vars_from_req(struct ast_msg *msg, struct sip_request *req)
+{
+ size_t x;
+ char name_buf[1024] = "";
+ char val_buf[1024] = "";
+ char *c;
+
+ for (x = 0; x < req->headers; x++) {
+ const char *header = REQ_OFFSET_TO_STR(req, header[x]);
+ if ((c = strchr(header, ':'))) {
+ ast_copy_string(name_buf, header, MIN((c - header + 1), sizeof(name_buf)));
+ ast_copy_string(val_buf, ast_skip_blanks(c + 1), sizeof(val_buf));
+ ast_trim_blanks(name_buf);
+ ast_msg_set_var(msg, name_buf, val_buf);
+ }
+ }
+}
+
+AST_THREADSTORAGE(sip_msg_buf);
/*! \brief Receive SIP MESSAGE method messages
\note We only handle messages within current calls currently
Reference: RFC 3428 */
-static void receive_message(struct sip_pvt *p, struct sip_request *req)
+static void receive_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e)
{
- char buf[1400];
- char *bufp;
+ struct ast_str *buf;
+ char *cbuf;
+ size_t len;
struct ast_frame f;
const char *content_type = get_header(req, "Content-Type");
+ struct ast_msg *msg;
+ int res;
+ char *from, *to, stripped[SIPBUFSIZE];
if (strncmp(content_type, "text/plain", strlen("text/plain"))) { /* No text/plain attachment */
transmit_response(p, "415 Unsupported Media Type", req); /* Good enough, or? */
return;
}
- if (get_msg_text(buf, sizeof(buf), req)) {
+ if (!(buf = ast_str_thread_get(&sip_msg_buf, 128))) {
+ transmit_response(p, "500 Internal Server Error", req);
+ if (!p->owner) {
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ }
+ return;
+ }
+
+ if (get_msg_text2(&buf, req)) {
ast_log(LOG_WARNING, "Unable to retrieve text from %s\n", p->callid);
transmit_response(p, "500 Internal Server Error", req);
if (!p->owner) {
return;
}
- /* Strip trailing line feeds from message body. (get_msg_text may add
+ /* Strip trailing line feeds from message body. (get_msg_text2 may add
* a trailing linefeed and we don't need any at the end) */
- bufp = buf + strlen(buf);
- while (--bufp >= buf && *bufp == '\n') {
- *bufp = '\0';
+ cbuf = ast_str_buffer(buf);
+ len = ast_str_strlen(buf);
+ while (len > 0) {
+ if (cbuf[--len] != '\n') {
+ ++len;
+ break;
+ }
}
+ ast_str_truncate(buf, len);
if (p->owner) {
if (sip_debug_test_pvt(p))
- ast_verbose("SIP Text message received: '%s'\n", buf);
+ ast_verbose("SIP Text message received: '%s'\n", ast_str_buffer(buf));
memset(&f, 0, sizeof(f));
f.frametype = AST_FRAME_TEXT;
f.subclass.integer = 0;
f.offset = 0;
- f.data.ptr = buf;
- f.datalen = strlen(buf) + 1;
+ f.data.ptr = ast_str_buffer(buf);
+ f.datalen = ast_str_strlen(buf) + 1;
ast_queue_frame(p->owner, &f);
transmit_response(p, "202 Accepted", req); /* We respond 202 accepted, since we relay the message */
return;
}
- /* Message outside of a call, we do not support that */
- ast_log(LOG_WARNING, "Received message to %s from %s, dropped it...\n Content-Type:%s\n Message: %s\n", get_header(req, "To"), get_header(req, "From"), content_type, buf);
- transmit_response(p, "405 Method Not Allowed", req);
+ if (!sip_cfg.accept_outofcall_message) {
+ /* Message outside of a call, we do not support that */
+ ast_debug(1, "MESSAGE outside of a call administratively disabled.\n");
+ transmit_response(p, "405 Method Not Allowed", req);
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ return;
+ }
+
+ copy_request(&p->initreq, req);
+
+ if (sip_cfg.auth_message_requests) {
+ int res;
+
+ set_pvt_allowed_methods(p, req);
+ res = check_user(p, req, SIP_MESSAGE, e, XMIT_UNRELIABLE, addr);
+ if (res == AUTH_CHALLENGE_SENT) {
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ return;
+ }
+ if (res < 0) { /* Something failed in authentication */
+ if (res == AUTH_FAKE_AUTH) {
+ ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+ transmit_fake_auth_response(p, SIP_OPTIONS, req, XMIT_UNRELIABLE);
+ } else {
+ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+ transmit_response(p, "403 Forbidden", req);
+ }
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ return;
+ }
+ /* Auth was successful. Proceed. */
+ } else {
+ struct sip_peer *peer;
+
+ /*
+ * MESSAGE outside of a call, not authenticating it.
+ * Check to see if we match a peer anyway so that we can direct
+ * it to the right context.
+ */
+
+ peer = find_peer(NULL, &p->recv, TRUE, FINDPEERS, 0, p->socket.type);
+ if (peer) {
+ /* Only if no auth is required. */
+ if (ast_strlen_zero(peer->secret) && ast_strlen_zero(peer->md5secret)) {
+ ast_string_field_set(p, context, peer->context);
+ }
+ if (!ast_strlen_zero(peer->messagecontext)) {
+ ast_string_field_set(p, messagecontext, peer->messagecontext);
+ }
+ ast_string_field_set(p, peername, peer->name);
+ peer = unref_peer(peer, "from find_peer() in receive_message");
+ }
+ }
+
+ /* Override the context with the message context _BEFORE_
+ * getting the destination. This way we can guarantee the correct
+ * extension is used in the message context when it is present. */
+ if (!ast_strlen_zero(p->messagecontext)) {
+ ast_string_field_set(p, context, p->messagecontext);
+ } else if (!ast_strlen_zero(sip_cfg.messagecontext)) {
+ ast_string_field_set(p, context, sip_cfg.messagecontext);
+ }
+
+ get_destination(p, NULL, NULL);
+
+ if (!(msg = ast_msg_alloc())) {
+ transmit_response(p, "500 Internal Server Error", req);
+ if (!p->owner) {
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ }
+ return;
+ }
+
+ to = ast_strdupa(REQ_OFFSET_TO_STR(req, rlPart2));
+ from = ast_strdupa(get_header(req, "From"));
+
+ res = ast_msg_set_to(msg, "%s", to);
+ res |= ast_msg_set_from(msg, "%s", get_in_brackets(from));
+ res |= ast_msg_set_body(msg, "%s", ast_str_buffer(buf));
+ res |= ast_msg_set_context(msg, "%s", p->context);
+
+ res |= ast_msg_set_var(msg, "SIP_RECVADDR", ast_sockaddr_stringify(&p->recv));
+ if (!ast_strlen_zero(p->peername)) {
+ res |= ast_msg_set_var(msg, "SIP_PEERNAME", p->peername);
+ }
+
+ ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped));
+ res |= ast_msg_set_var(msg, "SIP_FULLCONTACT", get_in_brackets(stripped));
+
+ res |= ast_msg_set_exten(msg, "%s", p->exten);
+
+ if (res) {
+ ast_msg_destroy(msg);
+ } else {
+ set_message_vars_from_req(msg, req);
+ ast_msg_queue(msg);
+ }
+
+ transmit_response(p, "202 Accepted", req);
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return;
}
/*! \brief CLI Command to show calls within limits set by call_limit */
pvt_set_needdestroy(p, "received 200 response");
}
if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
+ struct state_notify_data data = {
+ .state = p->laststate,
+ .presence_state = p->last_presence_state,
+ .presence_subtype = p->last_presence_subtype,
+ .presence_message = p->last_presence_message,
+ };
/* Ready to send the next state we have on queue */
ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
- cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
+ extensionstate_update((char *)p->context, (char *)p->exten, &data, (void *) p);
}
}
break;
}
/*!
- * \internal
* \brief Handle responses to INFO messages
*
* \note The INFO method MUST NOT change the state of calls or
/*!
* \internal
+ * \brief Handle auth requests to a MESSAGE request
+ * \return TRUE if authentication failed.
+ */
+static int do_message_auth(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
+{
+ char *header;
+ char *respheader;
+ char digest[1024];
+
+ if (p->options) {
+ p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
+ }
+
+ if (p->authtries == MAX_AUTHTRIES) {
+ ast_log(LOG_NOTICE, "Failed to authenticate MESSAGE with host '%s'\n",
+ ast_sockaddr_stringify(&p->sa));
+ return -1;
+ }
+
+ ++p->authtries;
+ auth_headers((resp == 401 ? WWW_AUTH : PROXY_AUTH), &header, &respheader);
+ memset(digest, 0, sizeof(digest));
+ if (reply_digest(p, req, header, SIP_MESSAGE, digest, sizeof(digest))) {
+ /* There's nothing to use for authentication */
+ ast_debug(1, "Nothing to use for MESSAGE authentication\n");
+ return -1;
+ }
+
+ if (p->do_history) {
+ append_history(p, "MessageAuth", "Try: %d", p->authtries);
+ }
+
+ transmit_message_with_text(p, p->msg_body, 0, 1);
+ return 0;
+}
+
+/*!
* \brief Handle responses to MESSAGE messages
*
* \note The MESSAGE method should not change the state of calls
static void handle_response_message(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno)
{
int sipmethod = SIP_MESSAGE;
- /* Out-of-dialog MESSAGE currently not supported. */
- //int in_dialog = ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
+ int in_dialog = ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
switch (resp) {
case 401: /* Not www-authorized on SIP method */
case 407: /* Proxy auth required */
- ast_log(LOG_WARNING, "Host '%s' requests authentication (%d) for '%s'\n",
- ast_sockaddr_stringify(&p->sa), resp, sip_methods[sipmethod].text);
+ if (do_message_auth(p, resp, rest, req, seqno) && !in_dialog) {
+ pvt_set_needdestroy(p, "MESSAGE authentication failed");
+ }
break;
case 405: /* Method not allowed */
case 501: /* Not Implemented */
}
ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n",
ast_sockaddr_stringify(&p->sa), sip_methods[sipmethod].text);
+ if (!in_dialog) {
+ pvt_set_needdestroy(p, "MESSAGE not implemented or allowed");
+ }
break;
default:
if (100 <= resp && resp < 200) {
/* Must allow provisional responses for out-of-dialog requests. */
} else if (200 <= resp && resp < 300) {
p->authtries = 0; /* Reset authentication counter */
+ if (!in_dialog) {
+ pvt_set_needdestroy(p, "MESSAGE delivery accepted");
+ }
} else if (300 <= resp && resp < 700) {
ast_verb(3, "Got SIP %s response %d \"%s\" back from host '%s'\n",
sip_methods[sipmethod].text, resp, rest, ast_sockaddr_stringify(&p->sa));
+ if (!in_dialog) {
+ pvt_set_needdestroy(p, (300 <= resp && resp < 600)
+ ? "MESSAGE delivery failed" : "MESSAGE delivery refused");
+ }
}
break;
}
#ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
if (res) {
- transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n");
+ transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n", 0, 0);
} else {
/* Then tell the transferer what happened */
sprintf(buf, "Call parked on extension '%d'", ext);
- transmit_message_with_text(transferer->tech_pvt, buf);
+ transmit_message_with_text(transferer->tech_pvt, buf, 0, 0);
}
#endif
int localtransfer = 0;
int attendedtransfer = 0;
int res = 0;
+ struct ast_party_redirecting redirecting;
+ struct ast_set_party_redirecting update_redirecting;
if (req->debug) {
ast_verbose("Call %s got a SIP call transfer from %s: (REFER)!\n",
}
ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
- /* Do not hold the pvt lock during the indicate and async_goto. Those functions
- * lock channels which will invalidate locking order if the pvt lock is held.*/
+ /* When a call is transferred to voicemail from a Digium phone, there may be
+ * a Diversion header present in the REFER with an appropriate reason parameter
+ * set. We need to update the redirecting information appropriately.
+ */
+ ast_party_redirecting_init(&redirecting);
+ memset(&update_redirecting, 0, sizeof(update_redirecting));
+ change_redirecting_information(p, req, &redirecting, &update_redirecting, FALSE);
+
+ /* Do not hold the pvt lock during a call that causes an indicate or an async_goto.
+ * Those functions lock channels which will invalidate locking order if the pvt lock
+ * is held.*/
+ sip_pvt_unlock(p);
+ ast_channel_update_redirecting(current.chan2, &redirecting, &update_redirecting);
+ ast_party_redirecting_free(&redirecting);
+
/* For blind transfers, move the call to the new extensions. For attended transfers on multiple
* servers - generate an INVITE with Replaces. Either way, let the dial plan decided
* indicate before masquerade so the indication actually makes it to the real channel
* when using local channels with MOH passthru */
- sip_pvt_unlock(p);
ast_indicate(current.chan2, AST_CONTROL_UNHOLD);
res = ast_async_goto(current.chan2, refer_to_context, refer_to, 1);
}
/*! \brief Handle incoming MESSAGE request */
-static int handle_request_message(struct sip_pvt *p, struct sip_request *req)
+static int handle_request_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e)
{
if (!req->ignore) {
if (req->debug)
ast_verbose("Receiving message!\n");
- receive_message(p, req);
+ receive_message(p, req, addr, e);
} else
transmit_response(p, "202 Accepted", req);
return 1;
}
+static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from);
+
+static const struct ast_msg_tech sip_msg_tech = {
+ .name = "sip",
+ .msg_send = sip_msg_send,
+};
+
+static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from)
+{
+ struct sip_pvt *pvt;
+ int res;
+ char *to_uri, *to_host, *to_user;
+ struct sip_peer *peer_ptr;
+
+ if (!(pvt = sip_alloc(NULL, NULL, 0, SIP_MESSAGE, NULL))) {
+ return -1;
+ }
+
+ to_uri = ast_strdupa(to);
+ parse_uri(to_uri, "sip:,sips:", &to_user, NULL, &to_host, NULL);
+
+ if (ast_strlen_zero(to_host)) {
+ ast_log(LOG_WARNING, "MESSAGE(to) is invalid for SIP - '%s'\n", to);
+ return -1;
+ }
+
+ if (!ast_strlen_zero(from)) {
+ if ((peer_ptr = find_peer(from, NULL, 0, 1, 0, 0))) {
+ ast_string_field_set(pvt, fromname, S_OR(peer_ptr->cid_name, peer_ptr->name));
+ ast_string_field_set(pvt, fromuser, S_OR(peer_ptr->cid_num, peer_ptr->name));
+ unref_peer(peer_ptr, "sip_unref_peer, from sip_msg_send, sip_find_peer");
+ } else if (strchr(from, '<')) { /* from is callerid-style */
+ char *sender;
+ char *name = NULL, *location = NULL, *user = NULL, *domain = NULL;
+
+ sender = ast_strdupa(from);
+ ast_callerid_parse(sender, &name, &location);
+ ast_string_field_set(pvt, fromname, name);
+ if (strchr(location, ':')) { /* Must be a URI */
+ parse_uri(location, "sip:,sips:", &user, NULL, &domain, NULL);
+ SIP_PEDANTIC_DECODE(user);
+ SIP_PEDANTIC_DECODE(domain);
+ extract_host_from_hostport(&domain);
+ ast_string_field_set(pvt, fromuser, user);
+ ast_string_field_set(pvt, fromdomain, domain);
+ } else { /* Treat it as an exten/user */
+ ast_string_field_set(pvt, fromuser, location);
+ }
+ } else { /* assume we just have the name, use defaults for the rest */
+ ast_string_field_set(pvt, fromname, from);
+ }
+ }
+
+ sip_pvt_lock(pvt);
+
+ /* Look up the host to contact */
+ if (create_addr(pvt, to_host, NULL, TRUE, NULL)) {
+ sip_pvt_unlock(pvt);
+ dialog_unlink_all(pvt);
+ dialog_unref(pvt, "create_addr failed sending a MESSAGE");
+ return -1;
+ }
+
+ if (!ast_strlen_zero(to_user)) {
+ ast_string_field_set(pvt, username, to_user);
+ }
+ ast_sip_ouraddrfor(&pvt->sa, &pvt->ourip, pvt);
+ ast_set_flag(&pvt->flags[0], SIP_OUTGOING);
+
+ /* XXX Does pvt->expiry need to be set? */
+
+ res = transmit_message_with_msg(pvt, msg);
+
+ sip_pvt_unlock(pvt);
+ sip_scheddestroy(pvt, DEFAULT_TRANS_TIMEOUT);
+ dialog_unref(pvt, "sent a MESSAGE");
+
+ return res;
+}
+
static enum sip_publish_type determine_sip_publish_type(struct sip_request *req, const char * const event, const char * const etag, const char * const expires, int *expires_int)
{
int etag_present = !ast_strlen_zero(etag);
{
int gotdest = 0;
int res = 0;
- int firststate;
struct sip_peer *authpeer = NULL;
const char *eventheader = get_header(req, "Event"); /* Get Event package name */
int resubscribe = (p->subscribed != NONE) && !req->ignore;
unref_peer(peer, "release a peer ref now that MWI is sent");
}
} else if (p->subscribed != CALL_COMPLETION) {
- if ((firststate = ast_extension_state(NULL, p->context, p->exten)) < 0) {
+ struct state_notify_data data = { 0, };
+ char *subtype = NULL;
+ char *message = NULL;
+ if ((data.state = ast_extension_state(NULL, p->context, p->exten)) < 0) {
ast_log(LOG_NOTICE, "Got SUBSCRIBE for extension %s@%s from %s, but there is no hint for that extension.\n", p->exten, p->context, ast_sockaddr_stringify(&p->sa));
transmit_response(p, "404 Not found", req);
}
return 0;
}
+ if (allow_notify_user_presence(p)) {
+ data.presence_state = ast_hint_presence_state(NULL, p->context, p->exten, &subtype, &message);
+ data.presence_subtype = subtype;
+ data.presence_message = message;
+ }
ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
transmit_response(p, "200 OK", req);
- transmit_state_notify(p, firststate, 1, FALSE); /* Send first notification */
- append_history(p, "Subscribestatus", "%s", ast_extension_state2str(firststate));
+ transmit_state_notify(p, &data, 1, FALSE); /* Send first notification */
+ append_history(p, "Subscribestatus", "%s", ast_extension_state2str(data.state));
/* hide the 'complete' exten/context in the refer_to field for later display */
ast_string_field_build(p, subscribeuri, "%s@%s", p->exten, p->context);
/* Deleted the slow iteration of all sip dialogs to find old subscribes from this peer for exten@context */
+ ast_free(subtype);
+ ast_free(message);
}
if (!p->expiry) {
pvt_set_needdestroy(p, "forcing expiration");
res = handle_request_bye(p, req);
break;
case SIP_MESSAGE:
- res = handle_request_message(p, req);
+ res = handle_request_message(p, req, addr, e);
break;
case SIP_PUBLISH:
res = handle_request_publish(p, req, addr, seqno, e);
ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
ast_copy_flags(&peer->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY);
ast_string_field_set(peer, context, sip_cfg.default_context);
+ ast_string_field_set(peer, messagecontext, sip_cfg.messagecontext);
ast_string_field_set(peer, subscribecontext, sip_cfg.default_subscribecontext);
ast_string_field_set(peer, language, default_language);
ast_string_field_set(peer, mohinterpret, default_mohinterpret);
} else if (!strcasecmp(v->name, "context")) {
ast_string_field_set(peer, context, v->value);
ast_set_flag(&peer->flags[1], SIP_PAGE2_HAVEPEERCONTEXT);
+ } else if (!strcasecmp(v->name, "outofcall_message_context")) {
+ ast_string_field_set(peer, messagecontext, v->value);
} else if (!strcasecmp(v->name, "subscribecontext")) {
ast_string_field_set(peer, subscribecontext, v->value);
} else if (!strcasecmp(v->name, "fromdomain")) {
sip_cfg.directrtpsetup = FALSE; /* Experimental feature, disabled by default */
sip_cfg.alwaysauthreject = DEFAULT_ALWAYSAUTHREJECT;
sip_cfg.auth_options_requests = DEFAULT_AUTH_OPTIONS;
+ sip_cfg.auth_message_requests = DEFAULT_AUTH_MESSAGE;
+ sip_cfg.messagecontext[0] = '\0';
+ sip_cfg.accept_outofcall_message = DEFAULT_ACCEPT_OUTOFCALL_MESSAGE;
sip_cfg.allowsubscribe = FALSE;
sip_cfg.disallowed_methods = SIP_UNKNOWN;
sip_cfg.contact_ha = NULL; /* Reset the contact ACL */
if (ast_true(v->value)) {
sip_cfg.auth_options_requests = 1;
}
+ } else if (!strcasecmp(v->name, "auth_message_requests")) {
+ sip_cfg.auth_message_requests = ast_true(v->value) ? 1 : 0;
+ } else if (!strcasecmp(v->name, "accept_outofcall_message")) {
+ sip_cfg.accept_outofcall_message = ast_true(v->value) ? 1 : 0;
+ } else if (!strcasecmp(v->name, "outofcall_message_context")) {
+ ast_copy_string(sip_cfg.messagecontext, v->value, sizeof(sip_cfg.messagecontext));
} else if (!strcasecmp(v->name, "mohinterpret")) {
ast_copy_string(default_mohinterpret, v->value, sizeof(default_mohinterpret));
} else if (!strcasecmp(v->name, "mohsuggest")) {
static char *app_dtmfmode = "SIPDtmfMode";
static char *app_sipaddheader = "SIPAddHeader";
static char *app_sipremoveheader = "SIPRemoveHeader";
+#ifdef TEST_FRAMEWORK
+static char *app_sipsendcustominfo = "SIPSendCustomINFO";
+#endif
/*! \brief Set the DTMFmode for an outbound SIP call (application) */
static int sip_dtmfmode(struct ast_channel *chan, const char *data)
return 0;
}
+#ifdef TEST_FRAMEWORK
+/*! \brief Send a custom INFO message via AST_CONTROL_CUSTOM indication */
+static int sip_sendcustominfo(struct ast_channel *chan, const char *data)
+{
+ char *info_data, *useragent;
+ struct ast_custom_payload *pl = NULL;
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "You must provide data to be sent\n");
+ return 0;
+ }
+
+ useragent = ast_strdupa(data);
+ info_data = strsep(&useragent, ",");
+
+ if (!(pl = ast_custom_payload_sipinfo_encode(NULL, "text/plain", info_data, useragent))) {
+ ast_log(LOG_WARNING, "Failed to create payload for custom SIP INFO\n");
+ return 0;
+ }
+
+ ast_indicate_data(chan, AST_CONTROL_CUSTOM, pl, ast_custom_payload_len(pl));
+ ast_free(pl);
+ return 0;
+}
+#endif
+
/*! \brief Transfer call before connect with a 302 redirect
\note Called by the transfer() dialplan application through the sip_transfer()
pbx interface function if the call is in ringing state
memcpy(&sip_tech_info, &sip_tech, sizeof(sip_tech));
memset((void *) &sip_tech_info.send_digit_begin, 0, sizeof(sip_tech_info.send_digit_begin));
+ if (ast_msg_tech_register(&sip_msg_tech)) {
+ /* LOAD_FAILURE stops Asterisk, so cleanup is a moot point. */
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
/* Make sure we can register our sip channel type */
if (ast_channel_register(&sip_tech)) {
ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n");
ast_register_application_xml(app_dtmfmode, sip_dtmfmode);
ast_register_application_xml(app_sipaddheader, sip_addheader);
ast_register_application_xml(app_sipremoveheader, sip_removeheader);
+#ifdef TEST_FRAMEWORK
+ ast_register_application_xml(app_sipsendcustominfo, sip_sendcustominfo);
+#endif
/* Register dialplan functions */
ast_custom_function_register(&sip_header_function);
/* First, take us out of the channel type list */
ast_channel_unregister(&sip_tech);
+ ast_msg_tech_unregister(&sip_msg_tech);
+
/* Unregister dial plan functions */
ast_custom_function_unregister(&sipchaninfo_function);
ast_custom_function_unregister(&sippeer_function);
ast_unregister_application(app_dtmfmode);
ast_unregister_application(app_sipaddheader);
ast_unregister_application(app_sipremoveheader);
-
#ifdef TEST_FRAMEWORK
+ ast_unregister_application(app_sipsendcustominfo);
+
AST_TEST_UNREGISTER(test_sip_peers_get);
AST_TEST_UNREGISTER(test_sip_mwi_subscribe_parse);
#endif
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
.bridge = ast_rtp_instance_bridge,
};
-static int skinny_extensionstate_cb(char *context, char* exten, int state, void *data);
+static int skinny_extensionstate_cb(char *context, char* id, struct ast_state_cb_info *info, void *data);
static int skinny_transfer(struct skinny_subchannel *sub);
static void *get_button_template(struct skinnysession *s, struct button_definition_template *btn)
}
-static int skinny_extensionstate_cb(char *context, char *exten, int state, void *data)
+static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
{
struct skinny_speeddial *sd = data;
struct skinny_device *d = sd->parent;
char hint[AST_MAX_EXTENSION];
+ int state = info->exten_state;
+
+ /* only interested in device state here */
+ if (info->reason != AST_HINT_UPDATE_DEVICE) {
+ return 0;
+ }
if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, sd->context, sd->exten)) {
/* If they are not registered, we will override notification and show no availability */
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
#define DEFAULT_CALLEVENTS FALSE /*!< Extra manager SIP call events */
#define DEFAULT_ALWAYSAUTHREJECT TRUE /*!< Don't reject authentication requests always */
#define DEFAULT_AUTH_OPTIONS FALSE
+#define DEFAULT_AUTH_MESSAGE TRUE
+#define DEFAULT_ACCEPT_OUTOFCALL_MESSAGE TRUE
#define DEFAULT_REGEXTENONQUALIFY FALSE
#define DEFAULT_LEGACY_USEROPTION_PARSING FALSE
#define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */
int allowguest; /*!< allow unauthenticated peers to connect? */
int alwaysauthreject; /*!< Send 401 Unauthorized for all failing requests */
int auth_options_requests; /*!< Authenticate OPTIONS requests */
+ int auth_message_requests; /*!< Authenticate MESSAGE requests */
+ int accept_outofcall_message; /*!< Accept MESSAGE outside of a call */
int compactheaders; /*!< send compact sip headers */
int allow_external_domains; /*!< Accept calls to external SIP domains? */
int callevents; /*!< Whether we send manager events or not */
int domainsasrealm; /*!< Use domains lists as realms */
struct sip_proxy outboundproxy; /*!< Outbound proxy */
char default_context[AST_MAX_CONTEXT];
+ char messagecontext[AST_MAX_CONTEXT];
char default_subscribecontext[AST_MAX_CONTEXT];
struct ast_ha *contact_ha; /*! \brief Global list of addresses dynamic peers are not allowed to use */
format_t capability; /*!< Supported codecs */
AST_STRING_FIELD(useragent); /*!< User agent in SIP request */
AST_STRING_FIELD(exten); /*!< Extension where to start */
AST_STRING_FIELD(context); /*!< Context for this call */
+ AST_STRING_FIELD(messagecontext);/*!< Default context for outofcall messages*/
AST_STRING_FIELD(subscribecontext); /*!< Subscribecontext */
AST_STRING_FIELD(subscribeuri); /*!< Subscribecontext */
AST_STRING_FIELD(fromdomain); /*!< Domain to show in the from field */
AST_STRING_FIELD(parkinglot); /*!< Parkinglot */
AST_STRING_FIELD(engine); /*!< RTP engine to use */
AST_STRING_FIELD(dialstring); /*!< The dialstring used to call this SIP endpoint */
+ AST_STRING_FIELD(last_presence_subtype); /*!< The last presence subtype sent for a subscription. */
+ AST_STRING_FIELD(last_presence_message); /*!< The last presence message for a subscription */
+ AST_STRING_FIELD(msg_body); /*!< Text for a MESSAGE body */
);
char via[128]; /*!< Via: header */
int maxforwards; /*!< SIP Loop prevention */
enum subscriptiontype subscribed; /*!< SUBSCRIBE: Is this dialog a subscription? */
int stateid; /*!< SUBSCRIBE: ID for devicestate subscriptions */
int laststate; /*!< SUBSCRIBE: Last known extension state */
+ int last_presence_state; /*!< SUBSCRIBE: Last known presence state */
uint32_t dialogver; /*!< SUBSCRIBE: Version for subscription dialog-info */
struct ast_dsp *dsp; /*!< Inband DTMF or Fax CNG tone Detection dsp */
AST_STRING_FIELD(md5secret); /*!< Password in MD5 */
AST_STRING_FIELD(remotesecret); /*!< Remote secret (trunks, remote devices) */
AST_STRING_FIELD(context); /*!< Default context for incoming calls */
+ AST_STRING_FIELD(messagecontext);/*!< Default context for outofcall messages*/
AST_STRING_FIELD(subscribecontext); /*!< Default context for subscriptions */
AST_STRING_FIELD(username); /*!< Temporary username until registration */
AST_STRING_FIELD(accountcode); /*!< Account code */
; Messages stored longer than this value will be deleted by Asterisk.
; This option applies to incoming messages only, which are intended to
; be processed by the JABBER_RECEIVE dialplan function.
+;sendtodialplan=yes ; Send incoming messages into the dialplan. Off by default.
+;context=messages ; Dialplan context to send incoming messages to. If not set,
+ ; "default" will be used.
; test - Ability to read TestEvent notifications sent to the Asterisk Test
; Suite. Note that this is only enabled when the TEST_FRAMEWORK
; compiler flag is defined.
+; message - Permissions to send out of call messages. Write-only
+;
;
;read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan
-;write = system,call,agent,user,config,command,reporting,originate
+;write = system,call,agent,user,config,command,reporting,originate,message
;auth_options_requests = yes ; Enabling this option will authenticate OPTIONS requests just like
; INVITE requests are. By default this option is disabled.
+;accept_outofcall_message = no ; Disable this option to reject all MESSAGE requests outside of a
+ ; call. By default, this option is enabled. When enabled, MESSAGE
+ ; requests are passed in to the dialplan.
+
+;outofcall_message_context = messages ; Context all out of dialog msgs are sent to. When this
+ ; option is not set, the context used during peer matching
+ ; is used. This option can be defined at both the peer and
+ ; global level.
+
+;auth_message_requests = yes ; Enabling this option will authenticate MESSAGE requests.
+ ; By default this option is enabled. However, it can be disabled
+ ; should an application desire to not load the Asterisk server with
+ ; doing authentication and implement end to end security in the
+ ; message body.
+
;g726nonstandard = yes ; If the peer negotiates G726-32 audio, use AAL2 packing
; order instead of RFC3551 packing order (this is required
; for Sipura and Grandstream ATAs, among others). This is
#! /bin/sh
-# From configure.ac Revision: 360488 .
+# From configure.ac Revision: 370665 .
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for asterisk trunk.
+# Generated by GNU Autoconf 2.67 for asterisk trunk.
#
# Report bugs to <https://issues.asterisk.org>.
#
IFS=" "" $as_nl"
# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
case $0 in #((
*[\\/]* ) as_myself=$0 ;;
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
- # Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
export CONFIG_SHELL
- case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
- esac
- exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
fi
if test x$as_have_required = xno; then :
$as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
$as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
- : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
;;
esac
if $ac_init_version; then
cat <<\_ACEOF
asterisk configure trunk
-generated by GNU Autoconf 2.68
+generated by GNU Autoconf 2.67
Copyright (C) 2010 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
ac_retval=1
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_try_compile
ac_retval=1
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_try_cpp
ac_fn_c_check_header_mongrel ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if eval \${$3+:} false; then :
+ if eval "test \"\${$3+set}\"" = set; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if eval "test \"\${$3+set}\"" = set; then :
$as_echo_n "(cached) " >&6
fi
eval ac_res=\$$3
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if eval "test \"\${$3+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
eval "$3=\$ac_header_compiler"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_header_mongrel
ac_retval=$ac_status
fi
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_try_run
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if eval "test \"\${$3+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_header_compile
ac_retval=1
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_compile
ac_retval=1
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_cpp
# interfere with the next link command; also delete a directory that is
# left behind by Apple's compiler. We do this before executing the actions.
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_try_link
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if eval "test \"\${$3+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_func
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if eval "test \"\${$3+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
eval "$3=no"
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_type
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
$as_echo_n "checking for $2.$3... " >&6; }
-if eval \${$4+:} false; then :
+if eval "test \"\${$4+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
eval ac_res=\$$4
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_member
rm -f conftest.val
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_compute_int
ac_fn_cxx_check_header_mongrel ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if eval \${$3+:} false; then :
+ if eval "test \"\${$3+set}\"" = set; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if eval "test \"\${$3+set}\"" = set; then :
$as_echo_n "(cached) " >&6
fi
eval ac_res=\$$3
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if eval "test \"\${$3+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
eval "$3=\$ac_header_compiler"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_cxx_check_header_mongrel
# interfere with the next link command; also delete a directory that is
# left behind by Apple's compiler. We do this before executing the actions.
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_link
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if eval "test \"\${$3+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_cxx_check_header_compile
cat >config.log <<_ACEOF
running configure, to aid debugging if configure makes a mistake.
It was created by asterisk $as_me trunk, which was
-generated by GNU Autoconf 2.68. Invocation command line was
+generated by GNU Autoconf 2.67. Invocation command line was
$ $0 $@
|| { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
fi
done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
+if test "${ac_cv_build+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_build_alias=$build_alias
$as_echo "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
+if test "${ac_cv_host+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "x$host_alias" = x; then
$as_echo "$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;;
esac
host=$ac_cv_host
ac_save_IFS=$IFS; IFS='-'
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "C compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
fi
rm -f conftest conftest$ac_cv_exeext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
fi
fi
fi
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
$as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
+if test "${ac_cv_objext+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
ac_objext=$OBJEXT
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
ac_save_CFLAGS=$CFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
+if test "${ac_cv_prog_cc_g+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_save_c_werror_flag=$ac_c_werror_flag
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_prog_cc_c89=no
CPP=
fi
if test -z "$CPP"; then
- if ${ac_cv_prog_CPP+:} false; then :
+ if test "${ac_cv_prog_CPP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# Double quotes because CPP needs to be expanded
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
fi
ac_ext=c
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
+if test "${ac_cv_path_GREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -z "$GREP"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
+if test "${ac_cv_path_EGREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
+if test "${ac_cv_header_stdc+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
-if test "x$ac_cv_header_minix_config_h" = xyes; then :
+if test "x$ac_cv_header_minix_config_h" = x""yes; then :
MINIX=yes
else
MINIX=
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
-if ${ac_cv_safe_to_define___extensions__+:} false; then :
+if test "${ac_cv_safe_to_define___extensions__+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
set dummy ${ac_tool_prefix}uname; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_UNAME+:} false; then :
+if test "${ac_cv_path_UNAME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $UNAME in
set dummy uname; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_UNAME+:} false; then :
+if test "${ac_cv_path_ac_pt_UNAME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_UNAME in
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
set dummy ${ac_tool_prefix}g++; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CXX+:} false; then :
+if test "${ac_cv_prog_CXX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CXX"; then
set dummy g++; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CXX"; then
set dummy ${ac_tool_prefix}ld; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_LD+:} false; then :
+if test "${ac_cv_prog_LD+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$LD"; then
set dummy ld; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_LD+:} false; then :
+if test "${ac_cv_prog_ac_ct_LD+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_LD"; then
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$RANLIB"; then
set dummy ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_RANLIB"; then
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
ac_save_CFLAGS=$CFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
+if test "${ac_cv_prog_cc_g+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_save_c_werror_flag=$ac_c_werror_flag
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_prog_cc_c89=no
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CXX+:} false; then :
+if test "${ac_cv_prog_CXX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CXX"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CXX"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
-if ${ac_cv_cxx_compiler_gnu+:} false; then :
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
ac_save_CXXFLAGS=$CXXFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
$as_echo_n "checking whether $CXX accepts -g... " >&6; }
-if ${ac_cv_prog_cxx_g+:} false; then :
+if test "${ac_cv_prog_cxx_g+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_save_cxx_werror_flag=$ac_cxx_werror_flag
CPP=
fi
if test -z "$CPP"; then
- if ${ac_cv_prog_CPP+:} false; then :
+ if test "${ac_cv_prog_CPP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# Double quotes because CPP needs to be expanded
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
fi
ac_ext=c
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
if test -z "$CXXCPP"; then
- if ${ac_cv_prog_CXXCPP+:} false; then :
+ if test "${ac_cv_prog_CXXCPP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# Double quotes because CXXCPP needs to be expanded
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
fi
ac_ext=c
# the developers regenerating the configure script don't have to install libtool.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
$as_echo_n "checking for a sed that does not truncate output... " >&6; }
-if ${ac_cv_path_SED+:} false; then :
+if test "${ac_cv_path_SED+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_prog_egrep+:} false; then :
+if test "${ac_cv_prog_egrep+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if echo a | (grep -E '(a|b)') >/dev/null 2>&1
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
$as_echo_n "checking for non-GNU ld... " >&6; }
fi
-if ${lt_cv_path_LD+:} false; then :
+if test "${lt_cv_path_LD+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -z "$LD"; then
test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if ${lt_cv_prog_gnu_ld+:} false; then :
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# I'd rather use --version here, but apparently some GNU lds only accept -v.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
+if test "${ac_cv_prog_AWK+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AWK"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
$as_echo_n "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
-if ${ac_cv_path_install+:} false; then :
+if test "${ac_cv_path_install+set}" = set; then :
$as_echo_n "(cached) " >&6
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$RANLIB"; then
set dummy ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_RANLIB"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU make" >&5
$as_echo_n "checking for GNU make... " >&6; }
-if ${ac_cv_GNU_MAKE+:} false; then :
+if test "${ac_cv_GNU_MAKE+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_GNU_MAKE='Not Found' ;
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
+if test "${ac_cv_path_EGREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_STRIP+:} false; then :
+if test "${ac_cv_prog_STRIP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$STRIP"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_STRIP"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AR+:} false; then :
+if test "${ac_cv_prog_AR+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AR"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_AR+:} false; then :
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_AR"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_SHA1SUM+:} false; then :
+if test "${ac_cv_prog_SHA1SUM+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$SHA1SUM"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_SHA1SUM+:} false; then :
+if test "${ac_cv_prog_ac_ct_SHA1SUM+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_SHA1SUM"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OPENSSL+:} false; then :
+if test "${ac_cv_prog_OPENSSL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$OPENSSL"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OPENSSL+:} false; then :
+if test "${ac_cv_prog_ac_ct_OPENSSL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_OPENSSL"; then
set dummy bison; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_BISON+:} false; then :
+if test "${ac_cv_path_BISON+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $BISON in
set dummy cmp; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CMP+:} false; then :
+if test "${ac_cv_path_CMP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CMP in
set dummy flex; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_FLEX+:} false; then :
+if test "${ac_cv_path_FLEX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $FLEX in
set dummy grep; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
+if test "${ac_cv_path_GREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $GREP in
set dummy find; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_FIND+:} false; then :
+if test "${ac_cv_path_FIND+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $FIND in
set dummy compress; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_COMPRESS+:} false; then :
+if test "${ac_cv_path_COMPRESS+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $COMPRESS in
set dummy basename; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_BASENAME+:} false; then :
+if test "${ac_cv_path_BASENAME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $BASENAME in
set dummy dirname; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_DIRNAME+:} false; then :
+if test "${ac_cv_path_DIRNAME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $DIRNAME in
set dummy sh; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_SHELL+:} false; then :
+if test "${ac_cv_path_SHELL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $SHELL in
set dummy ln; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_LN+:} false; then :
+if test "${ac_cv_path_LN+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $LN in
set dummy dot; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_DOT+:} false; then :
+if test "${ac_cv_path_DOT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $DOT in
set dummy wget; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_WGET+:} false; then :
+if test "${ac_cv_path_WGET+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $WGET in
set dummy curl; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CURL+:} false; then :
+if test "${ac_cv_path_CURL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CURL in
set dummy rubber; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_RUBBER+:} false; then :
+if test "${ac_cv_path_RUBBER+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $RUBBER in
set dummy catdvi; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CATDVI+:} false; then :
+if test "${ac_cv_path_CATDVI+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CATDVI in
set dummy kpsewhich; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_KPATHSEA+:} false; then :
+if test "${ac_cv_path_KPATHSEA+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $KPATHSEA in
set dummy xmllint; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_XMLLINT+:} false; then :
+if test "${ac_cv_path_XMLLINT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $XMLLINT in
set dummy xmlstarlet; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_XMLSTARLET+:} false; then :
+if test "${ac_cv_path_XMLSTARLET+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $XMLSTARLET in
set dummy fetch; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_FETCH+:} false; then :
+if test "${ac_cv_path_FETCH+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $FETCH in
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for bison that supports parse-param" >&5
$as_echo_n "checking for bison that supports parse-param... " >&6; }
-if ${ac_cv_path_BISON2+:} false; then :
+if test "${ac_cv_path_BISON2+set}" = set; then :
$as_echo_n "(cached) " >&6
else
set dummy ${ac_tool_prefix}soxmix; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_SOXMIX+:} false; then :
+if test "${ac_cv_prog_SOXMIX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$SOXMIX"; then
set dummy soxmix; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_SOXMIX+:} false; then :
+if test "${ac_cv_prog_ac_ct_SOXMIX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_SOXMIX"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_MD5+:} false; then :
+if test "${ac_cv_prog_MD5+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$MD5"; then
set dummy pthread-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_acx_pthread_config+:} false; then :
+if test "${ac_cv_prog_acx_pthread_config+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$acx_pthread_config"; then
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_PTHREAD_CC+:} false; then :
+if test "${ac_cv_prog_PTHREAD_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$PTHREAD_CC"; then
AST_DEVMODE=yes
NOISY_BUILD=yes
;;
- *) as_fn_error $? "bad value ${enableval} for --enable-dev-mode" "$LINENO" 5 ;;
+ *) as_fn_error $? "bad value ${enableval} for --enable-dev-mode" "$LINENO" 5 ;;
esac
fi
enableval=$enable_coverage; case "${enableval}" in
y|ye|yes) AST_CODE_COVERAGE=yes ;;
n|no) AST_CODE_COVERAGE=no ;;
- *) as_fn_error $? "bad value ${enableval} for --enable-coverage" "$LINENO" 5 ;;
+ *) as_fn_error $? "bad value ${enableval} for --enable-coverage" "$LINENO" 5 ;;
esac
fi
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
+if test "${ac_cv_prog_AWK+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AWK"; then
set dummy curl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path__libcurl_config+:} false; then :
+if test "${ac_cv_path__libcurl_config+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $_libcurl_config in
set dummy curl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path__libcurl_config+:} false; then :
+if test "${ac_cv_path__libcurl_config+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $_libcurl_config in
if test x$_libcurl_config != "x" ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the version of libcurl" >&5
$as_echo_n "checking for the version of libcurl... " >&6; }
-if ${libcurl_cv_lib_curl_version+:} false; then :
+if test "${libcurl_cv_lib_curl_version+set}" = set; then :
$as_echo_n "(cached) " >&6
else
libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $2}'`
if test $_libcurl_wanted -gt 0 ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcurl >= version 7.10.1" >&5
$as_echo_n "checking for libcurl >= version 7.10.1... " >&6; }
-if ${libcurl_cv_lib_version_ok+:} false; then :
+if test "${libcurl_cv_lib_version_ok+set}" = set; then :
$as_echo_n "(cached) " >&6
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libcurl is usable" >&5
$as_echo_n "checking whether libcurl is usable... " >&6; }
-if ${libcurl_cv_lib_curl_usable+:} false; then :
+if test "${libcurl_cv_lib_curl_usable+set}" = set; then :
$as_echo_n "(cached) " >&6
else
LIBS="$LIBS $CURL_LIB"
ac_fn_c_check_func "$LINENO" "curl_free" "ac_cv_func_curl_free"
-if test "x$ac_cv_func_curl_free" = xyes; then :
+if test "x$ac_cv_func_curl_free" = x""yes; then :
else
# check for basic system features and functionality before
# checking for package libraries
-ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
-if test "x$ac_cv_type_size_t" = xyes; then :
-
-else
-
-cat >>confdefs.h <<_ACEOF
-#define size_t unsigned int
-_ACEOF
-
-fi
-
# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
# for constant arguments. Useless!
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5
$as_echo_n "checking for working alloca.h... " >&6; }
-if ${ac_cv_working_alloca_h+:} false; then :
+if test "${ac_cv_working_alloca_h+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5
$as_echo_n "checking for alloca... " >&6; }
-if ${ac_cv_func_alloca_works+:} false; then :
+if test "${ac_cv_func_alloca_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
-void *alloca (size_t);
+char *alloca ();
# endif
# endif
# endif
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5
$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; }
-if ${ac_cv_os_cray+:} false; then :
+if test "${ac_cv_os_cray+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5
$as_echo_n "checking stack direction for C alloca... " >&6; }
-if ${ac_cv_c_stack_direction+:} false; then :
+if test "${ac_cv_c_stack_direction+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
-if eval \${$as_ac_Header+:} false; then :
+if eval "test \"\${$as_ac_Header+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
if test $ac_header_dirent = dirent.h; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
$as_echo_n "checking for library containing opendir... " >&6; }
-if ${ac_cv_search_opendir+:} false; then :
+if test "${ac_cv_search_opendir+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_opendir+:} false; then :
+ if test "${ac_cv_search_opendir+set}" = set; then :
break
fi
done
-if ${ac_cv_search_opendir+:} false; then :
+if test "${ac_cv_search_opendir+set}" = set; then :
else
ac_cv_search_opendir=no
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
$as_echo_n "checking for library containing opendir... " >&6; }
-if ${ac_cv_search_opendir+:} false; then :
+if test "${ac_cv_search_opendir+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_opendir+:} false; then :
+ if test "${ac_cv_search_opendir+set}" = set; then :
break
fi
done
-if ${ac_cv_search_opendir+:} false; then :
+if test "${ac_cv_search_opendir+set}" = set; then :
else
ac_cv_search_opendir=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
+if test "${ac_cv_header_stdc+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
-if ${ac_cv_header_sys_wait_h+:} false; then :
+if test "${ac_cv_header_sys_wait_h+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
as_ac_Lib=`$as_echo "ac_cv_lib_termcap_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ltermcap" >&5
$as_echo_n "checking for ${pbxfuncname} in -ltermcap... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${TERMCAP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default"
-if test "x$ac_cv_header_" = xyes; then :
+if test "x$ac_cv_header_" = x""yes; then :
TERMCAP_HEADER_FOUND=1
else
TERMCAP_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_tinfo_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ltinfo" >&5
$as_echo_n "checking for ${pbxfuncname} in -ltinfo... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${TINFO_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default"
-if test "x$ac_cv_header_" = xyes; then :
+if test "x$ac_cv_header_" = x""yes; then :
TINFO_HEADER_FOUND=1
else
TINFO_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_curses_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcurses" >&5
$as_echo_n "checking for ${pbxfuncname} in -lcurses... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${CURSES_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default"
-if test "x$ac_cv_header_curses_h" = xyes; then :
+if test "x$ac_cv_header_curses_h" = x""yes; then :
CURSES_HEADER_FOUND=1
else
CURSES_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ncurses_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lncurses" >&5
$as_echo_n "checking for ${pbxfuncname} in -lncurses... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${NCURSES_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default"
-if test "x$ac_cv_header_curses_h" = xyes; then :
+if test "x$ac_cv_header_curses_h" = x""yes; then :
NCURSES_HEADER_FOUND=1
else
NCURSES_HEADER_FOUND=0
enableval=$enable_xmldoc; case "${enableval}" in
y|ye|yes) disable_xmldoc=no ;;
n|no) disable_xmldoc=yes ;;
- *) as_fn_error $? "bad value ${enableval} for --disable-xmldoc" "$LINENO" 5 ;;
+ *) as_fn_error $? "bad value ${enableval} for --disable-xmldoc" "$LINENO" 5 ;;
esac
else
disable_xmldoc=no
set dummy ${ac_tool_prefix}xml2-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_LIBXML2+:} false; then :
+if test "${ac_cv_path_CONFIG_LIBXML2+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_LIBXML2 in
set dummy xml2-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_LIBXML2+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_LIBXML2+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_LIBXML2 in
for ac_header in xlocale.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "xlocale.h" "ac_cv_header_xlocale_h" "$ac_includes_default"
-if test "x$ac_cv_header_xlocale_h" = xyes; then :
+if test "x$ac_cv_header_xlocale_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_XLOCALE_H 1
_ACEOF
ac_fn_c_check_header_mongrel "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_poll_h" = xyes; then :
+if test "x$ac_cv_header_sys_poll_h" = x""yes; then :
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
-if ${ac_cv_sys_largefile_CC+:} false; then :
+if test "${ac_cv_sys_largefile_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_sys_largefile_CC=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
-if ${ac_cv_sys_file_offset_bits+:} false; then :
+if test "${ac_cv_sys_file_offset_bits+set}" = set; then :
$as_echo_n "(cached) " >&6
else
while :; do
if test $ac_cv_sys_file_offset_bits = unknown; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
-if ${ac_cv_sys_large_files+:} false; then :
+if test "${ac_cv_sys_large_files+set}" = set; then :
$as_echo_n "(cached) " >&6
else
while :; do
# Checks for typedefs, structures, and compiler characteristics.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5
$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; }
-if ${ac_cv_header_stdbool_h+:} false; then :
+if test "${ac_cv_header_stdbool_h+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
char b[false == 0 ? 1 : -1];
char c[__bool_true_false_are_defined == 1 ? 1 : -1];
char d[(bool) 0.5 == true ? 1 : -1];
- /* See body of main program for 'e'. */
+ bool e = &s;
char f[(_Bool) 0.0 == false ? 1 : -1];
char g[true];
char h[sizeof (_Bool)];
_Bool n[m];
char o[sizeof n == m * sizeof n[0] ? 1 : -1];
char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];
+# if defined __xlc__ || defined __GNUC__
+ /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0
+ reported by James Lemley on 2005-10-05; see
+ http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html
+ This test is not quite right, since xlc is allowed to
+ reject this program, as the initializer for xlcbug is
+ not one of the forms that C requires support for.
+ However, doing the test right would require a runtime
+ test, and that would make cross-compilation harder.
+ Let us hope that IBM fixes the xlc bug, and also adds
+ support for this kind of constant expression. In the
+ meantime, this test will reject xlc, which is OK, since
+ our stdbool.h substitute should suffice. We also test
+ this with GCC, where it should work, to detect more
+ quickly whether someone messes up the test in the
+ future. */
+ char digs[] = "0123456789";
+ int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1);
+# endif
/* Catch a bug in an HP-UX C compiler. See
http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html
http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html
main ()
{
- bool e = &s;
*pq |= q;
*pq |= ! q;
/* Refer to every declared value, to avoid compiler optimizations. */
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5
$as_echo "$ac_cv_header_stdbool_h" >&6; }
ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default"
-if test "x$ac_cv_type__Bool" = xyes; then :
+if test "x$ac_cv_type__Bool" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE__BOOL 1
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
-if ${ac_cv_c_const+:} false; then :
+if test "${ac_cv_c_const+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
-if ${ac_cv_type_uid_t+:} false; then :
+if test "${ac_cv_type_uid_t+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
$as_echo_n "checking for inline... " >&6; }
-if ${ac_cv_c_inline+:} false; then :
+if test "${ac_cv_c_inline+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_c_inline=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double with more range or precision than double" >&5
$as_echo_n "checking for long double with more range or precision than double... " >&6; }
-if ${ac_cv_type_long_double_wider+:} false; then :
+if test "${ac_cv_type_long_double_wider+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
fi
ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default"
-if test "x$ac_cv_type_mode_t" = xyes; then :
+if test "x$ac_cv_type_mode_t" = x""yes; then :
else
fi
ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
-if test "x$ac_cv_type_off_t" = xyes; then :
+if test "x$ac_cv_type_off_t" = x""yes; then :
else
fi
ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
-if test "x$ac_cv_type_pid_t" = xyes; then :
+if test "x$ac_cv_type_pid_t" = x""yes; then :
else
fi
ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
-if test "x$ac_cv_type_size_t" = xyes; then :
+if test "x$ac_cv_type_size_t" = x""yes; then :
else
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default"
-if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then :
+if test "x$ac_cv_member_struct_stat_st_blksize" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
ac_fn_c_check_member "$LINENO" "struct ucred" "uid" "ac_cv_member_struct_ucred_uid" "#include <sys/types.h>
#include <sys/socket.h>
"
-if test "x$ac_cv_member_struct_ucred_uid" = xyes; then :
+if test "x$ac_cv_member_struct_ucred_uid" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_UCRED_UID 1
ac_fn_c_check_member "$LINENO" "struct ucred" "cr_uid" "ac_cv_member_struct_ucred_cr_uid" "#include <sys/types.h>
#include <sys/socket.h>
"
-if test "x$ac_cv_member_struct_ucred_cr_uid" = xyes; then :
+if test "x$ac_cv_member_struct_ucred_cr_uid" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_UCRED_CR_UID 1
ac_fn_c_check_member "$LINENO" "struct sockpeercred" "uid" "ac_cv_member_struct_sockpeercred_uid" "#include <sys/types.h>
#include <sys/socket.h>
"
-if test "x$ac_cv_member_struct_sockpeercred_uid" = xyes; then :
+if test "x$ac_cv_member_struct_sockpeercred_uid" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_SOCKPEERCRED_UID 1
ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_ifru.ifru_hwaddr" "ac_cv_member_struct_ifreq_ifr_ifru_ifru_hwaddr" "#include <net/if.h>
"
-if test "x$ac_cv_member_struct_ifreq_ifr_ifru_ifru_hwaddr" = xyes; then :
+if test "x$ac_cv_member_struct_ifreq_ifr_ifru_ifru_hwaddr" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR 1
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
-if ${ac_cv_header_time+:} false; then :
+if test "${ac_cv_header_time+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
-if ${ac_cv_struct_tm+:} false; then :
+if test "${ac_cv_struct_tm+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5
$as_echo_n "checking for working volatile... " >&6; }
-if ${ac_cv_c_volatile+:} false; then :
+if test "${ac_cv_c_volatile+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
fi
ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default"
-if test "x$ac_cv_type_ptrdiff_t" = xyes; then :
+if test "x$ac_cv_type_ptrdiff_t" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_PTRDIFF_T 1
for ac_header in unistd.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default"
-if test "x$ac_cv_header_unistd_h" = xyes; then :
+if test "x$ac_cv_header_unistd_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_UNISTD_H 1
_ACEOF
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5
$as_echo_n "checking for working chown... " >&6; }
-if ${ac_cv_func_chown_works+:} false; then :
+if test "${ac_cv_func_chown_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether closedir returns void" >&5
$as_echo_n "checking whether closedir returns void... " >&6; }
-if ${ac_cv_func_closedir_void+:} false; then :
+if test "${ac_cv_func_closedir_void+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5
$as_echo_n "checking for error_at_line... " >&6; }
-if ${ac_cv_lib_error_at_line+:} false; then :
+if test "${ac_cv_lib_error_at_line+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
for ac_header in vfork.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default"
-if test "x$ac_cv_header_vfork_h" = xyes; then :
+if test "x$ac_cv_header_vfork_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_VFORK_H 1
_ACEOF
if test "x$ac_cv_func_fork" = xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5
$as_echo_n "checking for working fork... " >&6; }
-if ${ac_cv_func_fork_works+:} false; then :
+if test "${ac_cv_func_fork_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
if test "x$ac_cv_func_vfork" = xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5
$as_echo_n "checking for working vfork... " >&6; }
-if ${ac_cv_func_vfork_works+:} false; then :
+if test "${ac_cv_func_vfork_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5
$as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; }
-if ${ac_cv_sys_largefile_source+:} false; then :
+if test "${ac_cv_sys_largefile_source+set}" = set; then :
$as_echo_n "(cached) " >&6
else
while :; do
if test $ac_cv_c_compiler_gnu = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5
$as_echo_n "checking whether $CC needs -traditional... " >&6; }
-if ${ac_cv_prog_gcc_traditional+:} false; then :
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_pattern="Autoconf.*'x'"
# AC_FUNC_REALLOC
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5
$as_echo_n "checking for working memcmp... " >&6; }
-if ${ac_cv_func_memcmp_working+:} false; then :
+if test "${ac_cv_func_memcmp_working+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
for ac_func in getpagesize
do :
ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
-if test "x$ac_cv_func_getpagesize" = xyes; then :
+if test "x$ac_cv_func_getpagesize" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_GETPAGESIZE 1
_ACEOF
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5
$as_echo_n "checking for working mmap... " >&6; }
-if ${ac_cv_func_mmap_fixed_mapped+:} false; then :
+if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5
$as_echo_n "checking types of arguments for select... " >&6; }
-if ${ac_cv_func_select_args+:} false; then :
+if test "${ac_cv_func_select_args+set}" = set; then :
$as_echo_n "(cached) " >&6
else
for ac_arg234 in 'fd_set *' 'int *' 'void *'; do
done
done
# Provide a safe default value.
-: "${ac_cv_func_select_args=int,int *,struct timeval *}"
+: ${ac_cv_func_select_args='int,int *,struct timeval *'}
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5
rm -f conftest*
-if ${ac_cv_func_setvbuf_reversed+:} false; then :
+if test "${ac_cv_func_setvbuf_reversed+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_func_setvbuf_reversed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
$as_echo_n "checking return type of signal handlers... " >&6; }
-if ${ac_cv_type_signal+:} false; then :
+if test "${ac_cv_type_signal+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5
$as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; }
-if ${ac_cv_func_lstat_dereferences_slashed_symlink+:} false; then :
+if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then :
$as_echo_n "(cached) " >&6
else
rm -f conftest.sym conftest.file
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5
$as_echo_n "checking whether stat accepts an empty string... " >&6; }
-if ${ac_cv_func_stat_empty_string_bug+:} false; then :
+if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strcoll" >&5
$as_echo_n "checking for working strcoll... " >&6; }
-if ${ac_cv_func_strcoll_works+:} false; then :
+if test "${ac_cv_func_strcoll_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
for ac_func in strftime
do :
ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime"
-if test "x$ac_cv_func_strftime" = xyes; then :
+if test "x$ac_cv_func_strftime" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRFTIME 1
_ACEOF
# strftime is in -lintl on SCO UNIX.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5
$as_echo_n "checking for strftime in -lintl... " >&6; }
-if ${ac_cv_lib_intl_strftime+:} false; then :
+if test "${ac_cv_lib_intl_strftime+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5
$as_echo "$ac_cv_lib_intl_strftime" >&6; }
-if test "x$ac_cv_lib_intl_strftime" = xyes; then :
+if test "x$ac_cv_lib_intl_strftime" = x""yes; then :
$as_echo "#define HAVE_STRFTIME 1" >>confdefs.h
LIBS="-lintl $LIBS"
fi
done
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strnlen" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strnlen" >&5
$as_echo_n "checking for working strnlen... " >&6; }
-if ${ac_cv_func_strnlen_working+:} false; then :
+if test "${ac_cv_func_strnlen_working+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
- # Guess no on AIX systems, yes otherwise.
- case "$host_os" in
- aix*) ac_cv_func_strnlen_working=no;;
- *) ac_cv_func_strnlen_working=yes;;
- esac
+ ac_cv_func_strnlen_working=no
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strtod" >&5
$as_echo_n "checking for working strtod... " >&6; }
-if ${ac_cv_func_strtod+:} false; then :
+if test "${ac_cv_func_strtod+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
esac
ac_fn_c_check_func "$LINENO" "pow" "ac_cv_func_pow"
-if test "x$ac_cv_func_pow" = xyes; then :
+if test "x$ac_cv_func_pow" = x""yes; then :
fi
if test $ac_cv_func_pow = no; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5
$as_echo_n "checking for pow in -lm... " >&6; }
-if ${ac_cv_lib_m_pow+:} false; then :
+if test "${ac_cv_lib_m_pow+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5
$as_echo "$ac_cv_lib_m_pow" >&6; }
-if test "x$ac_cv_lib_m_pow" = xyes; then :
+if test "x$ac_cv_lib_m_pow" = x""yes; then :
POW_LIB=-lm
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find library containing definition of pow" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether utime accepts a null argument" >&5
$as_echo_n "checking whether utime accepts a null argument... " >&6; }
-if ${ac_cv_func_utime_null+:} false; then :
+if test "${ac_cv_func_utime_null+set}" = set; then :
$as_echo_n "(cached) " >&6
else
rm -f conftest.data; >conftest.data
for ac_func in vprintf
do :
ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf"
-if test "x$ac_cv_func_vprintf" = xyes; then :
+if test "x$ac_cv_func_vprintf" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_VPRINTF 1
_ACEOF
ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt"
-if test "x$ac_cv_func__doprnt" = xyes; then :
+if test "x$ac_cv_func__doprnt" = x""yes; then :
$as_echo "#define HAVE_DOPRNT 1" >>confdefs.h
# so that AC_CHECK_FUNCS can detect functions in that library.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5
$as_echo_n "checking for sqrt in -lm... " >&6; }
-if ${ac_cv_lib_m_sqrt+:} false; then :
+if test "${ac_cv_lib_m_sqrt+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5
$as_echo "$ac_cv_lib_m_sqrt" >&6; }
-if test "x$ac_cv_lib_m_sqrt" = xyes; then :
+if test "x$ac_cv_lib_m_sqrt" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBM 1
_ACEOF
rm -f conftest.dynamics
ac_fn_c_check_header_mongrel "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_poll_h" = xyes; then :
+if test "x$ac_cv_header_sys_poll_h" = x""yes; then :
HAS_POLL=1
$as_echo "#define HAVE_SYS_POLL_H 1" >>confdefs.h
enableval=$enable_internal_poll; case "${enableval}" in
y|ye|yes) HAS_POLL="";;
n|no) HAS_POLL="${HAS_POLL}" ;;
- *) as_fn_error $? "bad value ${enableval} for --enable-internal-poll" "$LINENO" 5 ;;
+ *) as_fn_error $? "bad value ${enableval} for --enable-internal-poll" "$LINENO" 5 ;;
esac
fi
for ac_func in inet_aton
do :
ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton"
-if test "x$ac_cv_func_inet_aton" = xyes; then :
+if test "x$ac_cv_func_inet_aton" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_INET_ATON 1
_ACEOF
# some systems already have gethostbyname_r so we don't need to build ours in main/utils.c
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname_r" >&5
$as_echo_n "checking for library containing gethostbyname_r... " >&6; }
-if ${ac_cv_search_gethostbyname_r+:} false; then :
+if test "${ac_cv_search_gethostbyname_r+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_gethostbyname_r+:} false; then :
+ if test "${ac_cv_search_gethostbyname_r+set}" = set; then :
break
fi
done
-if ${ac_cv_search_gethostbyname_r+:} false; then :
+if test "${ac_cv_search_gethostbyname_r+set}" = set; then :
else
ac_cv_search_gethostbyname_r=no
conftest$ac_exeext conftest.$ac_ext
ac_fn_c_check_header_mongrel "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default"
-if test "x$ac_cv_header_byteswap_h" = xyes; then :
+if test "x$ac_cv_header_byteswap_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_BYTESWAP_H 1
then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
$as_echo_n "checking for /dev/urandom... " >&6; }
-if ${ac_cv_file__dev_urandom+:} false; then :
+if test "${ac_cv_file__dev_urandom+set}" = set; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_urandom" >&5
$as_echo "$ac_cv_file__dev_urandom" >&6; }
-if test "x$ac_cv_file__dev_urandom" = xyes; then :
+if test "x$ac_cv_file__dev_urandom" = x""yes; then :
$as_echo "#define HAVE_DEV_URANDOM 1" >>confdefs.h
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_9_ninit" >&5
$as_echo_n "checking for library containing res_9_ninit... " >&6; }
-if ${ac_cv_search_res_9_ninit+:} false; then :
+if test "${ac_cv_search_res_9_ninit+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_res_9_ninit+:} false; then :
+ if test "${ac_cv_search_res_9_ninit+set}" = set; then :
break
fi
done
-if ${ac_cv_search_res_9_ninit+:} false; then :
+if test "${ac_cv_search_res_9_ninit+set}" = set; then :
else
ac_cv_search_res_9_ninit=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_9_ndestroy" >&5
$as_echo_n "checking for library containing res_9_ndestroy... " >&6; }
-if ${ac_cv_search_res_9_ndestroy+:} false; then :
+if test "${ac_cv_search_res_9_ndestroy+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_res_9_ndestroy+:} false; then :
+ if test "${ac_cv_search_res_9_ndestroy+set}" = set; then :
break
fi
done
-if ${ac_cv_search_res_9_ndestroy+:} false; then :
+if test "${ac_cv_search_res_9_ndestroy+set}" = set; then :
else
ac_cv_search_res_9_ndestroy=no
conftest$ac_exeext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_9_close" >&5
$as_echo_n "checking for library containing res_9_close... " >&6; }
-if ${ac_cv_search_res_9_close+:} false; then :
+if test "${ac_cv_search_res_9_close+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_res_9_close+:} false; then :
+ if test "${ac_cv_search_res_9_close+set}" = set; then :
break
fi
done
-if ${ac_cv_search_res_9_close+:} false; then :
+if test "${ac_cv_search_res_9_close+set}" = set; then :
else
ac_cv_search_res_9_close=no
ac_fn_c_check_header_mongrel "$LINENO" "libkern/OSAtomic.h" "ac_cv_header_libkern_OSAtomic_h" "$ac_includes_default"
-if test "x$ac_cv_header_libkern_OSAtomic_h" = xyes; then :
+if test "x$ac_cv_header_libkern_OSAtomic_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_OSX_ATOMICS 1
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
$as_echo_n "checking size of int... " >&6; }
-if ${ac_cv_sizeof_int+:} false; then :
+if test "${ac_cv_sizeof_int+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (int)
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
ac_cv_sizeof_int=0
fi
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
$as_echo_n "checking size of long... " >&6; }
-if ${ac_cv_sizeof_long+:} false; then :
+if test "${ac_cv_sizeof_long+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (long)
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
ac_cv_sizeof_long=0
fi
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5
$as_echo_n "checking size of long long... " >&6; }
-if ${ac_cv_sizeof_long_long+:} false; then :
+if test "${ac_cv_sizeof_long_long+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (long long)
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
ac_cv_sizeof_long_long=0
fi
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char *" >&5
$as_echo_n "checking size of char *... " >&6; }
-if ${ac_cv_sizeof_char_p+:} false; then :
+if test "${ac_cv_sizeof_char_p+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char *))" "ac_cv_sizeof_char_p" "$ac_includes_default"; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (char *)
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
ac_cv_sizeof_char_p=0
fi
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
$as_echo_n "checking size of long... " >&6; }
-if ${ac_cv_sizeof_long+:} false; then :
+if test "${ac_cv_sizeof_long+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (long)
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
ac_cv_sizeof_long=0
fi
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5
$as_echo_n "checking size of long long... " >&6; }
-if ${ac_cv_sizeof_long_long+:} false; then :
+if test "${ac_cv_sizeof_long_long+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (long long)
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
ac_cv_sizeof_long_long=0
fi
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fd_set.fds_bits" >&5
$as_echo_n "checking size of fd_set.fds_bits... " >&6; }
-if ${ac_cv_sizeof_fd_set_fds_bits+:} false; then :
+if test "${ac_cv_sizeof_fd_set_fds_bits+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fd_set.fds_bits))" "ac_cv_sizeof_fd_set_fds_bits" "$ac_includes_default"; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (fd_set.fds_bits)
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
ac_cv_sizeof_fd_set_fds_bits=0
fi
set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_PKGCONFIG+:} false; then :
+if test "${ac_cv_prog_PKGCONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$PKGCONFIG"; then
set dummy pkg-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_PKGCONFIG+:} false; then :
+if test "${ac_cv_prog_ac_ct_PKGCONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_PKGCONFIG"; then
as_ac_Lib=`$as_echo "ac_cv_lib_asound_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lasound" >&5
$as_echo_n "checking for ${pbxfuncname} in -lasound... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ALSA_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "alsa/asoundlib.h" "ac_cv_header_alsa_asoundlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_alsa_asoundlib_h" = xyes; then :
+if test "x$ac_cv_header_alsa_asoundlib_h" = x""yes; then :
ALSA_HEADER_FOUND=1
else
ALSA_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_bfd_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lbfd" >&5
$as_echo_n "checking for ${pbxfuncname} in -lbfd... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BFD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "bfd.h" "ac_cv_header_bfd_h" "$ac_includes_default"
-if test "x$ac_cv_header_bfd_h" = xyes; then :
+if test "x$ac_cv_header_bfd_h" = x""yes; then :
BFD_HEADER_FOUND=1
else
BFD_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_bfd_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lbfd" >&5
$as_echo_n "checking for ${pbxfuncname} in -lbfd... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BFD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "bfd.h" "ac_cv_header_bfd_h" "$ac_includes_default"
-if test "x$ac_cv_header_bfd_h" = xyes; then :
+if test "x$ac_cv_header_bfd_h" = x""yes; then :
BFD_HEADER_FOUND=1
else
BFD_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_cap_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcap" >&5
$as_echo_n "checking for ${pbxfuncname} in -lcap... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${CAP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_capability_h" = xyes; then :
+if test "x$ac_cv_header_sys_capability_h" = x""yes; then :
CAP_HEADER_FOUND=1
else
CAP_HEADER_FOUND=0
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gsm_create in -lgsm" >&5
$as_echo_n "checking for gsm_create in -lgsm... " >&6; }
-if ${ac_cv_lib_gsm_gsm_create+:} false; then :
+if test "${ac_cv_lib_gsm_gsm_create+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gsm_gsm_create" >&5
$as_echo "$ac_cv_lib_gsm_gsm_create" >&6; }
-if test "x$ac_cv_lib_gsm_gsm_create" = xyes; then :
+if test "x$ac_cv_lib_gsm_gsm_create" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_GSM 1
else
ac_fn_c_check_header_mongrel "$LINENO" "gsm.h" "ac_cv_header_gsm_h" "$ac_includes_default"
-if test "x$ac_cv_header_gsm_h" = xyes; then :
+if test "x$ac_cv_header_gsm_h" = x""yes; then :
GSM_HEADER_FOUND=1
else
GSM_HEADER_FOUND=0
ac_fn_c_check_header_mongrel "$LINENO" "gsm/gsm.h" "ac_cv_header_gsm_gsm_h" "$ac_includes_default"
-if test "x$ac_cv_header_gsm_gsm_h" = xyes; then :
+if test "x$ac_cv_header_gsm_gsm_h" = x""yes; then :
GSM_GSM_HEADER_FOUND=1
else
GSM_GSM_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_iconv_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -liconv" >&5
$as_echo_n "checking for ${pbxfuncname} in -liconv... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ICONV_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default"
-if test "x$ac_cv_header_iconv_h" = xyes; then :
+if test "x$ac_cv_header_iconv_h" = x""yes; then :
ICONV_HEADER_FOUND=1
else
ICONV_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_iconv_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -liconv" >&5
$as_echo_n "checking for ${pbxfuncname} in -liconv... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ICONV_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default"
-if test "x$ac_cv_header_iconv_h" = xyes; then :
+if test "x$ac_cv_header_iconv_h" = x""yes; then :
ICONV_HEADER_FOUND=1
else
ICONV_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ICONV_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default"
-if test "x$ac_cv_header_iconv_h" = xyes; then :
+if test "x$ac_cv_header_iconv_h" = x""yes; then :
ICONV_HEADER_FOUND=1
else
ICONV_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ical_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lical" >&5
$as_echo_n "checking for ${pbxfuncname} in -lical... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ICAL_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libical/ical.h" "ac_cv_header_libical_ical_h" "$ac_includes_default"
-if test "x$ac_cv_header_libical_ical_h" = xyes; then :
+if test "x$ac_cv_header_libical_ical_h" = x""yes; then :
ICAL_HEADER_FOUND=1
else
ICAL_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_iksemel_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -liksemel" >&5
$as_echo_n "checking for ${pbxfuncname} in -liksemel... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${IKSEMEL_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "iksemel.h" "ac_cv_header_iksemel_h" "$ac_includes_default"
-if test "x$ac_cv_header_iksemel_h" = xyes; then :
+if test "x$ac_cv_header_iksemel_h" = x""yes; then :
IKSEMEL_HEADER_FOUND=1
else
IKSEMEL_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_iodbc_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -liodbc" >&5
$as_echo_n "checking for ${pbxfuncname} in -liodbc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${IODBC_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sql.h" "ac_cv_header_sql_h" "$ac_includes_default"
-if test "x$ac_cv_header_sql_h" = xyes; then :
+if test "x$ac_cv_header_sql_h" = x""yes; then :
IODBC_HEADER_FOUND=1
else
IODBC_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${INOTIFY_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_inotify_h" = xyes; then :
+if test "x$ac_cv_header_sys_inotify_h" = x""yes; then :
INOTIFY_HEADER_FOUND=1
else
INOTIFY_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_jack_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ljack" >&5
$as_echo_n "checking for ${pbxfuncname} in -ljack... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${JACK_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "jack/jack.h" "ac_cv_header_jack_jack_h" "$ac_includes_default"
-if test "x$ac_cv_header_jack_jack_h" = xyes; then :
+if test "x$ac_cv_header_jack_jack_h" = x""yes; then :
JACK_HEADER_FOUND=1
else
JACK_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${KQUEUE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_event_h" = xyes; then :
+if test "x$ac_cv_header_sys_event_h" = x""yes; then :
KQUEUE_HEADER_FOUND=1
else
KQUEUE_HEADER_FOUND=0
for ac_func in kevent64
do :
ac_fn_c_check_func "$LINENO" "kevent64" "ac_cv_func_kevent64"
-if test "x$ac_cv_func_kevent64" = xyes; then :
+if test "x$ac_cv_func_kevent64" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_KEVENT64 1
_ACEOF
as_ac_Lib=`$as_echo "ac_cv_lib_ltdl_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lltdl" >&5
$as_echo_n "checking for ${pbxfuncname} in -lltdl... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${LTDL_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "ltdl.h" "ac_cv_header_ltdl_h" "$ac_includes_default"
-if test "x$ac_cv_header_ltdl_h" = xyes; then :
+if test "x$ac_cv_header_ltdl_h" = x""yes; then :
LTDL_HEADER_FOUND=1
else
LTDL_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ldap_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lldap" >&5
$as_echo_n "checking for ${pbxfuncname} in -lldap... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${LDAP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "ldap.h" "ac_cv_header_ldap_h" "$ac_includes_default"
-if test "x$ac_cv_header_ldap_h" = xyes; then :
+if test "x$ac_cv_header_ldap_h" = x""yes; then :
LDAP_HEADER_FOUND=1
else
LDAP_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_mISDN_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lmISDN" >&5
$as_echo_n "checking for ${pbxfuncname} in -lmISDN... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${MISDN_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "mISDNuser/mISDNlib.h" "ac_cv_header_mISDNuser_mISDNlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_mISDNuser_mISDNlib_h" = xyes; then :
+if test "x$ac_cv_header_mISDNuser_mISDNlib_h" = x""yes; then :
MISDN_HEADER_FOUND=1
else
MISDN_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_isdnnet_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lisdnnet" >&5
$as_echo_n "checking for ${pbxfuncname} in -lisdnnet... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ISDNNET_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "mISDNuser/isdn_net.h" "ac_cv_header_mISDNuser_isdn_net_h" "$ac_includes_default"
-if test "x$ac_cv_header_mISDNuser_isdn_net_h" = xyes; then :
+if test "x$ac_cv_header_mISDNuser_isdn_net_h" = x""yes; then :
ISDNNET_HEADER_FOUND=1
else
ISDNNET_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_suppserv_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsuppserv" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsuppserv... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SUPPSERV_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "mISDNuser/suppserv.h" "ac_cv_header_mISDNuser_suppserv_h" "$ac_includes_default"
-if test "x$ac_cv_header_mISDNuser_suppserv_h" = xyes; then :
+if test "x$ac_cv_header_mISDNuser_suppserv_h" = x""yes; then :
SUPPSERV_HEADER_FOUND=1
else
SUPPSERV_HEADER_FOUND=0
ac_fn_c_check_header_mongrel "$LINENO" "linux/mISDNdsp.h" "ac_cv_header_linux_mISDNdsp_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_mISDNdsp_h" = xyes; then :
+if test "x$ac_cv_header_linux_mISDNdsp_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define MISDN_1_2 1
ac_fn_c_check_member "$LINENO" "Q931_info_t" "redirect_dn" "ac_cv_member_Q931_info_t_redirect_dn" "#include <mISDNuser/mISDNlib.h>
"
-if test "x$ac_cv_member_Q931_info_t_redirect_dn" = xyes; then :
+if test "x$ac_cv_member_Q931_info_t_redirect_dn" = x""yes; then :
else
PBX_MISDN=0
set dummy ${ac_tool_prefix}mysql_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_MYSQLCLIENT+:} false; then :
+if test "${ac_cv_path_CONFIG_MYSQLCLIENT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_MYSQLCLIENT in
set dummy mysql_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_MYSQLCLIENT+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_MYSQLCLIENT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_MYSQLCLIENT in
as_ac_Lib=`$as_echo "ac_cv_lib_nbs_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lnbs" >&5
$as_echo_n "checking for ${pbxfuncname} in -lnbs... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${NBS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "nbs.h" "ac_cv_header_nbs_h" "$ac_includes_default"
-if test "x$ac_cv_header_nbs_h" = xyes; then :
+if test "x$ac_cv_header_nbs_h" = x""yes; then :
NBS_HEADER_FOUND=1
else
NBS_HEADER_FOUND=0
set dummy ${ac_tool_prefix}neon-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_NEON+:} false; then :
+if test "${ac_cv_path_CONFIG_NEON+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_NEON in
set dummy neon-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_NEON+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_NEON+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_NEON in
set dummy ${ac_tool_prefix}neon-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_NEON29+:} false; then :
+if test "${ac_cv_path_CONFIG_NEON29+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_NEON29 in
set dummy neon-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_NEON29+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_NEON29+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_NEON29 in
set dummy ${ac_tool_prefix}net-snmp-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_NETSNMP+:} false; then :
+if test "${ac_cv_path_CONFIG_NETSNMP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_NETSNMP in
set dummy net-snmp-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_NETSNMP+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_NETSNMP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_NETSNMP in
as_ac_Lib=`$as_echo "ac_cv_lib_newt_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lnewt" >&5
$as_echo_n "checking for ${pbxfuncname} in -lnewt... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${NEWT_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "newt.h" "ac_cv_header_newt_h" "$ac_includes_default"
-if test "x$ac_cv_header_newt_h" = xyes; then :
+if test "x$ac_cv_header_newt_h" = x""yes; then :
NEWT_HEADER_FOUND=1
else
NEWT_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_odbc_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lodbc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lodbc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${UNIXODBC_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sql.h" "ac_cv_header_sql_h" "$ac_includes_default"
-if test "x$ac_cv_header_sql_h" = xyes; then :
+if test "x$ac_cv_header_sql_h" = x""yes; then :
UNIXODBC_HEADER_FOUND=1
else
UNIXODBC_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ogg_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -logg" >&5
$as_echo_n "checking for ${pbxfuncname} in -logg... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OGG_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default"
-if test "x$ac_cv_header_" = xyes; then :
+if test "x$ac_cv_header_" = x""yes; then :
OGG_HEADER_FOUND=1
else
OGG_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_execinfo_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lexecinfo" >&5
$as_echo_n "checking for ${pbxfuncname} in -lexecinfo... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BKTR_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
-if test "x$ac_cv_header_execinfo_h" = xyes; then :
+if test "x$ac_cv_header_execinfo_h" = x""yes; then :
BKTR_HEADER_FOUND=1
else
BKTR_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BKTR_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
-if test "x$ac_cv_header_execinfo_h" = xyes; then :
+if test "x$ac_cv_header_execinfo_h" = x""yes; then :
BKTR_HEADER_FOUND=1
else
BKTR_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_bluetooth_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lbluetooth" >&5
$as_echo_n "checking for ${pbxfuncname} in -lbluetooth... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BLUETOOTH_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default"
-if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then :
+if test "x$ac_cv_header_bluetooth_bluetooth_h" = x""yes; then :
BLUETOOTH_HEADER_FOUND=1
else
BLUETOOTH_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ossaudio_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lossaudio" >&5
$as_echo_n "checking for ${pbxfuncname} in -lossaudio... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OSS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "linux/soundcard.h" "ac_cv_header_linux_soundcard_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_soundcard_h" = xyes; then :
+if test "x$ac_cv_header_linux_soundcard_h" = x""yes; then :
OSS_HEADER_FOUND=1
else
OSS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ossaudio_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lossaudio" >&5
$as_echo_n "checking for ${pbxfuncname} in -lossaudio... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OSS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sys/soundcard.h" "ac_cv_header_sys_soundcard_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_soundcard_h" = xyes; then :
+if test "x$ac_cv_header_sys_soundcard_h" = x""yes; then :
OSS_HEADER_FOUND=1
else
OSS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ossaudio_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lossaudio" >&5
$as_echo_n "checking for ${pbxfuncname} in -lossaudio... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OSS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "soundcard.h" "ac_cv_header_soundcard_h" "$ac_includes_default"
-if test "x$ac_cv_header_soundcard_h" = xyes; then :
+if test "x$ac_cv_header_soundcard_h" = x""yes; then :
OSS_HEADER_FOUND=1
else
OSS_HEADER_FOUND=0
set dummy ${ac_tool_prefix}pg_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PG_CONFIG+:} false; then :
+if test "${ac_cv_path_PG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PG_CONFIG in
set dummy pg_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PG_CONFIG+:} false; then :
+if test "${ac_cv_path_ac_pt_PG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_PG_CONFIG in
set dummy ${ac_tool_prefix}pg_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PG_CONFIG+:} false; then :
+if test "${ac_cv_path_PG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PG_CONFIG in
set dummy pg_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PG_CONFIG+:} false; then :
+if test "${ac_cv_path_ac_pt_PG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_PG_CONFIG in
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PQescapeStringConn in -lpq" >&5
$as_echo_n "checking for PQescapeStringConn in -lpq... " >&6; }
-if ${ac_cv_lib_pq_PQescapeStringConn+:} false; then :
+if test "${ac_cv_lib_pq_PQescapeStringConn+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pq_PQescapeStringConn" >&5
$as_echo "$ac_cv_lib_pq_PQescapeStringConn" >&6; }
-if test "x$ac_cv_lib_pq_PQescapeStringConn" = xyes; then :
+if test "x$ac_cv_lib_pq_PQescapeStringConn" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_PGSQL 1
as_ac_Lib=`$as_echo "ac_cv_lib_popt_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpopt" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpopt... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${POPT_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "popt.h" "ac_cv_header_popt_h" "$ac_includes_default"
-if test "x$ac_cv_header_popt_h" = xyes; then :
+if test "x$ac_cv_header_popt_h" = x""yes; then :
POPT_HEADER_FOUND=1
else
POPT_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_portaudio_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lportaudio" >&5
$as_echo_n "checking for ${pbxfuncname} in -lportaudio... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PORTAUDIO_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "portaudio.h" "ac_cv_header_portaudio_h" "$ac_includes_default"
-if test "x$ac_cv_header_portaudio_h" = xyes; then :
+if test "x$ac_cv_header_portaudio_h" = x""yes; then :
PORTAUDIO_HEADER_FOUND=1
else
PORTAUDIO_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_HEADER_FOUND=1
else
PRI_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_L2_PERSISTENCE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_L2_PERSISTENCE_HEADER_FOUND=1
else
PRI_L2_PERSISTENCE_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_MWI_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_MWI_HEADER_FOUND=1
else
PRI_MWI_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_MCID_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_MCID_HEADER_FOUND=1
else
PRI_MCID_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_CALL_WAITING_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_CALL_WAITING_HEADER_FOUND=1
else
PRI_CALL_WAITING_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_AOC_EVENTS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_AOC_EVENTS_HEADER_FOUND=1
else
PRI_AOC_EVENTS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_TRANSFER_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_TRANSFER_HEADER_FOUND=1
else
PRI_TRANSFER_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_CCSS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_CCSS_HEADER_FOUND=1
else
PRI_CCSS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_HANGUP_FIX_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_HANGUP_FIX_HEADER_FOUND=1
else
PRI_HANGUP_FIX_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_SUBADDR_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_SUBADDR_HEADER_FOUND=1
else
PRI_SUBADDR_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_CALL_HOLD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_CALL_HOLD_HEADER_FOUND=1
else
PRI_CALL_HOLD_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_CALL_REROUTING_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_CALL_REROUTING_HEADER_FOUND=1
else
PRI_CALL_REROUTING_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_SETUP_KEYPAD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_SETUP_KEYPAD_HEADER_FOUND=1
else
PRI_SETUP_KEYPAD_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_PROG_W_CAUSE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_PROG_W_CAUSE_HEADER_FOUND=1
else
PRI_PROG_W_CAUSE_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_INBANDDISCONNECT_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_INBANDDISCONNECT_HEADER_FOUND=1
else
PRI_INBANDDISCONNECT_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_SERVICE_MESSAGES_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_SERVICE_MESSAGES_HEADER_FOUND=1
else
PRI_SERVICE_MESSAGES_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_REVERSE_CHARGE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_REVERSE_CHARGE_HEADER_FOUND=1
else
PRI_REVERSE_CHARGE_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_resample_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lresample" >&5
$as_echo_n "checking for ${pbxfuncname} in -lresample... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${RESAMPLE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libresample.h" "ac_cv_header_libresample_h" "$ac_includes_default"
-if test "x$ac_cv_header_libresample_h" = xyes; then :
+if test "x$ac_cv_header_libresample_h" = x""yes; then :
RESAMPLE_HEADER_FOUND=1
else
RESAMPLE_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_spandsp_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspandsp" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspandsp... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPANDSP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "spandsp.h" "ac_cv_header_spandsp_h" "$ac_includes_default"
-if test "x$ac_cv_header_spandsp_h" = xyes; then :
+if test "x$ac_cv_header_spandsp_h" = x""yes; then :
SPANDSP_HEADER_FOUND=1
else
SPANDSP_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_spandsp_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspandsp" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspandsp... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPANDSP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "spandsp.h" "ac_cv_header_spandsp_h" "$ac_includes_default"
-if test "x$ac_cv_header_spandsp_h" = xyes; then :
+if test "x$ac_cv_header_spandsp_h" = x""yes; then :
SPANDSP_HEADER_FOUND=1
else
SPANDSP_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ss7_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lss7" >&5
$as_echo_n "checking for ${pbxfuncname} in -lss7... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SS7_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libss7.h" "ac_cv_header_libss7_h" "$ac_includes_default"
-if test "x$ac_cv_header_libss7_h" = xyes; then :
+if test "x$ac_cv_header_libss7_h" = x""yes; then :
SS7_HEADER_FOUND=1
else
SS7_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_openr2_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lopenr2" >&5
$as_echo_n "checking for ${pbxfuncname} in -lopenr2... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OPENR2_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "openr2.h" "ac_cv_header_openr2_h" "$ac_includes_default"
-if test "x$ac_cv_header_openr2_h" = xyes; then :
+if test "x$ac_cv_header_openr2_h" = x""yes; then :
OPENR2_HEADER_FOUND=1
else
OPENR2_HEADER_FOUND=0
PWLIBDIR="${HOME}/pwlib"
else
ac_fn_cxx_check_header_mongrel "$LINENO" "/usr/local/include/ptlib.h" "ac_cv_header__usr_local_include_ptlib_h" "$ac_includes_default"
-if test "x$ac_cv_header__usr_local_include_ptlib_h" = xyes; then :
+if test "x$ac_cv_header__usr_local_include_ptlib_h" = x""yes; then :
HAS_PWLIB=1
fi
set dummy ptlib-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PTLIB_CONFIG+:} false; then :
+if test "${ac_cv_path_PTLIB_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PTLIB_CONFIG in
PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
else
ac_fn_cxx_check_header_mongrel "$LINENO" "/usr/include/ptlib.h" "ac_cv_header__usr_include_ptlib_h" "$ac_includes_default"
-if test "x$ac_cv_header__usr_include_ptlib_h" = xyes; then :
+if test "x$ac_cv_header__usr_include_ptlib_h" = x""yes; then :
HAS_PWLIB=1
fi
set dummy ptlib-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PTLIB_CONFIG+:} false; then :
+if test "${ac_cv_path_PTLIB_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PTLIB_CONFIG in
CPPFLAGS="${CPPFLAGS} -I/usr/local/include/openh323 -I${PWLIB_INCDIR}"
ac_fn_cxx_check_header_compile "$LINENO" "/usr/local/include/openh323/h323.h" "ac_cv_header__usr_local_include_openh323_h323_h" "#include <ptlib.h>
"
-if test "x$ac_cv_header__usr_local_include_openh323_h323_h" = xyes; then :
+if test "x$ac_cv_header__usr_local_include_openh323_h323_h" = x""yes; then :
HAS_OPENH323=1
fi
CPPFLAGS="${CPPFLAGS} -I/usr/include/openh323 -I${PWLIB_INCDIR}"
ac_fn_cxx_check_header_compile "$LINENO" "/usr/include/openh323/h323.h" "ac_cv_header__usr_include_openh323_h323_h" "#include <ptlib.h>
"
-if test "x$ac_cv_header__usr_include_openh323_h323_h" = xyes; then :
+if test "x$ac_cv_header__usr_include_openh323_h323_h" = x""yes; then :
HAS_OPENH323=1
fi
as_ac_Lib=`$as_echo "ac_cv_lib_lua5.1_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -llua5.1" >&5
$as_echo_n "checking for ${pbxfuncname} in -llua5.1... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "lua5.1/lua.h" "ac_cv_header_lua5_1_lua_h" "$ac_includes_default"
-if test "x$ac_cv_header_lua5_1_lua_h" = xyes; then :
+if test "x$ac_cv_header_lua5_1_lua_h" = x""yes; then :
LUA_HEADER_FOUND=1
else
LUA_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_lua_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -llua" >&5
$as_echo_n "checking for ${pbxfuncname} in -llua... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "lua.h" "ac_cv_header_lua_h" "$ac_includes_default"
-if test "x$ac_cv_header_lua_h" = xyes; then :
+if test "x$ac_cv_header_lua_h" = x""yes; then :
LUA_HEADER_FOUND=1
else
LUA_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_radiusclient-ng_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lradiusclient-ng" >&5
$as_echo_n "checking for ${pbxfuncname} in -lradiusclient-ng... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${RADIUS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "radiusclient-ng.h" "ac_cv_header_radiusclient_ng_h" "$ac_includes_default"
-if test "x$ac_cv_header_radiusclient_ng_h" = xyes; then :
+if test "x$ac_cv_header_radiusclient_ng_h" = x""yes; then :
RADIUS_HEADER_FOUND=1
else
RADIUS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_SaClm_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lSaClm" >&5
$as_echo_n "checking for ${pbxfuncname} in -lSaClm... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OPENAIS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "openais/saClm.h" "ac_cv_header_openais_saClm_h" "$ac_includes_default"
-if test "x$ac_cv_header_openais_saClm_h" = xyes; then :
+if test "x$ac_cv_header_openais_saClm_h" = x""yes; then :
OPENAIS_HEADER_FOUND=1
else
OPENAIS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_speex_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspeex" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspeex... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPEEX_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "speex/speex.h" "ac_cv_header_speex_speex_h" "$ac_includes_default"
-if test "x$ac_cv_header_speex_speex_h" = xyes; then :
+if test "x$ac_cv_header_speex_speex_h" = x""yes; then :
SPEEX_HEADER_FOUND=1
else
SPEEX_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_speex_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspeex" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspeex... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPEEX_PREPROCESS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "speex/speex.h" "ac_cv_header_speex_speex_h" "$ac_includes_default"
-if test "x$ac_cv_header_speex_speex_h" = xyes; then :
+if test "x$ac_cv_header_speex_speex_h" = x""yes; then :
SPEEX_PREPROCESS_HEADER_FOUND=1
else
SPEEX_PREPROCESS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_speexdsp_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspeexdsp" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspeexdsp... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPEEXDSP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "speex/speex.h" "ac_cv_header_speex_speex_h" "$ac_includes_default"
-if test "x$ac_cv_header_speex_speex_h" = xyes; then :
+if test "x$ac_cv_header_speex_speex_h" = x""yes; then :
SPEEXDSP_HEADER_FOUND=1
else
SPEEXDSP_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_sqlite_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsqlite" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsqlite... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SQLITE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sqlite.h" "ac_cv_header_sqlite_h" "$ac_includes_default"
-if test "x$ac_cv_header_sqlite_h" = xyes; then :
+if test "x$ac_cv_header_sqlite_h" = x""yes; then :
SQLITE_HEADER_FOUND=1
else
SQLITE_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_sqlite3_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsqlite3" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsqlite3... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SQLITE3_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default"
-if test "x$ac_cv_header_sqlite3_h" = xyes; then :
+if test "x$ac_cv_header_sqlite3_h" = x""yes; then :
SQLITE3_HEADER_FOUND=1
else
SQLITE3_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_crypto_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcrypto" >&5
$as_echo_n "checking for ${pbxfuncname} in -lcrypto... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${CRYPTO_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "openssl/aes.h" "ac_cv_header_openssl_aes_h" "$ac_includes_default"
-if test "x$ac_cv_header_openssl_aes_h" = xyes; then :
+if test "x$ac_cv_header_openssl_aes_h" = x""yes; then :
CRYPTO_HEADER_FOUND=1
else
CRYPTO_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_ssl_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lssl" >&5
$as_echo_n "checking for ${pbxfuncname} in -lssl... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OPENSSL_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default"
-if test "x$ac_cv_header_openssl_ssl_h" = xyes; then :
+if test "x$ac_cv_header_openssl_ssl_h" = x""yes; then :
OPENSSL_HEADER_FOUND=1
else
OPENSSL_HEADER_FOUND=0
osptk_saved_cppflags="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${osptk_cflags}"
ac_fn_c_check_header_mongrel "$LINENO" "osp/osp.h" "ac_cv_header_osp_osp_h" "$ac_includes_default"
-if test "x$ac_cv_header_osp_osp_h" = xyes; then :
+if test "x$ac_cv_header_osp_osp_h" = x""yes; then :
osptk_header_found=yes
else
osptk_header_found=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OSPPInit in -losptk" >&5
$as_echo_n "checking for OSPPInit in -losptk... " >&6; }
-if ${ac_cv_lib_osptk_OSPPInit+:} false; then :
+if test "${ac_cv_lib_osptk_OSPPInit+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_osptk_OSPPInit" >&5
$as_echo "$ac_cv_lib_osptk_OSPPInit" >&6; }
-if test "x$ac_cv_lib_osptk_OSPPInit" = xyes; then :
+if test "x$ac_cv_lib_osptk_OSPPInit" = x""yes; then :
osptk_library_found=yes
else
osptk_library_found=no
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details" "$LINENO" 5 ; }
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
as_ac_Lib=`$as_echo "ac_cv_lib_srtp_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsrtp... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SRTP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "srtp/srtp.h" "ac_cv_header_srtp_srtp_h" "$ac_includes_default"
-if test "x$ac_cv_header_srtp_srtp_h" = xyes; then :
+if test "x$ac_cv_header_srtp_srtp_h" = x""yes; then :
SRTP_HEADER_FOUND=1
else
SRTP_HEADER_FOUND=0
set dummy ${ac_tool_prefix}gmime-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_GMIME+:} false; then :
+if test "${ac_cv_path_CONFIG_GMIME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_GMIME in
set dummy gmime-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_GMIME+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_GMIME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_GMIME in
as_ac_Lib=`$as_echo "ac_cv_lib_hoard_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lhoard" >&5
$as_echo_n "checking for ${pbxfuncname} in -lhoard... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${HOARD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default"
-if test "x$ac_cv_header_" = xyes; then :
+if test "x$ac_cv_header_" = x""yes; then :
HOARD_HEADER_FOUND=1
else
HOARD_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_sybdb_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsybdb" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsybdb... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${FREETDS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sybdb.h" "ac_cv_header_sybdb_h" "$ac_includes_default"
-if test "x$ac_cv_header_sybdb_h" = xyes; then :
+if test "x$ac_cv_header_sybdb_h" = x""yes; then :
FREETDS_HEADER_FOUND=1
else
FREETDS_HEADER_FOUND=0
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tone_zone_find_by_num in -ltonezone" >&5
$as_echo_n "checking for tone_zone_find_by_num in -ltonezone... " >&6; }
-if ${ac_cv_lib_tonezone_tone_zone_find_by_num+:} false; then :
+if test "${ac_cv_lib_tonezone_tone_zone_find_by_num+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tonezone_tone_zone_find_by_num" >&5
$as_echo "$ac_cv_lib_tonezone_tone_zone_find_by_num" >&6; }
-if test "x$ac_cv_lib_tonezone_tone_zone_find_by_num" = xyes; then :
+if test "x$ac_cv_lib_tonezone_tone_zone_find_by_num" = x""yes; then :
tonezone_does_not_need_lm=yes
else
tonezone_does_not_need_lm=no
as_ac_Lib=`$as_echo "ac_cv_lib_tonezone_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ltonezone" >&5
$as_echo_n "checking for ${pbxfuncname} in -ltonezone... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${TONEZONE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "dahdi/tonezone.h" "ac_cv_header_dahdi_tonezone_h" "$ac_includes_default"
-if test "x$ac_cv_header_dahdi_tonezone_h" = xyes; then :
+if test "x$ac_cv_header_dahdi_tonezone_h" = x""yes; then :
TONEZONE_HEADER_FOUND=1
else
TONEZONE_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_vorbis_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lvorbis" >&5
$as_echo_n "checking for ${pbxfuncname} in -lvorbis... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${VORBIS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "vorbis/codec.h" "ac_cv_header_vorbis_codec_h" "$ac_includes_default"
-if test "x$ac_cv_header_vorbis_codec_h" = xyes; then :
+if test "x$ac_cv_header_vorbis_codec_h" = x""yes; then :
VORBIS_HEADER_FOUND=1
else
VORBIS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_vorbis_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lvorbis" >&5
$as_echo_n "checking for ${pbxfuncname} in -lvorbis... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${VORBIS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "vorbis/codec.h" "ac_cv_header_vorbis_codec_h" "$ac_includes_default"
-if test "x$ac_cv_header_vorbis_codec_h" = xyes; then :
+if test "x$ac_cv_header_vorbis_codec_h" = x""yes; then :
VORBIS_HEADER_FOUND=1
else
VORBIS_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_z_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lz" >&5
$as_echo_n "checking for ${pbxfuncname} in -lz... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ZLIB_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_zlib_h" = xyes; then :
+if test "x$ac_cv_header_zlib_h" = x""yes; then :
ZLIB_HEADER_FOUND=1
else
ZLIB_HEADER_FOUND=0
fi
ac_fn_c_check_header_mongrel "$LINENO" "h323.h" "ac_cv_header_h323_h" "$ac_includes_default"
-if test "x$ac_cv_header_h323_h" = xyes; then :
+if test "x$ac_cv_header_h323_h" = x""yes; then :
PBX_H323=1
else
PBX_H323=0
ac_fn_c_check_header_mongrel "$LINENO" "linux/compiler.h" "ac_cv_header_linux_compiler_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_compiler_h" = xyes; then :
+if test "x$ac_cv_header_linux_compiler_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LINUX_COMPILER_H 1
#endif
"
-if test "x$ac_cv_header_linux_ixjuser_h" = xyes; then :
+if test "x$ac_cv_header_linux_ixjuser_h" = x""yes; then :
PBX_IXJUSER=1
else
PBX_IXJUSER=0
set dummy ${ac_tool_prefix}sdl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_SDL+:} false; then :
+if test "${ac_cv_path_CONFIG_SDL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_SDL in
set dummy sdl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_SDL+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_SDL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_SDL in
as_ac_Lib=`$as_echo "ac_cv_lib_SDL_image_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lSDL_image" >&5
$as_echo_n "checking for ${pbxfuncname} in -lSDL_image... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SDL_IMAGE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "SDL_image.h" "ac_cv_header_SDL_image_h" "$ac_includes_default"
-if test "x$ac_cv_header_SDL_image_h" = xyes; then :
+if test "x$ac_cv_header_SDL_image_h" = x""yes; then :
SDL_IMAGE_HEADER_FOUND=1
else
SDL_IMAGE_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_avcodec_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lavcodec" >&5
$as_echo_n "checking for ${pbxfuncname} in -lavcodec... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${FFMPEG_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "ffmpeg/avcodec.h" "ac_cv_header_ffmpeg_avcodec_h" "$ac_includes_default"
-if test "x$ac_cv_header_ffmpeg_avcodec_h" = xyes; then :
+if test "x$ac_cv_header_ffmpeg_avcodec_h" = x""yes; then :
FFMPEG_HEADER_FOUND=1
else
FFMPEG_HEADER_FOUND=0
# possible places for video4linux version 1
ac_fn_c_check_header_mongrel "$LINENO" "linux/videodev.h" "ac_cv_header_linux_videodev_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_videodev_h" = xyes; then :
+if test "x$ac_cv_header_linux_videodev_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_VIDEODEV_H 1
as_ac_Lib=`$as_echo "ac_cv_lib_X11_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lX11" >&5
$as_echo_n "checking for ${pbxfuncname} in -lX11... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${X11_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "X11/Xlib.h" "ac_cv_header_X11_Xlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_X11_Xlib_h" = xyes; then :
+if test "x$ac_cv_header_X11_Xlib_h" = x""yes; then :
X11_HEADER_FOUND=1
else
X11_HEADER_FOUND=0
as_ac_Lib=`$as_echo "ac_cv_lib_X11_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lX11" >&5
$as_echo_n "checking for ${pbxfuncname} in -lX11... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${X11_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "X11/Xlib.h" "ac_cv_header_X11_Xlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_X11_Xlib_h" = xyes; then :
+if test "x$ac_cv_header_X11_Xlib_h" = x""yes; then :
X11_HEADER_FOUND=1
else
X11_HEADER_FOUND=0
then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /sbin/launchd" >&5
$as_echo_n "checking for /sbin/launchd... " >&6; }
-if ${ac_cv_file__sbin_launchd+:} false; then :
+if test "${ac_cv_file__sbin_launchd+set}" = set; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__sbin_launchd" >&5
$as_echo "$ac_cv_file__sbin_launchd" >&6; }
-if test "x$ac_cv_file__sbin_launchd" = xyes; then :
+if test "x$ac_cv_file__sbin_launchd" = x""yes; then :
$as_echo "#define HAVE_SBIN_LAUNCHD 1" >>confdefs.h
:end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
if test -w "$cache_file"; then
- if test "x$cache_file" != "x/dev/null"; then
+ test "x$cache_file" != "x/dev/null" &&
{ $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
$as_echo "$as_me: updating cache $cache_file" >&6;}
- if test ! -f "$cache_file" || test -h "$cache_file"; then
- cat confcache >"$cache_file"
- else
- case $cache_file in #(
- */* | ?:*)
- mv -f confcache "$cache_file"$$ &&
- mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
- mv -f confcache "$cache_file" ;;
- esac
- fi
- fi
+ cat confcache >$cache_file
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
-: "${CONFIG_STATUS=./config.status}"
+: ${CONFIG_STATUS=./config.status}
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
IFS=" "" $as_nl"
# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
case $0 in #((
*[\\/]* ) as_myself=$0 ;;
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
# values after options handling.
ac_log="
This file was extended by asterisk $as_me trunk, which was
-generated by GNU Autoconf 2.68. Invocation command line was
+generated by GNU Autoconf 2.67. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
asterisk config.status trunk
-configured by $0, generated by GNU Autoconf 2.68,
+configured by $0, generated by GNU Autoconf 2.67,
with options \\"\$ac_cs_config\\"
Copyright (C) 2010 Free Software Foundation, Inc.
"makeopts") CONFIG_FILES="$CONFIG_FILES makeopts" ;;
"channels/h323/Makefile") CONFIG_FILES="$CONFIG_FILES channels/h323/Makefile" ;;
- *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;;
esac
done
# after its creation but before its name has been assigned to `$tmp'.
$debug ||
{
- tmp= ac_tmp=
+ tmp=
trap 'exit_status=$?
- : "${ac_tmp:=$tmp}"
- { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
' 0
trap 'as_fn_exit 1' 1 2 13 15
}
{
tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
- test -d "$tmp"
+ test -n "$tmp" && test -d "$tmp"
} ||
{
tmp=./conf$$-$RANDOM
(umask 077 && mkdir "$tmp")
} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
# Set up the scripts for CONFIG_FILES section.
# No need to generate them if there are no CONFIG_FILES.
ac_cs_awk_cr=$ac_cr
fi
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
_ACEOF
rm -f conf$$subs.sh
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
_ACEOF
sed -n '
h
rm -f conf$$subs.awk
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
for (key in S) S_is_set[key] = 1
FS = "\a"
sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
else
cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
|| as_fn_error $? "could not setup config files machinery" "$LINENO" 5
_ACEOF
# No need to generate them if there are no CONFIG_HEADERS.
# This happens for instance with `./config.status Makefile'.
if test -n "$CONFIG_HEADERS"; then
-cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+cat >"$tmp/defines.awk" <<\_ACAWK ||
BEGIN {
_ACEOF
# handling of long lines.
ac_delim='%!_!# '
for ac_last_try in false false :; do
- ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
- if test -z "$ac_tt"; then
+ ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_t"; then
break
elif $ac_last_try; then
as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
esac
case $ac_mode$ac_tag in
:[FHL]*:*);;
- :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;;
:[FH]-) ac_tag=-:-;;
:[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
esac
for ac_f
do
case $ac_f in
- -) ac_f="$ac_tmp/stdin";;
+ -) ac_f="$tmp/stdin";;
*) # Look for the file first in the build tree, then in the source tree
# (if the path is not absolute). The absolute path cannot be DOS-style,
# because $ac_f cannot contain `:'.
[\\/$]*) false;;
*) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
esac ||
- as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;;
esac
case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
as_fn_append ac_file_inputs " '$ac_f'"
esac
case $ac_tag in
- *:-:* | *:-) cat >"$ac_tmp/stdin" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ *:-:* | *:-) cat >"$tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
esac
;;
esac
s&@INSTALL@&$ac_INSTALL&;t t
$ac_datarootdir_hack
"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
- >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
- { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
- "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined. Please make sure it is defined" >&5
$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined. Please make sure it is defined" >&2;}
- rm -f "$ac_tmp/stdin"
+ rm -f "$tmp/stdin"
case $ac_file in
- -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
- *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ -) cat "$tmp/out" && rm -f "$tmp/out";;
+ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
esac \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
;;
if test x"$ac_file" != x-; then
{
$as_echo "/* $configure_input */" \
- && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
- } >"$ac_tmp/config.h" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+ } >"$tmp/config.h" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
- if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
$as_echo "$as_me: $ac_file is unchanged" >&6;}
else
rm -f "$ac_file"
- mv "$ac_tmp/config.h" "$ac_file" \
+ mv "$tmp/config.h" "$ac_file" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
fi
else
$as_echo "/* $configure_input */" \
- && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
|| as_fn_error $? "could not create -" "$LINENO" 5
fi
;;
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
case AST_CONTROL_END_OF_Q:
ast_verbose("SubClass: END_OF_Q\n");
break;
+ case AST_CONTROL_CUSTOM:
+ ast_verbose("Subclass: Custom");
+ break;
case AST_CONTROL_UPDATE_RTP_PEER:
ast_verbose("SubClass: UPDATE_RTP_PEER\n");
break;
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Custom presence provider
+ * \ingroup functions
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/presencestate.h"
+#include "asterisk/cli.h"
+#include "asterisk/astdb.h"
+#include "asterisk/app.h"
+#ifdef TEST_FRAMEWORK
+#include "asterisk/test.h"
+#include "asterisk/event.h"
+#include <semaphore.h>
+#endif
+
+/*** DOCUMENTATION
+ <function name="PRESENCE_STATE" language="en_US">
+ <synopsis>
+ Get or Set a presence state.
+ </synopsis>
+ <syntax>
+ <parameter name="provider" required="true">
+ <para>The provider of the presence, such as <literal>CustomPresence</literal></para>
+ </parameter>
+ <parameter name="field" required="true">
+ <para>Which field of the presence state information is wanted.</para>
+ <optionlist>
+ <option name="value">
+ <para>The current presence, such as <literal>away</literal></para>
+ </option>
+ <option name="subtype">
+ <para>Further information about the current presence</para>
+ </option>
+ <option name="message">
+ <para>A custom message that may indicate further details about the presence</para>
+ </option>
+ </optionlist>
+ </parameter>
+ <parameter name="options" required="false">
+ <optionlist>
+ <option name="e">
+ <para>Base-64 encode the data.</para>
+ </option>
+ </optionlist>
+ </parameter>
+ </syntax>
+ <description>
+ <para>The PRESENCE_STATE function can be used to retrieve the presence from any
+ presence provider. For example:</para>
+ <para>NoOp(SIP/mypeer has presence ${PRESENCE_STATE(SIP/mypeer,value)})</para>
+ <para>NoOp(Conference number 1234 has presence message ${PRESENCE_STATE(MeetMe:1234,message)})</para>
+ <para>The PRESENCE_STATE function can also be used to set custom presence state from
+ the dialplan. The <literal>CustomPresence:</literal> prefix must be used. For example:</para>
+ <para>Set(PRESENCE_STATE(CustomPresence:lamp1)=away,temporary,Out to lunch)</para>
+ <para>Set(PRESENCE_STATE(CustomPresence:lamp2)=dnd,,Trying to get work done)</para>
+ <para>You can subscribe to the status of a custom presence state using a hint in
+ the dialplan:</para>
+ <para>exten => 1234,hint,CustomPresence:lamp1</para>
+ <para>The possible values for both uses of this function are:</para>
+ <para>not_set | unavailable | available | away | xa | chat | dnd</para>
+ </description>
+ </function>
+ ***/
+
+
+static const char astdb_family[] = "CustomPresence";
+
+static int presence_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ int state;
+ char *message = NULL;
+ char *subtype = NULL;
+ char *parse;
+ int base64encode = 0;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(provider);
+ AST_APP_ARG(field);
+ AST_APP_ARG(options);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "PRESENCE_STATE reading requires an argument \n");
+ return -1;
+ }
+
+ parse = ast_strdupa(data);
+
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (ast_strlen_zero(args.provider) || ast_strlen_zero(args.field)) {
+ ast_log(LOG_WARNING, "PRESENCE_STATE reading requires both presence provider and presence field arguments. \n");
+ return -1;
+ }
+
+ state = ast_presence_state(args.provider, &subtype, &message);
+ if (state < 0) {
+ ast_log(LOG_WARNING, "PRESENCE_STATE unknown \n");
+ return -1;
+ }
+
+ if (!(ast_strlen_zero(args.options)) && (strchr(args.options, 'e'))) {
+ base64encode = 1;
+ }
+
+ if (!ast_strlen_zero(subtype) && !strcasecmp(args.field, "subtype")) {
+ if (base64encode) {
+ ast_base64encode(buf, (unsigned char *) subtype, strlen(subtype), len);
+ } else {
+ ast_copy_string(buf, subtype, len);
+ }
+ } else if (!ast_strlen_zero(message) && !strcasecmp(args.field, "message")) {
+ if (base64encode) {
+ ast_base64encode(buf, (unsigned char *) message, strlen(message), len);
+ } else {
+ ast_copy_string(buf, message, len);
+ }
+
+ } else if (!strcasecmp(args.field, "value")) {
+ ast_copy_string(buf, ast_presence_state2str(state), len);
+ }
+
+ ast_free(message);
+ ast_free(subtype);
+
+ return 0;
+}
+
+static int parse_data(char *data, int *state, char **subtype, char **message, char **options)
+{
+ char *state_str;
+
+ /* data syntax is state,subtype,message,options */
+ *subtype = "";
+ *message = "";
+ *options = "";
+
+ state_str = strsep(&data, ",");
+ if (ast_strlen_zero(state_str)) {
+ return -1; /* state is required */
+ }
+
+ *state = ast_presence_state_val(state_str);
+
+ /* not a valid state */
+ if (*state < 0) {
+ ast_log(LOG_WARNING, "Unknown presence state value %s\n", state_str);
+ return -1;
+ }
+
+ if (!(*subtype = strsep(&data,","))) {
+ *subtype = "";
+ return 0;
+ }
+
+ if (!(*message = strsep(&data, ","))) {
+ *message = "";
+ return 0;
+ }
+
+ if (!(*options = strsep(&data, ","))) {
+ *options = "";
+ return 0;
+ }
+
+ if (!ast_strlen_zero(*options) && !(strchr(*options, 'e'))) {
+ ast_log(LOG_NOTICE, "Invalid options '%s'\n", *options);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int presence_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ size_t len = strlen("CustomPresence:");
+ char *tmp = data;
+ char *args = ast_strdupa(value);
+ int state;
+ char *options, *message, *subtype;
+
+ if (strncasecmp(data, "CustomPresence:", len)) {
+ ast_log(LOG_WARNING, "The PRESENCE_STATE function can only set CustomPresence: presence providers.\n");
+ return -1;
+ }
+ data += len;
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "PRESENCE_STATE function called with no custom device name!\n");
+ return -1;
+ }
+
+ if (parse_data(args, &state, &subtype, &message, &options)) {
+ ast_log(LOG_WARNING, "Invalid arguments to PRESENCE_STATE\n");
+ return -1;
+ }
+
+ ast_db_put(astdb_family, data, value);
+
+ ast_presence_state_changed(tmp);
+
+ return 0;
+}
+
+static enum ast_presence_state custom_presence_callback(const char *data, char **subtype, char **message)
+{
+ char buf[1301] = "";
+ int state;
+ char *_options;
+ char *_message;
+ char *_subtype;
+
+ ast_db_get(astdb_family, data, buf, sizeof(buf));
+
+ if (parse_data(buf, &state, &_subtype, &_message, &_options)) {
+ return -1;
+ }
+
+ if ((strchr(_options, 'e'))) {
+ char tmp[1301];
+ if (ast_strlen_zero(_subtype)) {
+ *subtype = NULL;
+ } else {
+ memset(tmp, 0, sizeof(tmp));
+ ast_base64decode((unsigned char *) tmp, _subtype, sizeof(tmp) - 1);
+ *subtype = ast_strdup(tmp);
+ }
+
+ if (ast_strlen_zero(_message)) {
+ *message = NULL;
+ } else {
+ memset(tmp, 0, sizeof(tmp));
+ ast_base64decode((unsigned char *) tmp, _message, sizeof(tmp) - 1);
+ *message = ast_strdup(tmp);
+ }
+ } else {
+ *subtype = ast_strlen_zero(_subtype) ? NULL : ast_strdup(_subtype);
+ *message = ast_strlen_zero(_message) ? NULL : ast_strdup(_message);
+ }
+ return state;
+}
+
+static struct ast_custom_function presence_function = {
+ .name = "PRESENCE_STATE",
+ .read = presence_read,
+ .write = presence_write,
+};
+
+#ifdef TEST_FRAMEWORK
+
+struct test_string {
+ char *parse_string;
+ struct {
+ int value;
+ const char *subtype;
+ const char *message;
+ const char *options;
+ } outputs;
+};
+
+AST_TEST_DEFINE(test_valid_parse_data)
+{
+ int i;
+ int state;
+ char *subtype;
+ char *message;
+ char *options;
+ enum ast_test_result_state res = AST_TEST_PASS;
+
+ struct test_string tests [] = {
+ { "away",
+ { AST_PRESENCE_AWAY,
+ "",
+ "",
+ ""
+ }
+ },
+ { "not_set",
+ { AST_PRESENCE_NOT_SET,
+ "",
+ "",
+ ""
+ }
+ },
+ { "unavailable",
+ { AST_PRESENCE_UNAVAILABLE,
+ "",
+ "",
+ ""
+ }
+ },
+ { "available",
+ { AST_PRESENCE_AVAILABLE,
+ "",
+ "",
+ ""
+ }
+ },
+ { "xa",
+ { AST_PRESENCE_XA,
+ "",
+ "",
+ ""
+ }
+ },
+ { "chat",
+ { AST_PRESENCE_CHAT,
+ "",
+ "",
+ ""
+ }
+ },
+ { "dnd",
+ { AST_PRESENCE_DND,
+ "",
+ "",
+ ""
+ }
+ },
+ { "away,down the hall",
+ { AST_PRESENCE_AWAY,
+ "down the hall",
+ "",
+ ""
+ }
+ },
+ { "away,down the hall,Quarterly financial meeting",
+ { AST_PRESENCE_AWAY,
+ "down the hall",
+ "Quarterly financial meeting",
+ ""
+ }
+ },
+ { "away,,Quarterly financial meeting",
+ { AST_PRESENCE_AWAY,
+ "",
+ "Quarterly financial meeting",
+ ""
+ }
+ },
+ { "away,,,e",
+ { AST_PRESENCE_AWAY,
+ "",
+ "",
+ "e",
+ }
+ },
+ { "away,down the hall,,e",
+ { AST_PRESENCE_AWAY,
+ "down the hall",
+ "",
+ "e"
+ }
+ },
+ { "away,down the hall,Quarterly financial meeting,e",
+ { AST_PRESENCE_AWAY,
+ "down the hall",
+ "Quarterly financial meeting",
+ "e"
+ }
+ },
+ { "away,,Quarterly financial meeting,e",
+ { AST_PRESENCE_AWAY,
+ "",
+ "Quarterly financial meeting",
+ "e"
+ }
+ }
+ };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "parse_valid_presence_data";
+ info->category = "/funcs/func_presence";
+ info->summary = "PRESENCESTATE parsing test";
+ info->description =
+ "Ensure that parsing function accepts proper values, and gives proper outputs";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ for (i = 0; i < ARRAY_LEN(tests); ++i) {
+ int parse_result;
+ char *parse_string = ast_strdup(tests[i].parse_string);
+ if (!parse_string) {
+ res = AST_TEST_FAIL;
+ break;
+ }
+ parse_result = parse_data(parse_string, &state, &subtype, &message, &options);
+ if (parse_result == -1) {
+ res = AST_TEST_FAIL;
+ ast_free(parse_string);
+ break;
+ }
+ if (tests[i].outputs.value != state ||
+ strcmp(tests[i].outputs.subtype, subtype) ||
+ strcmp(tests[i].outputs.message, message) ||
+ strcmp(tests[i].outputs.options, options)) {
+ res = AST_TEST_FAIL;
+ ast_free(parse_string);
+ break;
+ }
+ ast_free(parse_string);
+ }
+
+ return res;
+}
+
+AST_TEST_DEFINE(test_invalid_parse_data)
+{
+ int i;
+ int state;
+ char *subtype;
+ char *message;
+ char *options;
+ enum ast_test_result_state res = AST_TEST_PASS;
+
+ char *tests[] = {
+ "",
+ "bored",
+ "away,,,i",
+ /* XXX The following actually is parsed correctly. Should that
+ * be changed?
+ * "away,,,,e",
+ */
+ };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "parse_invalid_presence_data";
+ info->category = "/funcs/func_presence";
+ info->summary = "PRESENCESTATE parsing test";
+ info->description =
+ "Ensure that parsing function rejects improper values";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ for (i = 0; i < ARRAY_LEN(tests); ++i) {
+ int parse_result;
+ char *parse_string = ast_strdup(tests[i]);
+ if (!parse_string) {
+ res = AST_TEST_FAIL;
+ break;
+ }
+ printf("parse string is %s\n", parse_string);
+ parse_result = parse_data(parse_string, &state, &subtype, &message, &options);
+ if (parse_result == 0) {
+ res = AST_TEST_FAIL;
+ ast_free(parse_string);
+ break;
+ }
+ ast_free(parse_string);
+ }
+
+ return res;
+}
+
+struct test_cb_data {
+ enum ast_presence_state presence;
+ const char *provider;
+ const char *subtype;
+ const char *message;
+ /* That's right. I'm using a semaphore */
+ sem_t sem;
+};
+
+static void test_cb(const struct ast_event *event, void *userdata)
+{
+ struct test_cb_data *cb_data = userdata;
+ cb_data->presence = ast_event_get_ie_uint(event, AST_EVENT_IE_PRESENCE_STATE);
+ cb_data->provider = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_PROVIDER));
+ cb_data->subtype = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_SUBTYPE));
+ cb_data->message = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_MESSAGE));
+ sem_post(&cb_data->sem);
+ ast_log(LOG_NOTICE, "Callback called\n");
+}
+
+/* XXX This test could probably stand to be moved since
+ * it does not test func_presencestate but rather code in
+ * presencestate.h and presencestate.c. However, the convenience
+ * of presence_write() makes this a nice location for this test.
+ */
+AST_TEST_DEFINE(test_presence_state_change)
+{
+ struct ast_event_sub *test_sub;
+ struct test_cb_data *cb_data;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "test_presence_state_change";
+ info->category = "/funcs/func_presence";
+ info->summary = "presence state change subscription";
+ info->description =
+ "Ensure that presence state changes are communicated to subscribers";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ cb_data = ast_calloc(1, sizeof(*cb_data));
+ if (!cb_data) {
+ return AST_TEST_FAIL;
+ }
+
+ if (!(test_sub = ast_event_subscribe(AST_EVENT_PRESENCE_STATE,
+ test_cb, "Test presence state callbacks", cb_data, AST_EVENT_IE_END))) {
+ return AST_TEST_FAIL;
+ }
+
+ if (sem_init(&cb_data->sem, 0, 0)) {
+ return AST_TEST_FAIL;
+ }
+
+ presence_write(NULL, "PRESENCESTATE", "CustomPresence:Bob", "away,down the hall,Quarterly financial meeting");
+ sem_wait(&cb_data->sem);
+ if (cb_data->presence != AST_PRESENCE_AWAY ||
+ strcmp(cb_data->provider, "CustomPresence:Bob") ||
+ strcmp(cb_data->subtype, "down the hall") ||
+ strcmp(cb_data->message, "Quarterly financial meeting")) {
+ return AST_TEST_FAIL;
+ }
+
+ ast_free((char *)cb_data->provider);
+ ast_free((char *)cb_data->subtype);
+ ast_free((char *)cb_data->message);
+ ast_free((char *)cb_data);
+
+ return AST_TEST_PASS;
+}
+
+#endif
+
+static int unload_module(void)
+{
+ int res = 0;
+
+ res |= ast_custom_function_unregister(&presence_function);
+ res |= ast_presence_state_prov_del("CustomPresence");
+#ifdef TEST_FRAMEWORK
+ AST_TEST_UNREGISTER(test_valid_parse_data);
+ AST_TEST_UNREGISTER(test_invalid_parse_data);
+ AST_TEST_UNREGISTER(test_presence_state_change);
+#endif
+ return res;
+}
+
+static int load_module(void)
+{
+ int res = 0;
+
+ res |= ast_custom_function_register(&presence_function);
+ res |= ast_presence_state_prov_add("CustomPresence", custom_presence_callback);
+#ifdef TEST_FRAMEWORK
+ AST_TEST_REGISTER(test_valid_parse_data);
+ AST_TEST_REGISTER(test_invalid_parse_data);
+ AST_TEST_REGISTER(test_presence_state_change);
+#endif
+
+ return res;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gets or sets a presence state in the dialplan",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
+);
int ast_cel_engine_reload(void); /*!< Provided by cel.c */
int ast_ssl_init(void); /*!< Provided by ssl.c */
int ast_test_init(void); /*!< Provided by test.c */
+int ast_msg_init(void); /*!< Provided by message.c */
/*!
* \brief Reload asterisk modules.
#ifndef _ASTERISK_APP_H
#define _ASTERISK_APP_H
+#include "asterisk/stringfields.h"
#include "asterisk/strings.h"
#include "asterisk/threadstorage.h"
+#include "asterisk/file.h"
+#include "asterisk/linkedlists.h"
struct ast_flags64;
struct ast_ivr_option *options; /*!< All options */
};
+/*!
+ * \brief Structure used for ast_copy_recording_to_vm in order to cleanly supply
+ * data needed for making the recording from the recorded file.
+ */
+struct ast_vm_recording_data {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(context);
+ AST_STRING_FIELD(mailbox);
+ AST_STRING_FIELD(folder);
+ AST_STRING_FIELD(recording_file);
+ AST_STRING_FIELD(recording_ext);
+
+ AST_STRING_FIELD(call_context);
+ AST_STRING_FIELD(call_macrocontext);
+ AST_STRING_FIELD(call_extension);
+ AST_STRING_FIELD(call_callerchan);
+ AST_STRING_FIELD(call_callerid);
+ );
+ int call_priority;
+};
+
#define AST_IVR_FLAG_AUTORESTART (1 << 0)
#define AST_IVR_DECLARE_MENU(holder, title, flags, foo...) \
int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel
*macro_chan, const char * const macro_name, const char * const macro_args);
+enum ast_vm_snapshot_sort_val {
+ AST_VM_SNAPSHOT_SORT_BY_ID = 0,
+ AST_VM_SNAPSHOT_SORT_BY_TIME,
+};
+
+struct ast_vm_msg_snapshot {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(msg_id);
+ AST_STRING_FIELD(callerid);
+ AST_STRING_FIELD(callerchan);
+ AST_STRING_FIELD(exten);
+ AST_STRING_FIELD(origdate);
+ AST_STRING_FIELD(origtime);
+ AST_STRING_FIELD(duration);
+ AST_STRING_FIELD(folder_name);
+ AST_STRING_FIELD(flag);
+ );
+ unsigned int msg_number;
+
+ AST_LIST_ENTRY(ast_vm_msg_snapshot) msg;
+};
+
+struct ast_vm_mailbox_snapshot {
+ int total_msg_num;
+ int folders;
+ /* Things are not quite as they seem here. This points to an allocated array of lists. */
+ AST_LIST_HEAD_NOLOCK(, ast_vm_msg_snapshot) *snapshots;
+};
+
+/*!
+ * \brief Voicemail playback callback function definition
+ *
+ * \param channel to play the file back on.
+ * \param location of file on disk
+ * \param duration of file in seconds. This will be zero if msg is very short or
+ * has an unknown duration.
+ */
+typedef void (ast_vm_msg_play_cb)(struct ast_channel *chan, const char *playfile, int duration);
+
/*!
* \brief Set voicemail function callbacks
* \param[in] has_voicemail_func set function pointer
- * \param[in] inboxcount2_func set function pointer
- * \param[in] sayname_func set function pointer
* \param[in] inboxcount_func set function pointer
+ * \param[in] inboxcount2_func set function pointer
* \param[in] messagecount_func set function pointer
+ * \param[in] sayname_func set function pointer
* \version 1.6.1 Added inboxcount2_func, sayname_func
*/
void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
int (*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs),
int (*inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs),
int (*messagecount_func)(const char *context, const char *mailbox, const char *folder),
- int (*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context));
+ int (*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context),
+ int (*copy_recording_to_vm_func)(struct ast_vm_recording_data *vm_rec_data),
+ const char *vm_index_to_foldername(int id),
+ struct ast_vm_mailbox_snapshot *(*vm_mailbox_snapshot_create)(const char *mailbox,
+ const char *context,
+ const char *folder,
+ int descending,
+ enum ast_vm_snapshot_sort_val sort_val,
+ int combine_INBOX_and_OLD),
+ struct ast_vm_mailbox_snapshot *(*vm_mailbox_snapshot_destroy)(struct ast_vm_mailbox_snapshot *mailbox_snapshot),
+ int (*vm_msg_move)(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *oldfolder,
+ int *old_msg_ids,
+ const char *newfolder,
+ int *new_msg_ids),
+ int (*vm_msg_remove)(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *folder,
+ int *msgs),
+ int (*vm_msg_forward)(const char *from_mailbox,
+ const char *from_context,
+ const char *from_folder,
+ const char *to_mailbox,
+ const char *to_context,
+ const char *to_folder,
+ size_t num_msgs,
+ int *msg_ids,
+ int delete_old),
+ int (*vm_msg_play)(struct ast_channel *chan,
+ const char *mailbox,
+ const char *context,
+ const char *folder,
+ const char *msg_num,
+ ast_vm_msg_play_cb cb));
void ast_uninstall_vm_functions(void);
+#ifdef TEST_FRAMEWORK
+void ast_install_vm_test_functions(int (*vm_test_destroy_user)(const char *context, const char *mailbox),
+ int (*vm_test_create_user)(const char *context, const char *mailbox));
+
+void ast_uninstall_vm_test_functions(void);
+#endif
+
+/*!
+ * \brief
+ * param[in] vm_rec_data Contains data needed to make the recording.
+ * retval 0 voicemail successfully created from recording.
+ * retval -1 Failure
+ */
+int ast_app_copy_recording_to_vm(struct ast_vm_recording_data *vm_rec_data);
+
/*!
* \brief Determine if a given mailbox has any voicemail
* If folder is NULL, defaults to "INBOX". If folder is "INBOX", includes the
*/
int ast_app_messagecount(const char *context, const char *mailbox, const char *folder);
+/*!
+ * \brief Return name of folder, given an id
+ * \param[in] id Folder id
+ * \return Name of folder
+ */
+const char *ast_vm_index_to_foldername(int id);
+
+/*
+ * \brief Create a snapshot of a mailbox which contains information about every msg.
+ *
+ * \param mailbox, the mailbox to look for
+ * \param context, the context to look for the mailbox in
+ * \param folder, OPTIONAL. When not NULL only msgs from the specified folder will be included.
+ * \param desending, list the msgs in descending order rather than ascending order.
+ * \param combine_INBOX_and_OLD, When this argument is set, The OLD folder will be represented
+ * in the INBOX folder of the snapshot. This allows the snapshot to represent the
+ * OLD and INBOX messages in sorted order merged together.
+ *
+ * \retval snapshot on success
+ * \retval NULL on failure
+ */
+struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_create(const char *mailbox,
+ const char *context,
+ const char *folder,
+ int descending,
+ enum ast_vm_snapshot_sort_val sort_val,
+ int combine_INBOX_and_OLD);
+
+/*
+ * \brief destroy a snapshot
+ *
+ * \param mailbox_snapshot The snapshot to destroy.
+ * \retval NULL
+ */
+struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot);
+
+/*!
+ * \brief Move messages from one folder to another
+ *
+ * \param mailbox The mailbox to which the folders belong
+ * \param context The voicemail context for the mailbox
+ * \param num_msgs The number of messages to move
+ * \param oldfolder The folder from where messages should be moved
+ * \param old_msg_nums The message IDs of the messages to move
+ * \param newfolder The folder to which messages should be moved
+ * \param new_msg_ids[out] An array of message IDs for the messages as they are in the
+ * new folder. This array must be num_msgs sized.
+ *
+ * \retval -1 Failure
+ * \retval 0 Success
+ */
+int ast_vm_msg_move(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *oldfolder,
+ int *old_msg_ids,
+ const char *newfolder,
+ int *new_msg_ids);
+
+/*!
+ * \brief Remove/delete messages from a mailbox folder.
+ *
+ * \param mailbox The mailbox from which to delete messages
+ * \param context The voicemail context for the mailbox
+ * \param num_msgs The number of messages to delete
+ * \param folder The folder from which to remove messages
+ * \param msgs The message IDs of the messages to delete
+ *
+ * \retval -1 Failure
+ * \retval 0 Success
+ */
+int ast_vm_msg_remove(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *folder,
+ int *msgs);
+
+/*!
+ * \brief forward a message from one mailbox to another.
+ *
+ * \brief from_mailbox The original mailbox the message is being forwarded from
+ * \brief from_context The voicemail context of the from_mailbox
+ * \brief from_folder The folder from which the message is being forwarded
+ * \brief to_mailbox The mailbox to forward the message to
+ * \brief to_context The voicemail context of the to_mailbox
+ * \brief to_folder The folder to which the message is being forwarded
+ * \brief num_msgs The number of messages being forwarded
+ * \brief msg_ids The message IDs of the messages in from_mailbox to forward
+ * \brief delete_old If non-zero, the forwarded messages are also deleted from from_mailbox.
+ * Otherwise, the messages will remain in the from_mailbox.
+ *
+ * \retval -1 Failure
+ * \retval 0 Success
+ */
+int ast_vm_msg_forward(const char *from_mailbox,
+ const char *from_context,
+ const char *from_folder,
+ const char *to_mailbox,
+ const char *to_context,
+ const char *to_folder,
+ size_t num_msgs,
+ int *msg_ids,
+ int delete_old);
+
+/*!
+ * \brief Play a voicemail msg back on a channel.
+ *
+ * \param mailbox msg is in.
+ * \param context of mailbox.
+ * \param voicemail folder to look in.
+ * \param message number in the voicemailbox to playback to the channel.
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_vm_msg_play(struct ast_channel *chan,
+ const char *mailbox,
+ const char *context,
+ const char *folder,
+ const char *msg_num,
+ ast_vm_msg_play_cb cb);
+
+#ifdef TEST_FRAMEWORK
+int ast_vm_test_destroy_user(const char *context, const char *mailbox);
+int ast_vm_test_create_user(const char *context, const char *mailbox);
+#endif
+
/*! \brief Safely spawn an external program while closing file descriptors
\note This replaces the \b system call in all Asterisk modules
*/
*/
int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms, long *offsetms);
+/*!
+ * \brief Stream a file with fast forward, pause, reverse, restart.
+ * \param chan
+ * \param file filename
+ * \param fwd, rev, stop, pause, restart, skipms, offsetms
+ * \param waitstream callback to invoke when fastforward or rewind occurrs.
+ *
+ * Before calling this function, set this to be the number
+ * of ms to start from the beginning of the file. When the function
+ * returns, it will be the number of ms from the beginning where the
+ * playback stopped. Pass NULL if you don't care.
+ */
+int ast_control_streamfile_w_cb(struct ast_channel *chan,
+ const char *file,
+ const char *fwd,
+ const char *rev,
+ const char *stop,
+ const char *pause,
+ const char *restart,
+ int skipms,
+ long *offsetms,
+ ast_waitstream_fr_cb cb);
+
/*! \brief Play a stream and wait for a digit, returning the digit that was pressed */
int ast_play_and_wait(struct ast_channel *chan, const char *fn);
AST_REDIRECTING_REASON_OUT_OF_ORDER,
AST_REDIRECTING_REASON_AWAY,
AST_REDIRECTING_REASON_CALL_FWD_DTE, /* This is something defined in Q.931, and no I don't know what it means */
+ AST_REDIRECTING_REASON_SEND_TO_VM,
};
/*!
}
#endif
+/*!
+ * \brief Remove a channel from the global channels container
+ *
+ * \param chan channel to remove
+ *
+ * In a case where it is desired that a channel not be available in any lookups
+ * in the global channels conatiner, use this function.
+ */
+void ast_channel_unlink(struct ast_channel *chan);
+
#endif /* _ASTERISK_CHANNEL_H */
struct ast_config *ast_config_internal_load(const char *configfile, struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl_file, const char *who_asked);
+/*!
+ * \brief
+ * Copies the contents of one ast_config into another
+ *
+ * \note
+ * This creates a config on the heap. The caller of this must
+ * be prepared to free the memory returned.
+ *
+ * \param orig the config to copy
+ * \return The new config on success, NULL on failure.
+ */
+struct ast_config *ast_config_copy(const struct ast_config *orig);
+
+/*!
+ * \brief
+ * Flags that affect the behaviour of config hooks.
+ */
+enum config_hook_flags {
+ butt,
+};
+
+/*
+ * \brief Callback when configuration is updated
+ *
+ * \param cfg A copy of the configuration that is being changed.
+ * This MUST be freed by the callback before returning.
+ */
+typedef int (*config_hook_cb)(struct ast_config *cfg);
+
+/*!
+ * \brief
+ * Register a config hook for a particular file and module
+ *
+ * \param name The name of the hook you are registering.
+ * \param filename The file whose config you wish to hook into.
+ * \param module The module that is reloading the config. This
+ * can be useful if multiple modules may possibly
+ * reload the same file, but you are only interested
+ * when a specific module reloads the file
+ * \param flags Flags that affect the way hooks work.
+ * \param hook The callback to be called when config is loaded.
+ * return 0 Success
+ * return -1 Unsuccess, also known as UTTER AND COMPLETE FAILURE
+ */
+int ast_config_hook_register(const char *name,
+ const char *filename,
+ const char *module,
+ enum config_hook_flags flags,
+ config_hook_cb hook);
+
+/*!
+ * \brief
+ * Unregister a config hook
+ *
+ * \param name The name of the hook to unregister
+ */
+void ast_config_hook_unregister(const char *name);
+
+
/*!
* \brief Support code to parse config file arguments
*
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Defines the use of the AST_CONTROL_CUSTOM control frame subclass.
+ */
+
+#ifndef _ASTERISK_CUSTOM_FRAME_H
+#define _ASTERISK_CUSTOM_FRAME_H
+
+#include "asterisk/config.h"
+
+/*! \brief this is the payload structure used in every AST_CONTROL_CUSTOM frame. */
+struct ast_custom_payload;
+
+enum ast_custom_payload_type {
+ /*! Custom SIP INFO payload type, used only in the sip channel driver. */
+ AST_CUSTOM_SIP_INFO,
+};
+
+/*!
+ * \brief returns the type of payload the custom payload represents
+ *
+ * \retval payload type, on success
+ * \retval -1, on failure
+ */
+enum ast_custom_payload_type ast_custom_payload_type(struct ast_custom_payload *type);
+
+/*!
+ * \brief returns the length of a custom payload
+ *
+ * \retval len on success
+ * \retval -1 on failure
+ */
+size_t ast_custom_payload_len(struct ast_custom_payload *type);
+
+/*!
+ * \brief Encodes and allocates a sip info custom payload type
+ *
+ * \retval encoded custom payload on success
+ * \retval NULL on failure.
+ */
+struct ast_custom_payload *ast_custom_payload_sipinfo_encode(struct ast_variable *headers,
+ const char *content_type,
+ const char *content,
+ const char *useragent_filter);
+
+/*!
+ * \brief Decodes a sip info custom payload type, returns results in parameters.
+ *
+ * \note This is the reverse of the encode function. Pass in a payload, get the headers
+ * content type and content variables back out. Make sure to free all the variables
+ * this function returns.
+ *
+ * \retval 0, variables allocated and returned in output parameters
+ * \retval -1, failure no variables were allocated.
+ */
+int ast_custom_payload_sipinfo_decode(struct ast_custom_payload *pl,
+ struct ast_variable **headers,
+ char **content_type,
+ char **content,
+ char **useragent_filter);
+
+#endif
AST_EVENT_SECURITY = 0x08,
/*! Used by res_stun_monitor to alert listeners to an exernal network address change. */
AST_EVENT_NETWORK_CHANGE = 0x09,
+ /*! The presence state for a presence provider */
+ AST_EVENT_PRESENCE_STATE = 0x0a,
/*! Number of event types. This should be the last event type + 1 */
- AST_EVENT_TOTAL = 0x0a,
+ AST_EVENT_TOTAL = 0x0b,
+
};
/*! \brief Event Information Element types */
AST_EVENT_IE_CHALLENGE = 0x0032,
AST_EVENT_IE_RESPONSE = 0x0033,
AST_EVENT_IE_EXPECTED_RESPONSE = 0x0034,
+ AST_EVENT_IE_PRESENCE_PROVIDER = 0x0035,
+ AST_EVENT_IE_PRESENCE_STATE = 0x0036,
+ AST_EVENT_IE_PRESENCE_SUBTYPE = 0x0037,
+ AST_EVENT_IE_PRESENCE_MESSAGE = 0x0038,
/*! \brief Must be the last IE value +1 */
- AST_EVENT_IE_TOTAL = 0x0035,
+ AST_EVENT_IE_TOTAL = 0x0039,
};
/*!
#define AST_DIGIT_ANYNUM "0123456789"
#define SEEK_FORCECUR 10
-
+
+/*! The type of event associated with a ast_waitstream_fr_cb invocation */
+enum ast_waitstream_fr_cb_values {
+ AST_WAITSTREAM_CB_REWIND = 1,
+ AST_WAITSTREAM_CB_FASTFORWARD,
+ AST_WAITSTREAM_CB_START
+};
+
+/*!
+ * \brief callback used during dtmf controlled file playback to indicate
+ * location of playback in a file after rewinding or fastfowarding
+ * a file.
+ */
+typedef void (ast_waitstream_fr_cb)(struct ast_channel *chan, long ms, enum ast_waitstream_fr_cb_values val);
+
/*!
* \brief Streams a file
* \param c channel to stream the file to
*/
int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms);
+/*!
+ * \brief Same as waitstream_fr but allows a callback to be alerted when a user
+ * fastforwards or rewinds the file.
+ * \param c channel to waitstream on
+ * \param breakon string of DTMF digits to break upon
+ * \param forward DTMF digit to fast forward upon
+ * \param rewind DTMF digit to rewind upon
+ * \param ms How many milliseconds to skip forward/back
+ * \param cb to call when rewind or fastfoward occurs.
+ * Begins playback of a stream...
+ * Wait for a stream to stop or for any one of a given digit to arrive,
+ * \retval 0 if the stream finishes.
+ * \retval the character if it was interrupted.
+ * \retval -1 on error.
+ */
+int ast_waitstream_fr_w_cb(struct ast_channel *c,
+ const char *breakon,
+ const char *forward,
+ const char *rewind,
+ int ms,
+ ast_waitstream_fr_cb cb);
+
/*!
* Same as waitstream, but with audio output to fd and monitored fd checking.
*
AST_CONTROL_READ_ACTION = 27, /*!< Tell ast_read to take a specific action */
AST_CONTROL_AOC = 28, /*!< Advice of Charge with encoded generic AOC payload */
AST_CONTROL_END_OF_Q = 29, /*!< Indicate that this position was the end of the channel queue for a softhangup. */
+ AST_CONTROL_CUSTOM = 200, /*!< Indicate a custom channel driver specific payload. Look in custom_control_frame.h for how to define and use this frame. */
AST_CONTROL_INCOMPLETE = 30, /*!< Indication that the extension dialed is incomplete */
AST_CONTROL_UPDATE_RTP_PEER = 31, /*!< Interrupt the bridge and have it update the peer */
};
char name_space[256];
char sid[10]; /* Session ID */
char mid[6]; /* Message ID */
+ char context[AST_MAX_CONTEXT];
iksid *jid;
iksparser *p;
iksfilter *f;
int message_timeout;
int authorized;
int distribute_events;
+ int send_to_dialplan;
struct ast_flags flags;
int component; /* 0 client, 1 component */
struct aji_buddy_container buddies;
#define EVENT_FLAG_CC (1 << 15) /* Call Completion events */
#define EVENT_FLAG_AOC (1 << 16) /* Advice Of Charge events */
#define EVENT_FLAG_TEST (1 << 17) /* Test event used to signal the Asterisk Test Suite */
+#define EVENT_FLAG_MESSAGE (1 << 30) /* MESSAGE events. */
/*@} */
/*! \brief Export manager structures */
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Russell Bryant <russell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ *
+ * \brief Out-of-call text message support
+ *
+ * \author Russell Bryant <russell@digium.com>
+ *
+ * The purpose of this API is to provide support for text messages that
+ * are not session based. The messages are passed into the Asterisk core
+ * to be routed through the dialplan and potentially sent back out through
+ * a message technology that has been registered through this API.
+ */
+
+#ifndef __AST_MESSAGE_H__
+#define __AST_MESSAGE_H__
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*!
+ * \brief A text message.
+ *
+ * This is an opaque type that represents a text message.
+ */
+struct ast_msg;
+
+/*!
+ * \brief A message technology
+ *
+ * A message technology is capable of transmitting text messages.
+ */
+struct ast_msg_tech {
+ /*!
+ * \brief Name of this message technology
+ *
+ * This is the name that comes at the beginning of a URI for messages
+ * that should be sent to this message technology implementation.
+ * For example, messages sent to "xmpp:rbryant@digium.com" would be
+ * passed to the ast_msg_tech with a name of "xmpp".
+ */
+ const char * const name;
+ /*!
+ * \brief Send a message.
+ *
+ * \param msg the message to send
+ * \param to the URI of where the message is being sent
+ * \param from the URI of where the message was sent from
+ *
+ * The fields of the ast_msg are guaranteed not to change during the
+ * duration of this function call.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+ int (* const msg_send)(const struct ast_msg *msg, const char *to, const char *from);
+};
+
+/*!
+ * \brief Register a message technology
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_msg_tech_register(const struct ast_msg_tech *tech);
+
+/*!
+ * \brief Unregister a message technology.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_msg_tech_unregister(const struct ast_msg_tech *tech);
+
+/*!
+ * \brief Allocate a message.
+ *
+ * Allocate a message for the purposes of passing it into the Asterisk core
+ * to be routed through the dialplan. If ast_msg_queue() is not called, this
+ * message must be destroyed using ast_msg_destroy(). Otherwise, the message
+ * core code will take care of it.
+ *
+ * \return A message object. This function will return NULL if an allocation
+ * error occurs.
+ */
+struct ast_msg *ast_msg_alloc(void);
+
+/*!
+ * \brief Destroy an ast_msg
+ *
+ * This should only be called on a message if it was not
+ * passed on to ast_msg_queue().
+ *
+ * \return NULL, always.
+ */
+struct ast_msg *ast_msg_destroy(struct ast_msg *msg);
+
+/*!
+ * \brief Bump a msg's ref count
+ */
+struct ast_msg *ast_msg_ref(struct ast_msg *msg);
+
+/*!
+ * \brief Set the 'to' URI of a message
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int __attribute__((format(printf, 2, 3)))
+ ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...);
+
+/*!
+ * \brief Set the 'from' URI of a message
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int __attribute__((format(printf, 2, 3)))
+ ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...);
+
+/*!
+ * \brief Set the 'body' text of a message (in UTF-8)
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int __attribute__((format(printf, 2, 3)))
+ ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...);
+
+/*!
+ * \brief Set the dialplan context for this message
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int __attribute__((format(printf, 2, 3)))
+ ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...);
+
+/*!
+ * \brief Set the dialplan extension for this message
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int __attribute__((format(printf, 2, 3)))
+ ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...);
+
+/*!
+ * \brief Set a variable on the message going to the dialplan
+ * \note Setting a variable that already exists overwrites the existing variable value
+ *
+ * \param name Name of variable to set
+ * \param value Value of variable to set
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value);
+
+
+/*!
+ * \brief Set a variable on the message being sent to a message tech directly.
+ * \note Setting a variable that already exists overwrites the existing variable value
+ *
+ * \param name Name of variable to set
+ * \param value Value of variable to set
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value);
+
+/*!
+ * \brief Get the specified variable on the message
+ * \note The return value is valid only as long as the ast_message is valid. Hold a reference
+ * to the message if you plan on storing the return value. Do re-set the same
+ * message var name while holding a pointer to the result of this function.
+ *
+ * \return The value associated with variable "name". NULL if variable not found.
+ */
+const char *ast_msg_get_var(struct ast_msg *msg, const char *name);
+
+/*!
+ * \brief Get the body of a message.
+ * \note The return value is valid only as long as the ast_message is valid. Hold a reference
+ * to the message if you plan on storing the return value.
+ *
+ * \return The body of the messsage, encoded in UTF-8.
+ */
+const char *ast_msg_get_body(const struct ast_msg *msg);
+
+/*!
+ * \brief Queue a message for routing through the dialplan.
+ *
+ * Regardless of the return value of this function, this funciton will take
+ * care of ensuring that the message object is properly destroyed when needed.
+ *
+ * \retval 0 message successfully queued
+ * \retval non-zero failure, message not sent to dialplan
+ */
+int ast_msg_queue(struct ast_msg *msg);
+
+/*!
+ * \brief Send a msg directly to an endpoint.
+ *
+ * Regardless of the return value of this function, this funciton will take
+ * care of ensuring that the message object is properly destroyed when needed.
+ *
+ * \retval 0 message successfully queued to be sent out
+ * \retval non-zero failure, message not get sent out.
+ */
+int ast_msg_send(struct ast_msg *msg, const char *to, const char *from);
+
+/*!
+ * \brief Opaque iterator for msg variables
+ */
+struct ast_msg_var_iterator;
+
+/*!
+ * \brief Create a new message variable iterator
+ * \param msg A message whose variables are to be iterated over
+ *
+ * \return An opaque pointer to the new iterator
+ */
+struct ast_msg_var_iterator *ast_msg_var_iterator_init(const struct ast_msg *msg);
+
+/*!
+ * \brief Get the next variable name and value that is set for sending outbound
+ * \param msg The message with the variables
+ * \param i An iterator created with ast_msg_var_iterator_init
+ * \param name A pointer to the name result pointer
+ * \param value A pointer to the value result pointer
+ *
+ * \retval 0 No more entries
+ * \retval 1 Valid entry
+ */
+int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *i, const char **name, const char **value);
+
+/*!
+ * \brief Destroy a message variable iterator
+ * \param i Iterator to be destroyed
+ */
+void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *i);
+
+/*!
+ * \brief Unref a message var from inside an iterator loop
+ */
+void ast_msg_var_unref_current(struct ast_msg_var_iterator *i);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* __AST_MESSAGE_H__ */
#include "asterisk/channel.h"
#include "asterisk/sched.h"
#include "asterisk/devicestate.h"
+#include "asterisk/presencestate.h"
#include "asterisk/chanvars.h"
#include "asterisk/hashtab.h"
#include "asterisk/stringfields.h"
struct ast_ignorepat;
struct ast_sw;
+enum ast_state_cb_update_reason {
+ /*! The extension state update is a result of a device state changing on the extension. */
+ AST_HINT_UPDATE_DEVICE = 1,
+ /*! The extension state update is a result of presence state changing on the extension. */
+ AST_HINT_UPDATE_PRESENCE = 2,
+};
+
+struct ast_state_cb_info {
+ enum ast_state_cb_update_reason reason;
+ enum ast_extension_states exten_state;
+ enum ast_presence_state presence_state;
+ const char *presence_subtype;
+ const char *presence_message;
+};
+
/*! \brief Typedef for devicestate and hint callbacks */
-typedef int (*ast_state_cb_type)(char *context, char *id, enum ast_extension_states state, void *data);
+typedef int (*ast_state_cb_type)(char *context, char *id, struct ast_state_cb_info *info, void *data);
/*! \brief Typedef for devicestate and hint callback removal indication callback */
typedef void (*ast_state_cb_destroy_type)(int id, void *data);
*/
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten);
+/*!
+ * \brief Uses hint and presence state callback to get the presence state of an extension
+ *
+ * \param c this is not important
+ * \param context which context to look in
+ * \param exten which extension to get state
+ * \param[out] subtype Further information regarding the presence returned
+ * \param[out] message Custom message further describing current presence
+ *
+ * \note The subtype and message are dynamically allocated and must be freed by
+ * the caller of this function.
+ *
+ * \return returns the presence state value.
+ */
+int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message);
+
/*!
* \brief Return string representation of the state of an extension
*
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Presence state management
+ */
+
+#ifndef _ASTERISK_PRESSTATE_H
+#define _ASTERISK_PRESSTATE_H
+
+enum ast_presence_state {
+ AST_PRESENCE_NOT_SET = 0,
+ AST_PRESENCE_UNAVAILABLE,
+ AST_PRESENCE_AVAILABLE,
+ AST_PRESENCE_AWAY,
+ AST_PRESENCE_XA,
+ AST_PRESENCE_CHAT,
+ AST_PRESENCE_DND,
+};
+
+/*! \brief Presence state provider call back */
+typedef enum ast_presence_state (*ast_presence_state_prov_cb_type)(const char *data, char **subtype, char **message);
+
+/*!
+ * \brief Convert presence state to text string for output
+ *
+ * \param state Current presence state
+ */
+const char *ast_presence_state2str(enum ast_presence_state state);
+
+/*!
+ * \brief Convert presence state from text to integer value
+ *
+ * \param val The text representing the presence state. Valid values are anything
+ * that comes after AST_PRESENCE_ in one of the defined values.
+ *
+ * \return The AST_PRESENCE_ integer value
+ */
+enum ast_presence_state ast_presence_state_val(const char *val);
+
+/*!
+ * \brief Asks a presence state provider for the current presence state.
+ *
+ * \param presence_provider, The presence provider to retrieve the state from.
+ * \param subtype, The output paramenter to store the subtype string in. Must be freed if returned
+ * \param message, The output paramenter to store the message string in. Must be freed if returned
+ *
+ * \retval presence state value on success,
+ * \retval -1 on failure.
+ */
+enum ast_presence_state ast_presence_state(const char *presence_provider, char **subtype, char **message);
+
+/*!
+ * \brief Notify the world that a presence provider state changed.
+ */
+int ast_presence_state_changed(const char *presence_provider);
+
+/*!
+ * \brief Add presence state provider
+ *
+ * \param label to use in hint, like label:object
+ * \param callback Callback
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_presence_state_prov_add(const char *label, ast_presence_state_prov_cb_type callback);
+
+/*!
+ * \brief Remove presence state provider
+ *
+ * \param label to use in hint, like label:object
+ *
+ * \retval -1 on failure
+ * \retval 0 on success
+ */
+int ast_presence_state_prov_del(const char *label);
+
+int ast_presence_state_engine_init(void);
+#endif
static int (*ast_inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) = NULL;
static int (*ast_sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context) = NULL;
static int (*ast_messagecount_func)(const char *context, const char *mailbox, const char *folder) = NULL;
+static int (*ast_copy_recording_to_vm_func)(struct ast_vm_recording_data *vm_rec_data) = NULL;
+static const char *(*ast_vm_index_to_foldername_func)(int id) = NULL;
+static struct ast_vm_mailbox_snapshot *(*ast_vm_mailbox_snapshot_create_func)(const char *mailbox,
+ const char *context,
+ const char *folder,
+ int descending,
+ enum ast_vm_snapshot_sort_val sort_val,
+ int combine_INBOX_and_OLD) = NULL;
+static struct ast_vm_mailbox_snapshot *(*ast_vm_mailbox_snapshot_destroy_func)(struct ast_vm_mailbox_snapshot *mailbox_snapshot) = NULL;
+static int (*ast_vm_msg_move_func)(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *oldfolder,
+ int *old_msg_ids,
+ const char *newfolder,
+ int *new_msg_ids) = NULL;
+static int (*ast_vm_msg_remove_func)(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *folder,
+ int *msgs) = NULL;
+static int (*ast_vm_msg_forward_func)(const char *from_mailbox,
+ const char *from_context,
+ const char *from_folder,
+ const char *to_mailbox,
+ const char *to_context,
+ const char *to_folder,
+ size_t num_msgs,
+ int *msg_ids,
+ int delete_old) = NULL;
+static int (*ast_vm_msg_play_func)(struct ast_channel *chan,
+ const char *mailbox,
+ const char *context,
+ const char *folder,
+ const char *msg_num,
+ ast_vm_msg_play_cb cb) = NULL;
void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
int (*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs),
int (*inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs),
int (*messagecount_func)(const char *context, const char *mailbox, const char *folder),
- int (*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context))
+ int (*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context),
+ int (*copy_recording_to_vm_func)(struct ast_vm_recording_data *vm_rec_data),
+ const char *vm_index_to_foldername_func(int id),
+ struct ast_vm_mailbox_snapshot *(*vm_mailbox_snapshot_create_func)(const char *mailbox,
+ const char *context,
+ const char *folder,
+ int descending,
+ enum ast_vm_snapshot_sort_val sort_val,
+ int combine_INBOX_and_OLD),
+ struct ast_vm_mailbox_snapshot *(*vm_mailbox_snapshot_destroy_func)(struct ast_vm_mailbox_snapshot *mailbox_snapshot),
+ int (*vm_msg_move_func)(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *oldfolder,
+ int *old_msg_ids,
+ const char *newfolder,
+ int *new_msg_ids),
+ int (*vm_msg_remove_func)(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *folder,
+ int *msgs),
+ int (*vm_msg_forward_func)(const char *from_mailbox,
+ const char *from_context,
+ const char *from_folder,
+ const char *to_mailbox,
+ const char *to_context,
+ const char *to_folder,
+ size_t num_msgs,
+ int *msg_ids,
+ int delete_old),
+ int (*vm_msg_play_func)(struct ast_channel *chan,
+ const char *mailbox,
+ const char *context,
+ const char *folder,
+ const char *msg_num,
+ ast_vm_msg_play_cb cb))
{
ast_has_voicemail_func = has_voicemail_func;
ast_inboxcount_func = inboxcount_func;
ast_inboxcount2_func = inboxcount2_func;
ast_messagecount_func = messagecount_func;
ast_sayname_func = sayname_func;
+ ast_copy_recording_to_vm_func = copy_recording_to_vm_func;
+ ast_vm_index_to_foldername_func = vm_index_to_foldername_func;
+ ast_vm_mailbox_snapshot_create_func = vm_mailbox_snapshot_create_func;
+ ast_vm_mailbox_snapshot_destroy_func = vm_mailbox_snapshot_destroy_func;
+ ast_vm_msg_move_func = vm_msg_move_func;
+ ast_vm_msg_remove_func = vm_msg_remove_func;
+ ast_vm_msg_forward_func = vm_msg_forward_func;
+ ast_vm_msg_play_func = vm_msg_play_func;
}
void ast_uninstall_vm_functions(void)
ast_inboxcount2_func = NULL;
ast_messagecount_func = NULL;
ast_sayname_func = NULL;
+ ast_copy_recording_to_vm_func = NULL;
+ ast_vm_index_to_foldername_func = NULL;
+ ast_vm_mailbox_snapshot_create_func = NULL;
+ ast_vm_mailbox_snapshot_destroy_func = NULL;
+ ast_vm_msg_move_func = NULL;
+ ast_vm_msg_remove_func = NULL;
+ ast_vm_msg_forward_func = NULL;
+ ast_vm_msg_play_func = NULL;
}
+#ifdef TEST_FRAMEWORK
+int (*ast_vm_test_create_user_func)(const char *context, const char *mailbox) = NULL;
+int (*ast_vm_test_destroy_user_func)(const char *context, const char *mailbox) = NULL;
+
+void ast_install_vm_test_functions(int (*vm_test_create_user_func)(const char *context, const char *mailbox),
+ int (*vm_test_destroy_user_func)(const char *context, const char *mailbox))
+{
+ ast_vm_test_create_user_func = vm_test_create_user_func;
+ ast_vm_test_destroy_user_func = vm_test_destroy_user_func;
+}
+
+void ast_uninstall_vm_test_functions(void)
+{
+ ast_vm_test_create_user_func = NULL;
+ ast_vm_test_destroy_user_func = NULL;
+}
+#endif
+
int ast_app_has_voicemail(const char *mailbox, const char *folder)
{
static int warned = 0;
return 0;
}
+/*!
+ * \internal
+ * \brief Function used as a callback for ast_copy_recording_to_vm when a real one isn't installed.
+ * \param vm_rec_data Stores crucial information about the voicemail that will basically just be used
+ * to figure out what the name of the recipient was supposed to be
+ */
+int ast_app_copy_recording_to_vm(struct ast_vm_recording_data *vm_rec_data)
+{
+ static int warned = 0;
+
+ if (ast_copy_recording_to_vm_func) {
+ return ast_copy_recording_to_vm_func(vm_rec_data);
+ }
+
+ if (warned++ % 10 == 0) {
+ ast_verb(3, "copy recording to voicemail called to copy %s.%s to %s@%s, but voicemail not loaded.\n",
+ vm_rec_data->recording_file, vm_rec_data->recording_ext,
+ vm_rec_data->mailbox, vm_rec_data->context);
+ }
+
+ return -1;
+}
int ast_app_inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
{
return 0;
}
+const char *ast_vm_index_to_foldername(int id)
+{
+ if (ast_vm_index_to_foldername_func) {
+ return ast_vm_index_to_foldername_func(id);
+ }
+ return NULL;
+}
+
+struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_create(const char *mailbox,
+ const char *context,
+ const char *folder,
+ int descending,
+ enum ast_vm_snapshot_sort_val sort_val,
+ int combine_INBOX_and_OLD)
+{
+ if (ast_vm_mailbox_snapshot_create_func) {
+ return ast_vm_mailbox_snapshot_create_func(mailbox, context, folder, descending, sort_val, combine_INBOX_and_OLD);
+ }
+ return NULL;
+}
+
+struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
+{
+ if (ast_vm_mailbox_snapshot_destroy_func) {
+ return ast_vm_mailbox_snapshot_destroy_func(mailbox_snapshot);
+ }
+ return NULL;
+}
+
+int ast_vm_msg_move(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *oldfolder,
+ int *old_msg_ids,
+ const char *newfolder,
+ int *new_msg_ids)
+{
+ if (ast_vm_msg_move_func) {
+ return ast_vm_msg_move_func(mailbox, context, num_msgs, oldfolder, old_msg_ids, newfolder, new_msg_ids);
+ }
+ return 0;
+}
+
+int ast_vm_msg_remove(const char *mailbox,
+ const char *context,
+ size_t num_msgs,
+ const char *folder,
+ int *msgs)
+{
+ if (ast_vm_msg_remove_func) {
+ return ast_vm_msg_remove_func(mailbox, context, num_msgs, folder, msgs);
+ }
+ return 0;
+}
+
+int ast_vm_msg_forward(const char *from_mailbox,
+ const char *from_context,
+ const char *from_folder,
+ const char *to_mailbox,
+ const char *to_context,
+ const char *to_folder,
+ size_t num_msgs,
+ int *msg_ids,
+ int delete_old)
+{
+ if (ast_vm_msg_forward_func) {
+ return ast_vm_msg_forward_func(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, num_msgs, msg_ids, delete_old);
+ }
+ return 0;
+}
+
+int ast_vm_msg_play(struct ast_channel *chan,
+ const char *mailbox,
+ const char *context,
+ const char *folder,
+ const char *msg_num,
+ ast_vm_msg_play_cb cb)
+{
+ if (ast_vm_msg_play_func) {
+ return ast_vm_msg_play_func(chan, mailbox, context, folder, msg_num, cb);
+ }
+ return 0;
+}
+
+#ifdef TEST_FRAMEWORK
+int ast_vm_test_create_user(const char *context, const char *mailbox)
+{
+ if (ast_vm_test_create_user_func) {
+ return ast_vm_test_create_user_func(context, mailbox);
+ }
+ return 0;
+}
+
+int ast_vm_test_destroy_user(const char *context, const char *mailbox)
+{
+ if (ast_vm_test_destroy_user_func) {
+ return ast_vm_test_destroy_user_func(context, mailbox);
+ }
+ return 0;
+}
+#endif
+
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
{
const char *ptr;
return res;
}
-int ast_control_streamfile(struct ast_channel *chan, const char *file,
- const char *fwd, const char *rev,
- const char *stop, const char *suspend,
- const char *restart, int skipms, long *offsetms)
+static int control_streamfile(struct ast_channel *chan,
+ const char *file,
+ const char *fwd,
+ const char *rev,
+ const char *stop,
+ const char *suspend,
+ const char *restart,
+ int skipms,
+ long *offsetms,
+ ast_waitstream_fr_cb cb)
{
char *breaks = NULL;
char *end = NULL;
ast_seekstream(chan->stream, offset, SEEK_SET);
offset = 0;
}
- res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
+ if (cb) {
+ res = ast_waitstream_fr_w_cb(chan, breaks, fwd, rev, skipms, cb);
+ } else {
+ res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
+ }
}
if (res < 1) {
return res;
}
+int ast_control_streamfile_w_cb(struct ast_channel *chan,
+ const char *file,
+ const char *fwd,
+ const char *rev,
+ const char *stop,
+ const char *suspend,
+ const char *restart,
+ int skipms,
+ long *offsetms,
+ ast_waitstream_fr_cb cb)
+{
+ return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, cb);
+}
+
+int ast_control_streamfile(struct ast_channel *chan, const char *file,
+ const char *fwd, const char *rev,
+ const char *stop, const char *suspend,
+ const char *restart, int skipms, long *offsetms)
+{
+ return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, NULL);
+}
+
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
{
int d = 0;
#include "asterisk/ast_version.h"
#include "asterisk/linkedlists.h"
#include "asterisk/devicestate.h"
+#include "asterisk/presencestate.h"
#include "asterisk/module.h"
#include "asterisk/dsp.h"
#include "asterisk/buildinfo.h"
ast_xmldoc_load_documentation();
#endif
+ if (ast_msg_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
/* initialize the data retrieval API */
if (ast_data_init()) {
printf ("%s", term_quit());
exit(1);
}
+ if (ast_presence_state_engine_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
ast_dsp_init();
ast_udptl_init();
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out_of_order", "Called DTE Out-Of-Order" },
{ AST_REDIRECTING_REASON_AWAY, "away", "Callee is Away" },
{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", "Call Forwarding By The Called DTE" },
+ { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm", "Call is being redirected to user's voicemail"},
/* *INDENT-ON* */
};
case AST_CONTROL_CC:
case AST_CONTROL_READ_ACTION:
case AST_CONTROL_AOC:
+ case AST_CONTROL_CUSTOM:
case AST_CONTROL_END_OF_Q:
case AST_CONTROL_UPDATE_RTP_PEER:
break;
case AST_CONTROL_CC:
case AST_CONTROL_READ_ACTION:
case AST_CONTROL_AOC:
+ case AST_CONTROL_CUSTOM:
case AST_CONTROL_END_OF_Q:
case AST_CONTROL_UPDATE_RTP_PEER:
/* Nothing left to do for these. */
return result;
}
+
+void ast_channel_unlink(struct ast_channel *chan)
+{
+ ao2_unlink(channels, chan);
+}
static char *extconfig_conf = "extconfig.conf";
+static struct ao2_container *cfg_hooks;
+static void config_hook_exec(const char *filename, const char *module, struct ast_config *cfg);
+
/*! \brief Structure to keep comments for rewriting configuration files */
struct ast_comment {
struct ast_comment *next;
.load_func = config_text_file_load,
};
+struct ast_config *ast_config_copy(const struct ast_config *old)
+{
+ struct ast_config *new_config = ast_config_new();
+ struct ast_category *cat_iter;
+
+ if (!new_config) {
+ return NULL;
+ }
+
+ for (cat_iter = old->root; cat_iter; cat_iter = cat_iter->next) {
+ struct ast_category *new_cat =
+ ast_category_new(cat_iter->name, cat_iter->file, cat_iter->lineno);
+ if (!new_cat) {
+ goto fail;
+ }
+ ast_category_append(new_config, new_cat);
+ if (cat_iter->root) {
+ new_cat->root = ast_variables_dup(cat_iter->root);
+ if (!new_cat->root) {
+ goto fail;
+ }
+ new_cat->last = cat_iter->last;
+ }
+ }
+
+ return new_config;
+
+fail:
+ ast_config_destroy(new_config);
+ return NULL;
+}
+
struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
{
char db[256];
char table[256];
struct ast_config_engine *loader = &text_file_engine;
- struct ast_config *result;
+ struct ast_config *result;
/* The config file itself bumps include_level by 1 */
if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
- if (result && result != CONFIG_STATUS_FILEINVALID && result != CONFIG_STATUS_FILEUNCHANGED)
+ if (result && result != CONFIG_STATUS_FILEINVALID && result != CONFIG_STATUS_FILEUNCHANGED) {
result->include_level--;
- else if (result != CONFIG_STATUS_FILEINVALID)
+ config_hook_exec(filename, who_asked, result);
+ } else if (result != CONFIG_STATUS_FILEINVALID) {
cfg->include_level--;
+ }
return result;
}
AST_CLI_DEFINE(handle_cli_config_list, "Show all files that have loaded a configuration file"),
};
+struct cfg_hook {
+ const char *name;
+ const char *filename;
+ const char *module;
+ config_hook_cb hook_cb;
+};
+
+static void hook_destroy(void *obj)
+{
+ struct cfg_hook *hook = obj;
+ ast_free((void *) hook->name);
+ ast_free((void *) hook->filename);
+ ast_free((void *) hook->module);
+}
+
+static int hook_cmp(void *obj, void *arg, int flags)
+{
+ struct cfg_hook *hook1 = obj;
+ struct cfg_hook *hook2 = arg;
+
+ return !(strcasecmp(hook1->name, hook2->name)) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static int hook_hash(const void *obj, const int flags)
+{
+ const struct cfg_hook *hook = obj;
+
+ return ast_str_hash(hook->name);
+}
+
+void ast_config_hook_unregister(const char *name)
+{
+ struct cfg_hook tmp;
+
+ tmp.name = ast_strdupa(name);
+
+ ao2_find(cfg_hooks, &tmp, OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
+}
+
+static void config_hook_exec(const char *filename, const char *module, struct ast_config *cfg)
+{
+ struct ao2_iterator it;
+ struct cfg_hook *hook;
+ if (!(cfg_hooks)) {
+ return;
+ }
+ it = ao2_iterator_init(cfg_hooks, 0);
+ while ((hook = ao2_iterator_next(&it))) {
+ if (!strcasecmp(hook->filename, filename) &&
+ !strcasecmp(hook->module, module)) {
+ struct ast_config *copy = ast_config_copy(cfg);
+ hook->hook_cb(copy);
+ }
+ ao2_ref(hook, -1);
+ }
+ ao2_iterator_destroy(&it);
+}
+
+int ast_config_hook_register(const char *name,
+ const char *filename,
+ const char *module,
+ enum config_hook_flags flags,
+ config_hook_cb hook_cb)
+{
+ struct cfg_hook *hook;
+ if (!cfg_hooks && !(cfg_hooks = ao2_container_alloc(17, hook_hash, hook_cmp))) {
+ return -1;
+ }
+
+ if (!(hook = ao2_alloc(sizeof(*hook), hook_destroy))) {
+ return -1;
+ }
+
+ hook->hook_cb = hook_cb;
+ hook->filename = ast_strdup(filename);
+ hook->name = ast_strdup(name);
+ hook->module = ast_strdup(module);
+
+ ao2_link(cfg_hooks, hook);
+ return 0;
+}
+
+
int register_config_cli(void)
{
ast_cli_register_multiple(cli_config, ARRAY_LEN(cli_config));
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvosse@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Encode and Decode custom control frame payload types.
+ *
+ * \author David Vossel <dvossel@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/_private.h"
+
+#include "asterisk/custom_control_frame.h"
+
+struct ast_custom_payload {
+ enum ast_custom_payload_type type;
+ /*! length of data portion only */
+ size_t datalen;
+ char *data;
+};
+
+enum ast_custom_payload_type ast_custom_payload_type(struct ast_custom_payload *type)
+{
+ return type->type;
+}
+
+size_t ast_custom_payload_len(struct ast_custom_payload *type)
+{
+ return type->datalen + sizeof(struct ast_custom_payload);
+}
+
+struct custom_sipinfo {
+ size_t num_headers;
+ int content_present;
+ int useragent_filter_present;
+ char *data;
+};
+
+struct ast_custom_payload *ast_custom_payload_sipinfo_encode(struct ast_variable *headers,
+ const char *content_type,
+ const char *content,
+ const char *useragent_filter)
+{
+ int num_headers = 0;
+ int content_present = 0;
+ int content_strlen = 0;
+ int content_type_strlen = 0;
+ int useragent_filter_present = 0;
+ int useragent_filter_len = 0;
+ size_t datalen = 0;
+ struct ast_variable *var;
+ struct ast_custom_payload *payload;
+ struct custom_sipinfo *sipinfo;
+ char *data;
+
+ datalen += sizeof(struct custom_sipinfo);
+
+ for (var = headers; var; var = var->next) {
+ datalen += strlen(var->name) + 1;
+ datalen += strlen(var->value) + 1;
+ num_headers++;
+ }
+
+ if (!ast_strlen_zero(content_type) && !ast_strlen_zero(content)) {
+ content_type_strlen = strlen(content_type);
+ content_strlen = strlen(content);
+ datalen += content_type_strlen + 1;
+ datalen += content_strlen + 1;
+ content_present = 1;
+ }
+
+ if (!ast_strlen_zero(useragent_filter)) {
+ useragent_filter_len = strlen(useragent_filter);
+ datalen += useragent_filter_len + 1;
+ useragent_filter_present = 1;
+ }
+
+ if (!(payload = ast_calloc(1, datalen + sizeof(*payload)))) {
+ return NULL;
+ }
+
+ payload->type = AST_CUSTOM_SIP_INFO;
+ payload->datalen = datalen;
+ payload->data = (char *) payload + sizeof(struct ast_custom_payload);
+ sipinfo = (struct custom_sipinfo *) payload->data;
+ sipinfo->num_headers = num_headers;
+ sipinfo->content_present = content_present;
+ sipinfo->useragent_filter_present = useragent_filter_present;
+ sipinfo->data = (char *) sipinfo + sizeof(struct custom_sipinfo);
+
+ /* store string buffers in payload data
+ * headers are put in first, followed by content type and then content body. */
+ data = sipinfo->data;
+
+ for (var = headers; var; var = var->next) {
+ int namelen = strlen(var->name);
+ int vallen = strlen(var->value);
+
+ /*! we already know we have enough room for each of these */
+ ast_copy_string(data, var->name, namelen+1);
+ data += namelen + 1; /* skip over the '\0' character */
+ ast_copy_string(data, var->value, vallen+1);
+ data += vallen + 1; /* skip over the '\0' character */
+ }
+
+ if (content_present) {
+ ast_copy_string(data, content_type, content_type_strlen+1);
+ data += content_type_strlen + 1;
+ ast_copy_string(data, content, content_strlen+1);
+ data += content_strlen + 1;
+ }
+
+ if (useragent_filter_present) {
+ ast_copy_string(data, useragent_filter, useragent_filter_len+1);
+ }
+
+ return payload;
+}
+
+int ast_custom_payload_sipinfo_decode(struct ast_custom_payload *pl,
+ struct ast_variable **headers,
+ char **content_type,
+ char **content,
+ char **useragent_filter)
+{
+ struct custom_sipinfo *sipinfo;
+ struct ast_variable *cur = NULL;
+ char *data;
+ int i;
+
+ *headers = NULL;
+ *content_type = NULL;
+ *content = NULL;
+ *useragent_filter = NULL;
+
+ if (pl->type != AST_CUSTOM_SIP_INFO) {
+ return -1;
+ }
+
+ sipinfo = (struct custom_sipinfo *) pl->data;
+ data = sipinfo->data;
+ for (i = 0; i < sipinfo->num_headers; i++) {
+ const char *name;
+ const char *value;
+
+ name = data;
+ data += strlen(name) + 1;
+ value = data;
+ data += strlen(value) + 1;
+
+ if (*headers) {
+ if ((cur->next = ast_variable_new(name, value, ""))) {
+ cur = cur->next;
+ }
+ } else {
+ *headers = cur = ast_variable_new(name, value, "");
+ }
+ }
+
+ if (sipinfo->content_present) {
+ *content_type = ast_strdup(data);
+ data += strlen(data) + 1;
+ *content = ast_strdup(data);
+ data += strlen(data) + 1;
+ }
+
+ if (sipinfo->useragent_filter_present) {
+ *useragent_filter = ast_strdup(data);
+ }
+ return 0;
+}
static int ast_event_hash_mwi(const void *obj, const int flags);
static int ast_event_hash_devstate(const void *obj, const int flags);
static int ast_event_hash_devstate_change(const void *obj, const int flags);
+static int ast_event_hash_presence_state_change(const void *obj, const int flags);
#ifdef LOW_MEMORY
#define NUM_CACHE_BUCKETS 17
.hash_fn = ast_event_hash_devstate_change,
.cache_args = { AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, },
},
+ [AST_EVENT_PRESENCE_STATE] = {
+ .hash_fn = ast_event_hash_presence_state_change,
+ .cache_args = { AST_EVENT_IE_PRESENCE_STATE, },
+ },
+
};
/*!
return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
}
+/*!
+ * \internal
+ * \brief Hash function for AST_EVENT_PRESENCE_STATE
+ *
+ * \param[in] obj an ast_event
+ * \param[in] flags unused
+ *
+ * \return hash value
+ */
+static int ast_event_hash_presence_state_change(const void *obj, const int flags)
+{
+ const struct ast_event *event = obj;
+
+ return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_PROVIDER));
+}
+
static int ast_event_hash(const void *obj, const int flags)
{
const struct ast_event_ref *event_ref;
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
+#include "asterisk/custom_control_frame.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
<para>Bridge together two channels already in the PBX.</para>
</description>
</manager>
+ <manager name="Parkinglots" language="en_US">
+ <synopsis>
+ Get a list of parking lots
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ </syntax>
+ <description>
+ <para>List all parking lots as a series of AMI events</para>
+ </description>
+ </manager>
***/
#define DEFAULT_PARK_TIME 45000 /*!< ms */
AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
};
+static int manager_parkinglot_list(struct mansession *s, const struct message *m)
+{
+ const char *id = astman_get_header(m, "ActionID");
+ char idText[256] = "";
+ struct ao2_iterator iter;
+ struct ast_parkinglot *curlot;
+
+ if (!ast_strlen_zero(id))
+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+
+ astman_send_ack(s, m, "Parking lots will follow");
+
+ iter = ao2_iterator_init(parkinglots, 0);
+ while ((curlot = ao2_iterator_next(&iter))) {
+ astman_append(s, "Event: Parkinglot\r\n"
+ "Name: %s\r\n"
+ "StartExten: %d\r\n"
+ "StopExten: %d\r\n"
+ "Timeout: %d\r\n"
+ "\r\n",
+ curlot->name,
+ curlot->cfg.parking_start,
+ curlot->cfg.parking_stop,
+ curlot->cfg.parkingtime ? curlot->cfg.parkingtime / 1000 : curlot->cfg.parkingtime);
+ ao2_ref(curlot, -1);
+ }
+
+ astman_append(s,
+ "Event: ParkinglotsComplete\r\n"
+ "%s"
+ "\r\n",idText);
+
+ return RESULT_SUCCESS;
+}
+
/*!
* \brief Dump parking lot status
* \param s
struct ao2_iterator iter;
struct ast_parkinglot *curlot;
int numparked = 0;
+ long now = time(NULL);
if (!ast_strlen_zero(id))
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
"Channel: %s\r\n"
"From: %s\r\n"
"Timeout: %ld\r\n"
+ "Duration: %ld\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"\r\n",
curlot->name,
cur->parkingnum, cur->chan->name, cur->peername,
- (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
+ (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - now,
+ now - (long) cur->start.tv_sec,
S_COR(cur->chan->caller.id.number.valid, cur->chan->caller.id.number.str, ""), /* XXX in other places it is <unknown> */
S_COR(cur->chan->caller.id.name.valid, cur->chan->caller.id.name.str, ""),
S_COR(cur->chan->connected.id.number.valid, cur->chan->connected.id.number.str, ""), /* XXX in other places it is <unknown> */
res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
if (!res) {
ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
+ ast_manager_register_xml("Parkinglots", 0, manager_parkinglot_list);
ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
}
/*!
* \brief the core of all waitstream() functions
*/
-static int waitstream_core(struct ast_channel *c, const char *breakon,
- const char *forward, const char *reverse, int skip_ms,
- int audiofd, int cmdfd, const char *context)
+static int waitstream_core(struct ast_channel *c,
+ const char *breakon,
+ const char *forward,
+ const char *reverse,
+ int skip_ms,
+ int audiofd,
+ int cmdfd,
+ const char *context,
+ ast_waitstream_fr_cb cb)
{
const char *orig_chan_name = NULL;
+
int err = 0;
if (!breakon)
if (ast_test_flag(c, AST_FLAG_MASQ_NOSTREAM))
orig_chan_name = ast_strdupa(c->name);
+ if (c->stream && cb) {
+ long ms_len = ast_tellstream(c->stream) / (ast_format_rate(c->stream->fmt->format) / 1000);
+ cb(c, ms_len, AST_WAITSTREAM_CB_START);
+ }
+
while (c->stream) {
int res;
int ms;
return res;
}
} else {
+ enum ast_waitstream_fr_cb_values cb_val = 0;
res = fr->subclass.integer;
if (strchr(forward, res)) {
int eoftest;
} else {
ungetc(eoftest, c->stream->f);
}
+ cb_val = AST_WAITSTREAM_CB_FASTFORWARD;
} else if (strchr(reverse, res)) {
ast_stream_rewind(c->stream, skip_ms);
+ cb_val = AST_WAITSTREAM_CB_REWIND;
} else if (strchr(breakon, res)) {
ast_frfree(fr);
ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
return res;
- }
+ }
+ if (cb_val && cb) {
+ long ms_len = ast_tellstream(c->stream) / (ast_format_rate(c->stream->fmt->format) / 1000);
+ cb(c, ms_len, cb_val);
+ }
}
break;
case AST_FRAME_CONTROL:
return (err || c->_softhangup) ? -1 : 0;
}
+int ast_waitstream_fr_w_cb(struct ast_channel *c,
+ const char *breakon,
+ const char *forward,
+ const char *reverse,
+ int ms,
+ ast_waitstream_fr_cb cb)
+{
+ return waitstream_core(c, breakon, forward, reverse, ms,
+ -1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */, cb);
+}
+
int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *reverse, int ms)
{
return waitstream_core(c, breakon, forward, reverse, ms,
- -1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */);
+ -1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */, NULL /* no callback */);
}
int ast_waitstream(struct ast_channel *c, const char *breakon)
{
- return waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL);
+ return waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL, NULL /* no callback */);
}
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
{
return waitstream_core(c, breakon, NULL, NULL, 0,
- audiofd, cmdfd, NULL /* no context */);
+ audiofd, cmdfd, NULL /* no context */, NULL /* no callback */);
}
int ast_waitstream_exten(struct ast_channel *c, const char *context)
if (!context)
context = c->context;
return waitstream_core(c, NULL, NULL, NULL, 0,
- -1, -1, context);
+ -1, -1, context, NULL /* no callback */);
}
/*
{ EVENT_FLAG_CC, "cc" },
{ EVENT_FLAG_AOC, "aoc" },
{ EVENT_FLAG_TEST, "test" },
+ { EVENT_FLAG_MESSAGE, "message" },
{ INT_MAX, "all" },
{ 0, "none" },
};
return 0;
}
-static int manager_state_cb(char *context, char *exten, int state, void *data)
+static int manager_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
{
/* Notify managers of change */
char hint[512];
+ int state = info->exten_state;
+
+ /* only interested in device state for this right now */
+ if (info->reason != AST_HINT_UPDATE_DEVICE) {
+ return 0;
+ }
+
ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nHint: %s\r\nStatus: %d\r\n", exten, context, hint, state);
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Russell Bryant <russell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Out-of-call text message support
+ *
+ * \author Russell Bryant <russell@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/_private.h"
+
+#include "asterisk/module.h"
+#include "asterisk/datastore.h"
+#include "asterisk/pbx.h"
+#include "asterisk/manager.h"
+#include "asterisk/strings.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/app.h"
+#include "asterisk/taskprocessor.h"
+#include "asterisk/message.h"
+
+/*** DOCUMENTATION
+ <function name="MESSAGE" language="en_US">
+ <synopsis>
+ Create a message or read fields from a message.
+ </synopsis>
+ <syntax argsep="/">
+ <parameter name="argument" required="true">
+ <para>Field of the message to get or set.</para>
+ <enumlist>
+ <enum name="to">
+ <para>Read-only. The destination of the message. When processing an
+ incoming message, this will be set to the destination listed as
+ the recipient of the message that was received by Asterisk.</para>
+ </enum>
+ <enum name="from">
+ <para>Read-only. The source of the message. When processing an
+ incoming message, this will be set to the source of the message.</para>
+ </enum>
+ <enum name="custom_data">
+ <para>Write-only. Mark or unmark all message headers for an outgoing
+ message. The following values can be set:</para>
+ <enumlist>
+ <enum name="mark_all_outbound">
+ <para>Mark all headers for an outgoing message.</para>
+ </enum>
+ <enum name="clear_all_outbound">
+ <para>Unmark all headers for an outgoing message.</para>
+ </enum>
+ </enumlist>
+ </enum>
+ <enum name="body">
+ <para>Read/Write. The message body. When processing an incoming
+ message, this includes the body of the message that Asterisk
+ received. When MessageSend() is executed, the contents of this
+ field are used as the body of the outgoing message. The body
+ will always be UTF-8.</para>
+ </enum>
+ </enumlist>
+ </parameter>
+ </syntax>
+ <description>
+ <para>This function will read from or write a value to a text message.
+ It is used both to read the data out of an incoming message, as well as
+ modify or create a message that will be sent outbound.</para>
+ </description>
+ <see-also>
+ <ref type="application">MessageSend</ref>
+ </see-also>
+ </function>
+ <function name="MESSAGE_DATA" language="en_US">
+ <synopsis>
+ Read or write custom data attached to a message.
+ </synopsis>
+ <syntax argsep="/">
+ <parameter name="argument" required="true">
+ <para>Field of the message to get or set.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>This function will read from or write a value to a text message.
+ It is used both to read the data out of an incoming message, as well as
+ modify a message that will be sent outbound.</para>
+ <para>NOTE: If you want to set an outbound message to carry data in the
+ current message, do Set(MESSAGE_DATA(key)=${MESSAGE_DATA(key)}).</para>
+ </description>
+ <see-also>
+ <ref type="application">MessageSend</ref>
+ </see-also>
+ </function>
+ <application name="MessageSend" language="en_US">
+ <synopsis>
+ Send a text message.
+ </synopsis>
+ <syntax>
+ <parameter name="to" required="true">
+ <para>A To URI for the message.</para>
+ </parameter>
+ <parameter name="from" required="false">
+ <para>A From URI for the message if needed for the
+ message technology being used to send this message.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Send a text message. The body of the message that will be
+ sent is what is currently set to <literal>MESSAGE(body)</literal>.</para>
+
+ <para>This application sets the following channel variables:</para>
+ <variablelist>
+ <variable name="MESSAGE_SEND_STATUS">
+ <para>This is the time from dialing a channel until when it is disconnected.</para>
+ <value name="INVALID_PROTOCOL">
+ No handler for the technology part of the URI was found.
+ </value>
+ <value name="INVALID_URI">
+ The protocol handler reported that the URI was not valid.
+ </value>
+ <value name="SUCCESS">
+ Successfully passed on to the protocol handler, but delivery has not necessarily been guaranteed.
+ </value>
+ <value name="FAILURE">
+ The protocol handler reported that it was unabled to deliver the message for some reason.
+ </value>
+ </variable>
+ </variablelist>
+ </description>
+ </application>
+ <manager name="MessageSend" language="en_US">
+ <synopsis>
+ Send an out of call message to an endpoint.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="To" required="true">
+ <para>The URI the message is to be sent to.</para>
+ </parameter>
+ <parameter name="From">
+ <para>A From URI for the message if needed for the
+ message technology being used to send this message.</para>
+ <note>
+ <para>For SIP the from parameter can be a configured peer name
+ or in the form of "display-name" <URI>.</para>
+ </note>
+ </parameter>
+ <parameter name="Body">
+ <para>The message body text. This must not contain any newlines as that
+ conflicts with the AMI protocol.</para>
+ </parameter>
+ <parameter name="Base64Body">
+ <para>Text bodies requiring the use of newlines have to be base64 encoded
+ in this field. Base64Body will be decoded before being sent out.
+ Base64Body takes precedence over Body.</para>
+ </parameter>
+ <parameter name="Variable">
+ <para>Message variable to set, multiple Variable: headers are
+ allowed. The header value is a comma separated list of
+ name=value pairs.</para>
+ </parameter>
+ </syntax>
+ </manager>
+ ***/
+
+struct msg_data {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name);
+ AST_STRING_FIELD(value);
+ );
+ unsigned int send:1; /* Whether to send out on outbound messages */
+};
+
+AST_LIST_HEAD_NOLOCK(outhead, msg_data);
+
+/*!
+ * \brief A message.
+ *
+ * \todo Consider whether stringfields would be an appropriate optimization here.
+ */
+struct ast_msg {
+ struct ast_str *to;
+ struct ast_str *from;
+ struct ast_str *body;
+ struct ast_str *context;
+ struct ast_str *exten;
+ struct ao2_container *vars;
+};
+
+struct ast_msg_tech_holder {
+ const struct ast_msg_tech *tech;
+ /*!
+ * \brief A rwlock for this object
+ *
+ * a read/write lock must be used to protect the wrapper instead
+ * of the ao2 lock. A rdlock must be held to read tech_holder->tech.
+ */
+ ast_rwlock_t tech_lock;
+};
+
+static struct ao2_container *msg_techs;
+
+static struct ast_taskprocessor *msg_q_tp;
+
+static const char app_msg_send[] = "MessageSend";
+
+static void msg_ds_destroy(void *data);
+
+static const struct ast_datastore_info msg_datastore = {
+ .type = "message",
+ .destroy = msg_ds_destroy,
+};
+
+static int msg_func_read(struct ast_channel *chan, const char *function,
+ char *data, char *buf, size_t len);
+static int msg_func_write(struct ast_channel *chan, const char *function,
+ char *data, const char *value);
+
+static struct ast_custom_function msg_function = {
+ .name = "MESSAGE",
+ .read = msg_func_read,
+ .write = msg_func_write,
+};
+
+static int msg_data_func_read(struct ast_channel *chan, const char *function,
+ char *data, char *buf, size_t len);
+static int msg_data_func_write(struct ast_channel *chan, const char *function,
+ char *data, const char *value);
+
+static struct ast_custom_function msg_data_function = {
+ .name = "MESSAGE_DATA",
+ .read = msg_data_func_read,
+ .write = msg_data_func_write,
+};
+
+static struct ast_frame *chan_msg_read(struct ast_channel *chan);
+static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr);
+static int chan_msg_indicate(struct ast_channel *chan, int condition,
+ const void *data, size_t datalen);
+static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit);
+static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
+ unsigned int duration);
+
+/*!
+ * \internal
+ * \brief A bare minimum channel technology
+ *
+ * This will not be registered as we never want anything to try
+ * to create Message channels other than internally in this file.
+ */
+static const struct ast_channel_tech msg_chan_tech_hack = {
+ .type = "Message",
+ .description = "Internal Text Message Processing",
+ .read = chan_msg_read,
+ .write = chan_msg_write,
+ .indicate = chan_msg_indicate,
+ .send_digit_begin = chan_msg_send_digit_begin,
+ .send_digit_end = chan_msg_send_digit_end,
+};
+
+/*!
+ * \internal
+ * \brief ast_channel_tech read callback
+ *
+ * This should never be called. However, we say that about chan_iax2's
+ * read callback, too, and it seems to randomly get called for some
+ * reason. If it does, a simple NULL frame will suffice.
+ */
+static struct ast_frame *chan_msg_read(struct ast_channel *chan)
+{
+ return &ast_null_frame;
+}
+
+/*!
+ * \internal
+ * \brief ast_channel_tech write callback
+ *
+ * Throw all frames away. We don't care about any of them.
+ */
+static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr)
+{
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief ast_channel_tech indicate callback
+ *
+ * The indicate callback is here just so it can return success.
+ * We don't want any callers of ast_indicate() to think something
+ * has failed. We also don't want ast_indicate() itself to try
+ * to generate inband tones since we didn't tell it that we took
+ * care of it ourselves.
+ */
+static int chan_msg_indicate(struct ast_channel *chan, int condition,
+ const void *data, size_t datalen)
+{
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief ast_channel_tech send_digit_begin callback
+ *
+ * This is here so that just in case a digit comes at a message channel
+ * that the Asterisk core doesn't waste any time trying to generate
+ * inband DTMF in audio. It's a waste of resources.
+ */
+static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit)
+{
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief ast_channel_tech send_digit_end callback
+ *
+ * This is here so that just in case a digit comes at a message channel
+ * that the Asterisk core doesn't waste any time trying to generate
+ * inband DTMF in audio. It's a waste of resources.
+ */
+static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
+ unsigned int duration)
+{
+ return 0;
+}
+
+static void msg_ds_destroy(void *data)
+{
+ struct ast_msg *msg = data;
+
+ ao2_ref(msg, -1);
+}
+
+static int msg_data_hash_fn(const void *obj, const int flags)
+{
+ const struct msg_data *data = obj;
+ return ast_str_case_hash(data->name);
+}
+
+static int msg_data_cmp_fn(void *obj, void *arg, int flags)
+{
+ const struct msg_data *one = obj, *two = arg;
+ return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static void msg_data_destructor(void *obj)
+{
+ struct msg_data *data = obj;
+ ast_string_field_free_memory(data);
+}
+
+static void msg_destructor(void *obj)
+{
+ struct ast_msg *msg = obj;
+
+ ast_free(msg->to);
+ msg->to = NULL;
+
+ ast_free(msg->from);
+ msg->from = NULL;
+
+ ast_free(msg->body);
+ msg->body = NULL;
+
+ ast_free(msg->context);
+ msg->context = NULL;
+
+ ast_free(msg->exten);
+ msg->exten = NULL;
+
+ ao2_ref(msg->vars, -1);
+}
+
+struct ast_msg *ast_msg_alloc(void)
+{
+ struct ast_msg *msg;
+
+ if (!(msg = ao2_alloc(sizeof(*msg), msg_destructor))) {
+ return NULL;
+ }
+
+ if (!(msg->to = ast_str_create(32))) {
+ ao2_ref(msg, -1);
+ return NULL;
+ }
+
+ if (!(msg->from = ast_str_create(32))) {
+ ao2_ref(msg, -1);
+ return NULL;
+ }
+
+ if (!(msg->body = ast_str_create(128))) {
+ ao2_ref(msg, -1);
+ return NULL;
+ }
+
+ if (!(msg->context = ast_str_create(16))) {
+ ao2_ref(msg, -1);
+ return NULL;
+ }
+
+ if (!(msg->exten = ast_str_create(16))) {
+ ao2_ref(msg, -1);
+ return NULL;
+ }
+
+ if (!(msg->vars = ao2_container_alloc(1, msg_data_hash_fn, msg_data_cmp_fn))) {
+ ao2_ref(msg, -1);
+ return NULL;
+ }
+
+ ast_str_set(&msg->context, 0, "default");
+
+ return msg;
+}
+
+struct ast_msg *ast_msg_ref(struct ast_msg *msg)
+{
+ ao2_ref(msg, 1);
+ return msg;
+}
+
+struct ast_msg *ast_msg_destroy(struct ast_msg *msg)
+{
+ ao2_ref(msg, -1);
+
+ return NULL;
+}
+
+int ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...)
+{
+ va_list ap;
+ int res;
+
+ va_start(ap, fmt);
+ res = ast_str_set_va(&msg->to, 0, fmt, ap);
+ va_end(ap);
+
+ return res < 0 ? -1 : 0;
+}
+
+int ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...)
+{
+ va_list ap;
+ int res;
+
+ va_start(ap, fmt);
+ res = ast_str_set_va(&msg->from, 0, fmt, ap);
+ va_end(ap);
+
+ return res < 0 ? -1 : 0;
+}
+
+int ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...)
+{
+ va_list ap;
+ int res;
+
+ va_start(ap, fmt);
+ res = ast_str_set_va(&msg->body, 0, fmt, ap);
+ va_end(ap);
+
+ return res < 0 ? -1 : 0;
+}
+
+int ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...)
+{
+ va_list ap;
+ int res;
+
+ va_start(ap, fmt);
+ res = ast_str_set_va(&msg->context, 0, fmt, ap);
+ va_end(ap);
+
+ return res < 0 ? -1 : 0;
+}
+
+int ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...)
+{
+ va_list ap;
+ int res;
+
+ va_start(ap, fmt);
+ res = ast_str_set_va(&msg->exten, 0, fmt, ap);
+ va_end(ap);
+
+ return res < 0 ? -1 : 0;
+}
+
+const char *ast_msg_get_body(const struct ast_msg *msg)
+{
+ return ast_str_buffer(msg->body);
+}
+
+static struct msg_data *msg_data_alloc(void)
+{
+ struct msg_data *data;
+
+ if (!(data = ao2_alloc(sizeof(*data), msg_data_destructor))) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(data, 32)) {
+ ao2_ref(data, -1);
+ return NULL;
+ }
+
+ return data;
+}
+
+static struct msg_data *msg_data_find(struct ao2_container *vars, const char *name)
+{
+ struct msg_data tmp = {
+ .name = name,
+ };
+ return ao2_find(vars, &tmp, OBJ_POINTER);
+}
+
+static int msg_set_var_full(struct ast_msg *msg, const char *name, const char *value, unsigned int outbound)
+{
+ struct msg_data *data;
+
+ if (!(data = msg_data_find(msg->vars, name))) {
+ if (!(data = msg_data_alloc())) {
+ return -1;
+ };
+
+ ast_string_field_set(data, name, name);
+ ast_string_field_set(data, value, value);
+ data->send = outbound;
+ ao2_link(msg->vars, data);
+ } else {
+ if (ast_strlen_zero(value)) {
+ ao2_unlink(msg->vars, data);
+ } else {
+ ast_string_field_set(data, value, value);
+ data->send = outbound;
+ }
+ }
+
+ ao2_ref(data, -1);
+
+ return 0;
+}
+
+int ast_msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value)
+{
+ return msg_set_var_full(msg, name, value, 1);
+}
+
+int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
+{
+ return msg_set_var_full(msg, name, value, 0);
+}
+
+const char *ast_msg_get_var(struct ast_msg *msg, const char *name)
+{
+ struct msg_data *data;
+ const char *val = NULL;
+
+ if (!(data = msg_data_find(msg->vars, name))) {
+ return NULL;
+ }
+
+ /* Yep, this definitely looks like val would be a dangling pointer
+ * after the ref count is decremented. As long as the message structure
+ * is used in a thread safe manner, this will not be the case though.
+ * The ast_msg holds a reference to this object in the msg->vars container. */
+ val = data->value;
+ ao2_ref(data, -1);
+
+ return val;
+}
+
+struct ast_msg_var_iterator {
+ struct ao2_iterator i;
+ struct msg_data *current_used;
+};
+
+struct ast_msg_var_iterator *ast_msg_var_iterator_init(const struct ast_msg *msg)
+{
+ struct ast_msg_var_iterator *i;
+ if (!(i = ast_calloc(1, sizeof(*i)))) {
+ return NULL;
+ }
+
+ i->i = ao2_iterator_init(msg->vars, 0);
+
+ return i;
+}
+
+int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *i, const char **name, const char **value)
+{
+ struct msg_data *data;
+
+ /* Skip any that aren't marked for sending out */
+ while ((data = ao2_iterator_next(&i->i)) && !data->send) {
+ ao2_ref(data, -1);
+ }
+
+ if (!data) {
+ return 0;
+ }
+
+ if (data->send) {
+ *name = data->name;
+ *value = data->value;
+ }
+
+ /* Leave the refcount to be cleaned up by the caller with
+ * ast_msg_var_unref_current after they finish with the pointers to the data */
+ i->current_used = data;
+
+ return 1;
+}
+
+void ast_msg_var_unref_current(struct ast_msg_var_iterator *i) {
+ if (i->current_used) {
+ ao2_ref(i->current_used, -1);
+ }
+ i->current_used = NULL;
+}
+
+void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *i)
+{
+ ao2_iterator_destroy(&i->i);
+ ast_free(i);
+}
+
+static struct ast_channel *create_msg_q_chan(void)
+{
+ struct ast_channel *chan;
+ struct ast_datastore *ds;
+
+ chan = ast_channel_alloc(1, AST_STATE_UP,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, 0,
+ "%s", "Message/ast_msg_queue");
+
+ if (!chan) {
+ return NULL;
+ }
+
+ ast_channel_unlink(chan);
+
+ chan->tech = &msg_chan_tech_hack;
+
+ if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
+ ast_hangup(chan);
+ return NULL;
+ }
+
+ ast_channel_lock(chan);
+ ast_channel_datastore_add(chan, ds);
+ ast_channel_unlock(chan);
+
+ return chan;
+}
+
+/*!
+ * \internal
+ * \brief Run the dialplan for message processing
+ *
+ * \pre The message has already been set up on the msg datastore
+ * on this channel.
+ */
+static void msg_route(struct ast_channel *chan, struct ast_msg *msg)
+{
+ struct ast_pbx_args pbx_args;
+
+ ast_explicit_goto(chan, ast_str_buffer(msg->context), AS_OR(msg->exten, "s"), 1);
+
+ memset(&pbx_args, 0, sizeof(pbx_args));
+ pbx_args.no_hangup_chan = 1,
+ ast_pbx_run_args(chan, &pbx_args);
+}
+
+/*!
+ * \internal
+ * \brief Clean up ast_channel after each message
+ *
+ * Reset various bits of state after routing each message so the same ast_channel
+ * can just be reused.
+ */
+static void chan_cleanup(struct ast_channel *chan)
+{
+ struct ast_datastore *msg_ds, *ds;
+ struct varshead *headp;
+ struct ast_var_t *vardata;
+
+ ast_channel_lock(chan);
+
+ /*
+ * Remove the msg datastore. Free its data but keep around the datastore
+ * object and just reuse it.
+ */
+ if ((msg_ds = ast_channel_datastore_find(chan, &msg_datastore, NULL)) && msg_ds->data) {
+ ast_channel_datastore_remove(chan, msg_ds);
+ ao2_ref(msg_ds->data, -1);
+ msg_ds->data = NULL;
+ }
+
+ /*
+ * Destroy all other datastores.
+ */
+ while ((ds = AST_LIST_REMOVE_HEAD(&chan->datastores, entry))) {
+ ast_datastore_free(ds);
+ }
+
+ /*
+ * Destroy all channel variables.
+ */
+ headp = &chan->varshead;
+ while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
+ ast_var_delete(vardata);
+ }
+
+ /*
+ * Restore msg datastore.
+ */
+ if (msg_ds) {
+ ast_channel_datastore_add(chan, msg_ds);
+ }
+
+ ast_channel_unlock(chan);
+}
+
+AST_THREADSTORAGE(msg_q_chan);
+
+/*!
+ * \internal
+ * \brief Message queue task processor callback
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * \note Even though this returns a value, the taskprocessor code ignores the value.
+ */
+static int msg_q_cb(void *data)
+{
+ struct ast_msg *msg = data;
+ struct ast_channel **chan_p, *chan;
+ struct ast_datastore *ds;
+
+ if (!(chan_p = ast_threadstorage_get(&msg_q_chan, sizeof(struct ast_channel *)))) {
+ return -1;
+ }
+ if (!*chan_p) {
+ if (!(*chan_p = create_msg_q_chan())) {
+ return -1;
+ }
+ }
+ chan = *chan_p;
+
+ ast_channel_lock(chan);
+ if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
+ ast_channel_unlock(chan);
+ return -1;
+ }
+ ao2_ref(msg, +1);
+ ds->data = msg;
+ ast_channel_unlock(chan);
+
+ msg_route(chan, msg);
+ chan_cleanup(chan);
+
+ ao2_ref(msg, -1);
+
+ return 0;
+}
+
+int ast_msg_queue(struct ast_msg *msg)
+{
+ int res;
+
+ res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
+ if (res == -1) {
+ ao2_ref(msg, -1);
+ }
+
+ return res;
+}
+
+/*!
+ * \internal
+ * \brief Find or create a message datastore on a channel
+ *
+ * \pre chan is locked
+ *
+ * \param chan the relevant channel
+ *
+ * \return the channel's message datastore, or NULL on error
+ */
+static struct ast_datastore *msg_datastore_find_or_create(struct ast_channel *chan)
+{
+ struct ast_datastore *ds;
+
+ if ((ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
+ return ds;
+ }
+
+ if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
+ return NULL;
+ }
+
+ if (!(ds->data = ast_msg_alloc())) {
+ ast_datastore_free(ds);
+ return NULL;
+ }
+
+ ast_channel_datastore_add(chan, ds);
+
+ return ds;
+}
+
+static int msg_func_read(struct ast_channel *chan, const char *function,
+ char *data, char *buf, size_t len)
+{
+ struct ast_datastore *ds;
+ struct ast_msg *msg;
+
+ ast_channel_lock(chan);
+
+ if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
+ ast_channel_unlock(chan);
+ ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
+ return -1;
+ }
+
+ msg = ds->data;
+ ao2_ref(msg, +1);
+ ast_channel_unlock(chan);
+
+ ao2_lock(msg);
+
+ if (!strcasecmp(data, "to")) {
+ ast_copy_string(buf, ast_str_buffer(msg->to), len);
+ } else if (!strcasecmp(data, "from")) {
+ ast_copy_string(buf, ast_str_buffer(msg->from), len);
+ } else if (!strcasecmp(data, "body")) {
+ ast_copy_string(buf, ast_msg_get_body(msg), len);
+ } else {
+ ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
+ }
+
+ ao2_unlock(msg);
+ ao2_ref(msg, -1);
+
+ return 0;
+}
+
+static int msg_func_write(struct ast_channel *chan, const char *function,
+ char *data, const char *value)
+{
+ struct ast_datastore *ds;
+ struct ast_msg *msg;
+
+ ast_channel_lock(chan);
+
+ if (!(ds = msg_datastore_find_or_create(chan))) {
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ msg = ds->data;
+ ao2_ref(msg, +1);
+ ast_channel_unlock(chan);
+
+ ao2_lock(msg);
+
+ if (!strcasecmp(data, "to")) {
+ ast_msg_set_to(msg, "%s", value);
+ } else if (!strcasecmp(data, "from")) {
+ ast_msg_set_from(msg, "%s", value);
+ } else if (!strcasecmp(data, "body")) {
+ ast_msg_set_body(msg, "%s", value);
+ } else if (!strcasecmp(data, "custom_data")) {
+ int outbound = -1;
+ if (!strcasecmp(value, "mark_all_outbound")) {
+ outbound = 1;
+ } else if (!strcasecmp(value, "clear_all_outbound")) {
+ outbound = 0;
+ } else {
+ ast_log(LOG_WARNING, "'%s' is not a valid value for custom_data\n", value);
+ }
+
+ if (outbound != -1) {
+ struct msg_data *hdr_data;
+ struct ao2_iterator iter = ao2_iterator_init(msg->vars, 0);
+
+ while ((hdr_data = ao2_iterator_next(&iter))) {
+ hdr_data->send = outbound;
+ ao2_ref(hdr_data, -1);
+ }
+ ao2_iterator_destroy(&iter);
+ }
+ } else {
+ ast_log(LOG_WARNING, "'%s' is not a valid write argument.\n", data);
+ }
+
+ ao2_unlock(msg);
+ ao2_ref(msg, -1);
+
+ return 0;
+}
+
+static int msg_data_func_read(struct ast_channel *chan, const char *function,
+ char *data, char *buf, size_t len)
+{
+ struct ast_datastore *ds;
+ struct ast_msg *msg;
+ const char *val;
+
+ ast_channel_lock(chan);
+
+ if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
+ ast_channel_unlock(chan);
+ ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
+ return -1;
+ }
+
+ msg = ds->data;
+ ao2_ref(msg, +1);
+ ast_channel_unlock(chan);
+
+ ao2_lock(msg);
+
+ if ((val = ast_msg_get_var(msg, data))) {
+ ast_copy_string(buf, val, len);
+ }
+
+ ao2_unlock(msg);
+ ao2_ref(msg, -1);
+
+ return 0;
+}
+
+static int msg_data_func_write(struct ast_channel *chan, const char *function,
+ char *data, const char *value)
+{
+ struct ast_datastore *ds;
+ struct ast_msg *msg;
+
+ ast_channel_lock(chan);
+
+ if (!(ds = msg_datastore_find_or_create(chan))) {
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ msg = ds->data;
+ ao2_ref(msg, +1);
+ ast_channel_unlock(chan);
+
+ ao2_lock(msg);
+
+ ast_msg_set_var_outbound(msg, data, value);
+
+ ao2_unlock(msg);
+ ao2_ref(msg, -1);
+
+ return 0;
+}
+static int msg_tech_hash(const void *obj, const int flags)
+{
+ struct ast_msg_tech_holder *tech_holder = (struct ast_msg_tech_holder *) obj;
+ int res = 0;
+
+ ast_rwlock_rdlock(&tech_holder->tech_lock);
+ if (tech_holder->tech) {
+ res = ast_str_case_hash(tech_holder->tech->name);
+ }
+ ast_rwlock_unlock(&tech_holder->tech_lock);
+
+ return res;
+}
+
+static int msg_tech_cmp(void *obj, void *arg, int flags)
+{
+ struct ast_msg_tech_holder *tech_holder = obj;
+ const struct ast_msg_tech_holder *tech_holder2 = arg;
+ int res = 1;
+
+ ast_rwlock_rdlock(&tech_holder->tech_lock);
+ /*
+ * tech_holder2 is a temporary fake tech_holder.
+ */
+ if (tech_holder->tech) {
+ res = strcasecmp(tech_holder->tech->name, tech_holder2->tech->name) ? 0 : CMP_MATCH | CMP_STOP;
+ }
+ ast_rwlock_unlock(&tech_holder->tech_lock);
+
+ return res;
+}
+
+/*!
+ * \internal
+ * \brief MessageSend() application
+ */
+static int msg_send_exec(struct ast_channel *chan, const char *data)
+{
+ struct ast_datastore *ds;
+ struct ast_msg *msg;
+ char *tech_name;
+ struct ast_msg_tech_holder *tech_holder = NULL;
+ char *parse;
+ int res = -1;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(to);
+ AST_APP_ARG(from);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
+ pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
+ return 0;
+ }
+
+ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (ast_strlen_zero(args.to)) {
+ ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
+ pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
+ return 0;
+ }
+
+ ast_channel_lock(chan);
+
+ if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
+ ast_channel_unlock(chan);
+ ast_log(LOG_WARNING, "No message data found on channel to send.\n");
+ pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
+ return 0;
+ }
+
+ msg = ds->data;
+ ao2_ref(msg, +1);
+ ast_channel_unlock(chan);
+
+ tech_name = ast_strdupa(args.to);
+ tech_name = strsep(&tech_name, ":");
+
+ {
+ struct ast_msg_tech tmp_msg_tech = {
+ .name = tech_name,
+ };
+ struct ast_msg_tech_holder tmp_tech_holder = {
+ .tech = &tmp_msg_tech,
+ };
+
+ tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER);
+ }
+
+ if (!tech_holder) {
+ ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
+ pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
+ goto exit_cleanup;
+ }
+
+ /*
+ * The message lock is held here to safely allow the technology
+ * implementation to access the message fields without worrying
+ * that they could change.
+ */
+ ao2_lock(msg);
+ ast_rwlock_rdlock(&tech_holder->tech_lock);
+ if (tech_holder->tech) {
+ res = tech_holder->tech->msg_send(msg, S_OR(args.to, ""),
+ S_OR(args.from, ""));
+ }
+ ast_rwlock_unlock(&tech_holder->tech_lock);
+ ao2_unlock(msg);
+
+ pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
+
+exit_cleanup:
+ if (tech_holder) {
+ ao2_ref(tech_holder, -1);
+ tech_holder = NULL;
+ }
+
+ ao2_ref(msg, -1);
+
+ return 0;
+}
+
+static int action_messagesend(struct mansession *s, const struct message *m)
+{
+ const char *to = ast_strdupa(astman_get_header(m, "To"));
+ const char *from = astman_get_header(m, "From");
+ const char *body = astman_get_header(m, "Body");
+ const char *base64body = astman_get_header(m, "Base64Body");
+ char base64decoded[1301] = { 0, };
+ char *tech_name = NULL;
+ struct ast_variable *vars = NULL;
+ struct ast_variable *data = NULL;
+ struct ast_msg_tech_holder *tech_holder = NULL;
+ struct ast_msg *msg;
+ int res = -1;
+
+ if (ast_strlen_zero(to)) {
+ astman_send_error(s, m, "No 'To' address specified.");
+ return -1;
+ }
+
+ if (!ast_strlen_zero(base64body)) {
+ ast_base64decode((unsigned char *) base64decoded, base64body, sizeof(base64decoded) - 1);
+ body = base64decoded;
+ }
+
+ tech_name = ast_strdupa(to);
+ tech_name = strsep(&tech_name, ":");
+ {
+ struct ast_msg_tech tmp_msg_tech = {
+ .name = tech_name,
+ };
+ struct ast_msg_tech_holder tmp_tech_holder = {
+ .tech = &tmp_msg_tech,
+ };
+
+ tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER);
+ }
+
+ if (!tech_holder) {
+ astman_send_error(s, m, "Message technology not found.");
+ return -1;
+ }
+
+ if (!(msg = ast_msg_alloc())) {
+ ao2_ref(tech_holder, -1);
+ astman_send_error(s, m, "Internal failure\n");
+ return -1;
+ }
+
+ data = astman_get_variables(m);
+ for (vars = data; vars; vars = vars->next) {
+ ast_msg_set_var_outbound(msg, vars->name, vars->value);
+ }
+
+ ast_msg_set_body(msg, "%s", body);
+
+ ast_rwlock_rdlock(&tech_holder->tech_lock);
+ if (tech_holder->tech) {
+ res = tech_holder->tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
+ }
+ ast_rwlock_unlock(&tech_holder->tech_lock);
+
+ ast_variables_destroy(vars);
+ ao2_ref(tech_holder, -1);
+ ao2_ref(msg, -1);
+
+ if (res) {
+ astman_send_error(s, m, "Message failed to send.");
+ } else {
+ astman_send_ack(s, m, "Message successfully sent");
+ }
+ return res;
+}
+
+int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
+{
+ char *tech_name = NULL;
+ struct ast_msg_tech_holder *tech_holder = NULL;
+ int res = -1;
+
+ if (ast_strlen_zero(to)) {
+ ao2_ref(msg, -1);
+ return -1;
+ }
+
+ tech_name = ast_strdupa(to);
+ tech_name = strsep(&tech_name, ":");
+ {
+ struct ast_msg_tech tmp_msg_tech = {
+ .name = tech_name,
+ };
+ struct ast_msg_tech_holder tmp_tech_holder = {
+ .tech = &tmp_msg_tech,
+ };
+
+ tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER);
+ }
+
+ if (!tech_holder) {
+ ao2_ref(msg, -1);
+ return -1;
+ }
+
+ ast_rwlock_rdlock(&tech_holder->tech_lock);
+ if (tech_holder->tech) {
+ res = tech_holder->tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));
+ }
+ ast_rwlock_unlock(&tech_holder->tech_lock);
+
+ ao2_ref(tech_holder, -1);
+ ao2_ref(msg, -1);
+
+ return res;
+}
+
+int ast_msg_tech_register(const struct ast_msg_tech *tech)
+{
+ struct ast_msg_tech_holder tmp_tech_holder = {
+ .tech = tech,
+ };
+ struct ast_msg_tech_holder *tech_holder;
+
+ if ((tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER))) {
+ ao2_ref(tech_holder, -1);
+ ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
+ tech->name);
+ return -1;
+ }
+
+ if (!(tech_holder = ao2_alloc(sizeof(*tech_holder), NULL))) {
+ return -1;
+ }
+
+ ast_rwlock_init(&tech_holder->tech_lock);
+ tech_holder->tech = tech;
+
+ ao2_link(msg_techs, tech_holder);
+
+ ao2_ref(tech_holder, -1);
+ tech_holder = NULL;
+
+ ast_verb(3, "Message technology handler '%s' registered.\n", tech->name);
+
+ return 0;
+}
+
+int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
+{
+ struct ast_msg_tech_holder tmp_tech_holder = {
+ .tech = tech,
+ };
+ struct ast_msg_tech_holder *tech_holder;
+
+ tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER | OBJ_UNLINK);
+
+ if (!tech_holder) {
+ ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
+ return -1;
+ }
+
+ ast_rwlock_wrlock(&tech_holder->tech_lock);
+ tech_holder->tech = NULL;
+ ast_rwlock_unlock(&tech_holder->tech_lock);
+
+ ao2_ref(tech_holder, -1);
+ tech_holder = NULL;
+
+ ast_verb(3, "Message technology handler '%s' unregistered.\n", tech->name);
+
+ return 0;
+}
+
+/*
+ * \internal
+ * \brief Initialize stuff during Asterisk startup.
+ *
+ * Cleanup isn't a big deal in this function. If we return non-zero,
+ * Asterisk is going to exit.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_msg_init(void)
+{
+ int res;
+
+ msg_q_tp = ast_taskprocessor_get("ast_msg_queue", TPS_REF_DEFAULT);
+ if (!msg_q_tp) {
+ return -1;
+ }
+
+ msg_techs = ao2_container_alloc(17, msg_tech_hash, msg_tech_cmp);
+ if (!msg_techs) {
+ return -1;
+ }
+
+ res = __ast_custom_function_register(&msg_function, NULL);
+ res |= __ast_custom_function_register(&msg_data_function, NULL);
+ res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
+ res |= ast_manager_register_xml("MessageSend", EVENT_FLAG_MESSAGE, action_messagesend);
+
+ return res;
+}
#include "asterisk/musiconhold.h"
#include "asterisk/app.h"
#include "asterisk/devicestate.h"
+#include "asterisk/presencestate.h"
#include "asterisk/event.h"
#include "asterisk/hashtab.h"
#include "asterisk/module.h"
struct ast_context;
struct ast_app;
-static struct ast_taskprocessor *device_state_tps;
+static struct ast_taskprocessor *extension_state_tps;
AST_THREADSTORAGE(switch_data);
AST_THREADSTORAGE(extensionstate_buf);
* Will never be NULL while the hint is in the hints container.
*/
struct ast_exten *exten;
- struct ao2_container *callbacks; /*!< Callback container for this extension */
- int laststate; /*!< Last known state */
+ struct ao2_container *callbacks; /*!< Device state callback container for this extension */
+
+ /*! Dev state variables */
+ int laststate; /*!< Last known device state */
+
+ /*! Presence state variables */
+ int last_presence_state; /*!< Last known presence state */
+ char *last_presence_subtype; /*!< Last known presence subtype string */
+ char *last_presence_message; /*!< Last known presence message string */
+
char context_name[AST_MAX_CONTEXT];/*!< Context of destroyed hint extension. */
char exten_name[AST_MAX_EXTENSION];/*!< Extension of destroyed hint extension. */
};
{ AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
};
+struct presencechange {
+ char *provider;
+ int state;
+ char *subtype;
+ char *message;
+};
+
struct statechange {
AST_LIST_ENTRY(statechange) entry;
char dev[0];
/*! \brief Subscription for device state change events */
static struct ast_event_sub *device_state_sub;
+/*! \brief Subscription for presence state change events */
+static struct ast_event_sub *presence_state_sub;
AST_MUTEX_DEFINE_STATIC(maxcalllock);
static int countcalls;
return AST_EXTENSION_NOT_INUSE;
}
+/*!
+ * \internal
+ * \brief Parse out the presence portion of the hint string
+ */
+static char *parse_hint_presence(struct ast_str *hint_args)
+{
+ char *copy = ast_strdupa(ast_str_buffer(hint_args));
+ char *tmp = "";
+
+ if ((tmp = strrchr(copy, ','))) {
+ *tmp = '\0';
+ tmp++;
+ } else {
+ return NULL;
+ }
+ ast_str_set(&hint_args, 0, "%s", tmp);
+ return ast_str_buffer(hint_args);
+}
+
+/*!
+ * \internal
+ * \brief Parse out the device portion of the hint string
+ */
+static char *parse_hint_device(struct ast_str *hint_args)
+{
+ char *copy = ast_strdupa(ast_str_buffer(hint_args));
+ char *tmp;
+
+ if ((tmp = strrchr(copy, ','))) {
+ *tmp = '\0';
+ }
+
+ ast_str_set(&hint_args, 0, "%s", copy);
+ return ast_str_buffer(hint_args);
+}
static int ast_extension_state3(struct ast_str *hint_app)
{
struct ast_devstate_aggregate agg;
/* One or more devices separated with a & character */
- rest = ast_str_buffer(hint_app);
+ rest = parse_hint_device(hint_app);
ast_devstate_aggregate_init(&agg);
while ((cur = strsep(&rest, "&"))) {
return ast_extension_state2(e); /* Check all devices in the hint */
}
+static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
+{
+ struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
+ char *presence_provider;
+ const char *app;
+
+ if (!e || !hint_app) {
+ return -1;
+ }
+
+ app = ast_get_extension_app(e);
+ if (ast_strlen_zero(app)) {
+ return -1;
+ }
+ ast_str_set(&hint_app, 0, "%s", app);
+ presence_provider = parse_hint_presence(hint_app);
+
+ if (ast_strlen_zero(presence_provider)) {
+ /* No presence string in the hint */
+ return 0;
+ }
+
+ return ast_presence_state(presence_provider, subtype, message);
+}
+int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
+{
+ struct ast_exten *e;
+
+ if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */
+ return -1; /* No hint, return -1 */
+ }
+
+ if (e->exten[0] == '_') {
+ /* Create this hint on-the-fly */
+ ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
+ e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
+ e->registrar);
+ if (!(e = ast_hint_extension(c, context, exten))) {
+ /* Improbable, but not impossible */
+ return -1;
+ }
+ }
+
+ return extension_presence_state_helper(e, subtype, message);
+}
+
+static int execute_state_callback(ast_state_cb_type cb,
+ const char *context,
+ const char *exten,
+ void *data,
+ enum ast_state_cb_update_reason reason,
+ struct ast_hint *hint)
+{
+ int res = 0;
+ struct ast_state_cb_info info = { 0, };
+
+ info.reason = reason;
+
+ /* Copy over current hint data */
+ if (hint) {
+ ao2_lock(hint);
+ info.exten_state = hint->laststate;
+ info.presence_state = hint->last_presence_state;
+ if (!(ast_strlen_zero(hint->last_presence_subtype))) {
+ info.presence_subtype = ast_strdupa(hint->last_presence_subtype);
+ } else {
+ info.presence_subtype = "";
+ }
+ if (!(ast_strlen_zero(hint->last_presence_message))) {
+ info.presence_message = ast_strdupa(hint->last_presence_message);
+ } else {
+ info.presence_message = "";
+ }
+ ao2_unlock(hint);
+ } else {
+ info.exten_state = AST_EXTENSION_REMOVED;
+ }
+
+ /* NOTE: The casts will not be needed for v10 and later */
+ res = cb((char *) context, (char *) exten, &info, data);
+
+ return res;
+}
+
+static int handle_presencechange(void *datap)
+{
+ struct ast_hint *hint;
+ struct ast_str *hint_app = NULL;
+ struct presencechange *pc = datap;
+ struct ao2_iterator i;
+ struct ao2_iterator cb_iter;
+ char context_name[AST_MAX_CONTEXT];
+ char exten_name[AST_MAX_EXTENSION];
+ int res = -1;
+
+ hint_app = ast_str_create(1024);
+ if (!hint_app) {
+ goto presencechange_cleanup;
+ }
+
+ ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
+ i = ao2_iterator_init(hints, 0);
+ for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
+ struct ast_state_cb *state_cb;
+ const char *app;
+ char *parse;
+
+ ao2_lock(hint);
+
+ if (!hint->exten) {
+ /* The extension has already been destroyed */
+ ao2_unlock(hint);
+ continue;
+ }
+
+ /* Does this hint monitor the device that changed state? */
+ app = ast_get_extension_app(hint->exten);
+ if (ast_strlen_zero(app)) {
+ /* The hint does not monitor presence at all. */
+ ao2_unlock(hint);
+ continue;
+ }
+ ast_str_set(&hint_app, 0, "%s", app);
+ parse = parse_hint_presence(hint_app);
+ if (ast_strlen_zero(parse)) {
+ ao2_unlock(hint);
+ continue;
+ }
+ if (strcasecmp(parse, pc->provider)) {
+ /* The hint does not monitor the presence provider. */
+ ao2_unlock(hint);
+ continue;
+ }
+
+ /*
+ * Save off strings in case the hint extension gets destroyed
+ * while we are notifying the watchers.
+ */
+ ast_copy_string(context_name,
+ ast_get_context_name(ast_get_extension_context(hint->exten)),
+ sizeof(context_name));
+ ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
+ sizeof(exten_name));
+ ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
+
+ /* Check to see if update is necessary */
+ if ((hint->last_presence_state == pc->state) &&
+ ((hint->last_presence_subtype && pc->subtype && !strcmp(hint->last_presence_subtype, pc->subtype)) || (!hint->last_presence_subtype && !pc->subtype)) &&
+ ((hint->last_presence_message && pc->message && !strcmp(hint->last_presence_message, pc->message)) || (!hint->last_presence_message && !pc->message))) {
+
+ /* this update is the same as the last, do nothing */
+ ao2_unlock(hint);
+ continue;
+ }
+
+ /* update new values */
+ ast_free(hint->last_presence_subtype);
+ ast_free(hint->last_presence_message);
+ hint->last_presence_state = pc->state;
+ hint->last_presence_subtype = pc->subtype ? ast_strdup(pc->subtype) : NULL;
+ hint->last_presence_message = pc->message ? ast_strdup(pc->message) : NULL;
+
+ ao2_unlock(hint);
+
+ /* For general callbacks */
+ cb_iter = ao2_iterator_init(statecbs, 0);
+ for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+ execute_state_callback(state_cb->change_cb,
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_PRESENCE,
+ hint);
+ }
+ ao2_iterator_destroy(&cb_iter);
+
+ /* For extension callbacks */
+ cb_iter = ao2_iterator_init(hint->callbacks, 0);
+ for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+ execute_state_callback(state_cb->change_cb,
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_PRESENCE,
+ hint);
+ }
+ ao2_iterator_destroy(&cb_iter);
+ }
+ ao2_iterator_destroy(&i);
+ ast_mutex_unlock(&context_merge_lock);
+
+ res = 0;
+
+presencechange_cleanup:
+ ast_free(hint_app);
+ ao2_ref(pc, -1);
+
+ return res;
+}
+
static int handle_statechange(void *datap)
{
struct ast_hint *hint;
/* Does this hint monitor the device that changed state? */
ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
- parse = ast_str_buffer(hint_app);
+ parse = parse_hint_device(hint_app);
+
while ((cur = strsep(&parse, "&"))) {
if (!strcasecmp(cur, sc->dev)) {
/* The hint monitors the device. */
/* For general callbacks */
cb_iter = ao2_iterator_init(statecbs, 0);
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
- state_cb->change_cb(context_name, exten_name, state, state_cb->data);
+ execute_state_callback(state_cb->change_cb,
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_DEVICE,
+ hint);
}
ao2_iterator_destroy(&cb_iter);
/* For extension callbacks */
cb_iter = ao2_iterator_init(hint->callbacks, 0);
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
- state_cb->change_cb(context_name, exten_name, state, state_cb->data);
+ execute_state_callback(state_cb->change_cb,
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_DEVICE,
+ hint);
}
ao2_iterator_destroy(&cb_iter);
}
return ret;
}
-
static int hint_id_cmp(void *obj, void *arg, int flags)
{
const struct ast_state_cb *cb = obj;
context_name = hint->context_name;
exten_name = hint->exten_name;
}
+ hint->laststate = AST_EXTENSION_DEACTIVATED;
while ((state_cb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
/* Notify with -1 and remove all callbacks */
- /* NOTE: The casts will not be needed for v1.10 and later */
- state_cb->change_cb((char *) context_name, (char *) exten_name,
- AST_EXTENSION_DEACTIVATED, state_cb->data);
+ execute_state_callback(state_cb->change_cb,
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_DEVICE,
+ hint);
ao2_ref(state_cb, -1);
}
ao2_ref(hint->callbacks, -1);
}
+ ast_free(hint->last_presence_subtype);
+ ast_free(hint->last_presence_message);
}
/*! \brief Remove hint from extension */
{
struct ast_hint *hint_new;
struct ast_hint *hint_found;
+ char *message = NULL;
+ char *subtype = NULL;
+ int presence_state;
if (!e) {
return -1;
}
hint_new->exten = e;
hint_new->laststate = ast_extension_state2(e);
+ if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
+ hint_new->last_presence_state = presence_state;
+ hint_new->last_presence_subtype = subtype;
+ hint_new->last_presence_message = message;
+ message = subtype = NULL;
+ }
/* Prevent multiple add hints from adding the same hint at the same time. */
ao2_lock(hints);
char *exten;
AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks;
int laststate;
+ int last_presence_state;
+ char *last_presence_subtype;
+ char *last_presence_message;
+
AST_LIST_ENTRY(store_hint) list;
char data[1];
};
strcpy(saved_hint->data, hint->exten->parent->name);
saved_hint->exten = saved_hint->data + strlen(saved_hint->context) + 1;
strcpy(saved_hint->exten, hint->exten->exten);
+ if (hint->last_presence_subtype) {
+ saved_hint->last_presence_subtype = ast_strdup(hint->last_presence_subtype);
+ }
+ if (hint->last_presence_message) {
+ saved_hint->last_presence_message = ast_strdup(hint->last_presence_message);
+ }
+ saved_hint->last_presence_state = hint->last_presence_state;
ao2_unlock(hint);
AST_LIST_INSERT_HEAD(&hints_stored, saved_hint, list);
}
ao2_ref(thiscb, -1);
}
hint->laststate = saved_hint->laststate;
+ hint->last_presence_state = saved_hint->last_presence_state;
+ hint->last_presence_subtype = saved_hint->last_presence_subtype;
+ hint->last_presence_message = saved_hint->last_presence_message;
ao2_unlock(hint);
ao2_ref(hint, -1);
+ /*
+ * The free of saved_hint->last_presence_subtype and
+ * saved_hint->last_presence_message is not necessary here.
+ */
ast_free(saved_hint);
}
}
while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_removed, list))) {
/* this hint has been removed, notify the watchers */
while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
- thiscb->change_cb(saved_hint->context, saved_hint->exten,
- AST_EXTENSION_REMOVED, thiscb->data);
+ execute_state_callback(thiscb->change_cb,
+ saved_hint->context,
+ saved_hint->exten,
+ thiscb->data,
+ AST_HINT_UPDATE_DEVICE,
+ NULL);
/* Ref that we added when putting into saved_hint->callbacks */
ao2_ref(thiscb, -1);
}
+ ast_free(saved_hint->last_presence_subtype);
+ ast_free(saved_hint->last_presence_message);
ast_free(saved_hint);
}
return res;
}
+static void presencechange_destroy(void *data)
+{
+ struct presencechange *pc = data;
+ ast_free(pc->provider);
+ ast_free(pc->subtype);
+ ast_free(pc->message);
+}
+
+static void presence_state_cb(const struct ast_event *event, void *unused)
+{
+ struct presencechange *pc;
+ const char *tmp;
+
+ if (!(pc = ao2_alloc(sizeof(*pc), presencechange_destroy))) {
+ return;
+ }
+
+ tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_PROVIDER);
+ if (ast_strlen_zero(tmp)) {
+ ast_log(LOG_ERROR, "Received invalid event that had no presence provider IE\n");
+ ao2_ref(pc, -1);
+ return;
+ }
+ pc->provider = ast_strdup(tmp);
+
+ pc->state = ast_event_get_ie_uint(event, AST_EVENT_IE_PRESENCE_STATE);
+ if (pc->state < 0) {
+ ao2_ref(pc, -1);
+ return;
+ }
+
+ if ((tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_SUBTYPE))) {
+ pc->subtype = ast_strdup(tmp);
+ }
+
+ if ((tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_MESSAGE))) {
+ pc->message = ast_strdup(tmp);
+ }
+
+ /* The task processor thread is taking our reference to the presencechange object. */
+ if (ast_taskprocessor_push(extension_state_tps, handle_presencechange, pc) < 0) {
+ ao2_ref(pc, -1);
+ }
+}
+
static void device_state_cb(const struct ast_event *event, void *unused)
{
const char *device;
if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
return;
strcpy(sc->dev, device);
- if (ast_taskprocessor_push(device_state_tps, handle_statechange, sc) < 0) {
+ if (ast_taskprocessor_push(extension_state_tps, handle_statechange, sc) < 0) {
ast_free(sc);
}
}
ast_data_add_str(data_hint, "context", ast_get_context_name(ast_get_extension_context(hint->exten)));
ast_data_add_str(data_hint, "application", ast_get_extension_app(hint->exten));
ast_data_add_str(data_hint, "state", ast_extension_state2str(hint->laststate));
+ ast_data_add_str(data_hint, "presence_state", ast_presence_state2str(hint->last_presence_state));
+ ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_subtype, ""));
+ ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_message, ""));
ast_data_add_int(data_hint, "watchers", watchers);
if (!ast_data_search_match(search, data_hint)) {
/* Initialize the PBX */
ast_verb(1, "Asterisk PBX Core Initializing\n");
- if (!(device_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
+ if (!(extension_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
}
return -1;
}
+ if (!(presence_state_sub = ast_event_subscribe(AST_EVENT_PRESENCE_STATE, presence_state_cb, "pbx Presence State Change", NULL,
+ AST_EVENT_IE_END))) {
+ return -1;
+ }
+
return 0;
}
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Presence state management
+ */
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/_private.h"
+#include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/presencestate.h"
+#include "asterisk/pbx.h"
+#include "asterisk/app.h"
+#include "asterisk/event.h"
+
+/*! \brief Device state strings for printing */
+static const struct {
+ const char *string;
+ enum ast_presence_state state;
+
+} state2string[] = {
+ { "not_set", AST_PRESENCE_NOT_SET},
+ { "unavailable", AST_PRESENCE_UNAVAILABLE },
+ { "available", AST_PRESENCE_AVAILABLE},
+ { "away", AST_PRESENCE_AWAY},
+ { "xa", AST_PRESENCE_XA},
+ { "chat", AST_PRESENCE_CHAT},
+ { "dnd", AST_PRESENCE_DND},
+};
+
+/*! \brief Flag for the queue */
+static ast_cond_t change_pending;
+
+struct state_change {
+ AST_LIST_ENTRY(state_change) list;
+ char provider[1];
+};
+
+/*! \brief A presence state provider */
+struct presence_state_provider {
+ char label[40];
+ ast_presence_state_prov_cb_type callback;
+ AST_RWLIST_ENTRY(presence_state_provider) list;
+};
+
+/*! \brief A list of providers */
+static AST_RWLIST_HEAD_STATIC(presence_state_providers, presence_state_provider);
+
+/*! \brief The state change queue. State changes are queued
+ for processing by a separate thread */
+static AST_LIST_HEAD_STATIC(state_changes, state_change);
+
+/*! \brief The presence state change notification thread */
+static pthread_t change_thread = AST_PTHREADT_NULL;
+
+const char *ast_presence_state2str(enum ast_presence_state state)
+{
+ int i;
+ for (i = 0; i < ARRAY_LEN(state2string); i++) {
+ if (state == state2string[i].state) {
+ return state2string[i].string;
+ }
+ }
+ return "";
+}
+
+enum ast_presence_state ast_presence_state_val(const char *val)
+{
+ int i;
+ for (i = 0; i < ARRAY_LEN(state2string); i++) {
+ if (!strcasecmp(val, state2string[i].string)) {
+ return state2string[i].state;
+ }
+ }
+ return -1;
+}
+
+static enum ast_presence_state presence_state_cached(const char *presence_provider, char **subtype, char **message)
+{
+ enum ast_presence_state res = -1;
+ struct ast_event *event;
+ const char *_subtype;
+ const char *_message;
+
+ event = ast_event_get_cached(AST_EVENT_PRESENCE_STATE,
+ AST_EVENT_IE_PRESENCE_PROVIDER, AST_EVENT_IE_PLTYPE_STR, presence_provider,
+ AST_EVENT_IE_END);
+
+ if (!event) {
+ return res;
+ }
+
+ res = ast_event_get_ie_uint(event, AST_EVENT_IE_PRESENCE_STATE);
+ _subtype = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_SUBTYPE);
+ _message = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_MESSAGE);
+
+ *subtype = !ast_strlen_zero(_subtype) ? ast_strdup(_subtype) : NULL;
+ *message = !ast_strlen_zero(_message) ? ast_strdup(_message) : NULL;
+ ast_event_destroy(event);
+
+ return res;
+}
+
+static enum ast_presence_state ast_presence_state_helper(const char *presence_provider, char **subtype, char **message, int check_cache)
+{
+ struct presence_state_provider *provider;
+ char *address;
+ char *label = ast_strdupa(presence_provider);
+ int res = -1;
+
+ if (check_cache) {
+ res = presence_state_cached(presence_provider, subtype, message);
+ if (res > 0) {
+ return res;
+ }
+ }
+
+ if ((address = strchr(label, ':'))) {
+ *address = '\0';
+ address++;
+ } else {
+ ast_log(LOG_WARNING, "No label found for presence state provider: %s\n", presence_provider);
+ return res;
+ }
+
+ AST_RWLIST_RDLOCK(&presence_state_providers);
+ AST_RWLIST_TRAVERSE(&presence_state_providers, provider, list) {
+ ast_debug(5, "Checking provider %s with %s\n", provider->label, label);
+
+ if (!strcasecmp(provider->label, label)) {
+ res = provider->callback(address, subtype, message);
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&presence_state_providers);
+
+
+ return res;
+}
+
+enum ast_presence_state ast_presence_state(const char *presence_provider, char **subtype, char **message)
+{
+ return ast_presence_state_helper(presence_provider, subtype, message, 1);
+}
+
+int ast_presence_state_prov_add(const char *label, ast_presence_state_prov_cb_type callback)
+{
+ struct presence_state_provider *provider;
+
+ if (!callback || !(provider = ast_calloc(1, sizeof(*provider)))) {
+ return -1;
+ }
+
+ provider->callback = callback;
+ ast_copy_string(provider->label, label, sizeof(provider->label));
+
+ AST_RWLIST_WRLOCK(&presence_state_providers);
+ AST_RWLIST_INSERT_HEAD(&presence_state_providers, provider, list);
+ AST_RWLIST_UNLOCK(&presence_state_providers);
+
+ return 0;
+}
+int ast_presence_state_prov_del(const char *label)
+{
+ struct presence_state_provider *provider;
+ int res = -1;
+
+ AST_RWLIST_WRLOCK(&presence_state_providers);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&presence_state_providers, provider, list) {
+ if (!strcasecmp(provider->label, label)) {
+ AST_RWLIST_REMOVE_CURRENT(list);
+ ast_free(provider);
+ res = 0;
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&presence_state_providers);
+
+ return res;
+}
+
+static void do_presence_state_change(const char *provider)
+{
+ struct ast_event *event;
+ enum ast_event_type event_type;
+ char *subtype = NULL;
+ char *message = NULL;
+ int state;
+
+ state = ast_presence_state_helper(provider, &subtype, &message, 0);
+
+ if (state < 0) {
+ return;
+ }
+
+ event_type = AST_EVENT_PRESENCE_STATE;
+
+ if (!(event = ast_event_new(event_type,
+ AST_EVENT_IE_PRESENCE_PROVIDER, AST_EVENT_IE_PLTYPE_STR, provider,
+ AST_EVENT_IE_PRESENCE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+ AST_EVENT_IE_PRESENCE_SUBTYPE, AST_EVENT_IE_PLTYPE_STR, S_OR(subtype, ""),
+ AST_EVENT_IE_PRESENCE_MESSAGE, AST_EVENT_IE_PLTYPE_STR, S_OR(message, ""),
+ AST_EVENT_IE_END))) {
+ return;
+ }
+
+ ast_event_queue_and_cache(event);
+ ast_free(subtype);
+ ast_free(message);
+}
+
+int ast_presence_state_changed(const char *presence_provider)
+{
+ struct state_change *change;
+
+ if ((change_thread == AST_PTHREADT_NULL) ||
+ !(change = ast_calloc(1, sizeof(*change) + strlen(presence_provider)))) {
+ do_presence_state_change(presence_provider);
+ } else {
+ strcpy(change->provider, presence_provider);
+ AST_LIST_LOCK(&state_changes);
+ AST_LIST_INSERT_TAIL(&state_changes, change, list);
+ ast_cond_signal(&change_pending);
+ AST_LIST_UNLOCK(&state_changes);
+ }
+ return 0;
+}
+
+/*! \brief Go through the presence state change queue and update changes in the presence state thread */
+static void *do_presence_changes(void *data)
+{
+ struct state_change *next, *current;
+
+ for (;;) {
+ /* This basically pops off any state change entries, resets the list back to NULL, unlocks, and processes each state change */
+ AST_LIST_LOCK(&state_changes);
+ if (AST_LIST_EMPTY(&state_changes))
+ ast_cond_wait(&change_pending, &state_changes.lock);
+ next = AST_LIST_FIRST(&state_changes);
+ AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
+ AST_LIST_UNLOCK(&state_changes);
+
+ /* Process each state change */
+ while ((current = next)) {
+ next = AST_LIST_NEXT(current, list);
+ do_presence_state_change(current->provider);
+ ast_free(current);
+ }
+ }
+
+ return NULL;
+}
+
+int ast_presence_state_engine_init(void)
+{
+ ast_cond_init(&change_pending, NULL);
+ if (ast_pthread_create_background(&change_thread, NULL, do_presence_changes, NULL) < 0) {
+ ast_log(LOG_ERROR, "Unable to start presence state change thread.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
/*** MODULEINFO
<depend>res_ael_share</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
<depend>zlib</depend>
<use>crypto</use>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>lua</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>ais</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>ldap</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>pgsql</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>sqlite</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
<depend>spandsp</depend>
<depend>res_fax</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
<depend>iksemel</depend>
<use>openssl</use>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
#include "asterisk/manager.h"
#include "asterisk/event.h"
#include "asterisk/devicestate.h"
+#include "asterisk/message.h"
/*** DOCUMENTATION
<application name="JabberSend" language="en_US">
static int aji_register_transport2(void *data, ikspak *pak);
*/
+static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *from);
+
+static const struct ast_msg_tech msg_tech = {
+ .name = "xmpp",
+ .msg_send = msg_send_cb,
+};
+
static struct ast_cli_entry aji_cli[] = {
AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug"),
AST_CLI_DEFINE(aji_do_reload, "Reload Jabber configuration"),
return 0;
}
+static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *from)
+{
+ struct aji_client *client;
+ char *sender;
+ char *dest;
+ int res;
+
+ sender = ast_strdupa(from);
+ strsep(&sender, ":");
+ dest = ast_strdupa(to);
+ strsep(&dest, ":");
+
+ if (ast_strlen_zero(sender)) {
+ ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for xmpp\n", from);
+ return -1;
+ }
+
+ if (!(client = ast_aji_get_client(sender))) {
+ ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
+ return -1;
+ }
+
+
+ ast_debug(1, "Sending message to '%s' from '%s'\n", dest, client->name);
+
+ res = ast_aji_send_chat(client, dest, ast_msg_get_body(msg));
+ if (res != IKS_OK) {
+ ast_log(LOG_WARNING, "Failed to send xmpp message (%d).\n", res);
+ }
+
+ /*
+ * XXX Reference leak here. See note with ast_aji_get_client() about the problems
+ * with that function.
+ */
+
+ return res == IKS_OK ? 0 : -1;
+}
+
/*!
* \brief Application to send a message to a groupchat.
* \param chan ast_channel
{
struct aji_message *insert;
int deleted = 0;
+ struct ast_msg *msg;
ast_debug(3, "client %s received a message\n", client->name);
ast_debug(3, "message comes from %s\n", insert->from);
}
+ if (client->send_to_dialplan) {
+ if ((msg = ast_msg_alloc())) {
+ int res;
+
+ res = ast_msg_set_to(msg, "xmpp:%s", client->user);
+ res |= ast_msg_set_from(msg, "xmpp:%s", insert->from);
+ res |= ast_msg_set_body(msg, "%s", insert->message);
+ res |= ast_msg_set_context(msg, "%s", client->context);
+
+ if (res) {
+ ast_msg_destroy(msg);
+ } else {
+ ast_msg_queue(msg);
+ }
+
+ msg = NULL;
+ }
+ }
+
/* remove old messages received from this JID
* and insert received message */
deleted = delete_old_messages(client, pak->from->partial);
ASTOBJ_CONTAINER_MARKALL(&client->buddies);
ast_copy_string(client->name, label, sizeof(client->name));
ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
+ ast_copy_string(client->context, "default", sizeof(client->context));
/* Set default values for the client object */
client->debug = debug;
ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
client->priority = 0;
client->status = IKS_SHOW_AVAILABLE;
+ client->send_to_dialplan = 0;
if (flag) {
client->authorized = 0;
} else {
ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
}
+ } else if (!strcasecmp(var->name, "context")) {
+ ast_copy_string(client->context, var->value, sizeof(client->context));
+ } else if (!strcasecmp(var->name, "sendtodialplan")) {
+ client->send_to_dialplan = ast_true(var->value) ? 1 : 0;
}
/* no transport support in this version */
/* else if (!strcasecmp(var->name, "transport"))
* (without the resource string)
* \param name label or JID
* \return aji_client.
+ *
+ * XXX \bug This function leads to reference leaks all over the place.
+ * ASTOBJ_CONTAINER_FIND() returns a reference, but if the
+ * client is found via the traversal, no reference is returned.
+ * None of the calling code releases references. This code needs
+ * to be changed to always return a reference, and all of the users
+ * need to be fixed to release them.
*/
struct aji_client *ast_aji_get_client(const char *name)
{
*/
static int unload_module(void)
{
-
+ ast_msg_tech_unregister(&msg_tech);
ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
ast_unregister_application(app_ajisend);
ast_unregister_application(app_ajisendgroup);
ast_cli_register_multiple(aji_cli, ARRAY_LEN(aji_cli));
ast_custom_function_register(&jabberstatus_function);
ast_custom_function_register(&jabberreceive_function);
+ ast_msg_tech_register(&msg_tech);
ast_mutex_init(&messagelock);
ast_cond_init(&message_received_condition, NULL);
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<depend>netsnmp</depend>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
<depend>kqueue</depend>
<conflict>launchd</conflict>
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
/*** MODULEINFO
<support_level>extended</support_level>
+ <defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
+#include "asterisk/paths.h"
+
+#define CONFIG_FILE "test_config.conf"
+
+/*
+ * This builds the folowing config:
+ * [Capitals]
+ * Germany = Berlin
+ * China = Beijing
+ * Canada = Ottawa
+ *
+ * [Protagonists]
+ * 1984 = Winston Smith
+ * Green Eggs And Ham = Sam I Am
+ * The Kalevala = Vainamoinen
+ *
+ * This config is used for all tests below.
+ */
+const char cat1[] = "Capitals";
+const char cat1varname1[] = "Germany";
+const char cat1varvalue1[] = "Berlin";
+const char cat1varname2[] = "China";
+const char cat1varvalue2[] = "Beijing";
+const char cat1varname3[] = "Canada";
+const char cat1varvalue3[] = "Ottawa";
+
+const char cat2[] = "Protagonists";
+const char cat2varname1[] = "1984";
+const char cat2varvalue1[] = "Winston Smith";
+const char cat2varname2[] = "Green Eggs And Ham";
+const char cat2varvalue2[] = "Sam I Am";
+const char cat2varname3[] = "The Kalevala";
+const char cat2varvalue3[] = "Vainamoinen";
+
+struct pair {
+ const char *name;
+ const char *val;
+};
+
+struct association {
+ const char *category;
+ struct pair vars[3];
+} categories [] = {
+ { cat1,
+ {
+ { cat1varname1, cat1varvalue1 },
+ { cat1varname2, cat1varvalue2 },
+ { cat1varname3, cat1varvalue3 },
+ }
+ },
+ { cat2,
+ {
+ { cat2varname1, cat2varvalue1 },
+ { cat2varname2, cat2varvalue2 },
+ { cat2varname3, cat2varvalue3 },
+ }
+ },
+};
+
+/*!
+ * \brief Build ast_config struct from above definitions
+ *
+ * \retval NULL Failed to build the config
+ * \retval non-NULL An ast_config struct populated with data
+ */
+static struct ast_config *build_cfg(void)
+{
+ struct ast_config *cfg;
+ struct association *cat_iter;
+ struct pair *var_iter;
+ size_t i;
+ size_t j;
+
+ cfg = ast_config_new();
+ if (!cfg) {
+ goto fail;
+ }
+
+ for (i = 0; i < ARRAY_LEN(categories); ++i) {
+ struct ast_category *cat;
+ cat_iter = &categories[i];
+
+ cat = ast_category_new(cat_iter->category, "", 999999);
+ if (!cat) {
+ goto fail;
+ }
+ ast_category_append(cfg, cat);
+
+ for (j = 0; j < ARRAY_LEN(cat_iter->vars); ++j) {
+ struct ast_variable *var;
+ var_iter = &cat_iter->vars[j];
+
+ var = ast_variable_new(var_iter->name, var_iter->val, "");
+ if (!var) {
+ goto fail;
+ }
+ ast_variable_append(cat, var);
+ }
+ }
+
+ return cfg;
+
+fail:
+ ast_config_destroy(cfg);
+ return NULL;
+}
+
+/*!
+ * \brief Tests that the contents of an ast_config is what is expected
+ *
+ * \param cfg Config to test
+ * \retval -1 Failed to pass a test
+ * \retval 0 Config passes checks
+ */
+static int test_config_validity(struct ast_config *cfg)
+{
+ int i;
+ const char *cat_iter = NULL;
+ /* Okay, let's see if the correct content is there */
+ for (i = 0; i < ARRAY_LEN(categories); ++i) {
+ struct ast_variable *var = NULL;
+ size_t j;
+ cat_iter = ast_category_browse(cfg, cat_iter);
+ if (strcmp(cat_iter, categories[i].category)) {
+ ast_log(LOG_ERROR, "Category name mismatch, %s does not match %s\n", cat_iter, categories[i].category);
+ return -1;
+ }
+ for (j = 0; j < ARRAY_LEN(categories[i].vars); ++j) {
+ var = var ? var->next : ast_variable_browse(cfg, cat_iter);
+ if (strcmp(var->name, categories[i].vars[j].name)) {
+ ast_log(LOG_ERROR, "Variable name mismatch, %s does not match %s\n", var->name, categories[i].vars[j].name);
+ return -1;
+ }
+ if (strcmp(var->value, categories[i].vars[j].val)) {
+ ast_log(LOG_ERROR, "Variable value mismatch, %s does not match %s\n", var->value, categories[i].vars[j].val);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+AST_TEST_DEFINE(copy_config)
+{
+ enum ast_test_result_state res = AST_TEST_FAIL;
+ struct ast_config *cfg = NULL;
+ struct ast_config *copy = NULL;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "copy_config";
+ info->category = "/main/config/";
+ info->summary = "Test copying configuration";
+ info->description =
+ "Ensure that variables and categories are copied correctly";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ cfg = build_cfg();
+ if (!cfg) {
+ goto out;
+ }
+
+ copy = ast_config_copy(cfg);
+ if (!copy) {
+ goto out;
+ }
+
+ if (test_config_validity(copy) != 0) {
+ goto out;
+ }
+
+ res = AST_TEST_PASS;
+
+out:
+ ast_config_destroy(cfg);
+ ast_config_destroy(copy);
+ return res;
+}
+
+/*!
+ * \brief Write the config file to disk
+ *
+ * This is necessary for testing config hooks since
+ * they are only triggered when a config is read from
+ * its intended storage medium
+ */
+static int write_config_file(void)
+{
+ int i;
+ FILE *config_file;
+ char filename[PATH_MAX];
+
+ snprintf(filename, sizeof(filename), "%s/%s",
+ ast_config_AST_CONFIG_DIR, CONFIG_FILE);
+ config_file = fopen(filename, "w");
+
+ if (!config_file) {
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_LEN(categories); ++i) {
+ int j;
+ fprintf(config_file, "[%s]\n", categories[i].category);
+ for (j = 0; j < ARRAY_LEN(categories[i].vars); ++j) {
+ fprintf(config_file, "%s = %s\n",
+ categories[i].vars[j].name,
+ categories[i].vars[j].val);
+ }
+ }
+
+ fclose(config_file);
+ return 0;
+}
+
+/*!
+ * \brief Delete config file created by write_config_file
+ */
+static void delete_config_file(void)
+{
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s",
+ ast_config_AST_CONFIG_DIR, CONFIG_FILE);
+ unlink(filename);
+}
+
+/*
+ * Boolean to indicate if the config hook has run
+ */
+static int hook_run;
+
+/*
+ * Boolean to indicate if, when the hook runs, the
+ * data passed to it is what is expected
+ */
+static int hook_config_sane;
+
+static int hook_cb(struct ast_config *cfg)
+{
+ hook_run = 1;
+ if (test_config_validity(cfg) == 0) {
+ hook_config_sane = 1;
+ }
+ ast_config_destroy(cfg);
+ return 0;
+}
+
+AST_TEST_DEFINE(config_hook)
+{
+ enum ast_test_result_state res = AST_TEST_FAIL;
+ enum config_hook_flags hook_flags = { 0, };
+ struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
+ struct ast_config *cfg;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "config_hook";
+ info->category = "/main/config/";
+ info->summary = "Test config hooks";
+ info->description =
+ "Ensure that config hooks are called at approriate times,"
+ "not called at inappropriate times, and that all information"
+ "that should be present is present.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ write_config_file();
+
+ /*
+ * Register a config hook to run when CONFIG_FILE is loaded by this module
+ */
+ ast_config_hook_register("test_hook",
+ CONFIG_FILE,
+ AST_MODULE,
+ hook_flags,
+ hook_cb);
+
+ /*
+ * Try loading the config file. This should result in the hook
+ * being called
+ */
+ cfg = ast_config_load(CONFIG_FILE, config_flags);
+ ast_config_destroy(cfg);
+ if (!hook_run || !hook_config_sane) {
+ ast_test_status_update(test, "Config hook either did not run or was given bad data!\n");
+ goto out;
+ }
+
+ /*
+ * Now try loading the wrong config file but from the right module.
+ * Hook should not run
+ */
+ hook_run = 0;
+ cfg = ast_config_load("asterisk.conf", config_flags);
+ ast_config_destroy(cfg);
+ if (hook_run) {
+ ast_test_status_update(test, "Config hook ran even though an incorrect file was specified.\n");
+ goto out;
+ }
+
+ /*
+ * Now try loading the correct config file but from the wrong module.
+ * Hook should not run
+ */
+ hook_run = 0;
+ cfg = ast_config_load2(CONFIG_FILE, "fake_module.so", config_flags);
+ ast_config_destroy(cfg);
+ if (hook_run) {
+ ast_test_status_update(test, "Config hook ran even though an incorrect module was specified.\n");
+ goto out;
+ }
+
+ /*
+ * Now try loading the file correctly, but without any changes to the file.
+ * Hook should not run
+ */
+ hook_run = 0;
+ cfg = ast_config_load(CONFIG_FILE, config_flags);
+ /* Only destroy this cfg conditionally. Otherwise a crash happens. */
+ if (cfg != CONFIG_STATUS_FILEUNCHANGED) {
+ ast_config_destroy(cfg);
+ }
+ if (hook_run) {
+ ast_test_status_update(test, "Config hook ran even though file contents had not changed\n");
+ goto out;
+ }
+
+ res = AST_TEST_PASS;
+
+out:
+ delete_config_file();
+ return res;
+}
enum {
EXPECT_FAIL = 0,
static int unload_module(void)
{
+ AST_TEST_UNREGISTER(copy_config);
+ AST_TEST_UNREGISTER(config_hook);
AST_TEST_UNREGISTER(ast_parse_arg_test);
return 0;
}
static int load_module(void)
{
+ AST_TEST_REGISTER(copy_config);
+ AST_TEST_REGISTER(config_hook);
AST_TEST_REGISTER(ast_parse_arg_test);
return AST_MODULE_LOAD_SUCCESS;
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "config test module");
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Config test module");
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Test custom control frame encode and decode functions.
+ *
+ * \author David Vossel <dvossel@digium.com>
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/custom_control_frame.h"
+#include "asterisk/test.h"
+
+AST_TEST_DEFINE(sipinfo_encode_decode_test)
+{
+ struct ast_variable *headers = NULL;
+ struct ast_variable *var = NULL;
+ struct ast_variable **cur = NULL;
+ struct ast_custom_payload *pl = NULL;
+ char *out_content = NULL;
+ char *out_content_type = NULL;
+ char *useragent_filter = NULL;
+ int res = AST_TEST_FAIL;
+ struct {
+ int num_headers_set;
+ char *header1;
+ char *header_val1;
+ char *header2;
+ char *header_val2;
+ char *header3;
+ char *header_val3;
+ char *content;
+ char *content_type;
+ char *useragent_filter;
+ } test_cases[] = {
+ {
+ 3,
+ "X-blah-header",
+ "blah-value",
+ "X-blah2-header",
+ "blah2-value",
+ "X-blah3-header",
+ "blah3-value",
+ "{ 'jsonjunk': hooray }",
+ "application/json",
+ NULL,
+ },
+ {
+ 2,
+ "X-blah-header",
+ "blah-value",
+ "X-blah2-header",
+ "blah2-value",
+ NULL,
+ NULL,
+ "{ 'jsonjunk': hooray }",
+ "application/json",
+ NULL,
+ },
+ {
+ 2,
+ "X-blah-header",
+ "blah-value",
+ "X-blah2-header",
+ "blah2-value",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ },
+ {
+ 3,
+ "X-blah-header",
+ "blah-value",
+ "X-blah2-header",
+ "blah2-value",
+ "X-blah3-header",
+ "blah3-value",
+ "{ 'jsonjunk': hooray }",
+ "application/json",
+ "Digium",
+ },
+ {
+ 2,
+ "X-blah-header",
+ "blah-value",
+ "X-blah2-header",
+ "blah2-value",
+ NULL,
+ NULL,
+ "{ 'jsonjunk': hooray }",
+ "application/json",
+ "Digium",
+ },
+ {
+ 2,
+ "X-blah-header",
+ "blah-value",
+ "X-blah2-header",
+ "blah2-value",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Digium",
+ },
+ };
+ int i;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "sipinfo_encode_decode_test";
+ info->category = "/main/custom_control_frame/";
+ info->summary = "encode and decode sip info custom control frames.";
+ info->description = "Verifies the encode and decode routines for AST_CONTROL_CUSTOM sip info payloads.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ for (i = 0; i < ARRAY_LEN(test_cases); i++) {
+ int num_headers = 0;
+ cur = &headers;
+ if (test_cases[i].header1) {
+ *cur = ast_variable_new(test_cases[i].header1, test_cases[i].header_val1, "");
+ cur = &(*cur)->next;
+ }
+ if (test_cases[i].header2) {
+ *cur = ast_variable_new(test_cases[i].header2, test_cases[i].header_val2, "");
+ cur = &(*cur)->next;
+ }
+ if (test_cases[i].header3) {
+ *cur = ast_variable_new(test_cases[i].header3, test_cases[i].header_val3, "");
+ cur = &(*cur)->next;
+ }
+ if (!(pl = ast_custom_payload_sipinfo_encode(headers, test_cases[i].content, test_cases[i].content_type, test_cases[i].useragent_filter))) {
+ goto sipinfo_cleanup;
+ }
+ ast_variables_destroy(headers);
+ headers = NULL;
+
+ if (ast_custom_payload_sipinfo_decode(pl, &headers, &out_content, &out_content_type, &useragent_filter)) {
+ goto sipinfo_cleanup;
+ }
+
+ for (var = headers; var; var = var->next) {
+ num_headers++;
+ if (num_headers == 1) {
+ if (strcmp(var->name, test_cases[i].header1) || strcmp(var->value, test_cases[i].header_val1)) {
+ goto sipinfo_cleanup;
+ }
+ } else if (num_headers == 2) {
+ if (strcmp(var->name, test_cases[i].header2) || strcmp(var->value, test_cases[i].header_val2)) {
+ goto sipinfo_cleanup;
+ }
+
+ } else if (num_headers == 3) {
+ if (strcmp(var->name, test_cases[i].header3) || strcmp(var->value, test_cases[i].header_val3)) {
+ goto sipinfo_cleanup;
+ }
+ }
+ }
+ if (num_headers != test_cases[i].num_headers_set) {
+ goto sipinfo_cleanup;
+ }
+ if (test_cases[i].content && strcmp(test_cases[i].content, out_content)) {
+ goto sipinfo_cleanup;
+ }
+ if (test_cases[i].content_type && strcmp(test_cases[i].content_type, out_content_type)) {
+ goto sipinfo_cleanup;
+ }
+ if (test_cases[i].useragent_filter && strcmp(test_cases[i].useragent_filter, useragent_filter)) {
+ goto sipinfo_cleanup;
+ }
+ ast_variables_destroy(headers);
+ ast_free(pl);
+ ast_free(out_content);
+ ast_free(out_content_type);
+ ast_free(useragent_filter);
+ headers = NULL;
+ pl = NULL;
+ out_content = out_content_type = useragent_filter = NULL;
+ }
+ res = AST_TEST_PASS;
+
+sipinfo_cleanup:
+
+ ast_free(pl);
+ ast_free(out_content);
+ ast_free(out_content_type);
+ ast_variables_destroy(headers);
+ return res;
+}
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(sipinfo_encode_decode_test);
+ return 0;
+}
+
+static int load_module(void)
+{
+
+ AST_TEST_REGISTER(sipinfo_encode_decode_test);
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Custom control frames test module");
--- /dev/null
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012, Matt Jordan
+ *
+ * Matt Jordan <mjordan@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Skeleton Test
+ *
+ * \author\verbatim Matt Jordan <mjordan@digium.com> \endverbatim
+ *
+ * Tests for the publicly exposed Voicemail API
+ * \ingroup tests
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/stat.h>
+
+#include "asterisk/utils.h"
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "asterisk/paths.h"
+#include "asterisk/channel.h"
+#include "asterisk/app.h"
+
+/*! \internal \brief Permissions to set on the voicemail directories we create
+ * - taken from app_voicemail */
+#define VOICEMAIL_DIR_MODE 0777
+
+/*! \internal \brief Permissions to set on the voicemail files we create
+ * - taken from app_voicemail */
+#define VOICEMAIL_FILE_MODE 0666
+
+/*! \internal \brief The number of mock snapshot objects we use for tests */
+#define TOTAL_SNAPSHOTS 4
+
+/*! \internal \brief Create and populate the mock message objects and create the
+ * envelope files on the file system */
+#define VM_API_TEST_SETUP do { \
+ if (test_vm_api_test_setup()) { \
+ VM_API_TEST_CLEANUP; \
+ ast_test_status_update(test, "Failed to set up necessary mock objects for voicemail API test\n"); \
+ return AST_TEST_FAIL; \
+ } else { \
+ int i = 0; \
+ for (; i < TOTAL_SNAPSHOTS; i++) { \
+ ast_test_status_update(test, "Created message in %s/%s with ID %s\n", \
+ test_snapshots[i]->exten, test_snapshots[i]->folder_name, test_snapshots[i]->msg_id); \
+ } \
+} } while (0)
+
+/*! \internal \brief Safely cleanup after a test run. This should be called both when a
+ * test fails and when it passes */
+#define VM_API_TEST_CLEANUP test_vm_api_test_teardown()
+
+/*! \internal \brief Safely cleanup a snapshot and a test run. Note that it assumes
+ * that the mailbox snapshot object is test_mbox_snapshot */
+#define VM_API_SNAPSHOT_TEST_CLEANUP \
+ if (test_mbox_snapshot) { \
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
+ } \
+ VM_API_TEST_CLEANUP; \
+
+/*! \internal \brief Verify the expected result from two string values obtained
+ * from a mailbox snapshot. Note that it assumes the mailbox snapshot
+ * object is test_mbox_snapshot
+ */
+#define VM_API_STRING_FIELD_VERIFY(expected, actual) do { \
+ if (strncmp((expected), (actual), sizeof((expected)))) { \
+ ast_test_status_update(test, "Test failed for parameter %s: Expected [%s], Actual [%s]\n", #actual, expected, actual); \
+ VM_API_SNAPSHOT_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+/*! \internal \brief Verify the expected result from two integer values. Note
+ * that it assumes the mailbox snapshot object is test_mbox_snapshot */
+#define VM_API_INT_VERIFY(expected, actual) do { \
+ if ((expected) != (actual)) { \
+ ast_test_status_update(test, "Test failed for parameter %s: Expected [%d], Actual [%d]\n", #actual, expected, actual); \
+ VM_API_SNAPSHOT_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+/*! \internal \brief Verify that a mailbox snapshot contains the expected message
+ * snapshot, in the correct position, with the expected values. Note
+ * that it assumes the mailbox snapshot object is test_mbox_snapshot
+ */
+#define VM_API_SNAPSHOT_MSG_VERIFY(expected, actual, expected_folder, expected_index) do { \
+ struct ast_vm_msg_snapshot *msg; \
+ int found = 0; \
+ int counter = 0; \
+ AST_LIST_TRAVERSE(&((actual)->snapshots[get_folder_by_name(expected_folder)]), msg, msg) { \
+ if (!(strcmp(msg->msg_id, (expected)->msg_id))) { \
+ ast_test_status_update(test, "Found message %s in snapshot\n", msg->msg_id); \
+ found = 1; \
+ if ((expected_index) != counter) { \
+ ast_test_status_update(test, "Expected message %s at index %d; Actual [%d]\n", \
+ (expected)->msg_id, (expected_index), counter); \
+ VM_API_SNAPSHOT_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } \
+ VM_API_STRING_FIELD_VERIFY((expected)->callerid, msg->callerid); \
+ VM_API_STRING_FIELD_VERIFY((expected)->callerchan, msg->callerchan); \
+ VM_API_STRING_FIELD_VERIFY((expected)->exten, msg->exten); \
+ VM_API_STRING_FIELD_VERIFY((expected)->origdate, msg->origdate); \
+ VM_API_STRING_FIELD_VERIFY((expected)->origtime, msg->origtime); \
+ VM_API_STRING_FIELD_VERIFY((expected)->duration, msg->duration); \
+ VM_API_STRING_FIELD_VERIFY((expected)->folder_name, msg->folder_name); \
+ VM_API_STRING_FIELD_VERIFY((expected)->flag, msg->flag); \
+ VM_API_INT_VERIFY((expected)->msg_number, msg->msg_number); \
+ break; \
+ } \
+ ++counter; \
+ } \
+ if (!found) { \
+ ast_test_status_update(test, "Test failed for message snapshot %s: not found in mailbox snapshot\n", (expected)->msg_id); \
+ VM_API_SNAPSHOT_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+} } while (0)
+
+
+/*! \internal \brief Create a message snapshot, failing the test if the snapshot could not be created.
+ * This requires having a snapshot named test_mbox_snapshot.
+ */
+#define VM_API_SNAPSHOT_CREATE(mailbox, context, folder, desc, sort, old_and_inbox) do { \
+ if (!(test_mbox_snapshot = ast_vm_mailbox_snapshot_create( \
+ (mailbox), (context), (folder), (desc), (sort), (old_and_inbox)))) { \
+ ast_test_status_update(test, "Failed to create voicemail mailbox snapshot\n"); \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+/*! \internal \brief Create a message snapshot, failing the test if the snapshot could be created.
+ * This is used to test off nominal conditions.
+ * This requires having a snapshot named test_mbox_snapshot.
+ */
+#define VM_API_SNAPSHOT_OFF_NOMINAL_TEST(mailbox, context, folder, desc, sort, old_and_inbox) do { \
+ if ((test_mbox_snapshot = ast_vm_mailbox_snapshot_create( \
+ (mailbox), (context), (folder), (desc), (sort), (old_and_inbox)))) { \
+ ast_test_status_update(test, "Created mailbox snapshot when none was expected\n"); \
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+/*! \internal \brief Move a voicemail message, failing the test if the message could not be moved */
+#define VM_API_MOVE_MESSAGE(mailbox, context, number_of_messages, source, message_numbers_in, dest, message_numbers_out) do { \
+ if (ast_vm_msg_move((mailbox), (context), (number_of_messages), (source), (message_numbers_in), (dest), (message_numbers_out))) { \
+ ast_test_status_update(test, "Failed to move message %s@%s from %s to %s\n", \
+ (mailbox) ? (mailbox): "(NULL)", (context) ? (context) : "(NULL)", (source) ? (source) : "(NULL)", (dest) ? (dest) : "(NULL)"); \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+ /*! \internal \brief Attempt to move a voicemail message, failing the test if the message could be moved */
+#define VM_API_MOVE_MESSAGE_OFF_NOMINAL(mailbox, context, number_of_messages, source, message_numbers_in, dest, message_numbers_out) do { \
+ if (!ast_vm_msg_move((mailbox), (context), (number_of_messages), (source), (message_numbers_in), (dest), (message_numbers_out))) { \
+ ast_test_status_update(test, "Succeeded to move message %s@%s from %s to %s when we really shouldn't\n", \
+ (mailbox) ? (mailbox): "(NULL)", (context) ? (context) : "(NULL)", (source) ? (source) : "(NULL)", (dest) ? (dest) : "(NULL)"); \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+/*! \internal \brief Remove a message, failing the test if the method failed or if the message is still present. */
+#define VM_API_REMOVE_MESSAGE(mailbox, context, number_of_messages, folder, message_numbers_in) do { \
+ if (ast_vm_msg_remove((mailbox), (context), (number_of_messages), (folder), (message_numbers_in))) { \
+ ast_test_status_update(test, "Failed to remove message from mailbox %s@%s, folder %s", \
+ (mailbox) ? (mailbox): "(NULL)", (context) ? (context) : "(NULL)", (folder) ? (folder) : "(NULL)"); \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } \
+ VM_API_SNAPSHOT_CREATE((mailbox), (context), (folder), 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); \
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 0); \
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
+} while (0)
+
+/*! \internal \brief Remove a message, failing the test if the method succeeds */
+#define VM_API_REMOVE_MESSAGE_OFF_NOMINAL(mailbox, context, number_of_messages, folder, message_numbers_in) do { \
+ if (!ast_vm_msg_remove((mailbox), (context), (number_of_messages), (folder), (message_numbers_in))) { \
+ ast_test_status_update(test, "Succeeded in removing message from mailbox %s@%s, folder %s, when expected result was failure\n", \
+ (mailbox) ? (mailbox): "(NULL)", (context) ? (context) : "(NULL)", (folder) ? (folder) : "(NULL)"); \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+/*! \internal \brief Forward a message, failing the test if the message could not be forwarded */
+# define VM_API_FORWARD_MESSAGE(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, number_of_messages, message_numbers_in, delete_old) do { \
+ if (ast_vm_msg_forward((from_mailbox), (from_context), (from_folder), (to_mailbox), (to_context), (to_folder), (number_of_messages), (message_numbers_in), (delete_old))) { \
+ ast_test_status_update(test, "Failed to forward message from %s@%s [%s] to %s@%s [%s]\n", \
+ (from_mailbox) ? (from_mailbox) : "(NULL)", (from_context) ? (from_context) : "(NULL)", (from_folder) ? (from_folder) : "(NULL)", \
+ (to_mailbox) ? (to_mailbox) : "(NULL)", (to_context) ? (to_context) : "(NULL)", (to_folder) ? (to_folder) : "(NULL)"); \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+ /*! \internal \brief Forward a message, failing the test if the message was successfully forwarded */
+#define VM_API_FORWARD_MESSAGE_OFF_NOMINAL(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, number_of_messages, message_numbers_in, delete_old) do { \
+ if (!ast_vm_msg_forward((from_mailbox), (from_context), (from_folder), (to_mailbox), (to_context), (to_folder), (number_of_messages), (message_numbers_in), (delete_old))) { \
+ ast_test_status_update(test, "Succeeded in forwarding message from %s@%s [%s] to %s@%s [%s] when expected result was fail\n", \
+ (from_mailbox) ? (from_mailbox) : "(NULL)", (from_context) ? (from_context) : "(NULL)", (from_folder) ? (from_folder) : "(NULL)", \
+ (to_mailbox) ? (to_mailbox) : "(NULL)", (to_context) ? (to_context) : "(NULL)", (to_folder) ? (to_folder) : "(NULL)"); \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+/*! \internal \brief Playback a message on a channel or callback function. Note that the channel name must be test_channel.
+ * Fail the test if the message could not be played. */
+#define VM_API_PLAYBACK_MESSAGE(channel, mailbox, context, folder, message, callback_fn) do { \
+ if (ast_vm_msg_play((channel), (mailbox), (context), (folder), (message), (callback_fn))) { \
+ ast_test_status_update(test, "Failed nominal playback message test\n"); \
+ if (test_channel) { \
+ ast_hangup(test_channel); \
+ } \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+/*! \internal \brief Playback a message on a channel or callback function. Note that the channel name must be test_channel.
+ * Fail the test if the message is successfully played */
+#define VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(channel, mailbox, context, folder, message, callback_fn) do { \
+ if (!ast_vm_msg_play((channel), (mailbox), (context), (folder), (message), (callback_fn))) { \
+ ast_test_status_update(test, "Succeeded in playing back of message when expected result was to fail\n"); \
+ if (test_channel) { \
+ ast_hangup(test_channel); \
+ } \
+ VM_API_TEST_CLEANUP; \
+ return AST_TEST_FAIL; \
+ } } while (0)
+
+
+/*! \internal \brief Possible names of folders. Taken from app_voicemail */
+static const char * const mailbox_folders[] = {
+ "INBOX",
+ "Old",
+ "Work",
+ "Family",
+ "Friends",
+ "Cust1",
+ "Cust2",
+ "Cust3",
+ "Cust4",
+ "Cust5",
+ "Deleted",
+ "Urgent",
+};
+
+/*! \internal \brief Message snapshots representing the messages that are used by the various tests */
+static struct ast_vm_msg_snapshot *test_snapshots[TOTAL_SNAPSHOTS];
+
+/*! \internal \brief Tracks whether or not we entered into the message playback callback function */
+static int global_entered_playback_callback = 0;
+
+/*! \internal \brief Get a folder index by its name */
+static int get_folder_by_name(const char *folder)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
+ if (strcasecmp(folder, mailbox_folders[i]) == 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/*! \internal \brief Get a mock snapshot object
+ * \param context The mailbox context
+ * \param exten The mailbox extension
+ * \param callerid The caller ID of the person leaving the message
+ * \returns an ast_vm_msg_snapshot object on success
+ * \returns NULL on error
+ */
+static struct ast_vm_msg_snapshot *test_vm_api_create_mock_snapshot(const char *context, const char *exten, const char *callerid)
+{
+ char msg_id_hash[AST_MAX_CONTEXT + AST_MAX_EXTENSION + sizeof(callerid) + 1];
+ char msg_id_buf[256];
+ struct ast_vm_msg_snapshot *snapshot;
+
+ snprintf(msg_id_hash, sizeof(msg_id_hash), "%s%s%s", exten, context, callerid);
+ snprintf(msg_id_buf, sizeof(msg_id_buf), "%ld-%d", (long)time(NULL), ast_str_hash(msg_id_hash));
+
+ if ((snapshot = ast_calloc(1, sizeof(*snapshot)))) {
+ ast_string_field_init(snapshot, 128);
+ ast_string_field_set(snapshot, msg_id, msg_id_buf);
+ ast_string_field_set(snapshot, exten, exten);
+ ast_string_field_set(snapshot, callerid, callerid);
+ }
+ return snapshot;
+}
+
+/*! \internal \brief Make a voicemail mailbox folder based on the values provided in a message snapshot
+ * \param snapshot The snapshot containing the information to create the folder from
+ * \returns 0 on success
+ * \returns 1 on failure
+ */
+static int test_vm_api_create_voicemail_folder(const char *folder_path)
+{
+ mode_t mode = VOICEMAIL_DIR_MODE;
+ int res;
+
+ if ((res = ast_mkdir(folder_path, mode))) {
+ ast_log(AST_LOG_ERROR, "ast_mkdir '%s' failed: %s\n", folder_path, strerror(res));
+ return 1;
+ }
+ return 0;
+}
+
+/*! \internal \brief Create the voicemail files specified by a snapshot
+ * \param context The context of the mailbox
+ * \param mailbox The actual mailbox
+ * \param snapshot The message snapshot object containing the relevant envelope data
+ * \note This will symbolic link the sound file 'beep.gsm' to act as the 'sound' portion of the voicemail.
+ * Certain actions in app_voicemail will fail if an actual sound file does not exist
+ * \returns 0 on success
+ * \returns 1 on any failure
+ */
+static int test_vm_api_create_voicemail_files(const char *context, const char *mailbox, struct ast_vm_msg_snapshot *snapshot)
+{
+ FILE *msg_file;
+ char folder_path[PATH_MAX];
+ char msg_path[PATH_MAX];
+ char snd_path[PATH_MAX];
+ char beep_path[PATH_MAX];
+
+ /* Note that we create both the text and a dummy sound file here. Without
+ * the sound file, a number of the voicemail operations 'silently' fail, as it
+ * does not believe that an actual voicemail exists
+ */
+ snprintf(folder_path, sizeof(folder_path), "%s/voicemail/%s/%s/%s",
+ ast_config_AST_SPOOL_DIR, context, mailbox, snapshot->folder_name);
+ snprintf(msg_path, sizeof(msg_path), "%s/msg%04d.txt",
+ folder_path, snapshot->msg_number);
+ snprintf(snd_path, sizeof(snd_path), "%s/msg%04d.gsm",
+ folder_path, snapshot->msg_number);
+ snprintf(beep_path, sizeof(beep_path), "%s/sounds/en/beep.gsm", ast_config_AST_VAR_DIR);
+
+ if (test_vm_api_create_voicemail_folder(folder_path)) {
+ return 1;
+ }
+
+ if (ast_lock_path(folder_path) == AST_LOCK_FAILURE) {
+ ast_log(AST_LOG_ERROR, "Unable to lock directory %s\n", folder_path);
+ return 1;
+ }
+
+ if (symlink(beep_path, snd_path)) {
+ ast_unlock_path(folder_path);
+ ast_log(AST_LOG_ERROR, "Failed to create a symbolic link from %s to %s: %s\n",
+ beep_path, snd_path, strerror(errno));
+ return 1;
+ }
+
+ if (!(msg_file = fopen(msg_path, "w"))) {
+ /* Attempt to remove the sound file */
+ unlink(snd_path);
+ ast_unlock_path(folder_path);
+ ast_log(AST_LOG_ERROR, "Failed to open %s for writing\n", msg_path);
+ return 1;
+ }
+
+ fprintf(msg_file, ";\n; Message Information file\n;\n"
+ "[message]\n"
+ "origmailbox=%s\n"
+ "context=%s\n"
+ "macrocontext=%s\n"
+ "exten=%s\n"
+ "rdnis=%s\n"
+ "priority=%d\n"
+ "callerchan=%s\n"
+ "callerid=%s\n"
+ "origdate=%s\n"
+ "origtime=%s\n"
+ "category=%s\n"
+ "msg_id=%s\n"
+ "flag=%s\n"
+ "duration=%s\n",
+ mailbox,
+ context,
+ "",
+ snapshot->exten,
+ "unknown",
+ 1,
+ snapshot->callerchan,
+ snapshot->callerid,
+ snapshot->origdate,
+ snapshot->origtime,
+ "",
+ snapshot->msg_id,
+ snapshot->flag,
+ snapshot->duration);
+ fclose(msg_file);
+
+ if (chmod(msg_path, VOICEMAIL_FILE_MODE) < 0) {
+ ast_unlock_path(folder_path);
+ ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", msg_path, strerror(errno));
+ return 1;
+ }
+ ast_unlock_path(folder_path);
+
+ return 0;
+}
+
+/*! \internal \brief Destroy the voicemail on the file system associated with a snapshot
+ * \param snapshot The snapshot describing the voicemail
+ */
+static void test_vm_api_remove_voicemail(struct ast_vm_msg_snapshot *snapshot)
+{
+ char msg_path[PATH_MAX];
+ char snd_path[PATH_MAX];
+ char folder_path[PATH_MAX];
+
+ if (!snapshot) {
+ return;
+ }
+
+ snprintf(folder_path, sizeof(folder_path), "%s/voicemail/%s/%s/%s",
+ ast_config_AST_SPOOL_DIR, "default", snapshot->exten, snapshot->folder_name);
+
+ snprintf(msg_path, sizeof(msg_path), "%s/msg%04d.txt",
+ folder_path, snapshot->msg_number);
+ snprintf(snd_path, sizeof(snd_path), "%s/msg%04d.gsm",
+ folder_path, snapshot->msg_number);
+ unlink(msg_path);
+ unlink(snd_path);
+
+ return;
+}
+
+/*! \internal \brief Destroy the voicemails associated with a mailbox snapshot
+ * \param mailbox The actual mailbox name
+ * \param mailbox_snapshot The mailbox snapshot containing the voicemails to destroy
+ * \note Its necessary to specify not just the snapshot, but the mailbox itself. The
+ * message snapshots contained in the snapshot may have originated from a different mailbox
+ * then the one we're destroying, which means that we can't determine the files to delete
+ * without knowing the actual mailbox they exist in.
+ */
+static void test_vm_api_destroy_mailbox_voicemails(const char *mailbox, struct ast_vm_mailbox_snapshot *mailbox_snapshot)
+{
+ struct ast_vm_msg_snapshot *msg;
+ int i;
+
+ for (i = 0; i < 12; ++i) {
+ AST_LIST_TRAVERSE(&mailbox_snapshot->snapshots[i], msg, msg) {
+ ast_string_field_set(msg, exten, mailbox);
+ test_vm_api_remove_voicemail(msg);
+ }
+ }
+}
+
+/*! \internal \brief Use snapshots to remove all messages in the mailboxes */
+static void test_vm_api_remove_all_messages(void)
+{
+ struct ast_vm_mailbox_snapshot *mailbox_snapshot;
+
+ /* Take a snapshot of each mailbox and remove the contents. Note that we need to use
+ * snapshots of the mailboxes in addition to our tracked test snapshots, as there's a good chance
+ * we've created copies of the snapshots */
+ if ((mailbox_snapshot = ast_vm_mailbox_snapshot_create("test_vm_api_1234", "default", NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0))) {
+ test_vm_api_destroy_mailbox_voicemails("test_vm_api_1234", mailbox_snapshot);
+ mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
+ } else {
+ ast_log(AST_LOG_WARNING, "Failed to create mailbox snapshot - could not remove test messages for test_vm_api_1234\n");
+ }
+ if ((mailbox_snapshot = ast_vm_mailbox_snapshot_create("test_vm_api_2345", "default", NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0))) {
+ test_vm_api_destroy_mailbox_voicemails("test_vm_api_2345", mailbox_snapshot);
+ mailbox_snapshot = ast_vm_mailbox_snapshot_destroy(mailbox_snapshot);
+ } else {
+ ast_log(AST_LOG_WARNING, "Failed to create mailbox snapshot - could not remove test messages for test_vm_api_2345\n");
+ }
+}
+
+/*! \internal \brief Set up the necessary voicemails for a unit test run
+ * \note
+ * This creates 4 voicemails, stores them on the file system, and creates snapshot objects
+ * representing them for expected/actual value comparisons in the array test_snapshots.
+ *
+ * test_snapshots[0] => in test_vm_1234@default, folder INBOX, message 0
+ * test_snapshots[1] => in test_vm_1234@default, folder Old, message 0
+ * test_snapshots[2] => in test_vm_2345@default, folder INBOX, message 0
+ * test_snapshots[3] => in test_vm_2345@default, folder Old, message 1
+ *
+ * \returns 0 on success
+ * \returns 1 on failure
+ */
+static int test_vm_api_test_setup(void)
+{
+ int i, res = 0;
+ struct ast_vm_msg_snapshot *msg_one = NULL;
+ struct ast_vm_msg_snapshot *msg_two = NULL;
+ struct ast_vm_msg_snapshot *msg_three = NULL;
+ struct ast_vm_msg_snapshot *msg_four = NULL;
+
+ /* Make the four sample voicemails */
+ if ( !((msg_one = test_vm_api_create_mock_snapshot("default", "test_vm_api_1234", "\"Phil\" <2000>")))
+ || !((msg_two = test_vm_api_create_mock_snapshot("default", "test_vm_api_1234", "\"Noel\" <8000>")))
+ || !((msg_three = test_vm_api_create_mock_snapshot("default", "test_vm_api_2345", "\"Phil\" <2000>")))
+ || !((msg_four = test_vm_api_create_mock_snapshot("default", "test_vm_api_2345", "\"Bill\" <3000>")))) {
+ ast_log(AST_LOG_ERROR, "Failed to create mock snapshots for test\n");
+ ast_free(msg_one);
+ ast_free(msg_two);
+ ast_free(msg_three);
+ ast_free(msg_four);
+ return 1;
+ }
+
+ /* Create the voicemail users */
+ if (ast_vm_test_create_user("default", "test_vm_api_1234")
+ || ast_vm_test_create_user("default", "test_vm_api_2345")) {
+ ast_log(AST_LOG_ERROR, "Failed to create test voicemail users\n");
+ ast_free(msg_one);
+ ast_free(msg_two);
+ ast_free(msg_three);
+ ast_free(msg_four);
+ /* Note that the cleanup macro will ensure that any test user that
+ * was successfully created is removed
+ */
+ return 1;
+ }
+
+ /* Now that the users exist from the perspective of the voicemail
+ * application, attempt to remove any existing voicemails
+ */
+ test_vm_api_remove_all_messages();
+
+ /* Set the basic properties on each */
+ ast_string_field_set(msg_one, callerchan, "SIP/2000-00000000");
+ ast_string_field_set(msg_one, origdate, "Mon Mar 19 04:14:21 PM UTC 2012");
+ ast_string_field_set(msg_one, origtime, "1332173661");
+ ast_string_field_set(msg_one, duration, "8");
+ ast_string_field_set(msg_one, folder_name, "Old");
+ msg_one->msg_number = 0;
+ test_snapshots[0] = msg_one;
+
+ ast_string_field_set(msg_two, callerchan, "SIP/8000-00000001");
+ ast_string_field_set(msg_two, origdate, "Mon Mar 19 06:16:13 PM UTC 2012");
+ ast_string_field_set(msg_two, origtime, "1332180973");
+ ast_string_field_set(msg_two, duration, "24");
+ ast_string_field_set(msg_two, folder_name, "INBOX");
+ msg_two->msg_number = 0;
+ test_snapshots[1] = msg_two;
+
+ ast_string_field_set(msg_three, callerchan, "IAX/2000-000000a3");
+ ast_string_field_set(msg_three, origdate, "Thu Mar 22 23:13:03 PM UTC 2012");
+ ast_string_field_set(msg_three, origtime, "1332181251");
+ ast_string_field_set(msg_three, duration, "25");
+ ast_string_field_set(msg_three, folder_name, "INBOX");
+ msg_three->msg_number = 0;
+ test_snapshots[2] = msg_three;
+
+ ast_string_field_set(msg_four, callerchan, "DAHDI/3000-00000010");
+ ast_string_field_set(msg_four, origdate, "Fri Mar 23 03:01:03 AM UTC 2012");
+ ast_string_field_set(msg_four, origtime, "1332181362");
+ ast_string_field_set(msg_four, duration, "13");
+ ast_string_field_set(msg_four, folder_name, "INBOX");
+ msg_three->msg_number = 1;
+ test_snapshots[3] = msg_four;
+
+ /* Store the messages */
+ for (i = 0; i < TOTAL_SNAPSHOTS; ++i) {
+ if (test_vm_api_create_voicemail_files("default", test_snapshots[i]->exten, test_snapshots[i])) {
+ /* On a failure, the test_vm_api_test_teardown method will remove and
+ * unlink any created files. Since we failed to create the file, clean
+ * up the object here instead */
+ ast_log(AST_LOG_ERROR, "Failed to store voicemail %s/%s\n",
+ "default", test_snapshots[i]->exten);
+ ast_free(test_snapshots[i]);
+ test_snapshots[i] = NULL;
+ res = 1;
+ }
+ }
+
+ return res;
+}
+
+static void test_vm_api_test_teardown(void)
+{
+ int i;
+
+ /* Remove our test message snapshots */
+ for (i = 0; i < TOTAL_SNAPSHOTS; ++i) {
+ test_vm_api_remove_voicemail(test_snapshots[i]);
+ ast_free(test_snapshots[i]);
+ test_snapshots[i] = NULL;
+ }
+
+ test_vm_api_remove_all_messages();
+
+ /* Remove the test users */
+ ast_vm_test_destroy_user("default", "test_vm_api_1234");
+ ast_vm_test_destroy_user("default", "test_vm_api_2345");
+}
+
+/*! \internal \brief Update the test snapshots with a new mailbox snapshot
+ * \param mailbox_snapshot The new mailbox shapshot to update the test snapshots with
+ */
+static void test_vm_api_update_test_snapshots(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
+{
+ int i, j;
+ struct ast_vm_msg_snapshot *msg;
+
+ for (i = 0; i < TOTAL_SNAPSHOTS; ++i) {
+ for (j = 0; j < 12; ++j) {
+ AST_LIST_TRAVERSE(&mailbox_snapshot->snapshots[j], msg, msg) {
+ if (!strcmp(msg->msg_id, test_snapshots[i]->msg_id)) {
+ ast_string_field_set(test_snapshots[i], callerid, msg->callerid);
+ ast_string_field_set(test_snapshots[i], callerchan, msg->callerchan);
+ ast_string_field_set(test_snapshots[i], exten, msg->exten);
+ ast_string_field_set(test_snapshots[i], origdate, msg->origdate);
+ ast_string_field_set(test_snapshots[i], origtime, msg->origtime);
+ ast_string_field_set(test_snapshots[i], duration, msg->duration);
+ ast_string_field_set(test_snapshots[i], folder_name, msg->folder_name);
+ ast_string_field_set(test_snapshots[i], flag, msg->flag);
+ test_snapshots[i]->msg_number = msg->msg_number;
+ }
+ }
+ }
+ }
+}
+
+/*! \internal \brief A callback function for message playback
+ * \param chan The channel the file would be played back on
+ * \param file The file to play back
+ * \param duration The duration of the file
+ * \note This sets global_entered_playback_callback to 1 if the parameters
+ * passed to the callback are minimally valid
+ */
+static void message_playback_callback_fn(struct ast_channel *chan, const char *file, int duration)
+{
+ if ((chan) && !ast_strlen_zero(file) && duration > 0) {
+ global_entered_playback_callback = 1;
+ } else {
+ ast_log(AST_LOG_WARNING, "Entered into message playback callback function with invalid parameters\n");
+ }
+}
+
+/*! \internal \brief Dummy channel write function for mock_channel_tech */
+static int test_vm_api_mock_channel_write(struct ast_channel *chan, struct ast_frame *frame)
+{
+ return 0;
+}
+
+/*! \internal \brief Dummy channel read function for mock_channel_tech */
+static struct ast_frame *test_vm_api_mock_channel_read(struct ast_channel *chan)
+{
+ return &ast_null_frame;
+}
+
+/*! \internal \brief A dummy channel technology */
+static const struct ast_channel_tech mock_channel_tech = {
+ .write = test_vm_api_mock_channel_write,
+ .read = test_vm_api_mock_channel_read,
+};
+
+/*! \internal \brief Create a dummy channel suitable for 'playing back' gsm sound files on
+ * \returns a channel on success
+ * \returns NULL on failure
+ */
+static struct ast_channel *test_vm_api_create_mock_channel(void)
+{
+ struct ast_channel *mock_channel;
+
+ if (!(mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, 0, 0, "TestChannel"))) {
+ return NULL;
+ }
+
+ mock_channel->nativeformats = AST_FORMAT_GSM;
+ mock_channel->writeformat = AST_FORMAT_GSM;
+ mock_channel->rawwriteformat = AST_FORMAT_GSM;
+ mock_channel->readformat = AST_FORMAT_GSM;
+ mock_channel->rawreadformat = AST_FORMAT_GSM;
+ mock_channel->tech = &mock_channel_tech;
+
+ return mock_channel;
+}
+
+AST_TEST_DEFINE(voicemail_api_nominal_snapshot)
+{
+ struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "nominal_snapshot";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Nominal mailbox snapshot tests";
+ info->description =
+ "Test retrieving mailbox snapshots";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ ast_test_status_update(test, "Test retrieving message 1 from INBOX of test_vm_1234\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
+ ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test retrieving message 0 from Old of test_vm_1234\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "Old", 0);
+ ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test retrieving message 0, 1 from Old and INBOX of test_vm_1234 ordered by time\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 1);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "INBOX", 0);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 1);
+
+ ast_test_status_update(test, "Test retrieving message 1, 0 from Old and INBOX of test_vm_1234 ordered by time desc\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 1, AST_VM_SNAPSHOT_SORT_BY_TIME, 1);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "INBOX", 1);
+ ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test retrieving message 0, 1 from Old and INBOX of test_vm_1234 ordered by id\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_ID, 1);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "INBOX", 1);
+ ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test retrieving message 1, 0 from Old and INBOX of test_vm_1234 ordered by id desc\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 1, AST_VM_SNAPSHOT_SORT_BY_ID, 1);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "INBOX", 0);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 1);
+ ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test retrieving message 0, 1 from all folders of test_vm_1234 ordered by id\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", NULL, 0, AST_VM_SNAPSHOT_SORT_BY_ID, 0);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "Old", 0);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
+ ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test retrieving message 0, 1 from all folders of test_vm_1234 ordered by time\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", NULL, 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "Old", 0);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
+ ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test retrieving message 0, 1 from all folders of test_vm_1234, default context ordered by time\n");
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", NULL, NULL, 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[0], test_mbox_snapshot, "Old", 0);
+ VM_API_SNAPSHOT_MSG_VERIFY(test_snapshots[1], test_mbox_snapshot, "INBOX", 0);
+ ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_off_nominal_snapshot)
+{
+ struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "off_nominal_snapshot";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Off nominal mailbox snapshot tests";
+ info->description =
+ "Test off nominal requests for mailbox snapshots. This includes"
+ " testing the following:\n"
+ " * Access to non-exisstent mailbox\n"
+ " * Access to NULL mailbox\n"
+ " * Access to non-existent context\n"
+ " * Access to non-existent folder\n"
+ " * Access to NULL folder\n"
+ " * Invalid sort identifier\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ ast_test_status_update(test, "Test access to non-existent mailbox test_vm_api_3456\n");
+ VM_API_SNAPSHOT_OFF_NOMINAL_TEST("test_vm_api_3456", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+
+ ast_test_status_update(test, "Test access to null mailbox\n");
+ VM_API_SNAPSHOT_OFF_NOMINAL_TEST(NULL, "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+
+ ast_test_status_update(test, "Test access non-existent context test_vm_api_defunct\n");
+ VM_API_SNAPSHOT_OFF_NOMINAL_TEST("test_vm_api_1234", "test_vm_api_defunct", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+
+ ast_test_status_update(test, "Test non-existent folder test_vm_api_platypus\n");
+ VM_API_SNAPSHOT_OFF_NOMINAL_TEST("test_vm_api_1234", "default", "test_vm_api_platypus", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_nominal_move)
+{
+ struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
+ int single_msg_nums[] = { 0, };
+ int multi_msg_nums[] = { 0, 1, };
+ int output_msg_nums[] = { -1, -1, };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "nominal_move";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Nominal move voicemail tests";
+ info->description =
+ "Test nominal requests to move a voicemail to a different"
+ " folder. This includes moving messages given a context,"
+ " given a NULL context, and moving multiple messages";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ ast_test_status_update(test, "Test move of test_vm_api_1234 message from INBOX to Family\n");
+ VM_API_MOVE_MESSAGE("test_vm_api_1234", "default", 1, "INBOX", single_msg_nums, "Family", output_msg_nums);
+ VM_API_INT_VERIFY(output_msg_nums[0], 0);
+
+ ast_test_status_update(test, "Test move of test_vm_api_1234 message from Old to Family\n");
+ VM_API_MOVE_MESSAGE("test_vm_api_1234", NULL, 1, "Old", single_msg_nums, "Family", output_msg_nums);
+
+ /* Take a snapshot and update the test snapshots for verification */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Family", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ test_vm_api_update_test_snapshots(test_mbox_snapshot);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ VM_API_INT_VERIFY(output_msg_nums[0], 1);
+ VM_API_STRING_FIELD_VERIFY(test_snapshots[0]->folder_name, "Family");
+ VM_API_STRING_FIELD_VERIFY(test_snapshots[1]->folder_name, "Family");
+ VM_API_INT_VERIFY(test_snapshots[1]->msg_number, 0);
+ VM_API_INT_VERIFY(test_snapshots[0]->msg_number, 1);
+
+ /* Move both of the 2345 messages to Family */
+ ast_test_status_update(test, "Test move of test_vm_api_2345 messages from Inbox to Family\n");
+ VM_API_MOVE_MESSAGE("test_vm_api_2345", "default", 2, "INBOX", multi_msg_nums, "Family", output_msg_nums);
+
+ /* Take a snapshot and update the test snapshots for verification */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "Family", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ test_vm_api_update_test_snapshots(test_mbox_snapshot);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ VM_API_INT_VERIFY(output_msg_nums[0], 0);
+ VM_API_INT_VERIFY(output_msg_nums[1], 1);
+ VM_API_STRING_FIELD_VERIFY(test_snapshots[2]->folder_name, "Family");
+ VM_API_STRING_FIELD_VERIFY(test_snapshots[3]->folder_name, "Family");
+
+ ast_test_status_update(test, "Test move of test_vm_api_2345 message from Family to INBOX\n");
+ VM_API_MOVE_MESSAGE("test_vm_api_2345", "default", 2, "Family", multi_msg_nums, "INBOX", NULL);
+
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ test_vm_api_update_test_snapshots(test_mbox_snapshot);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ VM_API_STRING_FIELD_VERIFY(test_snapshots[2]->folder_name, "INBOX");
+ VM_API_STRING_FIELD_VERIFY(test_snapshots[3]->folder_name, "INBOX");
+
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_off_nominal_move)
+{
+ int single_msg_nums[] = { 0, };
+ int multi_msg_nums[] = { 0, 1, 2, 3};
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "off_nominal_move";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Off nominal mailbox message move tests";
+ info->description =
+ "Test nominal requests to move a voicemail to a different"
+ " folder. This includes testing the following:\n"
+ " * Moving to a non-existent mailbox\n"
+ " * Moving to a NULL mailbox\n"
+ " * Moving to a non-existent context\n"
+ " * Moving to/from non-existent folder\n"
+ " * Moving to/from NULL folder\n"
+ " * Invalid message identifier(s)\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ ast_test_status_update(test, "Test move attempt for invalid mailbox test_vm_3456\n");
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_3456", "default", 1, "INBOX", single_msg_nums, "Family", NULL);
+
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL(NULL, "default", 1, "INBOX", single_msg_nums, "Family", NULL);
+
+ ast_test_status_update(test, "Test move attempt for invalid context test_vm_api_defunct\n");
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "test_vm_api_defunct", 1, "INBOX", single_msg_nums, "Family", NULL);
+
+ ast_test_status_update(test, "Test move attempt to invalid folder\n");
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", single_msg_nums, "SPAMALOT", NULL);
+
+ ast_test_status_update(test, "Test move attempt from invalid folder\n");
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "MEATINACAN", single_msg_nums, "Family", NULL);
+
+ ast_test_status_update(test, "Test move attempt to NULL folder\n");
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", single_msg_nums, NULL, NULL);
+
+ ast_test_status_update(test, "Test move attempt from NULL folder\n");
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, NULL, single_msg_nums, "Family", NULL);
+
+ ast_test_status_update(test, "Test move attempt with non-existent message number\n");
+ single_msg_nums[0] = 6;
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", single_msg_nums, "Family", NULL);
+
+ ast_test_status_update(test, "Test move attempt with invalid message number\n");
+ single_msg_nums[0] = -4;
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", single_msg_nums, "Family", NULL);
+
+ ast_test_status_update(test, "Test move attempt with 0 number of messages\n");
+ single_msg_nums[0] = 0;
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 0, "INBOX", single_msg_nums, "Family", NULL);
+
+ ast_test_status_update(test, "Test move attempt with invalid number of messages\n");
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", -30, "INBOX", single_msg_nums, "Family", NULL);
+
+ ast_test_status_update(test, "Test move attempt with non-existent multiple messages, where some messages exist\n");
+ VM_API_MOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 4, "INBOX", multi_msg_nums, "Family", NULL);
+
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_nominal_remove)
+{
+ struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
+ int single_msg_nums[] = { 0, };
+ int multi_msg_nums[] = { 0, 1, };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "nominal_remove";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Nominal mailbox remove message tests";
+ info->description =
+ "Tests removing messages from voicemail folders. Includes"
+ " both removing messages one at a time, and in a set";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ ast_test_status_update(test, "Test removing a single message from INBOX\n");
+ VM_API_REMOVE_MESSAGE("test_vm_api_1234", "default", 1, "INBOX", single_msg_nums);
+
+ ast_test_status_update(test, "Test removing a single message from Old\n");
+ VM_API_REMOVE_MESSAGE("test_vm_api_1234", "default", 1, "Old", single_msg_nums);
+
+ ast_test_status_update(test, "Test removing multiple messages from INBOX\n");
+ VM_API_REMOVE_MESSAGE("test_vm_api_2345", "default", 2, "INBOX", multi_msg_nums);
+
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_off_nominal_remove)
+{
+ int single_msg_nums[] = { 0, };
+ int multi_msg_nums[] = { 0, 1, };
+ int empty_msg_nums[] = { };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "off_nominal_remove";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Off nominal mailbox message removal tests";
+ info->description =
+ "Test off nominal requests for removing messages from "
+ "a mailbox. This includes:\n"
+ " * Removing messages with an invalid mailbox\n"
+ " * Removing messages from a NULL mailbox\n"
+ " * Removing messages from an invalid context\n"
+ " * Removing messages from an invalid folder\n"
+ " * Removing messages from a NULL folder\n"
+ " * Removing messages with bad identifiers\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ ast_test_status_update(test, "Test removing a single message with an invalid mailbox\n");
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_3456", "default", 1, "INBOX", single_msg_nums);
+
+ ast_test_status_update(test, "Test removing a single message with a NULL mailbox\n");
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL(NULL, "default", 1, "INBOX", single_msg_nums);
+
+ ast_test_status_update(test, "Test removing a single message with an invalid context\n");
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "defunct", 1, "INBOX", single_msg_nums);
+
+ ast_test_status_update(test, "Test removing a single message with an invalid folder\n");
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "SPAMINACAN", single_msg_nums);
+
+ ast_test_status_update(test, "Test removing a single message with a NULL folder\n");
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, NULL, single_msg_nums);
+
+ ast_test_status_update(test, "Test removing a single message with an invalid message number\n");
+ single_msg_nums[0] = 6;
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 1, "INBOX", single_msg_nums);
+
+ ast_test_status_update(test, "Test removing multiple messages with a single invalid message number\n");
+ multi_msg_nums[1] = 6;
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_2345", "default", 2, "INBOX", multi_msg_nums);
+
+ ast_test_status_update(test, "Test removing no messages with no message numbers\n");
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", 0, "INBOX", empty_msg_nums);
+
+ ast_test_status_update(test, "Test removing multiple messages with an invalid size specifier\n");
+ VM_API_REMOVE_MESSAGE_OFF_NOMINAL("test_vm_api_2345", "default", -30, "INBOX", multi_msg_nums);
+
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_nominal_forward)
+{
+ struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
+ int single_msg_nums[] = { 0, };
+ int multi_msg_nums[] = { 0, 1, };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "nominal_forward";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Nominal message forward tests";
+ info->description =
+ "Tests the nominal cases of forwarding messages"
+ " between mailboxes";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX\n");
+ VM_API_FORWARD_MESSAGE("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, single_msg_nums, 0);
+
+ /* Make sure we didn't delete the message */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ /* We should now have a total of 3 messages in test_vm_api_2345 INBOX */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 3);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX with default context to test_vm_api_2345 INBOX\n");
+ VM_API_FORWARD_MESSAGE("test_vm_api_1234", NULL, "INBOX", "test_vm_api_2345", "default", "INBOX", 1, single_msg_nums, 0);
+
+ /* Make sure we didn't delete the message */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ /* We should now have a total of 4 messages in test_vm_api_2345 INBOX */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 4);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX with default context\n");
+ VM_API_FORWARD_MESSAGE("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", NULL, "INBOX", 1, single_msg_nums, 0);
+
+ /* Make sure we didn't delete the message */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ /* We should now have a total of 5 messages in test_vm_api_2345 INBOX */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 5);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX, deleting original\n");
+ VM_API_FORWARD_MESSAGE("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", NULL, "INBOX", 1, single_msg_nums, 1);
+
+ /* Make sure we deleted the message */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 0);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ /* We should now have a total of 6 messages in test_vm_api_2345 INBOX */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 6);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test forwarding 2 messages from test_vm_api_2345 INBOX to test_vm_api_1234 INBOX");
+ VM_API_FORWARD_MESSAGE("test_vm_api_2345", "default", "INBOX", "test_vm_api_1234", "default", "INBOX", 2, multi_msg_nums, 0);
+
+ /* Make sure we didn't delete the messages */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 6);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ /* We should now have a total of 2 messages in test_vm_api_1234 INBOX */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ ast_test_status_update(test, "Test forwarding 2 messages from test_vm_api_2345 INBOX to test_vm_api_1234 Family, deleting original\n");
+ VM_API_FORWARD_MESSAGE("test_vm_api_2345", "default", "INBOX", "test_vm_api_1234", "default", "Family", 2, multi_msg_nums, 1);
+ /* Make sure we deleted the messages */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 4);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ /* We should now have a total of 2 messages in test_vm_api_1234 Family */
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Family", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_off_nominal_forward)
+{
+ int single_msg_nums[] = { 0, };
+ int multi_msg_nums[] = { 0, 1, 2, 3};
+
+ int empty_msg_nums[] = { };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "off_nominal_forward";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Off nominal message forwarding tests";
+ info->description =
+ "Test off nominal forwarding of messages. This includes:\n"
+ " * Invalid/NULL from mailbox\n"
+ " * Invalid from context\n"
+ " * Invalid/NULL from folder\n"
+ " * Invalid/NULL to mailbox\n"
+ " * Invalid to context\n"
+ " * Invalid/NULL to folder\n"
+ " * Invalid message numbers\n"
+ " * Invalid number of messages\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ ast_test_status_update(test, "Test forwarding from an invalid mailbox\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_3456", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding from a NULL mailbox\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL(NULL, "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding from an invalid context\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "defunct", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding from an invalid folder\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "POTTEDMEAT", "test_vm_api_2345", "default", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding from a NULL folder\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", NULL, "test_vm_api_2345", "default", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding to an invalid mailbox\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_3456", "default", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding to a NULL mailbox\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", NULL, "default", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding to an invalid context\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "defunct", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding to an invalid folder\n");
+
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "POTTEDMEAT", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding to a NULL folder\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", NULL, 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding when no messages are select\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 0, empty_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding a message that doesn't exist\n");
+ single_msg_nums[0] = 6;
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", 1, single_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding multiple messages, where some messages don't exist\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_2345", "default", "INBOX", "test_vm_api_1234", "default", "INBOX", 4, multi_msg_nums, 0);
+
+ ast_test_status_update(test, "Test forwarding a message with an invalid size specifier\n");
+ VM_API_FORWARD_MESSAGE_OFF_NOMINAL("test_vm_api_1234", "default", "INBOX", "test_vm_api_2345", "default", "INBOX", -30, single_msg_nums, 0);
+
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_nominal_msg_playback)
+{
+ struct ast_vm_mailbox_snapshot *test_mbox_snapshot = NULL;
+ struct ast_channel *test_channel;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "nominal_msg_playback";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Nominal message playback";
+ info->description =
+ "Tests playing back a message on a provided"
+ " channel or callback function\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ if (!(test_channel = test_vm_api_create_mock_channel())) {
+ ast_log(AST_LOG_ERROR, "Failed to create mock channel for testing\n");
+ VM_API_TEST_CLEANUP;
+ return AST_TEST_FAIL;
+ }
+
+ ast_test_status_update(test, "Playing back message from test_vm_api_1234 to mock channel\n");
+ VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_1234", "default", "INBOX", "0", NULL);
+
+ ast_test_status_update(test, "Playing back message from test_vm_api_2345 to callback function\n");
+ VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_2345", "default", "INBOX", "0", &message_playback_callback_fn);
+ VM_API_INT_VERIFY(global_entered_playback_callback, 1);
+ global_entered_playback_callback = 0;
+
+ ast_test_status_update(test, "Playing back message from test_vm_api_2345 to callback function with default context\n");
+ VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_2345", NULL, "INBOX", "0", &message_playback_callback_fn);
+ VM_API_INT_VERIFY(global_entered_playback_callback, 1);
+ global_entered_playback_callback = 0;
+
+ VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
+ VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
+ test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
+
+ if (test_channel) {
+ ast_hangup(test_channel);
+ }
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(voicemail_api_off_nominal_msg_playback)
+{
+ struct ast_channel *test_channel;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "off_nominal_msg_playback";
+ info->category = "/main/voicemail_api/";
+ info->summary = "Off nominal message playback";
+ info->description =
+ "Tests off nominal conditions in playing back a "
+ "message. This includes:\n"
+ " * Invalid/NULL mailbox\n"
+ " * Invalid context\n"
+ " * Invalid/NULL folder\n"
+ " * Invalid message identifiers\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ VM_API_TEST_SETUP;
+
+ if (!(test_channel = test_vm_api_create_mock_channel())) {
+ ast_log(AST_LOG_ERROR, "Failed to create mock channel for testing\n");
+ VM_API_TEST_CLEANUP;
+ return AST_TEST_FAIL;
+ }
+
+ ast_test_status_update(test, "Playing back message from invalid mailbox\n");
+ VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_3456", "default", "INBOX", "0", NULL);
+
+ ast_test_status_update(test, "Playing back message from NULL mailbox\n");
+ VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, NULL, "default", "INBOX", "0", NULL);
+
+ ast_test_status_update(test, "Playing back message from invalid context\n");
+ VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "defunct", "INBOX", "0", NULL);
+
+ ast_test_status_update(test, "Playing back message from invalid folder\n");
+ VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default", "BACON", "0", NULL);
+
+ ast_test_status_update(test, "Playing back message from NULL folder\n");
+ VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default", NULL, "0", NULL);
+
+ ast_test_status_update(test, "Playing back message with invalid message specifier\n");
+ VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default", "INBOX", "6", NULL);
+
+ ast_test_status_update(test, "Playing back message with NULL message specifier\n");
+ VM_API_PLAYBACK_MESSAGE_OFF_NOMINAL(test_channel, "test_vm_api_1234", "default", "INBOX", NULL, NULL);
+ if (test_channel) {
+ ast_hangup(test_channel);
+ }
+ VM_API_TEST_CLEANUP;
+
+ return AST_TEST_PASS;
+}
+
+static int unload_module(void)
+{
+ /* Snapshot tests */
+ AST_TEST_UNREGISTER(voicemail_api_nominal_snapshot);
+ AST_TEST_UNREGISTER(voicemail_api_off_nominal_snapshot);
+
+ /* Move Tests */
+ AST_TEST_UNREGISTER(voicemail_api_nominal_move);
+ AST_TEST_UNREGISTER(voicemail_api_off_nominal_move);
+
+ /* Remove Tests */
+ AST_TEST_UNREGISTER(voicemail_api_nominal_remove);
+ AST_TEST_UNREGISTER(voicemail_api_off_nominal_remove);
+
+ /* Forward Tests */
+ AST_TEST_UNREGISTER(voicemail_api_nominal_forward);
+ AST_TEST_UNREGISTER(voicemail_api_off_nominal_forward);
+
+ /* Message Playback Tests */
+ AST_TEST_UNREGISTER(voicemail_api_nominal_msg_playback);
+ AST_TEST_UNREGISTER(voicemail_api_off_nominal_msg_playback);
+ return 0;
+}
+
+static int load_module(void)
+{
+ /* Snapshot tests */
+ AST_TEST_REGISTER(voicemail_api_nominal_snapshot);
+ AST_TEST_REGISTER(voicemail_api_off_nominal_snapshot);
+
+ /* Move Tests */
+ AST_TEST_REGISTER(voicemail_api_nominal_move);
+ AST_TEST_REGISTER(voicemail_api_off_nominal_move);
+
+ /* Remove Tests */
+ AST_TEST_REGISTER(voicemail_api_nominal_remove);
+ AST_TEST_REGISTER(voicemail_api_off_nominal_remove);
+
+ /* Forward Tests */
+ AST_TEST_REGISTER(voicemail_api_nominal_forward);
+ AST_TEST_REGISTER(voicemail_api_off_nominal_forward);
+
+ /* Message Playback Tests */
+ AST_TEST_REGISTER(voicemail_api_nominal_msg_playback);
+ AST_TEST_REGISTER(voicemail_api_off_nominal_msg_playback);
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Core Voicemail API Tests");