[asterisk-commits] mmichelson: branch jrothenberger/asterisk-urgent r115360 - in /team/jrothenbe...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue May 6 13:32:39 CDT 2008


Author: mmichelson
Date: Tue May  6 13:32:39 2008
New Revision: 115360

URL: http://svn.digium.com/view/asterisk?view=rev&rev=115360
Log:
Sync with trunk. Apparently automerge is not working


Added:
    team/jrothenberger/asterisk-urgent/include/asterisk/taskprocessor.h
      - copied unchanged from r115344, trunk/include/asterisk/taskprocessor.h
    team/jrothenberger/asterisk-urgent/main/taskprocessor.c
      - copied unchanged from r115344, trunk/main/taskprocessor.c
Modified:
    team/jrothenberger/asterisk-urgent/   (props changed)
    team/jrothenberger/asterisk-urgent/CHANGES
    team/jrothenberger/asterisk-urgent/Makefile
    team/jrothenberger/asterisk-urgent/UPGRADE.txt
    team/jrothenberger/asterisk-urgent/acinclude.m4
    team/jrothenberger/asterisk-urgent/apps/app_chanspy.c
    team/jrothenberger/asterisk-urgent/apps/app_queue.c
    team/jrothenberger/asterisk-urgent/apps/app_voicemail.c
    team/jrothenberger/asterisk-urgent/build_tools/menuselect-deps.in
    team/jrothenberger/asterisk-urgent/channels/chan_iax2.c
    team/jrothenberger/asterisk-urgent/channels/chan_sip.c
    team/jrothenberger/asterisk-urgent/codecs/codec_speex.c
    team/jrothenberger/asterisk-urgent/configure
    team/jrothenberger/asterisk-urgent/configure.ac
    team/jrothenberger/asterisk-urgent/contrib/init.d/rc.debian.asterisk
    team/jrothenberger/asterisk-urgent/contrib/init.d/rc.gentoo.asterisk
    team/jrothenberger/asterisk-urgent/contrib/init.d/rc.mandrake.asterisk
    team/jrothenberger/asterisk-urgent/contrib/init.d/rc.redhat.asterisk
    team/jrothenberger/asterisk-urgent/contrib/init.d/rc.slackware.asterisk
    team/jrothenberger/asterisk-urgent/contrib/init.d/rc.suse.asterisk
    team/jrothenberger/asterisk-urgent/contrib/scripts/safe_asterisk
    team/jrothenberger/asterisk-urgent/funcs/func_speex.c
    team/jrothenberger/asterisk-urgent/include/asterisk/_private.h
    team/jrothenberger/asterisk-urgent/include/asterisk/autoconfig.h.in
    team/jrothenberger/asterisk-urgent/include/asterisk/compiler.h
    team/jrothenberger/asterisk-urgent/include/asterisk/res_odbc.h
    team/jrothenberger/asterisk-urgent/main/Makefile
    team/jrothenberger/asterisk-urgent/main/asterisk.c
    team/jrothenberger/asterisk-urgent/main/config.c
    team/jrothenberger/asterisk-urgent/main/event.c
    team/jrothenberger/asterisk-urgent/main/logger.c
    team/jrothenberger/asterisk-urgent/main/manager.c
    team/jrothenberger/asterisk-urgent/main/pbx.c
    team/jrothenberger/asterisk-urgent/res/res_odbc.c

Propchange: team/jrothenberger/asterisk-urgent/
------------------------------------------------------------------------------
Binary property 'branch-1.4-blocked' - no diff available.

Propchange: team/jrothenberger/asterisk-urgent/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Propchange: team/jrothenberger/asterisk-urgent/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue May  6 13:32:39 2008
@@ -1,1 +1,1 @@
-/trunk:1-115216
+/trunk:1-115359

Modified: team/jrothenberger/asterisk-urgent/CHANGES
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/CHANGES?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/CHANGES (original)
+++ team/jrothenberger/asterisk-urgent/CHANGES Tue May  6 13:32:39 2008
@@ -96,6 +96,11 @@
 Dialplan function changes
 -------------------------
  * TIMEOUT() has been modified to be accurate down to the millisecond.
+
+AMI - The manager (TCP/TLS/HTTP)
+--------------------------------
+  * The Status command now takes an optional list of variables to display
+    along with channel status.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.4.X to Asterisk 1.6.0  -------------

Modified: team/jrothenberger/asterisk-urgent/Makefile
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/Makefile?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/Makefile (original)
+++ team/jrothenberger/asterisk-urgent/Makefile Tue May  6 13:32:39 2008
@@ -351,7 +351,7 @@
 	@exit 1
 
 menuselect.makeopts: menuselect/menuselect menuselect-tree makeopts
