[asterisk-commits] moy: branch moy/mfcr2 r175776 - in /team/moy/mfcr2: ./ apps/ build_tools/ cha...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Feb 14 23:16:53 CST 2009


Author: moy
Date: Sat Feb 14 23:16:52 2009
New Revision: 175776

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=175776
Log:
merged changes from trunk rev 175774

Added:
    team/moy/mfcr2/formats/format_siren14.c
      - copied unchanged from r175774, trunk/formats/format_siren14.c
    team/moy/mfcr2/formats/format_siren7.c
      - copied unchanged from r175774, trunk/formats/format_siren7.c
Modified:
    team/moy/mfcr2/   (props changed)
    team/moy/mfcr2/CHANGES
    team/moy/mfcr2/apps/app_chanspy.c
    team/moy/mfcr2/apps/app_queue.c
    team/moy/mfcr2/apps/app_record.c
    team/moy/mfcr2/apps/app_voicemail.c
    team/moy/mfcr2/build_tools/cflags.xml
    team/moy/mfcr2/channels/chan_dahdi.c
    team/moy/mfcr2/channels/chan_gtalk.c
    team/moy/mfcr2/channels/chan_h323.c
    team/moy/mfcr2/channels/chan_iax2.c
    team/moy/mfcr2/channels/chan_sip.c
    team/moy/mfcr2/channels/iax2.h
    team/moy/mfcr2/configs/chan_dahdi.conf.sample
    team/moy/mfcr2/configs/iax.conf.sample
    team/moy/mfcr2/doc/manager_1_1.txt
    team/moy/mfcr2/include/asterisk/astobj2.h
    team/moy/mfcr2/include/asterisk/frame.h
    team/moy/mfcr2/include/asterisk/rtp.h
    team/moy/mfcr2/main/astobj2.c
    team/moy/mfcr2/main/features.c
    team/moy/mfcr2/main/frame.c
    team/moy/mfcr2/main/pbx.c
    team/moy/mfcr2/main/rtp.c
    team/moy/mfcr2/main/udptl.c
    team/moy/mfcr2/res/res_jabber.c

Propchange: team/moy/mfcr2/
------------------------------------------------------------------------------
Binary property 'branch-1.4-blocked' - no diff available.

Propchange: team/moy/mfcr2/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Modified: team/moy/mfcr2/CHANGES
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/CHANGES?view=diff&rev=175776&r1=175775&r2=175776
==============================================================================
--- team/moy/mfcr2/CHANGES (original)
+++ team/moy/mfcr2/CHANGES Sat Feb 14 23:16:52 2009
@@ -48,6 +48,7 @@
    first INVITE is generated - SIPRemoveHeader()
  * Channel variables set with setvar= in a device configuration is now 
    set both for inbound and outbound calls.
+ * Added support for ITU G.722.1 and G.722.1C (Siren7 and Siren14) media streams.
 
 Skinny Changes
 --------------
@@ -59,6 +60,13 @@
 -------------
  * The UK option waitfordialtone has been added for use with BT analog
    lines.
+ * Added a 'faxbuffers' configuration option to chan_dahdi.conf.  This option
+   is used in conjunction with the 'faxdetect' configuration option.  When
+   'faxbuffers' is used and fax tones are detected, the channel will dynamically
+   switch to the configured faxbuffers policy.  For example, to use 6 buffers
+   and a 'full' buffer policy for a fax transmission, add:
+     faxbuffers=>6,full
+   The faxbuffers configuration will be in affect until the call is torn down.
 
 Dialplan Functions
 ------------------
@@ -128,6 +136,8 @@
  * The contrib/scripts/ directory now has a script called sip_nat_settings that will
    give you the correct output for an asterisk box behind nat. It will give you the
    externhost and localnet settings.
+ * The Asterisk core now supports ITU G.722.1 and G.722.1C media streams, and
+   can connect calls in passthrough mode, as well as record and play back files.
 
 Asterisk Manager Interface
 --------------------------
@@ -546,6 +556,7 @@
   * Added support for OSP.  The token is set and retrieved through the CHANNEL()
      dialplan function.
   * Added immediate option to iax.conf
+  * Added forceencryption option to iax.conf
 
 XMPP Google Talk/Jingle changes
 -------------------------------
@@ -725,6 +736,9 @@
   * Added a new parameter for member definition, called state_interface. This may be
     used so that a member may be called via one interface but have a different interface's
     device state reported.
+  * Added new CLI and Manager commands relating to reloading queues. From the CLI, see
+    "queue reload", "queue reset stats". Also see "manager show command QueueReload" and
+    "manager show command QueueReset."
   * New configuration option: randomperiodicannounce. If a list of periodic announcements is
     specified by the periodic-announce option, then one will be chosen randomly when it is time
     to play a periodic announcment

