[svn-commits] mmichelson: branch 10-digiumphones r361199 - /branches/10-digiumphones/main/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Apr 4 14:05:27 CDT 2012


Author: mmichelson
Date: Wed Apr  4 14:05:22 2012
New Revision: 361199

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=361199
Log:
Update everything in the main directory for Digium phone additions.


Added:
    branches/10-digiumphones/main/custom_control_frame.c   (with props)
    branches/10-digiumphones/main/presencestate.c   (with props)
Modified:
    branches/10-digiumphones/main/app.c
    branches/10-digiumphones/main/asterisk.c
    branches/10-digiumphones/main/channel.c
    branches/10-digiumphones/main/config.c
    branches/10-digiumphones/main/event.c
    branches/10-digiumphones/main/features.c
    branches/10-digiumphones/main/file.c
    branches/10-digiumphones/main/manager.c
    branches/10-digiumphones/main/pbx.c

Modified: branches/10-digiumphones/main/app.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/app.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/app.c (original)
+++ branches/10-digiumphones/main/app.c Wed Apr  4 14:05:22 2012
@@ -274,18 +274,21 @@
 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;
 
 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))
 {
 	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;
 }
 
 void ast_uninstall_vm_functions(void)
@@ -295,6 +298,7 @@
 	ast_inboxcount2_func = NULL;
 	ast_messagecount_func = NULL;
 	ast_sayname_func = NULL;
+	ast_copy_recording_to_vm_func = NULL;
 }
 
 int ast_app_has_voicemail(const char *mailbox, const char *folder)
@@ -309,7 +313,29 @@
 	}
 	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)
 {
@@ -560,10 +586,16 @@
 	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;
@@ -634,7 +666,11 @@
 				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) {
@@ -696,6 +732,28 @@
 	ast_stopstream(chan);
 
 	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)

Modified: branches/10-digiumphones/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/asterisk.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/asterisk.c (original)
+++ branches/10-digiumphones/main/asterisk.c Wed Apr  4 14:05:22 2012
@@ -136,6 +136,7 @@
 #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"
@@ -3893,6 +3894,11 @@
 		exit(1);
 	}
 
+	if (ast_presence_state_engine_init()) {
+		printf("%s", term_quit());
+		exit(1);
+	}
+
 	ast_dsp_init();
 	ast_udptl_init();
 

Modified: branches/10-digiumphones/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/channel.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/channel.c (original)
+++ branches/10-digiumphones/main/channel.c Wed Apr  4 14:05:22 2012
@@ -4365,6 +4365,7 @@
 	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_MCID:
 	case AST_CONTROL_UPDATE_RTP_PEER:
@@ -4554,6 +4555,7 @@
 	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_MCID:
 	case AST_CONTROL_UPDATE_RTP_PEER:

Modified: branches/10-digiumphones/main/config.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/config.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/config.c (original)
+++ branches/10-digiumphones/main/config.c Wed Apr  4 14:05:22 2012
@@ -64,6 +64,9 @@
 
 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 {
@@ -2265,12 +2268,44 @@
 	.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) {
@@ -2297,10 +2332,12 @@
 
 	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;
 }