-	menuselect/menuselect --check-deps $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts
+	menuselect/menuselect --check-deps menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS)
 
 $(MOD_SUBDIRS_EMBED_LDSCRIPT):
 	@echo "EMBED_LDSCRIPTS+="`$(SILENTMAKE) -C $(@:-embed-ldscript=) SUBDIR=$(@:-embed-ldscript=) __embed_ldscript` >> makeopts.embed_rules
@@ -821,16 +821,16 @@
 nmenuconfig: nmenuselect
 
 menuselect: menuselect/menuselect menuselect-tree
-	- at menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
+	- at menuselect/menuselect menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
 
 cmenuselect: menuselect/cmenuselect menuselect-tree
-	- at menuselect/cmenuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
+	- at menuselect/cmenuselect menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
 
 gmenuselect: menuselect/gmenuselect menuselect-tree
-	- at menuselect/gmenuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
+	- at menuselect/gmenuselect menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
 
 nmenuselect: menuselect/nmenuselect menuselect-tree
-	- at menuselect/nmenuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
+	- at menuselect/nmenuselect menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
 
 # options for make in menuselect/
 MAKE_MENUSELECT=CC="$(HOST_CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" CFLAGS="" $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
@@ -869,4 +869,4 @@
 asterisk.pdf:
 	$(MAKE) -C doc/tex asterisk.pdf
 
-.PHONY: menuselect main sounds clean dist-clean distclean all prereqs cleantest uninstall _uninstall uninstall-all pdf dont-optimize $(SUBDIRS_INSTALL) $(SUBDIRS_DIST_CLEAN) $(SUBDIRS_CLEAN) $(SUBDIRS_UNINSTALL) $(SUBDIRS) $(MOD_SUBDIRS_EMBED_LDSCRIPT) $(MOD_SUBDIRS_EMBED_LDFLAGS) $(MOD_SUBDIRS_EMBED_LIBS) badshell main/version.c include/asterisk/version.h installdirs
+.PHONY: menuselect menuselect.makeopts main sounds clean dist-clean distclean all prereqs cleantest uninstall _uninstall uninstall-all pdf dont-optimize $(SUBDIRS_INSTALL) $(SUBDIRS_DIST_CLEAN) $(SUBDIRS_CLEAN) $(SUBDIRS_UNINSTALL) $(SUBDIRS) $(MOD_SUBDIRS_EMBED_LDSCRIPT) $(MOD_SUBDIRS_EMBED_LDFLAGS) $(MOD_SUBDIRS_EMBED_LIBS) badshell main/version.c include/asterisk/version.h installdirs

Modified: team/jrothenberger/asterisk-urgent/UPGRADE.txt
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/UPGRADE.txt?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/UPGRADE.txt (original)
+++ team/jrothenberger/asterisk-urgent/UPGRADE.txt Tue May  6 13:32:39 2008
@@ -96,8 +96,8 @@
   these functions in any location where you desire to ensure that only one
   channel is executing that path at any one time.  The Macro() applications
   are deprecated for performance reasons.  However, since Macro() has been
-  around for a long time and so many dialplans depend heavily on it, it will
-  not be removed for the sake of backwards compatibility.  It is also worth
+  around for a long time and so many dialplans depend heavily on it, for the
+  sake of backwards compatibility it will not be removed .  It is also worth
   noting that using both Macro() and GoSub() at the same time is _heavily_
   discouraged.
 * Read() now sets a READSTATUS variable on exit.  It does NOT automatically
@@ -112,6 +112,8 @@
   instead.
 * While app_directory has always relied on having a voicemail.conf or users.conf file
   correctly set up, it now is dependent on app_voicemail being compiled as well.
+* The arguments in ExecIf changed a bit, to be more like other applications.
+  The syntax is now ExecIf(<cond>?appiftrue(args):appiffalse(args)).
 
 Dialplan Functions:
 

Modified: team/jrothenberger/asterisk-urgent/acinclude.m4
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/acinclude.m4?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/acinclude.m4 (original)
+++ team/jrothenberger/asterisk-urgent/acinclude.m4 Tue May  6 13:32:39 2008
@@ -7,13 +7,17 @@
 AC_DEFUN([AST_GCC_ATTRIBUTE],
 [
 AC_MSG_CHECKING(for compiler 'attribute $1' support)
+saved_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Werror"
 AC_COMPILE_IFELSE(
-	AC_LANG_PROGRAM([static int __attribute__(($1)) test(void) {}],
+	AC_LANG_PROGRAM([static void __attribute__(($1)) *test(void *muffin, ...) {}],
 			[]),
 	AC_MSG_RESULT(yes)
 	AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
 	AC_MSG_RESULT(no))
-])
+]
+CFLAGS="$saved_CFLAGS"
+)
 
 # Helper function to setup variables for a package.
 # $1 -> the package name. Used in configure.ac and also as a prefix