Modified: team/moy/mfcr2/apps/app_chanspy.c
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/apps/app_chanspy.c?view=diff&rev=175776&r1=175775&r2=175776
==============================================================================
--- team/moy/mfcr2/apps/app_chanspy.c (original)
+++ team/moy/mfcr2/apps/app_chanspy.c Sat Feb 14 23:16:52 2009
@@ -46,6 +46,7 @@
 #include "asterisk/say.h"
 #include "asterisk/pbx.h"
 #include "asterisk/translate.h"
+#include "asterisk/manager.h"
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
 #include "asterisk/options.h"
@@ -456,8 +457,9 @@
 	}
 	ast_mutex_unlock(&spyee_chanspy_ds->lock);
 
-	if (!spyee)
+	if (!spyee) {
 		return 0;
+	}
 
 	/* We now hold the channel lock on spyee */
 
@@ -467,7 +469,12 @@
 	}
 
 	name = ast_strdupa(spyee->name);
+
 	ast_verb(2, "Spying on channel %s\n", name);
+	manager_event(EVENT_FLAG_CALL, "ChanSpyStart",
+			"SpyerChannel: %s\r\n"
+			"SpyeeChannel: %s\r\n",
+			spyer_name, name);
 
 	memset(&csth, 0, sizeof(csth));
 
@@ -627,6 +634,7 @@
 	ast_audiohook_destroy(&csth.spy_audiohook);
 	
 	ast_verb(2, "Done Spying on channel %s\n", name);
+	manager_event(EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
 
 	return running;
 }

Modified: team/moy/mfcr2/apps/app_queue.c
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/apps/app_queue.c?view=diff&rev=175776&r1=175775&r2=175776
==============================================================================
--- team/moy/mfcr2/apps/app_queue.c (original)
+++ team/moy/mfcr2/apps/app_queue.c Sat Feb 14 23:16:52 2009
@@ -497,6 +497,13 @@
 	QUEUE_STRATEGY_WRANDOM
 };
 
+enum queue_reload_mask {
+	QUEUE_RELOAD_PARAMETERS = (1 << 0),
+	QUEUE_RELOAD_MEMBER = (1 << 1),
+	QUEUE_RELOAD_RULES = (1 << 2),
+	QUEUE_RESET_STATS = (1 << 3),
+};
+
 static const struct strategy {
 	int strategy;
 	const char *name;
@@ -543,9 +550,6 @@
 static const char *pm_family = "Queue/PersistentMembers";
 /* The maximum length of each persistent member queue database entry */
 #define PM_MAX_LEN 8192
-
-/*! \brief queues.conf [general] option */
-static int queue_keep_stats = 0;
 
 /*! \brief queues.conf [general] option */
 static int queue_persistent_members = 0;
@@ -1185,7 +1189,6 @@
 		else
 			q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
 	}
-	q->membercount = 0;
 	q->found = 1;
 
 	ast_string_field_set(q, sound_next, "queue-youarenext");
@@ -1238,7 +1241,6 @@
 	int penaltychangetime, inserted = 0;
 
 	if (!(rule = ast_calloc(1, sizeof(*rule)))) {
-		ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum);
 		return -1;
 	}
 
@@ -1511,10 +1513,6 @@
 		q->memberdelay = atoi(val);
 	} else if (!strcasecmp(param, "weight")) {
 		q->weight = atoi(val);
-		if (q->weight)
-			use_weight++;
-		/* With Realtime queues, if the last queue using weights is deleted in realtime,
-		   we will not see any effect on use_weight until next reload. */
 	} else if (!strcasecmp(param, "timeoutrestart")) {
 		q->timeoutrestart = ast_true(val);
 	} else if (!strcasecmp(param, "defaultrule")) {
@@ -1708,6 +1706,7 @@
 		ao2_lock(q);
 		clear_queue(q);
 		q->realtime = 1;
+		q->membercount = 0;
 		/*Before we initialize the queue, we need to set the strategy, so that linear strategy
 		 * will allocate the members properly
 		 */
@@ -1789,6 +1788,7 @@
 	struct call_queue *q = NULL, tmpq = {
 		.name = queuename,	
 	};
+	int prev_weight = 0;
 
 	/* Find the queue in the in-core list first. */
 	q = ao2_find(queues, &tmpq, OBJ_POINTER);
@@ -1812,13 +1812,27 @@
 				return NULL;
 			}
 		}
+		if (q) {
+			prev_weight = q->weight ? 1 : 0;
+		}
 
 		ao2_lock(queues);
+
 		q = find_queue_by_name_rt(queuename, queue_vars, member_config);
