]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merge changes for Digium phone support, and default module building.
authorJason Parker <jparker@digium.com>
Tue, 31 Jul 2012 20:59:52 +0000 (20:59 +0000)
committerJason Parker <jparker@digium.com>
Tue, 31 Jul 2012 20:59:52 +0000 (20:59 +0000)
All of these changes are merged from certified/branches/1.8.11/

git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/1.8.15@370667 65c4cc65-6c06-0410-ace0-fbb531ad65f3

110 files changed:
apps/app_adsiprog.c
apps/app_alarmreceiver.c
apps/app_amd.c
apps/app_chanisavail.c
apps/app_confbridge.c
apps/app_dahdibarge.c
apps/app_dahdiras.c
apps/app_dictate.c
apps/app_externalivr.c
apps/app_festival.c
apps/app_getcpeid.c
apps/app_ices.c
apps/app_image.c
apps/app_jack.c
apps/app_minivm.c
apps/app_mixmonitor.c
apps/app_morsecode.c
apps/app_mp3.c
apps/app_nbscat.c
apps/app_osplookup.c
apps/app_queue.c
apps/app_readfile.c
apps/app_setcallerid.c
apps/app_sms.c
apps/app_talkdetect.c
apps/app_test.c
apps/app_url.c
apps/app_voicemail.c
apps/app_waitforring.c
apps/app_waitforsilence.c
apps/app_zapateller.c
cdr/cdr_csv.c
cdr/cdr_odbc.c
cdr/cdr_pgsql.c
cdr/cdr_radius.c
cdr/cdr_sqlite.c
cdr/cdr_sqlite3_custom.c
cdr/cdr_tds.c
cel/cel_pgsql.c
cel/cel_radius.c
cel/cel_sqlite3_custom.c
cel/cel_tds.c
channels/chan_alsa.c
channels/chan_console.c
channels/chan_gtalk.c
channels/chan_h323.c
channels/chan_jingle.c
channels/chan_mgcp.c
channels/chan_misdn.c
channels/chan_nbs.c
channels/chan_oss.c
channels/chan_phone.c
channels/chan_sip.c
channels/chan_skinny.c
channels/chan_unistim.c
channels/sip/include/sip.h
configs/jabber.conf.sample
configs/manager.conf.sample
configs/sip.conf.sample
configure
formats/format_jpeg.c
formats/format_vox.c
funcs/func_frame_trace.c
funcs/func_pitchshift.c
funcs/func_presence_state.c [new file with mode: 0644]
include/asterisk/_private.h
include/asterisk/app.h
include/asterisk/callerid.h
include/asterisk/channel.h
include/asterisk/config.h
include/asterisk/custom_control_frame.h [new file with mode: 0644]
include/asterisk/event_defs.h
include/asterisk/file.h
include/asterisk/frame.h
include/asterisk/jabber.h
include/asterisk/manager.h
include/asterisk/message.h [new file with mode: 0644]
include/asterisk/pbx.h
include/asterisk/presencestate.h [new file with mode: 0644]
main/app.c
main/asterisk.c
main/callerid.c
main/channel.c
main/config.c
main/custom_control_frame.c [new file with mode: 0644]
main/event.c
main/features.c
main/file.c
main/manager.c
main/message.c [new file with mode: 0644]
main/pbx.c
main/presencestate.c [new file with mode: 0644]
pbx/pbx_ael.c
pbx/pbx_dundi.c
pbx/pbx_lua.c
pbx/pbx_realtime.c
res/res_ael_share.c
res/res_ais.c
res/res_config_ldap.c
res/res_config_pgsql.c
res/res_config_sqlite.c
res/res_fax_spandsp.c
res/res_jabber.c
res/res_phoneprov.c
res/res_snmp.c
res/res_timing_kqueue.c
res/res_timing_pthread.c
tests/test_config.c
tests/test_custom_control.c [new file with mode: 0644]
tests/test_voicemail_api.c [new file with mode: 0644]

index 430d8258d600222d81dbd964d1257d0a4e8e75b1..5593bcc2ef6637ca3881d0c180db0479de5fce57 100644 (file)
@@ -28,6 +28,7 @@
 /*** MODULEINFO
        <depend>res_adsi</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 4062ec9f01ee16cf138aa91d95ff1bc24ade2cbb..3066a7d8d751b4120d21e20a75869b3f40e3932a 100644 (file)
@@ -31,6 +31,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 679e0aebbd023e160435f248e4538b5d33d0efdc..3c915701d9aa2b9f2c110d81b1897a075f575f0b 100644 (file)
@@ -28,6 +28,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index bb1a492fb3448d600e2ae192c311af428f27858f..f5b3131c51017aa6f09ac803c7e8a9cb7dce3c82 100644 (file)
@@ -29,6 +29,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 18cfb746c71c3cbef8b2a14d1f8cc3331d73722e..ddde4331686544818271f9601d35b2f456660760 100644 (file)
@@ -28,6 +28,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index d5e0329b93674684154a25d3027e37f9056463be..a7f1dd8fa4d7dcb9fefc9831e8b25cb398306112 100644 (file)
@@ -34,6 +34,7 @@
 /*** MODULEINFO
        <depend>dahdi</depend>
        <support_level>deprecated</support_level>
+       <defaultenabled>no</defaultenabled>
        <replacement>app_chanspy</replacement>
  ***/
 
index fbaf984505347201e95975c1bc76273583db840f..bde8b9c4182831d87b84202dccb4e1e1f85d5304 100644 (file)
@@ -28,6 +28,7 @@
 /*** MODULEINFO
        <depend>dahdi</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 5057dcf42402928dd751d6fc5ddaa094733a3d50..2c7a319a5880124ff55f5fcfe5156cbee2b8f455 100644 (file)
@@ -29,6 +29,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index b05baed7bcf1cb83d86dc8406c4eb5bb5ff4adad..42c795aa4607088e8539ad42547086a010872138 100644 (file)
@@ -33,6 +33,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 2ed226c83ea1ea09e7d0edf17f65960050cb1ec1..8a6633fa3ea6a8de1704b5afb19201eec81ad4cf 100644 (file)
@@ -29,6 +29,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 7f59976eb23c25ca2a13d292be6b42967d5512dc..4d6a2ab2e91d64187f172ef79ad850e6633899d3 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index dbe3ec9f4ecc2629b8cfb7164d15e2cd7c829321..e2d7be1fa73d8eafbf7ee02e25b264b98151e8b0 100644 (file)
@@ -29,6 +29,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
  
 #include "asterisk.h"
index 160a28569701155aa89d8c3a062724cd8de6c5a8..0c127870d7445e365dd7ea098542791e421f2b20 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
  
 #include "asterisk.h"
index 5ba5d9ac005fe4bfee513e7487a4dd6ce020dbf9..32d1bf0d829a3bc833d0bd4fe8f13258e5489227 100644 (file)
@@ -38,6 +38,7 @@
        <depend>jack</depend>
        <depend>resample</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index dc81d3f15a93ac17ea77c73eb68ea898542f51d7..9fbbab0b4cf61fac8d4a50f863118ceb361b0797 100644 (file)
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 86237b3b306f24d2df6ea204ee6fb76d0d705472..01075062bab1fb5da9550f9e9b0df58819c241d2 100644 (file)
@@ -42,6 +42,7 @@
 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"
@@ -51,6 +52,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/channel.h"
 #include "asterisk/autochan.h"
 #include "asterisk/manager.h"
+#include "asterisk/callerid.h"
 
 /*** DOCUMENTATION
        <application name="MixMonitor" language="en_US">
@@ -93,6 +95,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                                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">
@@ -151,6 +160,54 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <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>
 
  ***/
 
@@ -162,6 +219,17 @@ static const char * const stop_app = "StopMixMonitor";
 
 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;
@@ -170,6 +238,20 @@ struct mixmonitor {
        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 {
@@ -178,12 +260,14 @@ 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,
 };
 
@@ -193,6 +277,7 @@ AST_APP_OPTIONS(mixmonitor_opts, {
        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 {
@@ -267,6 +352,70 @@ static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
        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)
@@ -277,15 +426,72 @@ 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;
 
@@ -366,6 +572,19 @@ static void *mixmonitor_thread(void *obj)
        }
 
        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;
 }
@@ -401,7 +620,7 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel
 }
 
 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;
@@ -431,6 +650,12 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename
                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);
@@ -456,6 +681,32 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename
                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);
 
@@ -481,6 +732,7 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 {
        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);
@@ -536,6 +788,14 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
                                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 */
@@ -553,7 +813,7 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
        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;
 }
@@ -702,6 +962,95 @@ static int manager_mute_mixmonitor(struct mansession *s, const struct message *m
        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")
 };
@@ -714,6 +1063,8 @@ static int unload_module(void)
        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;
 }
@@ -726,6 +1077,8 @@ static int load_module(void)
        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;
 }
index 2d7c117d19b6bd6ad5aa6fb58bb9c2a3922cbad5..38acc6e509b355cf9dd43c7d82209ef2c0e6e32b 100644 (file)
@@ -26,6 +26,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 0a2be4c3ed24c1bc22110ac2cbce19801e867819..745c203e7cdac36dec648fa295894198366ce990 100644 (file)
@@ -30,6 +30,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
  
 #include "asterisk.h"
index e8bbd4a2724e71f5805e12ed2781c59bf9ed4ef8..9779ebb38ec10ab35f791e3e98a1ff7149340ef3 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
  
 #include "asterisk.h"
index 9dbf39752a4769b07d45a801e7d1eee03dcdb2bb..87d20e06dc57daba3f3147d15c484f0c0ba8325d 100644 (file)
@@ -32,6 +32,7 @@
        <depend>osptk</depend>
        <depend>openssl</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index adedad72a7b32a242b4ff50d21f07c870389d3ca..4609f6e98034c6044e042da4420a9cd02446cd36 100644 (file)
@@ -1551,13 +1551,19 @@ static int extensionstate2devicestate(int state)
        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);
index 3c7629e722609ce9350b1fa4970d7e984a84cf5a..18aea8e6c6e2e2fda46d5699af020ce391400231 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>deprecated</support_level>
+       <defaultenabled>no</defaultenabled>
        <replacement>func_env (FILE())</replacement>
  ***/
 
index f6b9036756ca862b42aab9ad38e32286ff59b9ab..bcb937174838024d9ba76aa8afa568723b05f631 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>deprecated</support_level>
+       <defaultenabled>no</defaultenabled>
        <replacement>func_callerid</replacement>
  ***/
 
index 86ab0bce42a1d4fcf7b094ba7a4a05d0900d56b0..77005c61cd6449d9e53f0973e7ade4502689cec5 100644 (file)
@@ -36,6 +36,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index d8a6155c1ff538c2be60023c5ee32bc29084b87a..9c8c25ce2ee302dd00bfb6a9367115c173d82f4b 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 9ef8dfb7a6598cbc74733f4f6d4c02c65fe6e41f..5806c4b0dfdd02a7fff020b0e86c69b40f8cd3d2 100644 (file)
@@ -29,6 +29,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 00ea720472dc3963e6319021333fcd4fedff1efb..faaa6f6de9bf97751532485e9777c881f3e68b07 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
  
 #include "asterisk.h"