Modified: team/jrothenberger/asterisk-urgent/apps/app_chanspy.c
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/apps/app_chanspy.c?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/apps/app_chanspy.c (original)
+++ team/jrothenberger/asterisk-urgent/apps/app_chanspy.c Tue May  6 13:32:39 2008
@@ -71,6 +71,8 @@
 "        and a digit sequence.\n"
 "  Options:\n"
 "    b                      - Only spy on channels involved in a bridged call.\n"
+"    B                      - Instead of whispering on a single channel barge in on both\n"
+"                             channels involved in the call.\n"
 "    g(grp)                 - Only spy on channels in which one or more of the groups \n"
 "                             listed in 'grp' matches one or more groups from the\n"
 "                             SPYGROUP variable set on the channel to be spied upon.\n"

Modified: team/jrothenberger/asterisk-urgent/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/apps/app_queue.c?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/apps/app_queue.c (original)
+++ team/jrothenberger/asterisk-urgent/apps/app_queue.c Tue May  6 13:32:39 2008
@@ -92,6 +92,7 @@
 #include "asterisk/astobj2.h"
 #include "asterisk/strings.h"
 #include "asterisk/global_datastores.h"
+#include "asterisk/taskprocessor.h"
 
 /*!
  * \par Please read before modifying this file.
@@ -130,6 +131,8 @@
 	{ QUEUE_STRATEGY_LINEAR, "linear" },
 	{ QUEUE_STRATEGY_WRANDOM, "wrandom"},
 };
+
+static struct ast_taskprocessor *devicestate_tps;
 
 #define DEFAULT_RETRY		5
 #define DEFAULT_TIMEOUT		15
@@ -739,18 +742,20 @@
 }
 
 /*! \brief set a member's status based on device state of that member's interface*/
-static void *handle_statechange(struct statechange *sc)
+static int handle_statechange(void *datap)
 {
 	struct member_interface *curint;
 	char *loc;
 	char *technology;
+	struct statechange *sc = datap;
 
 	technology = ast_strdupa(sc->dev);
 	loc = strchr(technology, '/');
 	if (loc) {
 		*loc++ = '\0';
 	} else {
-		return NULL;
+		ast_free(sc);
+		return 0;
 	}
 
 	AST_LIST_LOCK(&interfaces);
@@ -770,84 +775,14 @@
 	if (!curint) {
 		if (option_debug > 2)
 			ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
-		return NULL;
+		return 0;
 	}
 
 	if (option_debug)
 		ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
 
 	update_status(sc->dev, sc->state);
-
-	return NULL;
-}
-
-/*! \brief Data used by the device state thread */
-static struct {
-	/*! Set to 1 to stop the thread */
-	unsigned int stop:1;
-	/*! The device state monitoring thread */
-	pthread_t thread;
-	/*! Lock for the state change queue */
-	ast_mutex_t lock;
-	/*! Condition for the state change queue */
-	ast_cond_t cond;
-	/*! Queue of state changes */
-	AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
-} device_state = {
-	.thread = AST_PTHREADT_NULL,
-};
-
-/*! \brief Consumer of the statechange queue */
-static void *device_state_thread(void *data)
-{
-	struct statechange *sc = NULL;
-
-	while (!device_state.stop) {
-		ast_mutex_lock(&device_state.lock);
-		if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
-			ast_cond_wait(&device_state.cond, &device_state.lock);
-			sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
-		}
-		ast_mutex_unlock(&device_state.lock);
-
-		/* Check to see if we were woken up to see the request to stop */
-		if (device_state.stop)
-			break;
-
-		if (!sc)
-			continue;
-
-		handle_statechange(sc);
-
-		ast_free(sc);
-		sc = NULL;
-	}
-
-	if (sc)
-		ast_free(sc);
-
-	while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
-		ast_free(sc);
-
-	return NULL;
-}
-
-/*! \brief Producer of the statechange queue */
-static int statechange_queue(const char *dev, enum ast_device_state state)
-{
-	struct statechange *sc;
-
-	if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
-		return 0;
-
-	sc->state = state;
-	strcpy(sc->dev, dev);
-
-	ast_mutex_lock(&device_state.lock);
-	AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
-	ast_cond_signal(&device_state.cond);
-	ast_mutex_unlock(&device_state.lock);
-
+	ast_free(sc);
 	return 0;
 }
 
@@ -855,6 +790,8 @@
 {
 	enum ast_device_state state;
 	const char *device;
+	struct statechange *sc;
+	size_t datapsize;
 
 	state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
 	device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
@@ -863,8 +800,16 @@
 		ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
 		return;
 	}
