From: Jason Parker Date: Tue, 31 Jul 2012 20:59:52 +0000 (+0000) Subject: Merge changes for Digium phone support, and default module building. X-Git-Tag: certified/1.8.28-cert1-rc1~2^2~2^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e809cb8d4e7f3c3da6358ba0332463e30d59e45;p=thirdparty%2Fasterisk.git Merge changes for Digium phone support, and default module building. 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 --- diff --git a/apps/app_adsiprog.c b/apps/app_adsiprog.c index 430d8258d6..5593bcc2ef 100644 --- a/apps/app_adsiprog.c +++ b/apps/app_adsiprog.c @@ -28,6 +28,7 @@ /*** MODULEINFO res_adsi extended + no ***/ #include "asterisk.h" diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c index 4062ec9f01..3066a7d8d7 100644 --- a/apps/app_alarmreceiver.c +++ b/apps/app_alarmreceiver.c @@ -31,6 +31,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_amd.c b/apps/app_amd.c index 679e0aebbd..3c915701d9 100644 --- a/apps/app_amd.c +++ b/apps/app_amd.c @@ -28,6 +28,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c index bb1a492fb3..f5b3131c51 100644 --- a/apps/app_chanisavail.c +++ b/apps/app_chanisavail.c @@ -29,6 +29,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 18cfb746c7..ddde433168 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -28,6 +28,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_dahdibarge.c b/apps/app_dahdibarge.c index d5e0329b93..a7f1dd8fa4 100644 --- a/apps/app_dahdibarge.c +++ b/apps/app_dahdibarge.c @@ -34,6 +34,7 @@ /*** MODULEINFO dahdi deprecated + no app_chanspy ***/ diff --git a/apps/app_dahdiras.c b/apps/app_dahdiras.c index fbaf984505..bde8b9c418 100644 --- a/apps/app_dahdiras.c +++ b/apps/app_dahdiras.c @@ -28,6 +28,7 @@ /*** MODULEINFO dahdi extended + no ***/ #include "asterisk.h" diff --git a/apps/app_dictate.c b/apps/app_dictate.c index 5057dcf424..2c7a319a58 100644 --- a/apps/app_dictate.c +++ b/apps/app_dictate.c @@ -29,6 +29,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_externalivr.c b/apps/app_externalivr.c index b05baed7bc..42c795aa46 100644 --- a/apps/app_externalivr.c +++ b/apps/app_externalivr.c @@ -33,6 +33,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_festival.c b/apps/app_festival.c index 2ed226c83e..8a6633fa3e 100644 --- a/apps/app_festival.c +++ b/apps/app_festival.c @@ -29,6 +29,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_getcpeid.c b/apps/app_getcpeid.c index 7f59976eb2..4d6a2ab2e9 100644 --- a/apps/app_getcpeid.c +++ b/apps/app_getcpeid.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_ices.c b/apps/app_ices.c index dbe3ec9f4e..e2d7be1fa7 100644 --- a/apps/app_ices.c +++ b/apps/app_ices.c @@ -29,6 +29,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_image.c b/apps/app_image.c index 160a285697..0c127870d7 100644 --- a/apps/app_image.c +++ b/apps/app_image.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_jack.c b/apps/app_jack.c index 5ba5d9ac00..32d1bf0d82 100644 --- a/apps/app_jack.c +++ b/apps/app_jack.c @@ -38,6 +38,7 @@ jack resample extended + no ***/ #include "asterisk.h" diff --git a/apps/app_minivm.c b/apps/app_minivm.c index dc81d3f15a..9fbbab0b4c 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -143,6 +143,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index 86237b3b30..01075062ba 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -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 @@ -93,6 +95,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") of x (range -4 to 4) + @@ -151,6 +160,54 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") This action may be used to mute a MixMonitor recording. + + + 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. + + + + + Used to specify the channel to record. + + + 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. + + + 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. + + + + This action records the audio on the current channel to the specified file. + + + Will contain the filename used to record the mixed stream. + + + + + + + Stop recording a call through MixMonitor, and free the recording's file handle. + + + + + The name of the channel monitored. + + + + This action stops the audio recording that was started with the MixMonitor + action on the current channel. + + ***/ @@ -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; } diff --git a/apps/app_morsecode.c b/apps/app_morsecode.c index 2d7c117d19..38acc6e509 100644 --- a/apps/app_morsecode.c +++ b/apps/app_morsecode.c @@ -26,6 +26,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_mp3.c b/apps/app_mp3.c index 0a2be4c3ed..745c203e7c 100644 --- a/apps/app_mp3.c +++ b/apps/app_mp3.c @@ -30,6 +30,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_nbscat.c b/apps/app_nbscat.c index e8bbd4a272..9779ebb38e 100644 --- a/apps/app_nbscat.c +++ b/apps/app_nbscat.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_osplookup.c b/apps/app_osplookup.c index 9dbf39752a..87d20e06dc 100644 --- a/apps/app_osplookup.c +++ b/apps/app_osplookup.c @@ -32,6 +32,7 @@ osptk openssl extended + no ***/ #include "asterisk.h" diff --git a/apps/app_queue.c b/apps/app_queue.c index adedad72a7..4609f6e980 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -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); diff --git a/apps/app_readfile.c b/apps/app_readfile.c index 3c7629e722..18aea8e6c6 100644 --- a/apps/app_readfile.c +++ b/apps/app_readfile.c @@ -27,6 +27,7 @@ /*** MODULEINFO deprecated + no func_env (FILE()) ***/ diff --git a/apps/app_setcallerid.c b/apps/app_setcallerid.c index f6b9036756..bcb9371748 100644 --- a/apps/app_setcallerid.c +++ b/apps/app_setcallerid.c @@ -27,6 +27,7 @@ /*** MODULEINFO deprecated + no func_callerid ***/ diff --git a/apps/app_sms.c b/apps/app_sms.c index 86ab0bce42..77005c61cd 100644 --- a/apps/app_sms.c +++ b/apps/app_sms.c @@ -36,6 +36,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_talkdetect.c b/apps/app_talkdetect.c index d8a6155c1f..9c8c25ce2e 100644 --- a/apps/app_talkdetect.c +++ b/apps/app_talkdetect.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_test.c b/apps/app_test.c index 9ef8dfb7a6..5806c4b0df 100644 --- a/apps/app_test.c +++ b/apps/app_test.c @@ -29,6 +29,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_url.c b/apps/app_url.c index 00ea720472..faaa6f6de9 100644 --- a/apps/app_url.c +++ b/apps/app_url.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index b1b201e409..5d03fb7a17 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -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$") + + + Play a single voice mail msg from a mailbox by msg id. + + + + + + + + The msg id of the msg to play back. + + + + This application sets the following channel variable upon completion: + + + The status of the playback attempt as a text string. + + + + + + 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 /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)" */ diff --git a/apps/app_waitforring.c b/apps/app_waitforring.c index bd0353b074..8f350c676f 100644 --- a/apps/app_waitforring.c +++ b/apps/app_waitforring.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_waitforsilence.c b/apps/app_waitforsilence.c index 9b42007d14..739141715e 100644 --- a/apps/app_waitforsilence.c +++ b/apps/app_waitforsilence.c @@ -40,6 +40,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/apps/app_zapateller.c b/apps/app_zapateller.c index b102ea4260..4ebcedf622 100644 --- a/apps/app_zapateller.c +++ b/apps/app_zapateller.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c index 068b7a9a2f..a953941cde 100644 --- a/cdr/cdr_csv.c +++ b/cdr/cdr_csv.c @@ -30,6 +30,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c index e940b9353b..79c989c902 100644 --- a/cdr/cdr_odbc.c +++ b/cdr/cdr_odbc.c @@ -31,6 +31,7 @@ /*** MODULEINFO res_odbc extended + no ***/ #include "asterisk.h" diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c index cd2a091fa1..7c59c5af45 100644 --- a/cdr/cdr_pgsql.c +++ b/cdr/cdr_pgsql.c @@ -36,6 +36,7 @@ /*** MODULEINFO pgsql extended + no ***/ #include "asterisk.h" diff --git a/cdr/cdr_radius.c b/cdr/cdr_radius.c index 140e7a01c0..e974c62bd4 100644 --- a/cdr/cdr_radius.c +++ b/cdr/cdr_radius.c @@ -30,6 +30,7 @@ /*** MODULEINFO radius extended + no ***/ #include "asterisk.h" diff --git a/cdr/cdr_sqlite.c b/cdr/cdr_sqlite.c index 28c8577123..561d06aeac 100644 --- a/cdr/cdr_sqlite.c +++ b/cdr/cdr_sqlite.c @@ -37,6 +37,7 @@ /*** MODULEINFO sqlite deprecated + no sqlite3_custom ***/ diff --git a/cdr/cdr_sqlite3_custom.c b/cdr/cdr_sqlite3_custom.c index 65ef5b8a2a..ae247019d5 100644 --- a/cdr/cdr_sqlite3_custom.c +++ b/cdr/cdr_sqlite3_custom.c @@ -35,6 +35,7 @@ /*** MODULEINFO sqlite3 extended + no ***/ #include "asterisk.h" diff --git a/cdr/cdr_tds.c b/cdr/cdr_tds.c index eead023fb0..e1252b7546 100644 --- a/cdr/cdr_tds.c +++ b/cdr/cdr_tds.c @@ -60,6 +60,7 @@ CREATE TABLE [dbo].[cdr] ( /*** MODULEINFO freetds extended + no ***/ #include "asterisk.h" diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c index 99374a824e..05ab3c2459 100644 --- a/cel/cel_pgsql.c +++ b/cel/cel_pgsql.c @@ -40,6 +40,7 @@ /*** MODULEINFO pgsql extended + no ***/ #include "asterisk.h" diff --git a/cel/cel_radius.c b/cel/cel_radius.c index 9b6812dc0e..87967d03a6 100644 --- a/cel/cel_radius.c +++ b/cel/cel_radius.c @@ -29,6 +29,7 @@ /*** MODULEINFO radius extended + no ***/ #include "asterisk.h" diff --git a/cel/cel_sqlite3_custom.c b/cel/cel_sqlite3_custom.c index 444df77d31..87f5f55274 100644 --- a/cel/cel_sqlite3_custom.c +++ b/cel/cel_sqlite3_custom.c @@ -37,6 +37,7 @@ /*** MODULEINFO sqlite3 extended + no ***/ #include "asterisk.h" diff --git a/cel/cel_tds.c b/cel/cel_tds.c index f5686c9b0c..c6dc42026c 100644 --- a/cel/cel_tds.c +++ b/cel/cel_tds.c @@ -57,6 +57,7 @@ CREATE TABLE [dbo].[cdr] ( /*** MODULEINFO freetds extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index 5014da5ab7..0c2da6f383 100644 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -30,6 +30,7 @@ /*** MODULEINFO alsa extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_console.c b/channels/chan_console.c index 1217392eab..b9e1e0c4c8 100644 --- a/channels/chan_console.c +++ b/channels/chan_console.c @@ -50,6 +50,7 @@ /*** MODULEINFO portaudio extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c index 85d855bd8c..74a511b207 100644 --- a/channels/chan_gtalk.c +++ b/channels/chan_gtalk.c @@ -36,6 +36,7 @@ res_jabber openssl extended + no ***/ diff --git a/channels/chan_h323.c b/channels/chan_h323.c index 907ae463de..ee647a6d9f 100644 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -36,7 +36,7 @@ /*** MODULEINFO openh323 - yes + no deprecated chan_ooh323 ***/ diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c index 56c89a361d..db0c706cf6 100644 --- a/channels/chan_jingle.c +++ b/channels/chan_jingle.c @@ -32,6 +32,7 @@ res_jabber openssl extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 01188ae1ec..35d61b38c6 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -32,6 +32,7 @@ /*** MODULEINFO res_pktccops extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index 7bcda32c42..934972c127 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -54,6 +54,7 @@ misdn suppserv extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c index e242e0d2e7..dcde12b3ae 100644 --- a/channels/chan_nbs.c +++ b/channels/chan_nbs.c @@ -28,6 +28,7 @@ /*** MODULEINFO nbs extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_oss.c b/channels/chan_oss.c index df25ceed8d..6332e136bd 100644 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -36,6 +36,7 @@ /*** MODULEINFO oss extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 584e8ea1e1..1ca21c630e 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -28,6 +28,7 @@ /*** MODULEINFO ixjuser extended + no ***/ #include "asterisk.h" diff --git a/channels/chan_sip.c b/channels/chan_sip.c index facf60cd63..bf54539d4b 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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$") Always returns 0. + + + Send a custom INFO frame on specified channels. + + + + + + + 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. + + 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 : ""); @@ -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, "open\n"); else ast_str_append(tmp, 0, "%s\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed"); + + if (allow_notify_user_presence(p) && (data->presence_state > 0)) { + ast_str_append(tmp, 0, "\n"); + ast_str_append(tmp, 0, "\n"); + ast_str_append(tmp, 0, "\n"); + ast_str_append(tmp, 0, "%s\n", + ast_presence_state2str(data->presence_state), + S_OR(data->presence_subtype, ""), + S_OR(data->presence_message, "")); + ast_str_append(tmp, 0, "\n"); + } ast_str_append(tmp, 0, "\n\n"); break; case DIALOG_INFO_XML: /* SNOM subscribes in this format */ ast_str_append(tmp, 0, "\n"); ast_str_append(tmp, 0, "\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, "\n", exten); } ast_str_append(tmp, 0, "%s\n", statestring); - if (state == AST_EXTENSION_ONHOLD) { + if (data->state == AST_EXTENSION_ONHOLD) { ast_str_append(tmp, 0, "\n\n" "\n" "\n\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, ¬ify_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 diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index a92bd48bc8..5d965157cc 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #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 */ diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index b07b8fa4f4..8e1991106f 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -34,6 +34,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 4ef73f9ffb..e4720f6961 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -211,6 +211,8 @@ #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 */ diff --git a/configs/jabber.conf.sample b/configs/jabber.conf.sample index 098122d916..a838568678 100644 --- a/configs/jabber.conf.sample +++ b/configs/jabber.conf.sample @@ -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. diff --git a/configs/manager.conf.sample b/configs/manager.conf.sample index fb44e74d4d..c48f643bbd 100644 --- a/configs/manager.conf.sample +++ b/configs/manager.conf.sample @@ -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 diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index 7901be3635..bd5285517a 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -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 diff --git a/configure b/configure index 8d8b029464..08a7e2e9db 100755 --- 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 . # @@ -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 @@ -11511,22 +11503,11 @@ fi # 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 #include " -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 #include " -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 #include " -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 " -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" @@ -14445,17 +14444,13 @@ fi 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 " -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 " -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 " -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 @@ -30544,10 +30527,9 @@ fi # 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 = "" @@ -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 ;; diff --git a/formats/format_jpeg.c b/formats/format_jpeg.c index 7a089eec37..64da7546a5 100644 --- a/formats/format_jpeg.c +++ b/formats/format_jpeg.c @@ -26,6 +26,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/formats/format_vox.c b/formats/format_vox.c index 457c3c65ed..7763c60c39 100644 --- a/formats/format_vox.c +++ b/formats/format_vox.c @@ -26,6 +26,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/funcs/func_frame_trace.c b/funcs/func_frame_trace.c index 0c1bc81cf6..2506686c37 100644 --- a/funcs/func_frame_trace.c +++ b/funcs/func_frame_trace.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #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; diff --git a/funcs/func_pitchshift.c b/funcs/func_pitchshift.c index 1b4e7fb1b6..632e5edf14 100644 --- a/funcs/func_pitchshift.c +++ b/funcs/func_pitchshift.c @@ -60,6 +60,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/funcs/func_presence_state.c b/funcs/func_presence_state.c new file mode 100644 index 0000000000..7383eb428b --- /dev/null +++ b/funcs/func_presence_state.c @@ -0,0 +1,595 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * David Vossel + * + * 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 +#endif + +/*** DOCUMENTATION + + + Get or Set a presence state. + + + + The provider of the presence, such as CustomPresence + + + Which field of the presence state information is wanted. + + + + + + + + + + + + + + The PRESENCE_STATE function can be used to retrieve the presence from any + presence provider. For example: + NoOp(SIP/mypeer has presence ${PRESENCE_STATE(SIP/mypeer,value)}) + NoOp(Conference number 1234 has presence message ${PRESENCE_STATE(MeetMe:1234,message)}) + The PRESENCE_STATE function can also be used to set custom presence state from + the dialplan. The CustomPresence: prefix must be used. For example: + Set(PRESENCE_STATE(CustomPresence:lamp1)=away,temporary,Out to lunch) + Set(PRESENCE_STATE(CustomPresence:lamp2)=dnd,,Trying to get work done) + You can subscribe to the status of a custom presence state using a hint in + the dialplan: + exten => 1234,hint,CustomPresence:lamp1 + The possible values for both uses of this function are: + not_set | unavailable | available | away | xa | chat | dnd + + + ***/ + + +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, +); diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index 560c8c1699..057255fa6b 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -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. diff --git a/include/asterisk/app.h b/include/asterisk/app.h index edc6530619..3df813d037 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -23,8 +23,11 @@ #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); diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h index e052f64781..eb25d27125 100644 --- a/include/asterisk/callerid.h +++ b/include/asterisk/callerid.h @@ -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, }; /*! diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 60ab9d18ff..afe7d9beec 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -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 */ diff --git a/include/asterisk/config.h b/include/asterisk/config.h index 86c2bb5dd4..b2224415c1 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -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 index 0000000000..e96d7107f3 --- /dev/null +++ b/include/asterisk/custom_control_frame.h @@ -0,0 +1,79 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * David Vossel + * + * 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 diff --git a/include/asterisk/event_defs.h b/include/asterisk/event_defs.h index 073d67bc6b..9401961a74 100644 --- a/include/asterisk/event_defs.h +++ b/include/asterisk/event_defs.h @@ -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, }; /*! diff --git a/include/asterisk/file.h b/include/asterisk/file.h index 69de811652..8e4d846916 100644 --- a/include/asterisk/file.h +++ b/include/asterisk/file.h @@ -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. * diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 6dcabda1f5..b9515f8589 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -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 */ }; diff --git a/include/asterisk/jabber.h b/include/asterisk/jabber.h index 6d7139ed8c..8c627466cc 100644 --- a/include/asterisk/jabber.h +++ b/include/asterisk/jabber.h @@ -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; diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 0748ca85c2..c20cdbdb91 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -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 index 0000000000..8564a6f646 --- /dev/null +++ b/include/asterisk/message.h @@ -0,0 +1,272 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Digium, Inc. + * + * Russell Bryant + * + * 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 + * + * 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__ */ diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 623451ef5d..d2d05c5b7b 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -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 index 0000000000..0304423705 --- /dev/null +++ b/include/asterisk/presencestate.h @@ -0,0 +1,95 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * David Vossel + * + * 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 diff --git a/main/app.c b/main/app.c index e2881cfb51..70d804d4fc 100644 --- a/main/app.c +++ b/main/app.c @@ -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; diff --git a/main/asterisk.c b/main/asterisk.c index d7c5e005a3..d8bc71886a 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -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(); diff --git a/main/callerid.c b/main/callerid.c index 525c853152..1c496e6e6b 100644 --- a/main/callerid.c +++ b/main/callerid.c @@ -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* */ }; diff --git a/main/channel.c b/main/channel.c index 4276d530d1..c3d2bf8ae5 100644 --- a/main/channel.c +++ b/main/channel.c @@ -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); +} diff --git a/main/config.c b/main/config.c index 4c87142608..e30ccc3a80 100644 --- a/main/config.c +++ b/main/config.c @@ -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 index 0000000000..b72ee5dad0 --- /dev/null +++ b/main/custom_control_frame.c @@ -0,0 +1,190 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * David Vossel + * + * 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 + */ + +#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; +} diff --git a/main/event.c b/main/event.c index 7714ad107c..f499ac7c6a 100644 --- a/main/event.c +++ b/main/event.c @@ -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; diff --git a/main/features.c b/main/features.c index b684b8bcff..ba4f9bd169 100644 --- a/main/features.c +++ b/main/features.c @@ -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$") Bridge together two channels already in the PBX. + + + Get a list of parking lots + + + + + + List all parking lots as a series of AMI events + + ***/ #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 */ 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 */ @@ -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); } diff --git a/main/file.c b/main/file.c index e978fab95c..f778d445c4 100644 --- a/main/file.c +++ b/main/file.c @@ -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 */); } /* diff --git a/main/manager.c b/main/manager.c index a61487b284..eaf8bd9282 100644 --- a/main/manager.c +++ b/main/manager.c @@ -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 index 0000000000..1c4b10a67b --- /dev/null +++ b/main/message.c @@ -0,0 +1,1307 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Digium, Inc. + * + * Russell Bryant + * + * 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 + */ + +#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 + + + Create a message or read fields from a message. + + + + Field of the message to get or set. + + + 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. + + + Read-only. The source of the message. When processing an + incoming message, this will be set to the source of the message. + + + Write-only. Mark or unmark all message headers for an outgoing + message. The following values can be set: + + + Mark all headers for an outgoing message. + + + Unmark all headers for an outgoing message. + + + + + 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. + + + + + + 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. + + + MessageSend + + + + + Read or write custom data attached to a message. + + + + Field of the message to get or set. + + + + 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. + NOTE: If you want to set an outbound message to carry data in the + current message, do Set(MESSAGE_DATA(key)=${MESSAGE_DATA(key)}). + + + MessageSend + + + + + Send a text message. + + + + A To URI for the message. + + + A From URI for the message if needed for the + message technology being used to send this message. + + + + Send a text message. The body of the message that will be + sent is what is currently set to MESSAGE(body). + + This application sets the following channel variables: + + + This is the time from dialing a channel until when it is disconnected. + + No handler for the technology part of the URI was found. + + + The protocol handler reported that the URI was not valid. + + + Successfully passed on to the protocol handler, but delivery has not necessarily been guaranteed. + + + The protocol handler reported that it was unabled to deliver the message for some reason. + + + + + + + + Send an out of call message to an endpoint. + + + + + The URI the message is to be sent to. + + + A From URI for the message if needed for the + message technology being used to send this message. + + For SIP the from parameter can be a configured peer name + or in the form of "display-name" <URI>. + + + + The message body text. This must not contain any newlines as that + conflicts with the AMI protocol. + + + 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. + + + Message variable to set, multiple Variable: headers are + allowed. The header value is a comma separated list of + name=value pairs. + + + + ***/ + +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; +} diff --git a/main/pbx.c b/main/pbx.c index 3ecdb5c1d4..ca81632e83 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -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 index 0000000000..967276ee78 --- /dev/null +++ b/main/presencestate.c @@ -0,0 +1,285 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * David Vossel + * + * 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; +} + diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c index 94a6212fa4..70b1913141 100644 --- a/pbx/pbx_ael.c +++ b/pbx/pbx_ael.c @@ -25,6 +25,7 @@ /*** MODULEINFO res_ael_share extended + no ***/ #include "asterisk.h" diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c index 558b627471..805f216ab2 100644 --- a/pbx/pbx_dundi.c +++ b/pbx/pbx_dundi.c @@ -25,6 +25,7 @@ zlib crypto extended + no ***/ #include "asterisk.h" diff --git a/pbx/pbx_lua.c b/pbx/pbx_lua.c index f302041f0b..0fbb85293b 100644 --- a/pbx/pbx_lua.c +++ b/pbx/pbx_lua.c @@ -27,6 +27,7 @@ /*** MODULEINFO lua extended + no ***/ #include "asterisk.h" diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c index 82261b1797..a10e49e4fb 100644 --- a/pbx/pbx_realtime.c +++ b/pbx/pbx_realtime.c @@ -25,6 +25,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/res/res_ael_share.c b/res/res_ael_share.c index f1ae9f33f5..713f46b025 100644 --- a/res/res_ael_share.c +++ b/res/res_ael_share.c @@ -27,6 +27,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/res/res_ais.c b/res/res_ais.c index 9d37815860..a35ce04fad 100644 --- a/res/res_ais.c +++ b/res/res_ais.c @@ -35,6 +35,7 @@ /*** MODULEINFO ais extended + no ***/ #include "asterisk.h" diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 0af926d5a1..c4d5ce214d 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -34,6 +34,7 @@ /*** MODULEINFO ldap extended + no ***/ #include "asterisk.h" diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index 2251c4097d..940eecdd21 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -25,6 +25,7 @@ /*** MODULEINFO pgsql extended + no ***/ #include "asterisk.h" diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c index 5dfbab1bcb..8139e9092c 100644 --- a/res/res_config_sqlite.c +++ b/res/res_config_sqlite.c @@ -74,6 +74,7 @@ /*** MODULEINFO sqlite extended + no ***/ #include "asterisk.h" diff --git a/res/res_fax_spandsp.c b/res/res_fax_spandsp.c index 02549f23d3..27cf82f56c 100644 --- a/res/res_fax_spandsp.c +++ b/res/res_fax_spandsp.c @@ -29,6 +29,7 @@ spandsp res_fax extended + no ***/ #include "asterisk.h" diff --git a/res/res_jabber.c b/res/res_jabber.c index 6b8c79a20e..3ef99815a3 100644 --- a/res/res_jabber.c +++ b/res/res_jabber.c @@ -34,6 +34,7 @@ iksemel openssl extended + no ***/ #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 @@ -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); diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c index c6dc009eaa..c9c3eca211 100644 --- a/res/res_phoneprov.c +++ b/res/res_phoneprov.c @@ -28,6 +28,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/res/res_snmp.c b/res/res_snmp.c index f717cead0e..811e479da1 100644 --- a/res/res_snmp.c +++ b/res/res_snmp.c @@ -20,6 +20,7 @@ /*** MODULEINFO netsnmp extended + no ***/ #include "asterisk.h" diff --git a/res/res_timing_kqueue.c b/res/res_timing_kqueue.c index 57091bf413..8e8e3b16c2 100644 --- a/res/res_timing_kqueue.c +++ b/res/res_timing_kqueue.c @@ -27,6 +27,7 @@ kqueue launchd extended + no ***/ #include "asterisk.h" diff --git a/res/res_timing_pthread.c b/res/res_timing_pthread.c index 654f1d0829..7f0a8617f2 100644 --- a/res/res_timing_pthread.c +++ b/res/res_timing_pthread.c @@ -25,6 +25,7 @@ /*** MODULEINFO extended + no ***/ #include "asterisk.h" diff --git a/tests/test_config.c b/tests/test_config.c index 1a58e46ffc..5f5e7351f0 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -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 index 0000000000..605c129761 --- /dev/null +++ b/tests/test_custom_control.c @@ -0,0 +1,235 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2011, Digium, Inc. + * + * David Vossel + * + * 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 + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#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 index 0000000000..f405978ec2 --- /dev/null +++ b/tests/test_voicemail_api.c @@ -0,0 +1,1400 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2012, Matt Jordan + * + * Matt Jordan + * + * 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 \endverbatim + * + * Tests for the publicly exposed Voicemail API + * \ingroup tests + */ + +/*** MODULEINFO + TEST_FRAMEWORK + core + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include + +#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");