-		if (member_config)
+		if (member_config) {
 			ast_config_destroy(member_config);
-		if (queue_vars)
+		}
+		if (queue_vars) {
 			ast_variables_destroy(queue_vars);
+		}
+		/* update the use_weight value if the queue's has gained or lost a weight */ 
+		if (!q->weight && prev_weight) {
+			ast_atomic_fetchadd_int(&use_weight, -1);
+		}
+		if (q->weight && !prev_weight) {
+			ast_atomic_fetchadd_int(&use_weight, +1);
+		}
+		/* Other cases will end up with the proper value for use_weight */
 		ao2_unlock(queues);
 
 	} else {
@@ -5473,6 +5487,12 @@
 	.write = queue_function_memberpenalty_write,
 };
 
+/*! \brief Reload the rules defined in queuerules.conf
+ *
+ * \param reload If 1, then only process queuerules.conf if the file
+ * has changed since the last time we inspected it.
+ * \return Always returns AST_MODULE_LOAD_SUCCESS
+ */
 static int reload_queue_rules(int reload)
 {
 	struct ast_config *cfg;
@@ -5484,59 +5504,80 @@
 	
 	if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
 		ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
+		return AST_MODULE_LOAD_SUCCESS;
 	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
 		ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
 		return AST_MODULE_LOAD_SUCCESS;
 	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
 		ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format.  Aborting.\n");
 		return AST_MODULE_LOAD_SUCCESS;
-	} else {
-		AST_LIST_LOCK(&rule_lists);
-		while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
-			while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
-				ast_free(pr_iter);
-			ast_free(rl_iter);
-		}
-		while ((rulecat = ast_category_browse(cfg, rulecat))) {
-			if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
-				ast_log(LOG_ERROR, "Memory allocation error while loading queuerules.conf! Aborting!\n");
-				AST_LIST_UNLOCK(&rule_lists);
-				return AST_MODULE_LOAD_FAILURE;
-			} else {
-				ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
-				AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
-				for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
-					if(!strcasecmp(rulevar->name, "penaltychange"))
-						insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
-					else
-						ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
-			}
-		}
-		AST_LIST_UNLOCK(&rule_lists);
-	}
+	}
+
+	AST_LIST_LOCK(&rule_lists);
+	while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
+		while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
+			ast_free(pr_iter);
+		ast_free(rl_iter);
+	}
+	while ((rulecat = ast_category_browse(cfg, rulecat))) {
+		if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
+			AST_LIST_UNLOCK(&rule_lists);
+			return AST_MODULE_LOAD_FAILURE;
+		} else {
+			ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
+			AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
+			for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
+				if(!strcasecmp(rulevar->name, "penaltychange"))
+					insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
+				else
+					ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
+		}
+	}
+	AST_LIST_UNLOCK(&rule_lists);
 
 	ast_config_destroy(cfg);
 
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
-
-static int reload_queues(int reload)
-{
-	struct call_queue *q;
-	struct ast_config *cfg;
-	char *cat, *tmp;
-	struct ast_variable *var;
+/*! Set the global queue parameters as defined in the "general" section of queues.conf */
+static void queue_set_global_params(struct ast_config *cfg)
+{
+	const char *general_val = NULL;
+	queue_persistent_members = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
+		queue_persistent_members = ast_true(general_val);
+	autofill_default = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
+		autofill_default = ast_true(general_val);
+	montype_default = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
+		if (!strcasecmp(general_val, "mixmonitor"))
+			montype_default = 1;
+	}
+	update_cdr = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
+		update_cdr = ast_true(general_val);
+	shared_lastcall = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
+		shared_lastcall = ast_true(general_val);
+}
+
+/*! \brief reload information pertaining to a single member
+ *
+ * This function is called when a member = line is encountered in
+ * queues.conf.
+ *
+ * \param memberdata The part after member = in the config file
+ * \param q The queue to which this member belongs
+ */
+static void reload_single_member(const char *memberdata, struct call_queue *q)
+{
+	char *membername, *interface, *state_interface, *tmp;
+	char *parse;
 	struct member *cur, *newm;
-	struct ao2_iterator mem_iter;
-	int new;
-	const char *general_val = NULL;
-	char parse[80];
-	char *interface, *state_interface;
-	char *membername = NULL;
+	struct member tmpmem;
 	int penalty;
-	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-	struct ao2_iterator queue_iter;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(interface);
 		AST_APP_ARG(penalty);
@@ -5544,195 +5585,323 @@
 		AST_APP_ARG(state_interface);
 	);
 