-
-	statechange_queue(device, state);
+	datapsize = sizeof(*sc) + strlen(device) + 1;
+	if (!(sc = ast_calloc(1, datapsize))) {
+		ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
+		return;
+	}
+	sc->state = state;
+	strcpy(sc->dev, device);
+	if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
+		ast_free(sc);
+	}
 }
 
 /*! \brief allocate space for new queue member and set fields based on parameters passed */
@@ -3349,7 +3294,6 @@
 		/* Ah ha!  Someone answered within the desired timeframe.  Of course after this
 		   we will always return with -1 so that it is hung up properly after the
 		   conversation.  */
-		qe->handled++;
 		if (!strcmp(qe->chan->tech->type, "Zap"))
 			ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
 		if (!strcmp(peer->tech->type, "Zap"))
@@ -3403,7 +3347,6 @@
 				/* Agent must have hung up */
 				ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
 				ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
-				record_abandoned(qe);
 				if (qe->parent->eventwhencalled)
 					manager_event(EVENT_FLAG_AGENT, "AgentDump",
 							"Queue: %s\r\n"
@@ -3683,6 +3626,7 @@
 			} else
 				ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
 		}
+		qe->handled++;
 		ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
 													(long)(orig - to > 0 ? (orig - to) / 1000 : 0));
 		if (update_cdr && qe->chan->cdr) 
@@ -6249,14 +6193,6 @@
 	struct ao2_iterator q_iter;
 	struct call_queue *q = NULL;
 
-	if (device_state.thread != AST_PTHREADT_NULL) {
-		device_state.stop = 1;
-		ast_mutex_lock(&device_state.lock);
-		ast_cond_signal(&device_state.cond);
-		ast_mutex_unlock(&device_state.lock);
-		pthread_join(device_state.thread, NULL);
-	}
-
 	ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
 	res = ast_manager_unregister("QueueStatus");
 	res |= ast_manager_unregister("Queues");
@@ -6296,7 +6232,7 @@
 		queue_unref(q);
 	}
 	ao2_ref(queues, -1);
-
+	devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
 	return res;
 }
 
@@ -6318,10 +6254,6 @@
 
 	if (queue_persistent_members)
 		reload_queue_members();
-
-	ast_mutex_init(&device_state.lock);
-	ast_cond_init(&device_state.cond, NULL);
-	ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
 
 	ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
 	res = ast_register_application(app, queue_exec, synopsis, descrip);
@@ -6345,6 +6277,11 @@
 	res |= ast_custom_function_register(&queuememberlist_function);
 	res |= ast_custom_function_register(&queuewaitingcount_function);
 	res |= ast_custom_function_register(&queuememberpenalty_function);
+
+	if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
+		ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
+	}
+
 	if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL, AST_EVENT_IE_END)))
 		res = -1;
 

Modified: team/jrothenberger/asterisk-urgent/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/apps/app_voicemail.c?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/apps/app_voicemail.c (original)
+++ team/jrothenberger/asterisk-urgent/apps/app_voicemail.c Tue May  6 13:32:39 2008
@@ -114,6 +114,7 @@
 #include "asterisk/stringfields.h"
 #include "asterisk/smdi.h"
 #include "asterisk/event.h"
+#include "asterisk/taskprocessor.h"
 
 #ifdef ODBC_STORAGE
 #include "asterisk/res_odbc.h"
@@ -627,6 +628,14 @@
 	uint32_t uniqueid;
 	char mailbox[1];
 };
+
+struct mwi_sub_task {
+	const char *mailbox;
+	const char *context;
+	uint32_t uniqueid;
+};
+
+static struct ast_taskprocessor *mwi_subscription_tps;
 
 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
 
@@ -9005,22 +9014,14 @@
 	ast_free(mwi_sub);
 }
 