@@ -2893,6 +2930,89 @@
 	AST_CLI_DEFINE(handle_cli_config_reload, "Force a reload on modules using a particular configuration file"),
 	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)
 {

Added: branches/10-digiumphones/main/custom_control_frame.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/custom_control_frame.c?view=auto&rev=361199
==============================================================================
--- branches/10-digiumphones/main/custom_control_frame.c (added)
+++ branches/10-digiumphones/main/custom_control_frame.c Wed Apr  4 14:05:22 2012
@@ -1,0 +1,191 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2011-2012, Digium, Inc.
+ *
+ * David Vossel <dvosse at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Encode and Decode custom control frame payload types.
+ *
+ * \author David Vossel <dvossel at digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/_private.h"
+
+#include "asterisk/custom_control_frame.h"
+
+struct ast_custom_payload {
+	enum ast_custom_payload_type type;
+	/*! length of data portion only */
+	size_t datalen;
+	char *data;
+};
+
+enum ast_custom_payload_type ast_custom_payload_type(struct ast_custom_payload *type)
+{
+	return type->type;
+}
+
+size_t ast_custom_payload_len(struct ast_custom_payload *type)
+{
+	return type->datalen + sizeof(struct ast_custom_payload);
+}
+
+struct custom_sipinfo {
+	size_t num_headers;
+	int content_present;
+	int useragent_filter_present;
+	char *data;
+};
+
+struct ast_custom_payload *ast_custom_payload_sipinfo_encode(struct ast_variable *headers,
+	const char *content_type,
+	const char *content,
+	const char *useragent_filter)
+{
+	int num_headers = 0;
+	int content_present = 0;
+	int content_strlen = 0;
+	int content_type_strlen = 0;
+	int useragent_filter_present = 0;
+	int useragent_filter_len = 0;
+	size_t datalen = 0;
+	struct ast_variable *var;
+	struct ast_custom_payload *payload;
+	struct custom_sipinfo *sipinfo;
+	char *data;
+
+	datalen += sizeof(struct custom_sipinfo);
+
+	for (var = headers; var; var = var->next) {
+		datalen += strlen(var->name) + 1;
+		datalen += strlen(var->value) + 1;
+		num_headers++;
+	}
+
+	if (!ast_strlen_zero(content_type) && !ast_strlen_zero(content)) {
+		content_type_strlen = strlen(content_type);
+		content_strlen = strlen(content);
+		datalen += content_type_strlen + 1;
+		datalen += content_strlen + 1;
+		content_present = 1;
+	}
+
+	if (!ast_strlen_zero(useragent_filter)) {
+		useragent_filter_len = strlen(useragent_filter);
+		datalen += useragent_filter_len + 1;
+		useragent_filter_present = 1;
+	}
+
+	if (!(payload = ast_calloc(1, datalen + sizeof(*payload)))) {
+		return NULL;
+	}
+
+	payload->type = AST_CUSTOM_SIP_INFO;
+	payload->datalen = datalen;
+	payload->data = (char *) payload + sizeof(struct ast_custom_payload);
+	sipinfo = (struct custom_sipinfo *) payload->data;
+	sipinfo->num_headers = num_headers;
+	sipinfo->content_present = content_present;
+	sipinfo->useragent_filter_present = useragent_filter_present;
+	sipinfo->data = (char *) sipinfo + sizeof(struct custom_sipinfo);
+
+	/* store string buffers in payload data
+	 * headers are put in first, followed by content type and then content body. */
+	data = sipinfo->data;
+
+	for (var = headers; var; var = var->next) {
+		int namelen = strlen(var->name);
+		int vallen = strlen(var->value);
+
+		/*! we already know we have enough room for each of these */
+		ast_copy_string(data, var->name, namelen+1);
+		data += namelen + 1; /* skip over the '\0' character */
+		ast_copy_string(data, var->value, vallen+1);
+		data += vallen + 1; /* skip over the '\0' character */
+	}
+
+	if (content_present) {
+		ast_copy_string(data, content_type, content_type_strlen+1);
+		data += content_type_strlen + 1;
+		ast_copy_string(data, content, content_strlen+1);
+		data += content_strlen + 1;
+	}
+
+	if (useragent_filter_present) {
+		ast_copy_string(data, useragent_filter, useragent_filter_len+1);
+	}
+
+	return payload;
+}
+
+int ast_custom_payload_sipinfo_decode(struct ast_custom_payload *pl,
+	struct ast_variable **headers,
+	char **content_type,
+	char **content,
+	char **useragent_filter)
+{
+	struct custom_sipinfo *sipinfo;
+	struct ast_variable *cur = NULL;
+	char *data;
+	int i;
+
+	*headers = NULL;
+	*content_type = NULL;
+	*content = NULL;
+	*useragent_filter = NULL;
+
+	if (pl->type != AST_CUSTOM_SIP_INFO) {
+		return -1;
+	}
+
+	sipinfo = (struct custom_sipinfo *) pl->data;
+	data = sipinfo->data;
+	for (i = 0; i < sipinfo->num_headers; i++) {
+		const char *name;
+		const char *value;
+
+		name = data;
+		data += strlen(name) + 1;
+		value = data;
+		data += strlen(value) + 1;
+
+		if (*headers) {
+			if ((cur->next = ast_variable_new(name, value, ""))) {
+				cur = cur->next;
+			}
+		} else {
+			*headers = cur = ast_variable_new(name, value, "");
+		}
+	}
+
+	if (sipinfo->content_present) {
+		*content_type = ast_strdup(data);
+		data += strlen(data) + 1;
+		*content = ast_strdup(data);
+		data += strlen(data) + 1;
+	}
+
+	if (sipinfo->useragent_filter_present) {
+		*useragent_filter = ast_strdup(data);
+	}
+	return 0;
+}
+

Propchange: branches/10-digiumphones/main/custom_control_frame.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: branches/10-digiumphones/main/custom_control_frame.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: branches/10-digiumphones/main/custom_control_frame.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: branches/10-digiumphones/main/event.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/event.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/event.c (original)
+++ branches/10-digiumphones/main/event.c Wed Apr  4 14:05:22 2012
@@ -137,6 +137,7 @@
 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
@@ -181,6 +182,11 @@
 		.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, },
+	},
+
 };
 
 /*!
@@ -1585,6 +1591,22 @@
 	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;

Modified: branches/10-digiumphones/main/features.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/features.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/features.c (original)
+++ branches/10-digiumphones/main/features.c Wed Apr  4 14:05:22 2012
@@ -49,6 +49,7 @@
 #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 @@
 			<para>Bridge together two channels already in the PBX.</para>
 		</description>
 	</manager>
+	<manager name="Parkinglots" language="en_US">
+		<synopsis>
+			Get a list of parking lots
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+		</syntax>
+		<description>
+			<para>List all parking lots as a series of AMI events</para>
+		</description>
+	</manager>
  ***/
 
 #define DEFAULT_PARK_TIME							45000	/*!< ms */