-	/*First things first. Let's load queuerules.conf*/
-	if (reload_queue_rules(reload) == AST_MODULE_LOAD_FAILURE)
-		return AST_MODULE_LOAD_FAILURE;
-		
+	/* Add a new member */
+	parse = ast_strdupa(memberdata);
+				
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	interface = args.interface;
+	if (!ast_strlen_zero(args.penalty)) {
+		tmp = args.penalty;
+		ast_strip(tmp);
+		penalty = atoi(tmp);
+		if (penalty < 0) {
+			penalty = 0;
+		}
+	} else {
+		penalty = 0;
+	}
+
+	if (!ast_strlen_zero(args.membername)) {
+		membername = args.membername;
+		ast_strip(membername);
+	} else {
+		membername = interface;
+	}
+
+	if (!ast_strlen_zero(args.state_interface)) {
+		state_interface = args.state_interface;
+		ast_strip(state_interface);
+	} else {
+		state_interface = interface;
+	}
+
+	/* Find the old position in the list */
+	ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
+	cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
+	if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
+		ao2_link(q->members, newm);
+		ao2_ref(newm, -1);
+	}
+	newm = NULL;
+
+	if (cur) {
+		ao2_ref(cur, -1);
+	} else {
+		q->membercount++;
+	}
+}
+
+static int mark_member_dead(void *obj, void *arg, int flags)
+{
+	struct member *member = obj;
+	if (!member->dynamic) {
+		member->delme = 1;
+	}
+	return 0;
+}
+
+static int kill_dead_members(void *obj, void *arg, int flags)
+{
+	struct member *member = obj;
+	struct call_queue *q = arg;
+
+	if (!member->delme) {
+		if (member->dynamic) {
+			/* dynamic members were not counted toward the member count
+			 * when reloading members from queues.conf, so we do that here
+			 */
+			q->membercount++;
+		}
+		member->status = ast_device_state(member->state_interface);
+		return 0;
+	} else {
+		q->membercount--;
+		return CMP_MATCH;
+	}
+}
+
+/*! \brief Reload information pertaining to a particular queue
+ *
+ * Once we have isolated a queue within reload_queues, we call this. This will either
+ * reload information for the queue or if we're just reloading member information, we'll just
+ * reload that without touching other settings within the queue 
+ *
+ * \param cfg The configuration which we are reading
+ * \param mask Tells us what information we need to reload
+ * \param queuename The name of the queue we are reloading information from
+ * \retval void
+ */
+static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
+{
+	int new;
+	struct call_queue *q = NULL;
+	/*We're defining a queue*/
+	struct call_queue tmpq = {
+		.name = queuename,
+	};
+	const char *tmpvar;
+	const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
+	const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
+	int prev_weight = 0;
+	struct ast_variable *var;
+	if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
+		if (queue_reload) {
+			/* Make one then */
+			if (!(q = alloc_queue(queuename))) {
+				return;
+			}
+		} else {
+			/* Since we're not reloading queues, this means that we found a queue
+			 * in the configuration file which we don't know about yet. Just return.
+			 */
+			return;
+		}
+		new = 1;
+	} else {
+		new = 0;
+	}
+	
+	if (!new) {
+		ao2_lock(q);
+		prev_weight = q->weight ? 1 : 0;
+	}
+	/* Check if we already found a queue with this name in the config file */
+	if (q->found) {
+		ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
+		if (!new) {
+			/* It should be impossible to *not* hit this case*/
+			ao2_unlock(q);
+		}
+		queue_unref(q);
+		return;
+	}
+	/* Due to the fact that the "linear" strategy will have a different allocation
+	 * scheme for queue members, we must devise the queue's strategy before other initializations.
+	 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
+	 * container used will have only a single bucket instead of the typical number.
+	 */
+	if (queue_reload) {
+		if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
+			q->strategy = strat2int(tmpvar);
+			if (q->strategy < 0) {
+				ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
+				tmpvar, q->name);
+				q->strategy = QUEUE_STRATEGY_RINGALL;
+			}
+		} else {
+			q->strategy = QUEUE_STRATEGY_RINGALL;
+		}
+		init_queue(q);
+	}
+	if (member_reload) {
+		q->membercount = 0;
+		ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
+	}
+	for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
+		if (member_reload && !strcasecmp(var->name, "member")) {
+			reload_single_member(var->value, q);
+		} else if (queue_reload) {
+			queue_set_param(q, var->name, var->value, var->lineno, 1);
+		}
+	}
+	/* At this point, we've determined if the queue has a weight, so update use_weight
+	 * as appropriate
+	 */
+	if (!q->weight && prev_weight) {
+		ast_atomic_fetchadd_int(&use_weight, -1);
+	}
+	else if (q->weight && !prev_weight) {
+		ast_atomic_fetchadd_int(&use_weight, +1);
+	}
+
+	/* Free remaining members marked as delme */
+	if (member_reload) {
+		ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
+	}
+
+	if (new) {
+		ao2_link(queues, q);
+	} else {
+		ao2_unlock(q);
+	}
+	queue_unref(q);
+}
+
+static int mark_dead_and_unfound(void *obj, void *arg, int flags)
+{
+	struct call_queue *q = obj;
+	char *queuename = arg;
+	if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
+		q->dead = 1;
+		q->found = 0;
+	}
+	return 0;
+}
+
+static int kill_dead_queues(void *obj, void *arg, int flags)
+{
+	struct call_queue *q = obj;
+	char *queuename = arg;
+	if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
+		return CMP_MATCH;
+	} else {
+		return 0;
+	}
+}
+
+/*! \brief reload the queues.conf file
+ *
+ * This function reloads the information in the general section of the queues.conf
+ * file and potentially more, depending on the value of mask.
+ *
+ * \param reload 0 if we are calling this the first time, 1 every other time
+ * \param mask Gives flags telling us what information to actually reload
+ * \param queuename If set to a non-zero string, then only reload information from
+ * that particular queue. Otherwise inspect all queues
+ * \retval -1 Failure occurred 
+ * \retval 0 All clear!
+ */
+static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
+{
+	struct ast_config *cfg;
+	char *cat;
+	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+	const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
+
 	if (!(cfg = ast_config_load("queues.conf", config_flags))) {
 		ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
-		return 0;
+		return -1;
 	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
 		return 0;
 	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
 		ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format.  Aborting.\n");
-		return 0;
-	}
+		return -1;
+	}
+
+	/* We've made it here, so it looks like we're doing operations on all queues. */
 	ao2_lock(queues);