-static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
-{
-	uint32_t uniqueid;
+static int handle_unsubscribe(void *datap)
+{
 	struct mwi_sub *mwi_sub;
-
-	if (ast_event_get_type(event) != AST_EVENT_UNSUB)
-		return;
-
-	if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
-		return;
-
-	uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
-
+	uint32_t *uniqueid = datap;
+	
 	AST_RWLIST_WRLOCK(&mwi_subs);
 	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
-		if (mwi_sub->uniqueid == uniqueid) {
+		if (mwi_sub->uniqueid == *uniqueid) {
 			AST_LIST_REMOVE_CURRENT(entry);
 			break;
 		}
@@ -9030,48 +9031,80 @@
 
 	if (mwi_sub)
 		mwi_sub_destroy(mwi_sub);
-}
-
-static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
-{
-	const char *mailbox;
-	const char *context;
-	uint32_t uniqueid;
+
+	ast_free(uniqueid);	
+	return 0;
+}
+
+static int handle_subscribe(void *datap)
+{
 	unsigned int len;
 	struct mwi_sub *mwi_sub;
-
-	if (ast_event_get_type(event) != AST_EVENT_SUB)
-		return;
-
-	if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
-		return;
-
-	mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
-	context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
-	uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+	struct mwi_sub_task *p = datap;
 
 	len = sizeof(*mwi_sub);
-	if (!ast_strlen_zero(mailbox))
-		len += strlen(mailbox);
-
-	if (!ast_strlen_zero(context))
-		len += strlen(context) + 1; /* Allow for seperator */
+	if (!ast_strlen_zero(p->mailbox))
+		len += strlen(p->mailbox);
+
+	if (!ast_strlen_zero(p->context))
+		len += strlen(p->context) + 1; /* Allow for seperator */
 
 	if (!(mwi_sub = ast_calloc(1, len)))
-		return;
-
-	mwi_sub->uniqueid = uniqueid;
-	if (!ast_strlen_zero(mailbox))
-		strcpy(mwi_sub->mailbox, mailbox);
-
-	if (!ast_strlen_zero(context)) {
+		return -1;
+
+	mwi_sub->uniqueid = p->uniqueid;
+	if (!ast_strlen_zero(p->mailbox))
+		strcpy(mwi_sub->mailbox, p->mailbox);
+
+	if (!ast_strlen_zero(p->context)) {
 		strcat(mwi_sub->mailbox, "@");
-		strcat(mwi_sub->mailbox, context);
+		strcat(mwi_sub->mailbox, p->context);
 	}
 
 	AST_RWLIST_WRLOCK(&mwi_subs);
 	AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
 	AST_RWLIST_UNLOCK(&mwi_subs);
+	ast_free(p);	
+	return 0;
+}
+
+static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
+{
+	uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
+	if (ast_event_get_type(event) != AST_EVENT_UNSUB)
+		return;
+
+	if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
+		return;
+
+	u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+	*uniqueid = u;
+	if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
+		ast_free(uniqueid);
+	}
+}
+
+static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
+{
+	struct mwi_sub_task *mwist;
+	
+	if (ast_event_get_type(event) != AST_EVENT_SUB)
+		return;
+
+	if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
+		return;
+
+	if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
+		ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
+		return;
+	}
+	mwist->mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
+	mwist->context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
+	mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+	
+	if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
+		ast_free(mwist);
+	}
 }
 
 static void start_poll_thread(void)
@@ -9893,6 +9926,7 @@
 	if (poll_thread != AST_PTHREADT_NULL)
 		stop_poll_thread();
 
+	mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
 	return res;
 }
 
@@ -9904,6 +9938,10 @@
 
 	/* compute the location of the voicemail spool directory */
 	snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
+	
+	if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
+		ast_log(LOG_WARNING, "failed to reference mwi subscription taskprocessor.  MWI will not work\n");
+	}
 
 	if ((res = load_config(0)))
 		return res;

Modified: team/jrothenberger/asterisk-urgent/build_tools/menuselect-deps.in
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/build_tools/menuselect-deps.in?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/build_tools/menuselect-deps.in (original)
+++ team/jrothenberger/asterisk-urgent/build_tools/menuselect-deps.in Tue May  6 13:32:39 2008
@@ -32,6 +32,7 @@
 RADIUS=@PBX_RADIUS@
 SPEEX=@PBX_SPEEX@
 SPEEXDSP=@PBX_SPEEXDSP@
+SPEEX_PREPROCESS=@PBX_SPEEX_PREPROCESS@
 SQLITE3=@PBX_SQLITE3@
 SQLITE=@PBX_SQLITE@
 SS7=@PBX_SS7@

Modified: team/jrothenberger/asterisk-urgent/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/channels/chan_iax2.c?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/channels/chan_iax2.c (original)
+++ team/jrothenberger/asterisk-urgent/channels/chan_iax2.c Tue May  6 13:32:39 2008
@@ -1588,20 +1588,7 @@
 	ao2_unlink(iax_peercallno_pvts, pvt);
 }
 
-/*!
- * \todo XXX Note that this function contains a very expensive operation that
- * happens for *every* incoming media frame.  It iterates through every
- * possible call number, locking and unlocking each one, to try to match the
- * incoming frame to an active call.  Call numbers can be up to 2^15, 32768.
- * So, for a call with a local call number of 20000, every incoming audio
- * frame would require 20000 mutex lock and unlock operations.  Ouch.
- *
- * It's a shame that IAX2 media frames carry the source call number instead of
- * the destination call number.  If they did, this lookup wouldn't be needed.
- * However, it's too late to change that now.  Instead, we need to come up with
- * a better way of indexing active calls so that these frequent lookups are not
- * so expensive.
- *
+/*
  * \note Calling this function while holding another pvt lock can cause a deadlock.
  */
 static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int full_frame)