@@ -7003,6 +7015,41 @@
 	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
@@ -8137,6 +8184,7 @@
 		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);
 	}

Modified: branches/10-digiumphones/main/file.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/file.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/file.c (original)
+++ branches/10-digiumphones/main/file.c Wed Apr  4 14:05:22 2012
@@ -1240,9 +1240,15 @@
 /*!
  * \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;
@@ -1259,6 +1265,11 @@
 
 	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;
@@ -1321,6 +1332,7 @@
 						return res;
 					}
 				} else {
+					enum ast_waitstream_fr_cb_values cb_val = 0;
 					res = fr->subclass.integer;
 					if (strchr(forward, res)) {
 						int eoftest;
@@ -1331,13 +1343,19 @@
 						} 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:
@@ -1387,21 +1405,32 @@
 	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)
@@ -1412,7 +1441,7 @@
 	if (!context)
 		context = c->context;
 	return waitstream_core(c, NULL, NULL, NULL, 0,
-		-1, -1, context);
+		-1, -1, context, NULL /* no callback */);
 }
 
 /*

Modified: branches/10-digiumphones/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/manager.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/manager.c (original)
+++ branches/10-digiumphones/main/manager.c Wed Apr  4 14:05:22 2012
@@ -1216,6 +1216,7 @@
 	{ EVENT_FLAG_CC, "cc" },
 	{ EVENT_FLAG_AOC, "aoc" },
 	{ EVENT_FLAG_TEST, "test" },
+	{ EVENT_FLAG_MESSAGE, "message" },
 	{ INT_MAX, "all" },
 	{ 0, "none" },
 };
@@ -5330,10 +5331,17 @@
 	return 0;
 }
 
-static int manager_state_cb(const char *context, const char *exten, enum ast_extension_states 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);

Modified: branches/10-digiumphones/main/pbx.c
URL: http://svnview.digium.com/svn/asterisk/branches/10-digiumphones/main/pbx.c?view=diff&rev=361199&r1=361198&r2=361199
==============================================================================
--- branches/10-digiumphones/main/pbx.c (original)
+++ branches/10-digiumphones/main/pbx.c Wed Apr  4 14:05:22 2012
@@ -59,6 +59,7 @@
 #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"
@@ -801,7 +802,7 @@
 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);
@@ -946,8 +947,16 @@
 	 * 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. */
 };
@@ -1092,6 +1101,13 @@
 	{ AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
 	{ AST_EXTENSION_ONHOLD,                        "Hold" },
 	{ AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
+};
+
+struct presencechange {
+	char *provider;
+	int state;
+	char *subtype;
+	char *message;
 };
 
 struct statechange {
@@ -1264,6 +1280,8 @@
 
 /*! \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;
@@ -3257,7 +3275,6 @@
 	int offset, length;
 	int i, need_substring;
 	struct varshead *places[2] = { headp, &globals };	/* list of places where we may look */
-	char workspace[20];
 
 	if (c) {
 		ast_channel_lock(c);
@@ -3353,6 +3370,7 @@
 		} else if (!strcmp(var, "ASTLOGDIR")) {
 			s = ast_config_AST_LOG_DIR;
 		} else if (!strcmp(var, "ENTITYID")) {
+			char workspace[20];
 			ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
 			s = workspace;
 		}
@@ -4473,6 +4491,42 @@
 	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)
 {
 	char *cur;
@@ -4480,7 +4534,7 @@
 	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, "&"))) {
@@ -4536,6 +4590,206 @@
 	}
 
 	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)
@@ -4625,14 +4879,24 @@
 		/* 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);
 	}
@@ -4804,7 +5068,6 @@
 	return ret;
 }
 
-
 static int hint_id_cmp(void *obj, void *arg, int flags)
 {
 	const struct ast_state_cb *cb = obj;
@@ -4839,14 +5102,21 @@
 			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 */
-			state_cb->change_cb(context_name, 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 */
@@ -4889,6 +5159,9 @@
 {
 	struct ast_hint *hint_new;
 	struct ast_hint *hint_found;
+	char *message = NULL;
+	char *subtype = NULL;
+	int presence_state;
 
 	if (!e) {
 		return -1;
@@ -4912,6 +5185,12 @@
 	}
 	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);
@@ -7402,6 +7681,10 @@
 	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];
 };
@@ -7601,6 +7884,13 @@
 			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);
 		}
@@ -7654,8 +7944,15 @@
 				ao2_ref(thiscb, -1);
 			}
 			hint->laststate = saved_hint->laststate;
+			hint->last_presence_state = saved_hint->last_presence_state;

[... 428 lines stripped ...]



More information about the svn-commits mailing list