-	use_weight=0;
-	/* Mark all queues as dead for the moment */
-	queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK);
-	while ((q = ao2_iterator_next(&queue_iter))) {
-		if (!q->realtime) {
-			q->dead = 1;
-			q->found = 0;
-		}
-		queue_unref(q);
+	
+	/* Mark all queues as dead for the moment if we're reloading queues.
+	 * For clarity, we could just be reloading members, in which case we don't want to mess
+	 * with the other queue parameters at all*/
+	if (queue_reload) {
+		ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
 	}
 
 	/* Chug through config file */
 	cat = NULL;
 	while ((cat = ast_category_browse(cfg, cat)) ) {
-		if (!strcasecmp(cat, "general")) {	
-			/* Initialize global settings */
-			queue_keep_stats = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "keepstats")))
-				queue_keep_stats = ast_true(general_val);
-			queue_persistent_members = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
-				queue_persistent_members = ast_true(general_val);
-			autofill_default = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
-				autofill_default = ast_true(general_val);
-			montype_default = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
-				if (!strcasecmp(general_val, "mixmonitor"))
-					montype_default = 1;
-			}
-			update_cdr = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
-				update_cdr = ast_true(general_val);
-			shared_lastcall = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
-				shared_lastcall = ast_true(general_val);
-		} else {	/* Define queue */
-			/* Look for an existing one */
-			struct call_queue tmpq = {
-				.name = cat,
-			};
-			if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
-				/* Make one then */
-				if (!(q = alloc_queue(cat))) {
-					/* TODO: Handle memory allocation failure */
-				}
-				new = 1;
-			} else
-				new = 0;
-			if (q) {
-				const char *tmpvar = NULL;
-				if (!new)
-					ao2_lock(q);
-				/* Check if a queue with this name already exists */
-				if (q->found) {
-					ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
-					if (!new) {
-						ao2_unlock(q);
-						queue_unref(q);
-					}
-					continue;
-				}
-				/* Due to the fact that the "linear" strategy will have a different allocation
-				 * scheme for queue members, we must devise the queue's strategy before other initializations
-				 */
-				if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) {
-					q->strategy = strat2int(tmpvar);
-					if (q->strategy < 0) {
-						ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
-						tmpvar, q->name);
-						q->strategy = QUEUE_STRATEGY_RINGALL;
-					}
-				} else
-					q->strategy = QUEUE_STRATEGY_RINGALL;
-				/* Re-initialize the queue, and clear statistics */
-				init_queue(q);
-				if (!queue_keep_stats) 
-					clear_queue(q);
-				mem_iter = ao2_iterator_init(q->members, 0);
-				while ((cur = ao2_iterator_next(&mem_iter))) {
-					if (!cur->dynamic) {
-						cur->delme = 1;
-					}
-					ao2_ref(cur, -1);
-				}
-				for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
-					if (!strcasecmp(var->name, "member")) {
-						struct member tmpmem;
-						membername = NULL;
-
-						/* Add a new member */
-						ast_copy_string(parse, var->value, sizeof(parse));
-						
-						AST_STANDARD_APP_ARGS(args, parse);
-
-						interface = args.interface;
-						if (!ast_strlen_zero(args.penalty)) {
-							tmp = args.penalty;
-							while (*tmp && *tmp < 33) tmp++;
-							penalty = atoi(tmp);
-							if (penalty < 0) {
-								penalty = 0;
-							}
-						} else
-							penalty = 0;
-
-						if (!ast_strlen_zero(args.membername)) {
-							membername = args.membername;
-							while (*membername && *membername < 33) membername++;
-						}
-
-						if (!ast_strlen_zero(args.state_interface)) {
-							state_interface = args.state_interface;
-							while (*state_interface && *state_interface < 33) state_interface++;
-						} else
-							state_interface = interface;
-
-						/* Find the old position in the list */
-						ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
-						cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
-						newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
-						ao2_link(q->members, newm);
-						ao2_ref(newm, -1);
-						newm = NULL;
-
-						if (cur)
-							ao2_ref(cur, -1);
-						else {
-							q->membercount++;
-						}
-					} else {
-						queue_set_param(q, var->name, var->value, var->lineno, 1);
-					}
-				}
-
-				/* Free remaining members marked as delme */
-				mem_iter = ao2_iterator_init(q->members, 0);
-				while ((cur = ao2_iterator_next(&mem_iter))) {
-					if (! cur->delme) {
-						ao2_ref(cur, -1);
-						continue;
-					}
-					q->membercount--;
-					ao2_unlink(q->members, cur);
-					ao2_ref(cur, -1);
-				}
-
-				if (new) {
-					ao2_link(queues, q);
-				} else 
-					ao2_unlock(q);
-				queue_unref(q);
-			}
-		}
-	}
+		if (!strcasecmp(cat, "general") && queue_reload) {
+			queue_set_global_params(cfg);
+			continue;
+		}
+		if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
+			reload_single_queue(cfg, mask, cat);
+	}
+
 	ast_config_destroy(cfg);