Modified: team/jrothenberger/asterisk-urgent/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/channels/chan_sip.c?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/channels/chan_sip.c (original)
+++ team/jrothenberger/asterisk-urgent/channels/chan_sip.c Tue May  6 13:32:39 2008
@@ -15055,6 +15055,7 @@
 	char resp[256];
 	char resp_hash[256];
 	char uri[256];
+	char opaque[256] = "";
 	char cnonce[80];
 	const char *username;
 	const char *secret;
@@ -15103,11 +15104,17 @@
 	else
 		snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, p->nonce, a2_hash);
 	ast_md5_hash(resp_hash, resp);
+
+	/* only include the opaque string if it's set */
+	if (!ast_strlen_zero(p->opaque)) {
+	  snprintf(opaque, sizeof(opaque), ", opaque=\"%s\"", p->opaque);
+	}
+
 	/* XXX We hard code our qop to "auth" for now.  XXX */
 	if (!ast_strlen_zero(p->qop))
-		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\", qop=auth, cnonce=\"%s\", nc=%08x", username, p->realm, uri, p->nonce, resp_hash, p->opaque, cnonce, p->noncecount);
+		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\"%s, qop=auth, cnonce=\"%s\", nc=%08x", username, p->realm, uri, p->nonce, resp_hash, opaque, cnonce, p->noncecount);
 	else
-		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\"", username, p->realm, uri, p->nonce, resp_hash, p->opaque);
+		snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\"%s", username, p->realm, uri, p->nonce, resp_hash, opaque);
 
 	append_history(p, "AuthResp", "Auth response sent for %s in realm %s - nc %d", username, p->realm, p->noncecount);
 
@@ -21967,7 +21974,7 @@
 	/* Done, tell the manager */
 	manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "ChannelType: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\nUser_Count: %d\r\n", channelreloadreason2txt(reason), registry_count, peer_count, user_count);
 	run_end = time(0);
-	ast_log(LOG_NOTICE, "reload_config done...Runtime= %d sec\n", (int)(run_end-run_start));
+	ast_debug(4, "reload_config done...Runtime= %d sec\n", (int)(run_end-run_start));
 
 	return 0;
 }
@@ -22486,7 +22493,7 @@
 	sip_send_all_registers();
 	end_poke = time(0);
 	
-	ast_log(LOG_NOTICE, "do_reload finished. peer poke/prune reg contact time = %d sec.\n", (int)(end_poke-start_poke));
+	ast_debug(4, "do_reload finished. peer poke/prune reg contact time = %d sec.\n", (int)(end_poke-start_poke));
 
 	ast_debug(4, "--------------- SIP reload done\n");
 

Modified: team/jrothenberger/asterisk-urgent/codecs/codec_speex.c
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/codecs/codec_speex.c?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/codecs/codec_speex.c (original)
+++ team/jrothenberger/asterisk-urgent/codecs/codec_speex.c Tue May  6 13:32:39 2008
@@ -32,6 +32,7 @@
 
 /*** MODULEINFO
 	<depend>speex</depend>
+	<depend>speex_preprocess</depend>
 	<use>speexdsp</use>
  ***/
 

Modified: team/jrothenberger/asterisk-urgent/configure.ac
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/configure.ac?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/configure.ac (original)
+++ team/jrothenberger/asterisk-urgent/configure.ac Tue May  6 13:32:39 2008
@@ -1314,7 +1314,18 @@
 
 AST_EXT_LIB_CHECK([SPEEX], [speex], [speex_encode], [speex/speex.h], [-lm])
 
+# See if the main speex library contains the preprocess functions
+AST_EXT_LIB_CHECK([SPEEX_PREPROCESS], [speex], [speex_preprocess_ctl], [speex/speex.h], [-lm])
+if test "${PBX_SPEEX_PREPROCESS}" = 1; then
+   PBX_SPEEX_PREPROCESS=1
+fi
+
 AST_EXT_LIB_CHECK([SPEEXDSP], [speexdsp], [speex_preprocess_ctl], [speex/speex.h], [-lm])
+if test "${PBX_SPEEXDSP}" = 1; then
+   PBX_SPEEX_PREPROCESS=1
+fi
+
+AC_SUBST(PBX_SPEEX_PREPROCESS)
 
 AST_EXT_LIB_CHECK([SQLITE], [sqlite], [sqlite_exec], [sqlite.h])
 