index b1b201e4098777b5a77572f6dfdc3e1b98b060e5..5d03fb7a17fa20edb9ca9994389089c8c40019eb 100644 (file)
@@ -119,6 +119,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #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"
@@ -330,6 +331,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        </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
@@ -491,7 +516,6 @@ static AST_LIST_HEAD_STATIC(vmstates, vmstate);
 #define ERROR_LOCK_PATH  -100
 #define OPERATOR_EXIT     300
 
-
 enum vm_box {
        NEW_FOLDER,
        OLD_FOLDER,
@@ -539,6 +563,25 @@ AST_APP_OPTIONS(vm_app_options, {
        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);
@@ -785,6 +828,8 @@ static char *app2 = "VoiceMailMain";
 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);
@@ -926,6 +971,19 @@ static int write_password_to_file(const char *secretfn, const char *password);
 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 {
@@ -1699,25 +1757,6 @@ static int create_dirpath(char *dest, int len, const char *context, const char *
        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
@@ -1728,6 +1767,12 @@ static const char *mbox(struct ast_vm_user *vmu, int id)
        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;
@@ -2181,7 +2226,9 @@ static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, str
        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;
        }
        
@@ -2189,8 +2236,10 @@ static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, str
        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;
        }
 
@@ -2302,8 +2351,8 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char
        }
 
        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);
@@ -2482,7 +2531,7 @@ static int has_voicemail(const char *mailbox, const char *folder)
  *
  * \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...*/
@@ -2500,7 +2549,7 @@ static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int i
        }
        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;
        }
@@ -4671,8 +4720,8 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
 #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);
@@ -5316,7 +5365,7 @@ static int has_voicemail(const char *mailbox, const char *folder)
  *
  * \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);
@@ -5328,6 +5377,8 @@ static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int i
 
        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";
        }
@@ -5349,7 +5400,7 @@ static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int i
        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
@@ -5367,11 +5418,12 @@ static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int i
                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
@@ -5573,6 +5625,296 @@ struct leave_vm_options {
        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
@@ -5709,7 +6051,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                        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))) {
@@ -5950,6 +6292,14 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                /* 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),
@@ -5970,7 +6320,8 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                "callerid=%s\n"
                                "origdate=%s\n"
                                "origtime=%ld\n"
-                               "category=%s\n",
+                               "category=%s\n"
+                               "msg_id=%s\n",
                                ext,
                                chan->context,
                                chan->macrocontext, 
@@ -5981,7 +6332,8 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                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);
@@ -6068,7 +6420,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                                        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);
                                                }
                                        }
@@ -6186,7 +6538,7 @@ static int say_and_wait(struct ast_channel *chan, int num, const char *language)
        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 */
@@ -6261,6 +6613,10 @@ static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg
                COPY(dir, msg, ddir, x, username, context, sfn, dfn);
        }
        ast_unlock_path(ddir);
+
+       if (newmsg) {
+               *newmsg = x;
+       }
 #endif
        return 0;
 }
@@ -7401,7 +7757,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                                        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);
@@ -7925,6 +8281,7 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
 
        /* traverses directory using readdir (or select query for ODBC) */
        count_msg = count_messages(vmu, vms->curdir);
+
        if (count_msg < 0) {
                return count_msg;
        } else {
@@ -8004,7 +8361,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
                        }
                } 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");
@@ -8014,7 +8371,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
                        }
                } 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;
@@ -9907,48 +10264,207 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
        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);
@@ -10510,7 +11026,7 @@ static int vm_execmain(struct ast_channel *chan, const char *data)
                                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;
@@ -13099,6 +13615,7 @@ static int unload_module(void)
        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");
@@ -13112,6 +13629,9 @@ static int unload_module(void)
 #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)
@@ -13150,6 +13670,7 @@ static int load_module(void)
        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);
@@ -13167,7 +13688,15 @@ static int load_module(void)
        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);
 
@@ -13676,6 +14205,796 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
        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)"
  */
index bd0353b074d15da07e0ea47ccd1f9e57b49f7b39..8f350c676f04afb3b8034bf358bf29595b6ab333 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 9b42007d14542ece8750dc22842448ead249f4e4..739141715e8801fc9d7b8685fa152f6c33f7be34 100644 (file)
@@ -40,6 +40,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index b102ea4260046583658ed752e427c3521043a9d4..4ebcedf62292b80d667a6d3369cdbad57bf33285 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
  
 #include "asterisk.h"
index 068b7a9a2f0035c6fb0dbab6bda91c0a33f502f6..a953941cde8e9842294dc72a5b381fd1b4038af7 100644 (file)
@@ -30,6 +30,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index e940b9353b0d3be7ad9d27c0e1d7f0b9022d27d4..79c989c902bb4881f909d6a2026d38bbf9d563e2 100644 (file)
@@ -31,6 +31,7 @@
 /*** MODULEINFO
        <depend>res_odbc</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index cd2a091fa119fddfa48441718e107a17214a3c91..7c59c5af459cd7fde878f8b4f9bb5b8c65583caf 100644 (file)
@@ -36,6 +36,7 @@
 /*** MODULEINFO
        <depend>pgsql</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 140e7a01c0fd3e569c1937cdc9c92e066bdf2b83..e974c62bd43be01fd584e1c56e313a8252d45d40 100644 (file)
@@ -30,6 +30,7 @@
 /*** MODULEINFO
        <depend>radius</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 28c85771236af7c5389e9669511d51f8dde46720..561d06aeac397f23ebcc50fed7594795a90dfb35 100644 (file)
@@ -37,6 +37,7 @@
 /*** MODULEINFO
        <depend>sqlite</depend>
        <support_level>deprecated</support_level>
+       <defaultenabled>no</defaultenabled>
        <replacement>sqlite3_custom</replacement>
  ***/
 
index 65ef5b8a2a8195a80e01a4729ac669f07a7291e7..ae247019d5a7adff39e4193472cabaffd7b642be 100644 (file)
@@ -35,6 +35,7 @@
 /*** MODULEINFO
        <depend>sqlite3</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index eead023fb067c2a52ef8a33620b3f189a8a55b8c..e1252b75462becb2616ebade068526db243b3586 100644 (file)
@@ -60,6 +60,7 @@ CREATE TABLE [dbo].[cdr] (
 /*** MODULEINFO
        <depend>freetds</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 99374a824e7c46ec2a3e5237a32940a9ca2c9292..05ab3c2459e939a39ffa92348a46af55e54f7a20 100644 (file)
@@ -40,6 +40,7 @@
 /*** MODULEINFO
        <depend>pgsql</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 9b6812dc0e93d375e3e9573e09698736a4c112bf..87967d03a62e334417434b3af7f4553869a52bc7 100644 (file)
@@ -29,6 +29,7 @@
 /*** MODULEINFO
        <depend>radius</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 444df77d3154f26bf77a51e3c9ec26ce2588c58c..87f5f552743897867b44fbd20f2ac09053743fbc 100644 (file)
@@ -37,6 +37,7 @@
 /*** MODULEINFO
        <depend>sqlite3</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index f5686c9b0cf7ddbe0ae050a99837d8867c71bfb0..c6dc42026ca7488c57ab0e5b5631b0a843ba8072 100644 (file)
@@ -57,6 +57,7 @@ CREATE TABLE [dbo].[cdr] (
 /*** MODULEINFO
        <depend>freetds</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 5014da5ab7b464eb9486f521c855afbc332e6e7f..0c2da6f3836699ee52beaf9855ee43bbc5433455 100644 (file)
@@ -30,6 +30,7 @@
 /*** MODULEINFO
        <depend>alsa</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 1217392eab15286ff1005f210fbda642a3e38d2e..b9e1e0c4c831e8cd59467955813540ebe2963ce7 100644 (file)
@@ -50,6 +50,7 @@
 /*** MODULEINFO
        <depend>portaudio</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 85d855bd8cdef3b26d91872bb2e4ead5c008e5e6..74a511b207e7e73bd126012ab0d358490f948f71 100644 (file)
@@ -36,6 +36,7 @@
        <depend>res_jabber</depend>
        <use>openssl</use>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 
index 907ae463de5eb252bacd856b59883de4fa398ccd..ee647a6d9ff092f63a3087a62f380cdf047eb989 100644 (file)
@@ -36,7 +36,7 @@
 
 /*** MODULEINFO
        <depend>openh323</depend>
-       <defaultenabled>yes</defaultenabled>
+       <defaultenabled>no</defaultenabled>
        <support_level>deprecated</support_level>
        <replacement>chan_ooh323</replacement>
  ***/
index 56c89a361d8e31c427838cba01b746f88ce8da31..db0c706cf655d11612d13510f90a9d93f4eeec19 100644 (file)
@@ -32,6 +32,7 @@
        <depend>res_jabber</depend>
        <use>openssl</use>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 01188ae1ecafc3f968fc20f8b6bf85ceee27285d..35d61b38c6d819911dd68b4270bbb9b60946f31a 100644 (file)
@@ -32,6 +32,7 @@
 /*** MODULEINFO
         <use>res_pktccops</use>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 7bcda32c42c8e0ca495813e2336604ba66701759..934972c1273cf4a091e1b4acf7212ef9a133ba6d 100644 (file)
@@ -54,6 +54,7 @@
        <depend>misdn</depend>
        <depend>suppserv</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index e242e0d2e788ce35d8c1b9dfe4872ce09f6acdc4..dcde12b3ae4eb9dd27fb8e5cb48d204d2fdf4496 100644 (file)
@@ -28,6 +28,7 @@
 /*** MODULEINFO
        <depend>nbs</depend>
        <support_level>extended</support_level> 
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index df25ceed8d757b900cd192908358c357dc38be19..6332e136bd336ba6566e09847324e1438da5d344 100644 (file)
@@ -36,6 +36,7 @@
 /*** MODULEINFO
        <depend>oss</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 584e8ea1e10291232cc6a5ca5c70f10083d97bcd..1ca21c630e65905c24db89bfe76d32238cf6f57d 100644 (file)
@@ -28,6 +28,7 @@
 /*** MODULEINFO
        <depend>ixjuser</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index facf60cd63bbb4a3b65b2cb599c0238651f598e0..bf54539d4b3760d256d3670a9f56ac2bbbae22b5 100644 (file)
@@ -264,6 +264,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #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"
@@ -337,6 +339,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <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.
@@ -667,7 +683,8 @@ static const struct sip_reasons {
        { 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"},
 };
 
 
@@ -1084,6 +1101,13 @@ static void destroy_escs(void)
        }
 }
 
+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.
@@ -1259,7 +1283,8 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old
 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);
@@ -1268,7 +1293,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
 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);
 
@@ -1356,7 +1381,8 @@ static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target
 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);
@@ -1491,7 +1517,7 @@ static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
 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);
@@ -1543,7 +1569,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
 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);
@@ -3836,7 +3862,10 @@ static int __sip_autodestruct(const void *data)
 
        /* 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>");
@@ -4488,7 +4517,7 @@ static int sip_sendtext(struct ast_channel *ast, const char *text)
                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;       
 }
 
@@ -6840,6 +6869,54 @@ static int initialize_udptl(struct sip_pvt *p)
        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
@@ -6969,6 +7046,11 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
        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);
@@ -12575,8 +12657,13 @@ static int find_calling_channel(void *obj, void *arg, void *data, int flags)
        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";
@@ -12584,7 +12671,7 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
        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;
@@ -12629,9 +12716,16 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
 
        /* 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++;
 
@@ -12679,12 +12773,23 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
                        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;
@@ -12761,7 +12866,7 @@ static void state_notify_build_xml(int state, int full, const char *exten, const
                        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);
@@ -12805,7 +12910,7 @@ static int transmit_cc_notify(struct ast_cc_agent *agent, struct sip_pvt *subscr
 }
 
 /*! \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];
@@ -12837,7 +12942,7 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
 
        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");
@@ -12860,19 +12965,19 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
        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;
@@ -13501,16 +13606,63 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
        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)
 {
@@ -13741,6 +13893,10 @@ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, uint32_t
                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);      
 }
 
@@ -14628,37 +14784,35 @@ static void cb_extensionstate_destroy(int id, void *data)
        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);
@@ -14666,6 +14820,27 @@ static int cb_extensionstate(char *context, char* exten, int state, void *data)
        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, &notify_data, p);
+}
+
 /*! \brief Send a fake 401 Unauthorized response when the administrator
   wants to hide the names of local devices  from fishers
  */