-	queue_iter = ao2_iterator_init(queues, 0);
+	/* Unref all the dead queues if we were reloading queues */
+	if (queue_reload) {
+		ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
+	}
+	ao2_unlock(queues);
+	return 0;
+}
+  
+/*! \brief Facilitates resetting statistics for a queue
+ *
+ * This function actually does not reset any statistics, but
+ * rather finds a call_queue struct which corresponds to the
+ * passed-in queue name and passes that structure to the 
+ * clear_queue function. If no queuename is passed in, then
+ * all queues will have their statistics reset.
+ *
+ * \param queuename The name of the queue to reset the statistics
+ * for. If this is NULL or zero-length, then this means to reset
+ * the statistics for all queues
+ * \retval void
+ */
+static int clear_stats(const char *queuename)
+{
+	struct call_queue *q;
+	struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_iterator_next(&queue_iter))) {
-		if (q->dead) {
-			ao2_unlink(queues, q);
-		} else {
-			ao2_lock(q);
-			mem_iter = ao2_iterator_init(q->members, 0);
-			while ((cur = ao2_iterator_next(&mem_iter))) {
-				if (cur->dynamic)
-					q->membercount++;
-				cur->status = ast_device_state(cur->state_interface);
-				ao2_ref(cur, -1);
-			}
-			ao2_unlock(q);
-		}
-		queue_unref(q);
-	}
-	ao2_unlock(queues);
-	return 1;
+		ao2_lock(q);
+		if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
+			clear_queue(q);
+		ao2_unlock(q);
+	}
+	return 0;
+}
+
+/*! \brief The command center for all reload operations
+ *
+ * Whenever any piece of queue information is to be reloaded, this function
+ * is called. It interprets the flags set in the mask parameter and acts
+ * based on how they are set.
+ *
+ * \param reload True if we are reloading information, false if we are loading
+ * information for the first time.
+ * \param mask A bitmask which tells the handler what actions to take
+ * \param queuename The name of the queue on which we wish to take action
+ * \retval 0 All reloads were successful
+ * \retval non-zero There was a failure
+ */
+static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
+{
+	int res = 0;
+
+	if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
+		res |= reload_queue_rules(reload);
+	}
+	if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
+		res |= clear_stats(queuename);
+	}
+	if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
+		res |= reload_queues(reload, mask, queuename);
+	}
+	return res;
 }
 
 /*! \brief direct ouput to manager or cli with proper terminator */
@@ -6256,6 +6425,53 @@
 	return 0;
 }
 