Modified: team/jrothenberger/asterisk-urgent/contrib/init.d/rc.debian.asterisk
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/contrib/init.d/rc.debian.asterisk?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/contrib/init.d/rc.debian.asterisk (original)
+++ team/jrothenberger/asterisk-urgent/contrib/init.d/rc.debian.asterisk Tue May  6 13:32:39 2008
@@ -51,6 +51,14 @@
 
 case "$1" in
   start)
+	# Check if Asterisk is already running.  If it is, then bug out, because
+	# starting up Asterisk when Asterisk is already running is very bad.
+	VERSION=`${ASTSBINDIR}/asterisk -rx 'core show version'`
+	if [ "${VERSION:0:8}" = "Asterisk" ]; then # otherwise "Unable t"
+		echo "Asterisk is already running.  $0 will exit now."
+		exit 1
+	fi
+
 	log_begin_msg "Starting $DESC: $NAME"
         if [ $AST_USER ] ; then
                 ASTARGS="-U $AST_USER"

Modified: team/jrothenberger/asterisk-urgent/contrib/init.d/rc.gentoo.asterisk
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/contrib/init.d/rc.gentoo.asterisk?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/contrib/init.d/rc.gentoo.asterisk (original)
+++ team/jrothenberger/asterisk-urgent/contrib/init.d/rc.gentoo.asterisk Tue May  6 13:32:39 2008
@@ -6,6 +6,14 @@
 }
 
 start() {
+	# Check if Asterisk is already running.  If it is, then bug out, because
+	# starting safe_asterisk when Asterisk is running is very bad.
+	VERSION=`${ASTSBINDIR}/asterisk -rx 'core show version'`
+	if [ "${VERSION:0:8}" = "Asterisk" ]; then # otherwise "Unable t"
+		echo "Asterisk is already running.  $0 will exit now."
+		exit 1
+	fi
+
 	ebegin "Starting Asterisk"
 	/usr/sbin/asterisk
 	eend $? "Failed to start Asterisk"

Modified: team/jrothenberger/asterisk-urgent/contrib/init.d/rc.mandrake.asterisk
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/contrib/init.d/rc.mandrake.asterisk?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/contrib/init.d/rc.mandrake.asterisk (original)
+++ team/jrothenberger/asterisk-urgent/contrib/init.d/rc.mandrake.asterisk Tue May  6 13:32:39 2008
@@ -119,6 +119,14 @@
 
 case "$1" in
 	start)
+		# Check if Asterisk is already running.  If it is, then bug out, because
+		# starting Asterisk when Asterisk is already running is very bad.
+		VERSION=`${ASTSBINDIR}/asterisk -rx 'core show version'`
+		if [ "${VERSION:0:8}" = "Asterisk" ]; then # otherwise "Unable t"
+			echo "Asterisk is already running.  $0 will exit now."
+			exit 1
+		fi
+
 		gprintf "Starting asterisk: "
 		run_asterisk >/dev/null 2>&1 &
 		sleep 2	# Give it time to die