@@ -16145,6 +16320,9 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
                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);
                }
@@ -16360,16 +16538,54 @@ static int get_msg_text(char *buf, int len, struct sip_request *req)
        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? */
@@ -16378,7 +16594,15 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req)
                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) {
@@ -16387,32 +16611,132 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req)
                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 */
@@ -20561,9 +20885,15 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest
                                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;
@@ -20977,7 +21307,6 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req
 }
 
 /*!
- * \internal
  * \brief Handle responses to INFO messages
  *
  * \note The INFO method MUST NOT change the state of calls or
@@ -21013,6 +21342,43 @@ static void handle_response_info(struct sip_pvt *p, int resp, const char *rest,
 
 /*!
  * \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
@@ -21022,14 +21388,14 @@ static void handle_response_info(struct sip_pvt *p, int resp, const char *rest,
 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 */
@@ -21039,15 +21405,25 @@ static void handle_response_message(struct sip_pvt *p, int resp, const char *res
                }
                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;
        }
@@ -21526,11 +21902,11 @@ static void *sip_park_thread(void *stuff)
 
 #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
 
@@ -23487,6 +23863,8 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
        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",
@@ -23791,13 +24169,25 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
        }
        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);
 
@@ -24081,17 +24471,97 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
 }
 
 /*! \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);
@@ -24684,7 +25154,6 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
 {
        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;
@@ -25035,7 +25504,10 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
                                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);
@@ -25045,14 +25517,21 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *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");
@@ -25355,7 +25834,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as
                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);
@@ -27256,6 +27735,7 @@ static void set_peer_defaults(struct sip_peer *peer)
        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);
@@ -27553,6 +28033,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                        } 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")) {
@@ -28270,6 +28752,9 @@ static int reload_config(enum channelreloadreason reason)
        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 */
@@ -28520,6 +29005,12 @@ static int reload_config(enum channelreloadreason reason)
                        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")) {
@@ -29591,6 +30082,9 @@ static struct ast_rtp_glue sip_rtp_glue = {
 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)
@@ -29718,6 +30212,32 @@ static int sip_removeheader(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
@@ -30623,6 +31143,11 @@ static int load_module(void)
        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");
@@ -30652,6 +31177,9 @@ static int load_module(void)
        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);
@@ -30732,6 +31260,8 @@ static int unload_module(void)
        /* 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);
@@ -30742,8 +31272,9 @@ static int unload_module(void)
        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
index a92bd48bc897146cbc974195100569bcfd21e6f0..5d965157cc830ea2b3e8dade1619af118a33b364 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
@@ -1408,7 +1409,7 @@ static const struct ast_channel_tech skinny_tech = {
        .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)
@@ -2623,11 +2624,17 @@ static void transmit_softkeytemplateres(struct skinny_device *d)
 }
 
 
-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 */
index b07b8fa4f4242b68335b0dca914e902ca46338e4..8e1991106f2545107d4dd42ae198afbd6157200d 100644 (file)
@@ -34,6 +34,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 4ef73f9ffbb59ffb6588823e1e527edd914fa704..e4720f6961daa5d6aa842b1717f385de1409abdf 100644 (file)
 #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 */