+static int manager_queue_reload(struct mansession *s, const struct message *m)
+{
+	struct ast_flags mask = {0,};
+	const char *queuename = NULL;
+	int header_found = 0;
+
+	queuename = astman_get_header(m, "Queue");
+	if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
+		header_found = 1;
+	}
+	if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_RULES);
+		header_found = 1;
+	}
+	if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
+		header_found = 1;
+	}
+
+	if (!header_found) {
+		ast_set_flag(&mask, AST_FLAGS_ALL);
+	}
+
+	if (!reload_handler(1, &mask, queuename)) {
+		astman_send_ack(s, m, "Queue reloaded successfully");
+	} else {
+		astman_send_error(s, m, "Error encountered while reloading queue");
+	}
+	return 0;
+}
+
+static int manager_queue_reset(struct mansession *s, const struct message *m)
+{
+	const char *queuename = NULL;
+	struct ast_flags mask = {QUEUE_RESET_STATS,};
+	
+	queuename = astman_get_header(m, "Queue");
+
+	if (!reload_handler(1, &mask, queuename)) {
+		astman_send_ack(s, m, "Queue stats reset successfully");
+	} else {
+		astman_send_error(s, m, "Error encountered while resetting queue stats");
+	}
+	return 0;
+}
+
 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
 {
 	/* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
@@ -6662,19 +6878,100 @@
 	return CLI_SUCCESS; 
 }
 
-static char *handle_queue_rule_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
+static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct ast_flags mask = {QUEUE_RESET_STATS,};
+	int i;
+
 	switch (cmd) {
 		case CLI_INIT:
-			e->command = "queue reload rules";
-			e->usage = 
-				"Usage: queue reload rules\n"
-				"	Reloads rules defined in queuerules.conf\n";
+			e->command = "queue reset stats";
+			e->usage =
+				"Usage: queue reset stats [<queuenames>]\n"
+				"\n"
+				"Issuing this command will reset statistics for\n"
+				"<queuenames>, or for all queues if no queue is\n"
+				"specified.\n";
 			return NULL;
 		case CLI_GENERATE:
+			if (a->pos >= 3) {
+				return complete_queue(a->line, a->word, a->pos, a->n);
+			} else {
+				return NULL;
+			}
+	}
+
+	if (a->argc < 3) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (a->argc == 3) {
+		reload_handler(1, &mask, NULL);
+		return CLI_SUCCESS;
+	}
+
+	for (i = 3; i < a->argc; ++i) {
+		reload_handler(1, &mask, a->argv[i]);
+	}
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct ast_flags mask = {0,};
+	int i;
+
+	switch (cmd) {
+		case CLI_INIT:
+			e->command = "queue reload {parameters|members|rules|all}";
+			e->usage =
+				"Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
+				"Reload queues. If <queuenames> are specified, only reload information pertaining\n"
+				"to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
+				"specified in order to know what information to reload. Below is an explanation\n"
+				"of each of these qualifiers.\n"
+				"\n"
+				"\t'members' - reload queue members from queues.conf\n"
+				"\t'parameters' - reload all queue options except for queue members\n"
+				"\t'rules' - reload the queuerules.conf file\n"
+				"\t'all' - reload queue rules, parameters, and members\n"
+				"\n"
+				"Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
+				"Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
+				"one queue is specified when using this command, reloading queue rules may cause\n"
+				"other queues to be affected\n";
 			return NULL;
-	}
-	reload_queue_rules(1);
+		case CLI_GENERATE:
+			if (a->pos >= 3) {
+				return complete_queue(a->line, a->word, a->pos, a->n);
+			} else {
+				return NULL;
+			}
+	}
+
+	if (a->argc < 3)
+		return CLI_SHOWUSAGE;
+
+	if (!strcasecmp(a->argv[2], "rules")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_RULES);
+	} else if (!strcasecmp(a->argv[2], "members")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
+	} else if (!strcasecmp(a->argv[2], "parameters")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
+	} else if (!strcasecmp(a->argv[2], "all")) {
+		ast_set_flag(&mask, AST_FLAGS_ALL);
+	}
+
+	if (a->argc == 3) {
+		reload_handler(1, &mask, NULL);
+		return CLI_SUCCESS;
+	}
+
+	for (i = 3; i < a->argc; ++i) {
+		reload_handler(1, &mask, a->argv[i]);
+	}
+
 	return CLI_SUCCESS;
 }
 
@@ -6694,7 +6991,8 @@
 	AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
 	AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
 	AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
-	AST_CLI_DEFINE(handle_queue_rule_reload, "Reload the rules defined in queuerules.conf"),
+	AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
+	AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
 };
 
 static int unload_module(void)
@@ -6750,10 +7048,13 @@
 {
 	int res;
 	struct ast_context *con;
+	struct ast_flags mask = {AST_FLAGS_ALL, };
 
 	queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
 
-	if (!reload_queues(0))
+	use_weight = 0;
+
+	if (reload_handler(0, &mask, NULL))
 		return AST_MODULE_LOAD_DECLINE;
 
 	con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
@@ -6781,6 +7082,8 @@
 	res |= ast_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log");
 	res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member"); 
 	res |= ast_manager_register("QueueRule", 0, manager_queue_rule_show, "Queue Rules");
+	res |= ast_manager_register("QueueReload", 0, manager_queue_reload, "Reload a queue, queues, or any sub-section of a queue or queues");
+	res |= ast_manager_register("QueueReset", 0, manager_queue_reset, "Reset queue statistics");
 	res |= ast_custom_function_register(&queuevar_function);
 	res |= ast_custom_function_register(&queuemembercount_function);
 	res |= ast_custom_function_register(&queuemembercount_dep);
@@ -6803,8 +7106,9 @@
 
 static int reload(void)
 {
+	struct ast_flags mask = {AST_FLAGS_ALL,};
 	ast_unload_realtime("queue_members");
-	reload_queues(1);
+	reload_handler(1, &mask, NULL);
 	return 0;
 }
 

Modified: team/moy/mfcr2/apps/app_record.c
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/apps/app_record.c?view=diff&rev=175776&r1=175775&r2=175776
==============================================================================
--- team/moy/mfcr2/apps/app_record.c (original)
+++ team/moy/mfcr2/apps/app_record.c Sat Feb 14 23:16:52 2009
@@ -75,6 +75,9 @@
 					<option name="x">
 						<para>Ignore all terminator keys (DTMF) and keep recording until hangup.</para>
 					</option>
+					<option name="k">
+					        <para>Keep recording if channel hangs up.</para>
+					</option>	
 				</optionlist>
 			</parameter>
 		</syntax>
@@ -112,11 +115,13 @@
 	OPTION_SKIP = (1 << 3),
 	OPTION_STAR_TERMINATE = (1 << 4),
 	OPTION_IGNORE_TERMINATE = (1 << 5),
-	FLAG_HAS_PERCENT = (1 << 6),
+	OPTION_KEEP = (1 << 6),
+	FLAG_HAS_PERCENT = (1 << 7),
 };
 
 AST_APP_OPTIONS(app_opts,{
 	AST_APP_OPTION('a', OPTION_APPEND),
+	AST_APP_OPTION('k', OPTION_KEEP),	
 	AST_APP_OPTION('n', OPTION_NOANSWER),
 	AST_APP_OPTION('q', OPTION_QUIET),
 	AST_APP_OPTION('s', OPTION_SKIP),
@@ -378,7 +383,9 @@
 		ast_debug(1, "Got hangup\n");
 		res = -1;
 		pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "HANGUP");
-		ast_filedelete(args.filename, NULL);
+		if (!ast_test_flag(&flags, OPTION_KEEP)) {
+			ast_filedelete(args.filename, NULL);
+		}
 	}
 
 	if (gotsilence) {

Modified: team/moy/mfcr2/apps/app_voicemail.c
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/apps/app_voicemail.c?view=diff&rev=175776&r1=175775&r2=175776
==============================================================================
--- team/moy/mfcr2/apps/app_voicemail.c (original)
+++ team/moy/mfcr2/apps/app_voicemail.c Sat Feb 14 23:16:52 2009
@@ -8894,7 +8894,8 @@
 #ifdef IMAP_STORAGE
 	vms.interactive = 1;
 	vms.updated = 1;
-	ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
+	if (vmu)
+		ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
 	vmstate_insert(&vms);
 	init_vm_state(&vms);
 #endif

Modified: team/moy/mfcr2/build_tools/cflags.xml
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/build_tools/cflags.xml?view=diff&rev=175776&r1=175775&r2=175776
==============================================================================
--- team/moy/mfcr2/build_tools/cflags.xml (original)
+++ team/moy/mfcr2/build_tools/cflags.xml Sat Feb 14 23:16:52 2009
@@ -22,7 +22,6 @@
 			<defaultenabled>no</defaultenabled>
 		</member>
 		<member name="G711_REDUCED_BRANCHING" displayname="New ulaw/alaw codec, reduced branching (might help it run faster in some architectures)">
-			<defaultenabled>yes</defaultenabled>
 			<depend>G711_NEW_ALGORITHM</depend>
 		</member>
 		<member name="TEST_CODING_TABLES" displayname="New ulaw/alaw codec, turn on table tests on init">

Modified: team/moy/mfcr2/channels/chan_dahdi.c
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/channels/chan_dahdi.c?view=diff&rev=175776&r1=175775&r2=175776
==============================================================================
--- team/moy/mfcr2/channels/chan_dahdi.c (original)
+++ team/moy/mfcr2/channels/chan_dahdi.c Sat Feb 14 23:16:52 2009
@@ -643,8 +643,11 @@
 	struct dahdi_pvt *master;				/*!< Master to us (we follow their conferencing) */
 	int inconference;				/*!< If our real should be in the conference */
 
+	int bufsize;                /*!< Size of the buffers */
 	int buf_no;					/*!< Number of buffers */
 	int buf_policy;				/*!< Buffer policy */
+	int faxbuf_no;              /*!< Number of Fax buffers */
+	int faxbuf_policy;          /*!< Fax buffer policy */
 	int sig;					/*!< Signalling style */
 	/*!
 	 * \brief Nonzero if the signaling type is sent over a radio.
@@ -741,6 +744,10 @@
 	unsigned int echocanon:1;
 	/*! \brief TRUE if a fax tone has already been handled. */
 	unsigned int faxhandled:1;
+	/*! \brief TRUE if dynamic faxbuffers are configured for use, default is OFF */
+	unsigned int usefaxbuffers:1;
+	/*! \brief TRUE while dynamic faxbuffers are in use */
+	unsigned int faxbuffersinuse:1;
 	/*! \brief TRUE if over a radio and dahdi_read() has been called. */
 	unsigned int firstradio:1;
 	/*!
@@ -1330,7 +1337,10 @@

[... 1855 lines stripped ...]



More information about the asterisk-commits mailing list