Modified: team/jrothenberger/asterisk-urgent/contrib/init.d/rc.redhat.asterisk
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/contrib/init.d/rc.redhat.asterisk?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/contrib/init.d/rc.redhat.asterisk (original)
+++ team/jrothenberger/asterisk-urgent/contrib/init.d/rc.redhat.asterisk Tue May  6 13:32:39 2008
@@ -68,6 +68,14 @@
 RETVAL=0
 
 start() {
+	# Check if Asterisk is already running.  If it is, then bug out, because
+	# starting safe_asterisk when Asterisk is running is very bad.
+	VERSION=`${AST_SBIN}/asterisk -rx 'core show version'`
+	if [ "${VERSION:0:8}" = "Asterisk" ]; then # otherwise "Unable t"
+		echo "Asterisk is already running."
+		exit 1
+	fi
+
 	# Start daemons.
 	echo -n $"Starting asterisk: "
         if [ -f $SAFE_ASTERISK ] ; then

Modified: team/jrothenberger/asterisk-urgent/contrib/init.d/rc.slackware.asterisk
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/contrib/init.d/rc.slackware.asterisk?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/contrib/init.d/rc.slackware.asterisk (original)
+++ team/jrothenberger/asterisk-urgent/contrib/init.d/rc.slackware.asterisk Tue May  6 13:32:39 2008
@@ -10,6 +10,14 @@
 
 asterisk_start() {
    if [ -x /usr/sbin/asterisk ]; then
+      # Check if Asterisk is already running.  If it is, then bug out, because
+      # starting safe_asterisk when Asterisk is running is very bad.
+      VERSION=`/usr/sbin/asterisk -rx 'core show version'`
+      if [ "${VERSION:0:8}" = "Asterisk" ]; then # otherwise "Unable t"
+         echo "Asterisk is already running.  $0 will exit now."
+         exit 1
+      fi
+
       echo "Starting Asterisk   /usr/sbin/asterisk"
       /usr/sbin/asterisk
    fi

Modified: team/jrothenberger/asterisk-urgent/contrib/init.d/rc.suse.asterisk
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/contrib/init.d/rc.suse.asterisk?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/contrib/init.d/rc.suse.asterisk (original)
+++ team/jrothenberger/asterisk-urgent/contrib/init.d/rc.suse.asterisk Tue May  6 13:32:39 2008
@@ -63,6 +63,15 @@
 
 start() {
 	# Start daemons.
+
+	# Check if Asterisk is already running.  If it is, then bug out, because
+	# starting Asterisk when Asterisk is already running is very bad.
+	VERSION=`/usr/sbin/asterisk -rx 'core show version'`
+	if [ "${VERSION:0:8}" = "Asterisk" ]; then # otherwise "Unable t"
+		echo "Asterisk is already running.  $0 will exit now."
+		exit 1
+	fi
+
 	echo -n $"Starting asterisk: "
         if [ -f $SAFE_ASTERISK ] ; then
 		DAEMON=$SAFE_ASTERISK

Modified: team/jrothenberger/asterisk-urgent/contrib/scripts/safe_asterisk
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/contrib/scripts/safe_asterisk?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/contrib/scripts/safe_asterisk (original)
+++ team/jrothenberger/asterisk-urgent/contrib/scripts/safe_asterisk Tue May  6 13:32:39 2008
@@ -37,6 +37,14 @@
 	    echo "safe_asterisk[$$]: $1" >> "$LOGFILE"
 	fi
 }
+
+# Check if Asterisk is already running.  If it is, then bug out, because
+# starting safe_asterisk when Asterisk is running is very bad.
+VERSION=`${ASTSBINDIR}/asterisk -rx 'core show version'`
+if [ "${VERSION:0:8}" = "Asterisk" ]; then # otherwise "Unable t"
+	message "Asterisk is already running.  $0 will exit now."
+	exit 1
+fi
 
 # since we're going to change priority and open files limits, we need to be
 # root. if running asterisk as other users, pass that to asterisk on the command

Modified: team/jrothenberger/asterisk-urgent/funcs/func_speex.c
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/funcs/func_speex.c?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/funcs/func_speex.c (original)
+++ team/jrothenberger/asterisk-urgent/funcs/func_speex.c Tue May  6 13:32:39 2008
@@ -31,6 +31,8 @@
 
 /*** MODULEINFO
 	<depend>speex</depend>
+	<depend>speex_preprocess</depend>
+	<use>speexdsp</use>
  ***/
 
 #include "asterisk.h"

Modified: team/jrothenberger/asterisk-urgent/include/asterisk/_private.h
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/include/asterisk/_private.h?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/include/asterisk/_private.h (original)
+++ team/jrothenberger/asterisk-urgent/include/asterisk/_private.h Tue May  6 13:32:39 2008
@@ -36,6 +36,7 @@
 void ast_autoservice_init(void);	/*!< Provided by autoservice.c */
 int ast_http_init(void);		/*!< Provided by http.c */
 int ast_http_reload(void);		/*!< Provided by http.c */
+int ast_tps_init(void); 		/*!< Provided by taskprocessor.c */
 
 /*!
  * \brief Reload asterisk modules.

Modified: team/jrothenberger/asterisk-urgent/include/asterisk/autoconfig.h.in
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/include/asterisk/autoconfig.h.in?view=diff&rev=115360&r1=115359&r2=115360
==============================================================================
--- team/jrothenberger/asterisk-urgent/include/asterisk/autoconfig.h.in (original)
+++ team/jrothenberger/asterisk-urgent/include/asterisk/autoconfig.h.in Tue May  6 13:32:39 2008
@@ -723,6 +723,12 @@
 
 /* Define to indicate the ${SPEEXDSP_DESCRIP} library version */
 #undef HAVE_SPEEXDSP_VERSION
+
+/* Define this to indicate the ${SPEEX_PREPROCESS_DESCRIP} library */
+#undef HAVE_SPEEX_PREPROCESS
+
+/* Define to indicate the ${SPEEX_PREPROCESS_DESCRIP} library version */
+#undef HAVE_SPEEX_PREPROCESS_VERSION
 
 /* Define to indicate the ${SPEEX_DESCRIP} library version */
 #undef HAVE_SPEEX_VERSION

Modified: team/jrothenberger/asterisk-urgent/include/asterisk/compiler.h
URL: http://svn.digium.com/view/asterisk/team/jrothenberger/asterisk-urgent/include/asterisk/compiler.h?view=diff&rev=115360&r1=115359&r2=115360

[... 1225 lines stripped ...]



More information about the asterisk-commits mailing list