@@ -686,6 +688,8 @@ struct sip_settings {
        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 */
@@ -704,6 +708,7 @@ struct sip_settings {
        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 */
@@ -946,6 +951,7 @@ struct sip_pvt {
                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 */
@@ -978,6 +984,9 @@ struct sip_pvt {
                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 */
@@ -1076,6 +1085,7 @@ struct sip_pvt {
        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 */
@@ -1180,6 +1190,7 @@ struct sip_peer {
                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 */
index 098122d9161d8cc060204e147653650ae5abe993..a8385686784acd67613faeef1e2fc2aeac767374 100644 (file)
@@ -34,3 +34,6 @@
                                        ; 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.
index fb44e74d4d3958cb76d5ae27f7d45078d3c4d6ac..c48f643bbd258bff0b7c99c84cc9ddebd919a7cc 100644 (file)
@@ -140,7 +140,9 @@ bindaddr = 0.0.0.0
 ; 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
 
index 7901be363564fa445f1ccbb986023341dcbd3487..bd5285517a7778b48aaab488ced97f79e9077c2c 100644 (file)
@@ -399,6 +399,21 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;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
index 8d8b029464483c1b8819d9378aeec360790c43e1..08a7e2e9db2bdeaf88b2ff8f7dd1049f326a9f6d 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
 #! /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>.
 #
@@ -94,7 +94,6 @@ fi
 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
@@ -220,18 +219,11 @@ IFS=$as_save_IFS
   # 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 :
@@ -1649,7 +1641,7 @@ Try \`$0 --help' for more information"
     $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
@@ -2024,7 +2016,7 @@ test -n "$ac_init_help" && exit $ac_status
 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
@@ -2072,7 +2064,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
 
        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
@@ -2109,7 +2101,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
 
     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
@@ -2122,10 +2114,10 @@ fi
 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
@@ -2192,7 +2184,7 @@ $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
 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"
@@ -2201,7 +2193,7 @@ eval ac_res=\$$3
               { $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
 
@@ -2242,7 +2234,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
        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
@@ -2256,7 +2248,7 @@ ac_fn_c_check_header_compile ()
   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
@@ -2274,7 +2266,7 @@ fi
 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
 
@@ -2311,7 +2303,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
 
        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
@@ -2348,7 +2340,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
 
     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
@@ -2394,7 +2386,7 @@ fi
   # 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
@@ -2407,7 +2399,7 @@ 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
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -2462,7 +2454,7 @@ fi
 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
 
@@ -2475,7 +2467,7 @@ 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" >&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"
@@ -2516,7 +2508,7 @@ fi
 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
 
@@ -2529,7 +2521,7 @@ ac_fn_c_check_member ()
   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
@@ -2573,7 +2565,7 @@ fi
 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
 
@@ -2750,7 +2742,7 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
 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
@@ -2763,10 +2755,10 @@ rm -f conftest.val
 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
@@ -2833,7 +2825,7 @@ $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
 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"
@@ -2842,7 +2834,7 @@ eval ac_res=\$$3
               { $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
 
@@ -2887,7 +2879,7 @@ fi
   # 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
@@ -2901,7 +2893,7 @@ ac_fn_cxx_check_header_compile ()
   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
@@ -2919,7 +2911,7 @@ fi
 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
@@ -2927,7 +2919,7 @@ This file contains any messages produced by compilers while
 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 $@
 
@@ -3185,7 +3177,7 @@ $as_echo "$as_me: loading site script $ac_site_file" >&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 $? "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
 
@@ -3315,7 +3307,7 @@ $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
 
 { $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
@@ -3331,7 +3323,7 @@ fi
 $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='-'
@@ -3349,7 +3341,7 @@ case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
 
 { $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
@@ -3364,7 +3356,7 @@ fi
 $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='-'
@@ -3443,7 +3435,7 @@ if test -n "$ac_tool_prefix"; 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
@@ -3483,7 +3475,7 @@ if test -z "$ac_cv_prog_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
@@ -3536,7 +3528,7 @@ if test -z "$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
@@ -3576,7 +3568,7 @@ if test -z "$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
@@ -3635,7 +3627,7 @@ if test -z "$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
@@ -3679,7 +3671,7 @@ do
 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
@@ -3734,7 +3726,7 @@ fi
 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
@@ -3849,7 +3841,7 @@ sed 's/^/| /' conftest.$ac_ext >&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; }
@@ -3892,7 +3884,7 @@ else
   { { $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
@@ -3951,7 +3943,7 @@ $as_echo "$ac_try_echo"; } >&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
@@ -3962,7 +3954,7 @@ rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
 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
@@ -4003,7 +3995,7 @@ sed 's/^/| /' conftest.$ac_ext >&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 $? "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
@@ -4013,7 +4005,7 @@ OBJEXT=$ac_cv_objext
 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
@@ -4050,7 +4042,7 @@ ac_test_CFLAGS=${CFLAGS+set}
 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
@@ -4128,7 +4120,7 @@ else
 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
@@ -4236,7 +4228,7 @@ if test -n "$CPP" && test -d "$CPP"; then
   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
@@ -4352,7 +4344,7 @@ else
   { { $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
@@ -4364,7 +4356,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 { $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
@@ -4427,7 +4419,7 @@ $as_echo "$ac_cv_path_GREP" >&6; }
 
 { $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
@@ -4494,7 +4486,7 @@ $as_echo "$ac_cv_path_EGREP" >&6; }
 
 { $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
@@ -4623,7 +4615,7 @@ done
 
 
   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=
@@ -4645,7 +4637,7 @@ $as_echo "#define _MINIX 1" >>confdefs.h
 
   { $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
@@ -4836,7 +4828,7 @@ if test -n "$ac_tool_prefix"; then
 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
@@ -4879,7 +4871,7 @@ if test -z "$ac_cv_path_UNAME"; then
 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
@@ -4946,7 +4938,7 @@ 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
@@ -4986,7 +4978,7 @@ if test -z "$ac_cv_prog_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
@@ -5038,7 +5030,7 @@ fi
 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
@@ -5078,7 +5070,7 @@ if test -z "$ac_cv_prog_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
@@ -5130,7 +5122,7 @@ fi
 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
@@ -5170,7 +5162,7 @@ if test -z "$ac_cv_prog_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
@@ -5222,7 +5214,7 @@ fi
 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
@@ -5262,7 +5254,7 @@ if test -z "$ac_cv_prog_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
@@ -5322,7 +5314,7 @@ if test -n "$ac_tool_prefix"; 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
@@ -5362,7 +5354,7 @@ if test -z "$ac_cv_prog_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
@@ -5415,7 +5407,7 @@ if test -z "$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
@@ -5455,7 +5447,7 @@ if test -z "$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
@@ -5514,7 +5506,7 @@ if test -z "$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
@@ -5558,7 +5550,7 @@ do
 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
@@ -5613,7 +5605,7 @@ fi
 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
@@ -5642,7 +5634,7 @@ done
 
 { $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
@@ -5679,7 +5671,7 @@ ac_test_CFLAGS=${CFLAGS+set}
 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
@@ -5757,7 +5749,7 @@ else
 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
@@ -5868,7 +5860,7 @@ if test -z "$CXX"; 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_CXX+:} false; then :
+if test "${ac_cv_prog_CXX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CXX"; then
@@ -5912,7 +5904,7 @@ do
 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
@@ -5990,7 +5982,7 @@ done
 
 { $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
@@ -6027,7 +6019,7 @@ ac_test_CXXFLAGS=${CXXFLAGS+set}
 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
@@ -6121,7 +6113,7 @@ if test -n "$CPP" && test -d "$CPP"; then
   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
@@ -6237,7 +6229,7 @@ else
   { { $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
@@ -6254,7 +6246,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
 { $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
@@ -6370,7 +6362,7 @@ else
   { { $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
@@ -6383,7 +6375,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 # 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/
@@ -6452,7 +6444,7 @@ $as_echo "$ac_cv_path_SED" >&6; }
 
 { $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
@@ -6512,7 +6504,7 @@ else
   { $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
@@ -6552,7 +6544,7 @@ fi
 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.
@@ -6576,7 +6568,7 @@ do
 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
@@ -6629,7 +6621,7 @@ done
 { $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
@@ -6721,7 +6713,7 @@ if test -n "$ac_tool_prefix"; 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
@@ -6761,7 +6753,7 @@ if test -z "$ac_cv_prog_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
@@ -6810,7 +6802,7 @@ fi
 
 { $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' ;
@@ -6838,7 +6830,7 @@ GNU_MAKE=$ac_cv_GNU_MAKE
 
 { $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
@@ -6911,7 +6903,7 @@ if test -n "$ac_tool_prefix"; 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_STRIP+:} false; then :
+if test "${ac_cv_prog_STRIP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$STRIP"; then
@@ -6955,7 +6947,7 @@ do
 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
@@ -7011,7 +7003,7 @@ if test -n "$ac_tool_prefix"; 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
@@ -7055,7 +7047,7 @@ do
 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
@@ -7111,7 +7103,7 @@ if test -n "$ac_tool_prefix"; 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
@@ -7155,7 +7147,7 @@ do
 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
@@ -7211,7 +7203,7 @@ if test -n "$ac_tool_prefix"; 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
@@ -7255,7 +7247,7 @@ do
 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
@@ -7315,7 +7307,7 @@ fi
 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
@@ -7356,7 +7348,7 @@ fi
 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
@@ -7397,7 +7389,7 @@ fi
 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
@@ -7438,7 +7430,7 @@ fi
 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
@@ -7479,7 +7471,7 @@ fi
 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
@@ -7520,7 +7512,7 @@ fi
 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
@@ -7561,7 +7553,7 @@ fi
 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
@@ -7602,7 +7594,7 @@ fi
 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
@@ -7643,7 +7635,7 @@ fi
 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
@@ -7684,7 +7676,7 @@ fi
 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
@@ -7725,7 +7717,7 @@ fi
 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
@@ -7766,7 +7758,7 @@ fi
 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
@@ -7807,7 +7799,7 @@ fi
 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
@@ -7848,7 +7840,7 @@ fi
 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
@@ -7889,7 +7881,7 @@ fi
 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
@@ -7930,7 +7922,7 @@ fi
 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
@@ -7971,7 +7963,7 @@ fi
 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
@@ -8012,7 +8004,7 @@ fi
 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
@@ -8058,7 +8050,7 @@ else
 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
@@ -8102,7 +8094,7 @@ fi
 
 { $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
 
@@ -8156,7 +8148,7 @@ if test -n "$ac_tool_prefix"; then
 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
@@ -8196,7 +8188,7 @@ if test -z "$ac_cv_prog_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
@@ -8255,7 +8247,7 @@ do
 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
@@ -8421,7 +8413,7 @@ $as_echo_n "checking whether pthreads work with $flag... " >&6; }
 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
@@ -8577,7 +8569,7 @@ do
 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
@@ -8659,7 +8651,7 @@ if test "${enable_dev_mode+set}" = set; 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
 
@@ -8672,7 +8664,7 @@ if test "${enable_coverage+set}" = set; then :
   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
 
@@ -9497,7 +9489,7 @@ do
 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
@@ -9545,7 +9537,7 @@ done
 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
@@ -9587,7 +9579,7 @@ fi
 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
@@ -9628,7 +9620,7 @@ fi
      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}'`
@@ -9642,7 +9634,7 @@ $as_echo "$libcurl_cv_lib_curl_version" >&6; }
         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
 
@@ -9696,7 +9688,7 @@ $as_echo "$libcurl_cv_lib_version_ok" >&6; }
 
         { $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
 
@@ -9755,7 +9747,7 @@ $as_echo "$libcurl_cv_lib_curl_usable" >&6; }
            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
@@ -11559,7 +11540,7 @@ fi
 
 { $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
@@ -11578,7 +11559,7 @@ else
  #pragma alloca
 #   else
 #    ifndef alloca /* predefined by HP cc +Olibcalls */
-void *alloca (size_t);
+char *alloca ();
 #    endif
 #   endif
 #  endif
@@ -11622,7 +11603,7 @@ $as_echo "#define C_ALLOCA 1" >>confdefs.h
 
 { $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
@@ -11663,7 +11644,7 @@ fi
 
 { $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 :
@@ -11716,7 +11697,7 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
   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
@@ -11756,7 +11737,7 @@ done
 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
@@ -11790,11 +11771,11 @@ for ac_lib in '' dir; do
 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
@@ -11813,7 +11794,7 @@ fi
 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
@@ -11847,11 +11828,11 @@ for ac_lib in '' x; do
 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
@@ -11871,7 +11852,7 @@ fi
 
 { $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
@@ -11983,7 +11964,7 @@ fi
 
 { $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
@@ -12057,7 +12038,7 @@ if test "x${PBX_TERMCAP}" != "x1" -a "${USE_TERMCAP}" != "no"; then
       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
@@ -12115,7 +12096,7 @@ fi
          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
@@ -12161,7 +12142,7 @@ if test "x${PBX_TINFO}" != "x1" -a "${USE_TINFO}" != "no"; then
       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
@@ -12219,7 +12200,7 @@ fi
          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
@@ -12265,7 +12246,7 @@ if test "x${PBX_CURSES}" != "x1" -a "${USE_CURSES}" != "no"; then
       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
@@ -12323,7 +12304,7 @@ fi
          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
@@ -12369,7 +12350,7 @@ if test "x${PBX_NCURSES}" != "x1" -a "${USE_NCURSES}" != "no"; then
       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
@@ -12427,7 +12408,7 @@ fi
          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
@@ -12474,7 +12455,7 @@ if test "${enable_xmldoc+set}" = set; then :
   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
@@ -12490,7 +12471,7 @@ if test "${disable_xmldoc}" != "yes"; then
 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
@@ -12534,7 +12515,7 @@ if test -z "$ac_cv_path_CONFIG_LIBXML2"; then
 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
@@ -12649,7 +12630,7 @@ fi
 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
@@ -12674,7 +12655,7 @@ done
 
 
 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
 
@@ -12693,7 +12674,7 @@ if test "$enable_largefile" != no; then
 
   { $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
@@ -12744,7 +12725,7 @@ $as_echo "$ac_cv_sys_largefile_CC" >&6; }
 
   { $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
@@ -12813,7 +12794,7 @@ rm -rf conftest*
   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
@@ -12886,7 +12867,7 @@ fi
 # 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
@@ -12918,7 +12899,7 @@ else
        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)];
@@ -12929,6 +12910,25 @@ else
        _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
@@ -12940,7 +12940,6 @@ int
 main ()
 {
 
-       bool e = &s;
        *pq |= q;
        *pq |= ! q;
        /* Refer to every declared value, to avoid compiler optimizations.  */
@@ -12961,7 +12960,7 @@ fi
 { $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
@@ -12978,7 +12977,7 @@ fi
 
 { $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
@@ -13058,7 +13057,7 @@ fi
 
 { $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
@@ -13088,7 +13087,7 @@ fi
 
 { $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
@@ -13131,7 +13130,7 @@ esac
 
   { $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
@@ -13180,7 +13179,7 @@ $as_echo "#define HAVE_LONG_DOUBLE_WIDER 1" >>confdefs.h
   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
 
@@ -13191,7 +13190,7 @@ _ACEOF
 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
 
@@ -13202,7 +13201,7 @@ _ACEOF
 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
 
@@ -13213,7 +13212,7 @@ _ACEOF
 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
 
@@ -13224,7 +13223,7 @@ _ACEOF
 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
@@ -13236,7 +13235,7 @@ fi
 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
@@ -13247,7 +13246,7 @@ fi
 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
@@ -13258,7 +13257,7 @@ fi
 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
@@ -13269,7 +13268,7 @@ fi
 
 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
@@ -13280,7 +13279,7 @@ fi
 
 { $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
@@ -13315,7 +13314,7 @@ fi
 
 { $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
@@ -13350,7 +13349,7 @@ fi
 
 { $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
@@ -13383,7 +13382,7 @@ $as_echo "#define volatile /**/" >>confdefs.h
 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
@@ -13397,7 +13396,7 @@ fi
 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
@@ -13408,7 +13407,7 @@ done
 
 { $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 :
@@ -13461,7 +13460,7 @@ fi
 
 { $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 :
@@ -13503,7 +13502,7 @@ fi
 
 { $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
@@ -13539,7 +13538,7 @@ fi
 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
@@ -13563,7 +13562,7 @@ done
 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 :
@@ -13616,7 +13615,7 @@ ac_cv_func_vfork_works=$ac_cv_func_vfork
 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 :
@@ -13753,7 +13752,7 @@ fi
 
 { $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
@@ -13822,7 +13821,7 @@ fi
 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'"
@@ -13867,7 +13866,7 @@ fi
 # 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 :
@@ -13954,7 +13953,7 @@ done
 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
@@ -13964,7 +13963,7 @@ done
 
 { $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 :
@@ -14143,7 +14142,7 @@ done
 
 { $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
@@ -14177,7 +14176,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
  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
@@ -14203,7 +14202,7 @@ _ACEOF
 
 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
@@ -14212,7 +14211,7 @@ fi
 
 { $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
@@ -14245,7 +14244,7 @@ _ACEOF
 
 { $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
@@ -14307,7 +14306,7 @@ fi
 
 { $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 :
@@ -14353,7 +14352,7 @@ fi
 
 { $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 :
@@ -14393,7 +14392,7 @@ fi
 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
@@ -14402,7 +14401,7 @@ else
   # 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
@@ -14436,7 +14435,7 @@ LIBS=$ac_check_lib_save_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.  */
@@ -14504,7 +14499,7 @@ esac
 
 { $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 :
@@ -14563,14 +14558,14 @@ if test $ac_cv_func_strtod = no; 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
@@ -14604,7 +14599,7 @@ LIBS=$ac_check_lib_save_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
@@ -14620,7 +14615,7 @@ fi
 
 { $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
@@ -14670,13 +14665,13 @@ rm -f 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
 
@@ -14703,7 +14698,7 @@ done
 # 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
@@ -14737,7 +14732,7 @@ LIBS=$ac_check_lib_save_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
@@ -14868,7 +14863,7 @@ LDFLAGS=${old_LDFLAGS}
 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
@@ -14882,7 +14877,7 @@ if test "${enable_internal_poll+set}" = set; then :
   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
 
@@ -14908,7 +14903,7 @@ done
 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
@@ -14948,7 +14943,7 @@ rm -f core conftest.err conftest.$ac_objext \
 # 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
@@ -14982,11 +14977,11 @@ for ac_lib in '' socket nsl; do
 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
@@ -15060,7 +15055,7 @@ rm -f core conftest.err conftest.$ac_objext \
     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
@@ -15128,7 +15123,7 @@ if test "${cross_compiling}" = "no";
 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 &&
@@ -15141,7 +15136,7 @@ fi
 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
 
@@ -15657,7 +15652,7 @@ if test "${ac_cv_have_variable_fdset}x" = "0x"; 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 $? "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.  */
@@ -16685,7 +16680,7 @@ rm -f core conftest.err conftest.$ac_objext \
 
 { $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
@@ -16719,11 +16714,11 @@ for ac_lib in '' resolv; do
 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
@@ -16770,7 +16765,7 @@ $as_echo "#define HAVE_RES_NINIT 1" >>confdefs.h
 
        { $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
@@ -16804,11 +16799,11 @@ for ac_lib in '' resolv; do
 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
@@ -16862,7 +16857,7 @@ rm -f core conftest.err conftest.$ac_objext \
     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
@@ -16896,11 +16891,11 @@ for ac_lib in '' resolv; do
 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
@@ -17102,7 +17097,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 
 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
@@ -17118,7 +17113,7 @@ fi
 # 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 :
@@ -17128,7 +17123,7 @@ else
      { { $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
@@ -17151,7 +17146,7 @@ _ACEOF
 # 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 :
@@ -17161,7 +17156,7 @@ else
      { { $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
@@ -17184,7 +17179,7 @@ _ACEOF
 # 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 :
@@ -17194,7 +17189,7 @@ else
      { { $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
@@ -17217,7 +17212,7 @@ _ACEOF
 # 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 :
@@ -17227,7 +17222,7 @@ else
      { { $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
@@ -17250,7 +17245,7 @@ _ACEOF
 # 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 :
@@ -17260,7 +17255,7 @@ else
      { { $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
@@ -17283,7 +17278,7 @@ _ACEOF
 # 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 :
@@ -17293,7 +17288,7 @@ else
      { { $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
@@ -17323,7 +17318,7 @@ 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 :
@@ -17333,7 +17328,7 @@ else
      { { $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
@@ -17409,7 +17404,7 @@ if test -n "$ac_tool_prefix"; then
 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
@@ -17449,7 +17444,7 @@ if test -z "$ac_cv_prog_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
@@ -17520,7 +17515,7 @@ if test "x${PBX_ALSA}" != "x1" -a "${USE_ALSA}" != "no"; 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
@@ -17578,7 +17573,7 @@ fi
          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
@@ -17625,7 +17620,7 @@ if test "x${PBX_BFD}" != "x1" -a "${USE_BFD}" != "no"; then
       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
@@ -17683,7 +17678,7 @@ fi
          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
@@ -17732,7 +17727,7 @@ if test "x${PBX_BFD}" != "x1" -a "${USE_BFD}" != "no"; then
       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
@@ -17790,7 +17785,7 @@ fi
          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
@@ -17839,7 +17834,7 @@ if test "x${PBX_CAP}" != "x1" -a "${USE_CAP}" != "no"; then
       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
@@ -17897,7 +17892,7 @@ fi
          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
@@ -18320,7 +18315,7 @@ if test "${USE_GSM}" != "no"; then
       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
@@ -18354,7 +18349,7 @@ LIBS=$ac_check_lib_save_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
@@ -18384,7 +18379,7 @@ fi
 
          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
@@ -18392,7 +18387,7 @@ fi
 
 
             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
@@ -18474,7 +18469,7 @@ if test "x${PBX_ICONV}" != "x1" -a "${USE_ICONV}" != "no"; then
       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
@@ -18532,7 +18527,7 @@ fi
          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
@@ -18579,7 +18574,7 @@ if test "x${PBX_ICONV}" != "x1" -a "${USE_ICONV}" != "no"; then
       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
@@ -18637,7 +18632,7 @@ fi
          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
@@ -18684,7 +18679,7 @@ if test "x${PBX_ICONV}" != "x1" -a "${USE_ICONV}" != "no"; then
       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
@@ -18742,7 +18737,7 @@ fi
          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
@@ -18790,7 +18785,7 @@ if test "x${PBX_ICAL}" != "x1" -a "${USE_ICAL}" != "no"; then
       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
@@ -18848,7 +18843,7 @@ fi
          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
@@ -18895,7 +18890,7 @@ if test "x${PBX_IKSEMEL}" != "x1" -a "${USE_IKSEMEL}" != "no"; then
       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
@@ -18953,7 +18948,7 @@ fi
          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
@@ -19628,7 +19623,7 @@ if test "x${PBX_IODBC}" != "x1" -a "${USE_IODBC}" != "no"; then
       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
@@ -19686,7 +19681,7 @@ fi
          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
@@ -19733,7 +19728,7 @@ if test "x${PBX_INOTIFY}" != "x1" -a "${USE_INOTIFY}" != "no"; then
       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
@@ -19791,7 +19786,7 @@ fi
          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
@@ -19838,7 +19833,7 @@ if test "x${PBX_JACK}" != "x1" -a "${USE_JACK}" != "no"; then
       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
@@ -19896,7 +19891,7 @@ fi
          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
@@ -19944,7 +19939,7 @@ if test "x${PBX_KQUEUE}" != "x1" -a "${USE_KQUEUE}" != "no"; then
       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
@@ -20002,7 +19997,7 @@ fi
          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
@@ -20033,7 +20028,7 @@ fi
 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
@@ -20063,7 +20058,7 @@ if test "x${PBX_LTDL}" != "x1" -a "${USE_LTDL}" != "no"; then
       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
@@ -20121,7 +20116,7 @@ fi
          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
@@ -20168,7 +20163,7 @@ if test "x${PBX_LDAP}" != "x1" -a "${USE_LDAP}" != "no"; then
       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
@@ -20226,7 +20221,7 @@ fi
          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
@@ -20273,7 +20268,7 @@ if test "x${PBX_MISDN}" != "x1" -a "${USE_MISDN}" != "no"; then
       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
@@ -20331,7 +20326,7 @@ fi
          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
@@ -20379,7 +20374,7 @@ if test "x${PBX_ISDNNET}" != "x1" -a "${USE_ISDNNET}" != "no"; then
       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
@@ -20437,7 +20432,7 @@ fi
          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
@@ -20483,7 +20478,7 @@ if test "x${PBX_SUPPSERV}" != "x1" -a "${USE_SUPPSERV}" != "no"; then
       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
@@ -20541,7 +20536,7 @@ fi
          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
@@ -20660,7 +20655,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 
    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
@@ -20671,7 +20666,7 @@ fi
 
    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
@@ -20687,7 +20682,7 @@ fi
 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
@@ -20731,7 +20726,7 @@ if test -z "$ac_cv_path_CONFIG_MYSQLCLIENT"; then
 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
@@ -20850,7 +20845,7 @@ if test "x${PBX_NBS}" != "x1" -a "${USE_NBS}" != "no"; then
       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
@@ -20908,7 +20903,7 @@ fi
          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
@@ -20943,7 +20938,7 @@ fi
 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
@@ -20987,7 +20982,7 @@ if test -z "$ac_cv_path_CONFIG_NEON"; then
 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
@@ -21094,7 +21089,7 @@ $as_echo "#define HAVE_NEON 1" >>confdefs.h
 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
@@ -21138,7 +21133,7 @@ if test -z "$ac_cv_path_CONFIG_NEON29"; then
 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
@@ -21247,7 +21242,7 @@ $as_echo "#define HAVE_NEON29 1" >>confdefs.h
 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
@@ -21291,7 +21286,7 @@ if test -z "$ac_cv_path_CONFIG_NETSNMP"; then
 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
@@ -21414,7 +21409,7 @@ if test "x${PBX_NEWT}" != "x1" -a "${USE_NEWT}" != "no"; then
       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
@@ -21472,7 +21467,7 @@ fi
          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
@@ -21519,7 +21514,7 @@ if test "x${PBX_UNIXODBC}" != "x1" -a "${USE_UNIXODBC}" != "no"; then
       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
@@ -21577,7 +21572,7 @@ fi
          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
@@ -21624,7 +21619,7 @@ if test "x${PBX_OGG}" != "x1" -a "${USE_OGG}" != "no"; then
       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
@@ -21682,7 +21677,7 @@ fi
          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
@@ -21730,7 +21725,7 @@ if test "x${PBX_BKTR}" != "x1" -a "${USE_BKTR}" != "no"; then
       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
@@ -21788,7 +21783,7 @@ fi
          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
@@ -21835,7 +21830,7 @@ if test "x${PBX_BKTR}" != "x1" -a "${USE_BKTR}" != "no"; then
       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
@@ -21893,7 +21888,7 @@ fi
          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
@@ -21940,7 +21935,7 @@ if test "x${PBX_BLUETOOTH}" != "x1" -a "${USE_BLUETOOTH}" != "no"; then
       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
@@ -21998,7 +21993,7 @@ fi
          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
@@ -22046,7 +22041,7 @@ if test "x${PBX_OSS}" != "x1" -a "${USE_OSS}" != "no"; then
       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
@@ -22104,7 +22099,7 @@ fi
          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
@@ -22150,7 +22145,7 @@ if test "x${PBX_OSS}" != "x1" -a "${USE_OSS}" != "no"; then
       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
@@ -22208,7 +22203,7 @@ fi
          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
@@ -22254,7 +22249,7 @@ if test "x${PBX_OSS}" != "x1" -a "${USE_OSS}" != "no"; then
       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
@@ -22312,7 +22307,7 @@ fi
          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
@@ -22347,7 +22342,7 @@ if test "${USE_PGSQL}" != "no"; then
 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
@@ -22390,7 +22385,7 @@ if test -z "$ac_cv_path_PG_CONFIG"; then
 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
@@ -22459,7 +22454,7 @@ $as_echo "$as_me: *** including --without-postgres" >&6;}
 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
@@ -22502,7 +22497,7 @@ if test -z "$ac_cv_path_PG_CONFIG"; then
 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
@@ -22572,7 +22567,7 @@ $as_echo "$as_me: *** including --without-postgres" >&6;}
    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
@@ -22606,7 +22601,7 @@ LIBS=$ac_check_lib_save_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
@@ -22688,7 +22683,7 @@ if test "x${PBX_POPT}" != "x1" -a "${USE_POPT}" != "no"; then
       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
@@ -22746,7 +22741,7 @@ fi
          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
@@ -22793,7 +22788,7 @@ if test "x${PBX_PORTAUDIO}" != "x1" -a "${USE_PORTAUDIO}" != "no"; then
       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
@@ -22851,7 +22846,7 @@ fi
          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
@@ -22898,7 +22893,7 @@ if test "x${PBX_PRI}" != "x1" -a "${USE_PRI}" != "no"; then
       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
@@ -22956,7 +22951,7 @@ fi
          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
@@ -23002,7 +22997,7 @@ if test "x${PBX_PRI_L2_PERSISTENCE}" != "x1" -a "${USE_PRI_L2_PERSISTENCE}" != "
       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
@@ -23060,7 +23055,7 @@ fi
          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
@@ -23106,7 +23101,7 @@ if test "x${PBX_PRI_MWI}" != "x1" -a "${USE_PRI_MWI}" != "no"; then
       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
@@ -23164,7 +23159,7 @@ fi
          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
@@ -23210,7 +23205,7 @@ if test "x${PBX_PRI_MCID}" != "x1" -a "${USE_PRI_MCID}" != "no"; then
       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
@@ -23268,7 +23263,7 @@ fi
          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
@@ -23314,7 +23309,7 @@ if test "x${PBX_PRI_CALL_WAITING}" != "x1" -a "${USE_PRI_CALL_WAITING}" != "no";
       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
@@ -23372,7 +23367,7 @@ fi
          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
@@ -23418,7 +23413,7 @@ if test "x${PBX_PRI_AOC_EVENTS}" != "x1" -a "${USE_PRI_AOC_EVENTS}" != "no"; the
       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
@@ -23476,7 +23471,7 @@ fi
          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
@@ -23522,7 +23517,7 @@ if test "x${PBX_PRI_TRANSFER}" != "x1" -a "${USE_PRI_TRANSFER}" != "no"; then
       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
@@ -23580,7 +23575,7 @@ fi
          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
@@ -23626,7 +23621,7 @@ if test "x${PBX_PRI_CCSS}" != "x1" -a "${USE_PRI_CCSS}" != "no"; then
       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
@@ -23684,7 +23679,7 @@ fi
          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
@@ -23730,7 +23725,7 @@ if test "x${PBX_PRI_HANGUP_FIX}" != "x1" -a "${USE_PRI_HANGUP_FIX}" != "no"; the
       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
@@ -23788,7 +23783,7 @@ fi
          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
@@ -23834,7 +23829,7 @@ if test "x${PBX_PRI_SUBADDR}" != "x1" -a "${USE_PRI_SUBADDR}" != "no"; then
       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
@@ -23892,7 +23887,7 @@ fi
          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
@@ -23938,7 +23933,7 @@ if test "x${PBX_PRI_CALL_HOLD}" != "x1" -a "${USE_PRI_CALL_HOLD}" != "no"; then
       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
@@ -23996,7 +23991,7 @@ fi
          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
@@ -24042,7 +24037,7 @@ if test "x${PBX_PRI_CALL_REROUTING}" != "x1" -a "${USE_PRI_CALL_REROUTING}" != "
       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
@@ -24100,7 +24095,7 @@ fi
          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
@@ -24146,7 +24141,7 @@ if test "x${PBX_PRI_SETUP_KEYPAD}" != "x1" -a "${USE_PRI_SETUP_KEYPAD}" != "no";
       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
@@ -24204,7 +24199,7 @@ fi
          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
@@ -24254,7 +24249,7 @@ if test "x${PBX_PRI_PROG_W_CAUSE}" != "x1" -a "${USE_PRI_PROG_W_CAUSE}" != "no";
       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
@@ -24312,7 +24307,7 @@ fi
          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
@@ -24358,7 +24353,7 @@ if test "x${PBX_PRI_INBANDDISCONNECT}" != "x1" -a "${USE_PRI_INBANDDISCONNECT}"
       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
@@ -24416,7 +24411,7 @@ fi
          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
@@ -24462,7 +24457,7 @@ if test "x${PBX_PRI_SERVICE_MESSAGES}" != "x1" -a "${USE_PRI_SERVICE_MESSAGES}"
       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
@@ -24520,7 +24515,7 @@ fi
          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
@@ -24566,7 +24561,7 @@ if test "x${PBX_PRI_REVERSE_CHARGE}" != "x1" -a "${USE_PRI_REVERSE_CHARGE}" != "
       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
@@ -24624,7 +24619,7 @@ fi
          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
@@ -24672,7 +24667,7 @@ if test "x${PBX_RESAMPLE}" != "x1" -a "${USE_RESAMPLE}" != "no"; then
       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
@@ -24730,7 +24725,7 @@ fi
          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
@@ -24839,7 +24834,7 @@ if test "x${PBX_SPANDSP}" != "x1" -a "${USE_SPANDSP}" != "no"; then
       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
@@ -24897,7 +24892,7 @@ fi
          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
@@ -24948,7 +24943,7 @@ if test "x${PBX_SPANDSP}" != "x1" -a "${USE_SPANDSP}" != "no"; then
       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
@@ -25006,7 +25001,7 @@ fi
          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
@@ -25054,7 +25049,7 @@ if test "x${PBX_SS7}" != "x1" -a "${USE_SS7}" != "no"; then
       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
@@ -25112,7 +25107,7 @@ fi
          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
@@ -25159,7 +25154,7 @@ if test "x${PBX_OPENR2}" != "x1" -a "${USE_OPENR2}" != "no"; then
       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
@@ -25217,7 +25212,7 @@ fi
          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
@@ -25292,7 +25287,7 @@ fi
       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
 
@@ -25302,7 +25297,7 @@ 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
@@ -25354,7 +25349,7 @@ fi
         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
 
@@ -25364,7 +25359,7 @@ 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
@@ -25743,7 +25738,7 @@ fi
       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
 
@@ -25762,7 +25757,7 @@ 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
 
@@ -26004,7 +25999,7 @@ if test "x${PBX_LUA}" != "x1" -a "${USE_LUA}" != "no"; then
       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
@@ -26062,7 +26057,7 @@ fi
          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
@@ -26117,7 +26112,7 @@ if test "x${PBX_LUA}" != "x1" -a "${USE_LUA}" != "no"; then
       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
@@ -26175,7 +26170,7 @@ fi
          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
@@ -26222,7 +26217,7 @@ if test "x${PBX_RADIUS}" != "x1" -a "${USE_RADIUS}" != "no"; then
       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
@@ -26280,7 +26275,7 @@ fi
          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
@@ -26336,7 +26331,7 @@ if test "x${PBX_OPENAIS}" != "x1" -a "${USE_OPENAIS}" != "no"; then
       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
@@ -26394,7 +26389,7 @@ fi
          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
@@ -26456,7 +26451,7 @@ if test "x${PBX_SPEEX}" != "x1" -a "${USE_SPEEX}" != "no"; then
       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
@@ -26514,7 +26509,7 @@ fi
          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
@@ -26562,7 +26557,7 @@ if test "x${PBX_SPEEX_PREPROCESS}" != "x1" -a "${USE_SPEEX_PREPROCESS}" != "no";
       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
@@ -26620,7 +26615,7 @@ fi
          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
@@ -26670,7 +26665,7 @@ if test "x${PBX_SPEEXDSP}" != "x1" -a "${USE_SPEEXDSP}" != "no"; then
       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
@@ -26728,7 +26723,7 @@ fi
          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
@@ -26780,7 +26775,7 @@ if test "x${PBX_SQLITE}" != "x1" -a "${USE_SQLITE}" != "no"; then
       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
@@ -26838,7 +26833,7 @@ fi
          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
@@ -26885,7 +26880,7 @@ if test "x${PBX_SQLITE3}" != "x1" -a "${USE_SQLITE3}" != "no"; then
       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
@@ -26943,7 +26938,7 @@ fi
          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
@@ -26990,7 +26985,7 @@ if test "x${PBX_CRYPTO}" != "x1" -a "${USE_CRYPTO}" != "no"; then
       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
@@ -27048,7 +27043,7 @@ fi
          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
@@ -27097,7 +27092,7 @@ if test "x${PBX_OPENSSL}" != "x1" -a "${USE_OPENSSL}" != "no"; then
       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
@@ -27155,7 +27150,7 @@ fi
          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
@@ -27201,7 +27196,7 @@ then
                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
@@ -27216,7 +27211,7 @@ fi
 
                        { $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
@@ -27250,7 +27245,7 @@ LIBS=$ac_check_lib_save_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
@@ -27268,7 +27263,7 @@ $as_echo_n "checking if OSP Toolkit version is compatible with app_osplookup...
   { { $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.  */
@@ -27334,7 +27329,7 @@ if test "x${PBX_SRTP}" != "x1" -a "${USE_SRTP}" != "no"; then
       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
@@ -27392,7 +27387,7 @@ fi
          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
@@ -27489,7 +27484,7 @@ fi
 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
@@ -27533,7 +27528,7 @@ if test -z "$ac_cv_path_CONFIG_GMIME"; then
 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
@@ -27668,7 +27663,7 @@ if test "x${PBX_HOARD}" != "x1" -a "${USE_HOARD}" != "no"; then
       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
@@ -27726,7 +27721,7 @@ fi
          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
@@ -27773,7 +27768,7 @@ if test "x${PBX_FREETDS}" != "x1" -a "${USE_FREETDS}" != "no"; then
       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
@@ -27831,7 +27826,7 @@ fi
          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
@@ -27860,7 +27855,7 @@ fi
 
 { $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
@@ -27894,7 +27889,7 @@ LIBS=$ac_check_lib_save_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
@@ -27925,7 +27920,7 @@ if test "x${PBX_TONEZONE}" != "x1" -a "${USE_TONEZONE}" != "no"; then
       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
@@ -27983,7 +27978,7 @@ fi
          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
@@ -28032,7 +28027,7 @@ if test "x${PBX_VORBIS}" != "x1" -a "${USE_VORBIS}" != "no"; then
       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
@@ -28090,7 +28085,7 @@ fi
          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
@@ -28137,7 +28132,7 @@ if test "x${PBX_VORBIS}" != "x1" -a "${USE_VORBIS}" != "no"; then
       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
@@ -28195,7 +28190,7 @@ fi
          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
@@ -28358,7 +28353,7 @@ if test "x${PBX_ZLIB}" != "x1" -a "${USE_ZLIB}" != "no"; then
       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
@@ -28416,7 +28411,7 @@ fi
          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
@@ -28475,7 +28470,7 @@ rm -f core conftest.err conftest.$ac_objext \
 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
@@ -28485,7 +28480,7 @@ fi
 
 
 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
@@ -28502,7 +28497,7 @@ ac_fn_c_check_header_compile "$LINENO" "linux/ixjuser.h" "ac_cv_header_linux_ixj
                                   #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
@@ -28613,7 +28608,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 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
@@ -28657,7 +28652,7 @@ if test -z "$ac_cv_path_CONFIG_SDL"; then
 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
@@ -28775,7 +28770,7 @@ if test "x${PBX_SDL_IMAGE}" != "x1" -a "${USE_SDL_IMAGE}" != "no"; then
       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
@@ -28833,7 +28828,7 @@ fi
          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
@@ -28879,7 +28874,7 @@ if test "x${PBX_FFMPEG}" != "x1" -a "${USE_FFMPEG}" != "no"; then
       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
@@ -28937,7 +28932,7 @@ fi
          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
@@ -28966,7 +28961,7 @@ fi
 
 # 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
@@ -28997,7 +28992,7 @@ if test "x${PBX_X11}" != "x1" -a "${USE_X11}" != "no"; then
       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
@@ -29055,7 +29050,7 @@ fi
          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
@@ -29105,7 +29100,7 @@ if test "x${PBX_X11}" != "x1" -a "${USE_X11}" != "no"; then
       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
@@ -29163,7 +29158,7 @@ fi
          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
@@ -29199,7 +29194,7 @@ if test "${cross_compiling}" = "no";
 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 &&
@@ -29212,7 +29207,7 @@ fi
 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
 
@@ -29878,21 +29873,10 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
      :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;}
@@ -29924,7 +29908,7 @@ LTLIBOBJS=$ac_ltlibobjs
 
 
 
-: "${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"
@@ -30025,7 +30009,6 @@ fi
 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
@@ -30333,7 +30316,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # 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
@@ -30395,7 +30378,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 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.
@@ -30522,7 +30505,7 @@ do
     "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
 }
@@ -30555,13 +30537,12 @@ $debug ||
 
 {
   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.
@@ -30583,7 +30564,7 @@ else
   ac_cs_awk_cr=$ac_cr
 fi
 
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
 _ACEOF
 
 
@@ -30611,7 +30592,7 @@ done
 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
@@ -30659,7 +30640,7 @@ t delim
 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"
 
@@ -30691,7 +30672,7 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
   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
 
@@ -30725,7 +30706,7 @@ fi # test -n "$CONFIG_FILES"
 # 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
 
@@ -30737,8 +30718,8 @@ _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
@@ -30839,7 +30820,7 @@ do
   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
@@ -30858,7 +30839,7 @@ do
     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 `:'.
@@ -30867,7 +30848,7 @@ do
           [\\/$]*) 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'"
@@ -30893,8 +30874,8 @@ $as_echo "$as_me: creating $ac_file" >&6;}
     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
@@ -31024,22 +31005,21 @@ s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
 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
  ;;
@@ -31050,20 +31030,20 @@ which seems to be undefined.  Please make sure it is defined" >&2;}
   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
  ;;
index 7a089eec3794d1b4e861e93ab0d0647693c94558..64da7546a5e3502453a7f916a9b4084c28519893 100644 (file)
@@ -26,6 +26,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
  
 #include "asterisk.h"
index 457c3c65ed18abfd339fb41fedb471d84e0c0309..7763c60c397f387275f8bc72cb61fe545c1feb75 100644 (file)
@@ -26,6 +26,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
  
 #include "asterisk.h"
index 0c1bc81cf6866b74c6fd41dd7419de91c3111b6b..2506686c37d9641641675409f0f9e3ac11069b6e 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
@@ -318,6 +319,9 @@ static void print_frame(struct ast_frame *frame)
                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;
index 1b4e7fb1b67f70deed9cb6a72de3c8bb23f12655..632e5edf14dd1685874484250b264bc21cc95930 100644 (file)
@@ -60,6 +60,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
diff --git a/funcs/func_presence_state.c b/funcs/func_presence_state.c
new file mode 100644 (file)
index 0000000..7383eb4
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * 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,
+);
index 560c8c1699b500c7f3007277211c748d439a48ed..057255fa6bf9b461c9277db9ba3dc467fbfe93dc 100644 (file)
@@ -47,6 +47,7 @@ int ast_cel_engine_init(void);                /*!< Provided by cel.c */
 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.
index edc6530619cda381466820c04dfd0a0bf4fa975f..3df813d037dc4bbe2391d27a52416dc59782c677 100644 (file)
 #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;
 
@@ -78,6 +81,27 @@ struct ast_ivr_menu {
        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...) \
@@ -134,23 +158,113 @@ int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int
 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
@@ -206,6 +320,133 @@ int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *c
  */
 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
 */
@@ -267,6 +508,29 @@ int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, in
  */
 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);
 
index e052f64781625a5a511d43cb06e3088747dedff9..eb25d27125f2cf69673af6467a5534ec364c8f13 100644 (file)
@@ -400,6 +400,7 @@ enum AST_REDIRECTING_REASON {
        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,
 };
 
 /*!
index 60ab9d18ff7cb87819b725860707c2572dcfa115..afe7d9beec8a4c23f08b8706a99ac31e54845025 100644 (file)
@@ -3507,4 +3507,14 @@ int ast_channel_get_cc_agent_type(struct ast_channel *chan, char *agent_type, si
 }
 #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 */
index 86c2bb5dd487692284143552a6408318f799180c..b2224415c17024d9b0d6451fb74142df500a3b68 100644 (file)
@@ -590,6 +590,65 @@ int config_text_file_save(const char *filename, const struct ast_config *cfg, co
 
 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
  *
diff --git a/include/asterisk/custom_control_frame.h b/include/asterisk/custom_control_frame.h
new file mode 100644 (file)
index 0000000..e96d710
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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
index 073d67bc6b9a14756fb36d8cd387e68a00533069..9401961a74d953e01c6f84957ee7a2e1f89dc703 100644 (file)
@@ -54,8 +54,11 @@ enum ast_event_type {
        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 */
@@ -283,8 +286,12 @@ enum ast_event_ie_type {
        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,
 };
 
 /*!
index 69de811652abc41ccc6ace7b44e7fd8ddc916f29..8e4d8469164a85c270d4bd0df894ba1eb14fc7ba 100644 (file)
@@ -48,7 +48,21 @@ struct ast_format;
 #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
@@ -160,6 +174,28 @@ int ast_waitstream_exten(struct ast_channel *c, const char *context);
  */
 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.  
  *
index 6dcabda1f5c7414372fb803874a43f262c5f2ac1..b9515f85896b790fb20ca2cfd4fd7ea52e6a1e58 100644 (file)
@@ -334,6 +334,7 @@ enum ast_control_frame_type {
        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 */
 };
index 6d7139ed8c4b9e2c56d54a268d90a6e5c3ee3e7e..8c627466cccfc410a68cc7404b6271f72942d363 100644 (file)
@@ -157,6 +157,7 @@ struct aji_client {
        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;
@@ -179,6 +180,7 @@ struct aji_client {
        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;
index 0748ca85c2f3e02ec0541340c76776c4895cbb88..c20cdbdb9193ad8ffe7f23d7ec4abc27252406b7 100644 (file)
@@ -86,6 +86,7 @@
 #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 */
diff --git a/include/asterisk/message.h b/include/asterisk/message.h
new file mode 100644 (file)
index 0000000..8564a6f
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * 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__ */
index 623451ef5d36c920b4793fad8334a8ab85d6629d..d2d05c5b7b53a39ddd94bccf3f56c49697694e44 100644 (file)
@@ -26,6 +26,7 @@
 #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"
@@ -75,8 +76,23 @@ struct ast_include;
 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);
@@ -401,6 +417,22 @@ enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devst
  */
 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
  *
diff --git a/include/asterisk/presencestate.h b/include/asterisk/presencestate.h
new file mode 100644 (file)
index 0000000..0304423
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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
index e2881cfb518f629e21bd1bb96d3bd3186c9bd387..70d804d4fcc85c7599cade63cced594a187f1b10 100644 (file)
@@ -277,18 +277,98 @@ static int (*ast_inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsg
 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)
@@ -298,8 +378,34 @@ 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;
@@ -313,6 +419,28 @@ int ast_app_has_voicemail(const char *mailbox, const char *folder)
        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)
 {
@@ -380,6 +508,108 @@ int ast_app_messagecount(const char *context, const char *mailbox, const char *f
        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;
@@ -562,10 +792,16 @@ int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, in
        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;
@@ -637,7 +873,11 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
                                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) {
@@ -701,6 +941,28 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
        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;
index d7c5e005a3387f74d343988fd94b0b4c2f1060fb..d8bc71886a14c8512ed9bdbe307e5897780aaa96 100644 (file)
@@ -139,6 +139,7 @@ int daemon(int, int);  /* defined in libresolv of all places */
 #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"
@@ -3854,6 +3855,11 @@ int main(int argc, char *argv[])
        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());
@@ -3894,6 +3900,11 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       if (ast_presence_state_engine_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
        ast_dsp_init();
        ast_udptl_init();
 
index 525c853152c800a250966974795c0f5785b6b6d9..1c496e6e6b1e57411556e8eca92008553573d14e 100644 (file)
@@ -1207,6 +1207,7 @@ static const struct ast_value_translation redirecting_reason_types[] = {
        { 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* */
 };
 
index 4276d530d132eb8a1ea45507a4ffa9af4d310915..c3d2bf8ae58f9724e067839120dc3b6d542582c5 100644 (file)
@@ -4319,6 +4319,7 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
        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;
@@ -4507,6 +4508,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
        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. */
@@ -9612,3 +9614,8 @@ struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_
 
        return result;
 }
+
+void ast_channel_unlink(struct ast_channel *chan)
+{
+       ao2_unlink(channels, chan);
+}
index 4c8714260867cdf0040554ba730983fa36ea76ac..e30ccc3a80dce6fa837d2694b95f29539e36e064 100644 (file)
@@ -69,6 +69,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 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;
@@ -2279,12 +2282,44 @@ static struct ast_config_engine text_file_engine = {
        .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) {
@@ -2311,10 +2346,12 @@ struct ast_config *ast_config_internal_load(const char *filename, struct ast_con
 
        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;
 }
@@ -2950,6 +2987,89 @@ static struct ast_cli_entry cli_config[] = {
        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));
diff --git a/main/custom_control_frame.c b/main/custom_control_frame.c
new file mode 100644 (file)
index 0000000..b72ee5d
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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;
+}
index 7714ad107c9397d7fe9cf19ce0e379b5d83f2061..f499ac7c6ab9eadebceb4f1c0b2ff2807e49f2e0 100644 (file)
@@ -141,6 +141,7 @@ static int ast_event_cmp(void *obj, void *arg, int flags);
 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
@@ -185,6 +186,11 @@ static struct {
                .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, },
+       },
+
 };
 
 /*!
@@ -1586,6 +1592,22 @@ static int ast_event_hash_devstate_change(const void *obj, const int flags)
        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;
index b684b8bcff0559d38f1f46dcb748bab7075846b2..ba4f9bd16930ee9cca365ff6f7ae9824d4c49ca0 100644 (file)
@@ -49,6 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #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"
@@ -378,6 +379,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <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 */
@@ -7049,6 +7061,41 @@ static struct ast_cli_entry cli_features[] = {
        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
@@ -7065,6 +7112,7 @@ static int manager_parking_status(struct mansession *s, const struct message *m)
        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);
@@ -7081,6 +7129,7 @@ static int manager_parking_status(struct mansession *s, const struct message *m)
                                "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"
@@ -7089,7 +7138,8 @@ static int manager_parking_status(struct mansession *s, const struct message *m)
                                "\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> */
@@ -8213,6 +8263,7 @@ int ast_features_init(void)
                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);
        }
index e978fab95c05b9a80de24e180ac6ce52a02aeb42..f778d445c41816c3600afcfe02a981cef7c6ea10 100644 (file)
@@ -1181,11 +1181,18 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
 /*!
  * \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)
@@ -1201,6 +1208,11 @@ static int waitstream_core(struct ast_channel *c, const char *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;
@@ -1262,6 +1274,7 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
                                                return res;
                                        }
                                } else {
+                                       enum ast_waitstream_fr_cb_values cb_val = 0;
                                        res = fr->subclass.integer;
                                        if (strchr(forward, res)) {
                                                int eoftest;
@@ -1272,13 +1285,19 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
                                                } 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:
@@ -1328,21 +1347,32 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
        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)
@@ -1353,7 +1383,7 @@ 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 */);
 }
 
 /*
index a61487b284748f191ae451cd5708ad6c1191b189..eaf8bd9282d5d33a1053d02fd0578b191851ecc4 100644 (file)
@@ -1175,6 +1175,7 @@ static const struct permalias {
        { EVENT_FLAG_CC, "cc" },
        { EVENT_FLAG_AOC, "aoc" },
        { EVENT_FLAG_TEST, "test" },
+       { EVENT_FLAG_MESSAGE, "message" },
        { INT_MAX, "all" },
        { 0, "none" },
 };
@@ -5245,10 +5246,17 @@ int ast_manager_unregister(char *action)
        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);
diff --git a/main/message.c b/main/message.c
new file mode 100644 (file)
index 0000000..1c4b10a
--- /dev/null
@@ -0,0 +1,1307 @@
+/*
+ * 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" &lt;URI&gt;.</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;
+}
index 3ecdb5c1d4ef9f7e26fe15cf62d99c94a256b953..ca81632e83384f4ac0ac3eebb5581e0f7dc0d704 100644 (file)
@@ -64,6 +64,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #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"
@@ -817,7 +818,7 @@ AST_APP_OPTIONS(waitexten_opts, {
 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);
@@ -962,8 +963,16 @@ struct ast_hint {
         * 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. */
 };
@@ -989,6 +998,13 @@ static const struct cfextension_states {
        { 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];
@@ -1159,6 +1175,8 @@ static char *overrideswitch = NULL;
 
 /*! \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;
@@ -4348,6 +4366,41 @@ enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devst
 
        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)
 {
@@ -4356,7 +4409,7 @@ 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, "&"))) {
@@ -4414,6 +4467,206 @@ int ast_extension_state(struct ast_channel *c, const char *context, const char *
        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;
@@ -4446,7 +4699,8 @@ static int handle_statechange(void *datap)
 
                /* 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. */
@@ -4489,14 +4743,24 @@ static int handle_statechange(void *datap)
                /* 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);
        }
@@ -4668,7 +4932,6 @@ int ast_extension_state_del(int id, ast_state_cb_type change_cb)
        return ret;
 }
 
-
 static int hint_id_cmp(void *obj, void *arg, int flags)
 {
        const struct ast_state_cb *cb = obj;
@@ -4703,15 +4966,21 @@ static void destroy_hint(void *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 */
@@ -4752,6 +5021,9 @@ static int ast_add_hint(struct ast_exten *e)
 {
        struct ast_hint *hint_new;
        struct ast_hint *hint_found;
+       char *message = NULL;
+       char *subtype = NULL;
+       int presence_state;
 
        if (!e) {
                return -1;
@@ -4775,6 +5047,12 @@ static int ast_add_hint(struct ast_exten *e)
        }
        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);
@@ -7263,6 +7541,10 @@ struct store_hint {
        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];
 };
@@ -7464,6 +7746,13 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
                        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);
                }
@@ -7517,8 +7806,15 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
                                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);
                }
        }
@@ -7533,11 +7829,17 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_
        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);
        }
 
@@ -10238,6 +10540,51 @@ static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
        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;
@@ -10252,7 +10599,7 @@ static void device_state_cb(const struct ast_event *event, void *unused)
        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);
        }
 }
@@ -10284,6 +10631,9 @@ static int hints_data_provider_get(const struct ast_data_search *search,
                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)) {
@@ -10310,7 +10660,7 @@ int load_pbx(void)
 
        /* 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");
        }
 
@@ -10337,6 +10687,11 @@ int load_pbx(void)
                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;
 }
 
diff --git a/main/presencestate.c b/main/presencestate.c
new file mode 100644 (file)
index 0000000..967276e
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * 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;
+}
+
index 94a6212fa402226834f5ef1992ed10714102777d..70b19131413d934468b06b519d09859d9c3611a6 100644 (file)
@@ -25,6 +25,7 @@
 /*** MODULEINFO
        <depend>res_ael_share</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 558b6274718469b749ee05b868526122052c37d4..805f216ab24342a50635550000ee1feefdea35dd 100644 (file)
@@ -25,6 +25,7 @@
        <depend>zlib</depend>
        <use>crypto</use>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index f302041f0b20da0f7d97ab5aa58e839a507afdcf..0fbb85293bfee8476e107f0f556e4c578aa1b8d7 100644 (file)
@@ -27,6 +27,7 @@
 /*** MODULEINFO
        <depend>lua</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 82261b17976c6a9903302cdcde6d74b4c17316d0..a10e49e4fb5024a354b2bad25632e241d450b028 100644 (file)
@@ -25,6 +25,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index f1ae9f33f548cddd86ff182764c25a72a6c090f5..713f46b02582be000548118016842ae3e452e823 100644 (file)
@@ -27,6 +27,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 9d378158608780966f7b727be12f3f1acefb3e3c..a35ce04fad56fe801f2e0ed0ab4b09c6f10c1c9a 100644 (file)
@@ -35,6 +35,7 @@
 /*** MODULEINFO
        <depend>ais</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 0af926d5a1a020cd94a55c605bd98ad3898b2f9e..c4d5ce214da81610ba19fe6f95a5d5f34f949069 100644 (file)
@@ -34,6 +34,7 @@
 /*** MODULEINFO
        <depend>ldap</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 2251c4097d07a61fa6b0758fb0b9fbbf6c96a4ec..940eecdd212a3c0a0ef6653065b9fce84293df4c 100644 (file)
@@ -25,6 +25,7 @@
 /*** MODULEINFO
        <depend>pgsql</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 5dfbab1bcb69f3676cb74a2b227d69c4c4bd0843..8139e9092c60adda06c90c571670b09214d23d72 100644 (file)
@@ -74,6 +74,7 @@
 /*** MODULEINFO
        <depend>sqlite</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 02549f23d3791e2f9ce6056f0d0899c37da6bc30..27cf82f56cf4a93e91960eecf27c00a5656130b2 100644 (file)
@@ -29,6 +29,7 @@
        <depend>spandsp</depend>
        <depend>res_fax</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
 ***/
 
 #include "asterisk.h"
index 6b8c79a20e48266758bc9048a98eb81637ce96a2..3ef99815a37563fccbdf311ea443b66710782d28 100644 (file)
@@ -34,6 +34,7 @@
        <depend>iksemel</depend>
        <use>openssl</use>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
@@ -61,6 +62,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/manager.h"
 #include "asterisk/event.h"
 #include "asterisk/devicestate.h"
+#include "asterisk/message.h"
 
 /*** DOCUMENTATION
        <application name="JabberSend" language="en_US">
@@ -372,6 +374,13 @@ static int aji_register_transport(void *data, ikspak *pak);
 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"),
@@ -1140,6 +1149,44 @@ static int aji_send_exec(struct ast_channel *chan, const char *data)
        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
@@ -2228,6 +2275,7 @@ static void aji_handle_message(struct aji_client *client, ikspak *pak)
 {
        struct aji_message *insert;
        int deleted = 0;
+       struct ast_msg *msg;
 
        ast_debug(3, "client %s received a message\n", client->name);
 
@@ -2259,6 +2307,25 @@ static void aji_handle_message(struct aji_client *client, ikspak *pak)
                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);
@@ -4277,6 +4344,7 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
        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;
@@ -4294,6 +4362,7 @@ static int aji_create_client(char *label, struct ast_variable *var, int 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;
@@ -4385,6 +4454,10 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
                        } 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"))
@@ -4592,6 +4665,13 @@ static int aji_load_config(int reload)
  * (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)
 {
@@ -4708,7 +4788,7 @@ static int aji_reload(int reload)
  */
 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);
@@ -4761,6 +4841,7 @@ static int load_module(void)
        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);
index c6dc009eaa4a65a8c53484f908671c4a793397a1..c9c3eca211c7c7d96cde40934543782da1e291f1 100644 (file)
@@ -28,6 +28,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index f717cead0ed753360c49d50f575dd2158db11068..811e479da1721f1626b179f656c208fbc4f98574 100644 (file)
@@ -20,6 +20,7 @@
 /*** MODULEINFO
        <depend>netsnmp</depend>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 57091bf413d6ec0a2542013950be2ff320b41b6d..8e8e3b16c2f416a8e6c02b3f35fd8ea1804b2073 100644 (file)
@@ -27,6 +27,7 @@
        <depend>kqueue</depend>
        <conflict>launchd</conflict>
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 654f1d082943d0346b0e812041f81faf2c4cb9aa..7f0a8617f21f4830cd89ca26606c931435cc601b 100644 (file)
@@ -25,6 +25,7 @@
 
 /*** MODULEINFO
        <support_level>extended</support_level>
+       <defaultenabled>no</defaultenabled>
  ***/
 
 #include "asterisk.h"
index 1a58e46ffc3736a306b180e3ec7a57ad61321a75..5f5e7351f07d47d3d8a3a3258ffaf34bbe132ef5 100644 (file)
@@ -39,6 +39,343 @@ ASTERISK_FILE_VERSION(__FILE__, "")
 #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,
@@ -276,14 +613,18 @@ AST_TEST_DEFINE(ast_parse_arg_test)
 
 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");
diff --git a/tests/test_custom_control.c b/tests/test_custom_control.c
new file mode 100644 (file)
index 0000000..605c129
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * 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");
diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c
new file mode 100644 (file)
index 0000000..f405978
--- /dev/null
@@ -0,0 +1,1400 @@
+/*
+ * 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");