[asterisk-commits] oej: branch oej/tdd-sip r97628 - in /team/oej/tdd-sip: ./ apps/ channels/ cod...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jan 9 15:09:53 CST 2008


Author: oej
Date: Wed Jan  9 15:09:52 2008
New Revision: 97628

URL: http://svn.digium.com/view/asterisk?view=rev&rev=97628
Log:
Reset, resolve

Added:
    team/oej/tdd-sip/channels/console_board.c
      - copied unchanged from r97623, trunk/channels/console_board.c
    team/oej/tdd-sip/images/font.png
      - copied unchanged from r97623, trunk/images/font.png
Modified:
    team/oej/tdd-sip/   (props changed)
    team/oej/tdd-sip/CHANGES
    team/oej/tdd-sip/apps/app_meetme.c
    team/oej/tdd-sip/apps/app_queue.c
    team/oej/tdd-sip/apps/app_voicemail.c
    team/oej/tdd-sip/channels/Makefile
    team/oej/tdd-sip/channels/chan_console.c
    team/oej/tdd-sip/channels/chan_gtalk.c
    team/oej/tdd-sip/channels/chan_mgcp.c
    team/oej/tdd-sip/channels/chan_oss.c
    team/oej/tdd-sip/channels/chan_sip.c
    team/oej/tdd-sip/channels/chan_zap.c
    team/oej/tdd-sip/channels/console_gui.c
    team/oej/tdd-sip/channels/console_video.c
    team/oej/tdd-sip/channels/console_video.h
    team/oej/tdd-sip/codecs/codec_zap.c
    team/oej/tdd-sip/configs/queues.conf.sample
    team/oej/tdd-sip/funcs/func_groupcount.c
    team/oej/tdd-sip/images/kpad2.jpg
    team/oej/tdd-sip/main/asterisk.c
    team/oej/tdd-sip/main/autoservice.c
    team/oej/tdd-sip/main/cli.c
    team/oej/tdd-sip/main/editline/readline.c
    team/oej/tdd-sip/main/utils.c
    team/oej/tdd-sip/res/res_features.c
    team/oej/tdd-sip/res/res_jabber.c

Propchange: team/oej/tdd-sip/
------------------------------------------------------------------------------
    automerge = http://www.codename-pineapple.org/

Propchange: team/oej/tdd-sip/
------------------------------------------------------------------------------
Binary property 'branch-1.4-blocked' - no diff available.

Propchange: team/oej/tdd-sip/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Propchange: team/oej/tdd-sip/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Wed Jan  9 15:09:52 2008
@@ -1,1 +1,1 @@
-/trunk:1-97117
+/trunk:1-97627

Modified: team/oej/tdd-sip/CHANGES
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/CHANGES?view=diff&rev=97628&r1=97627&r2=97628
==============================================================================
--- team/oej/tdd-sip/CHANGES (original)
+++ team/oej/tdd-sip/CHANGES Wed Jan  9 15:09:52 2008
@@ -265,6 +265,9 @@
   * Added new channel variable QUEUE_MIN_PENALTY
   * QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY may be adjusted in mid-call by defining
      rules in queuerules.conf. See configs/queuerules.conf.sample for details
+  * 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.
 
 MeetMe Changes
 --------------

Modified: team/oej/tdd-sip/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/apps/app_meetme.c?view=diff&rev=97628&r1=97627&r2=97628
==============================================================================
--- team/oej/tdd-sip/apps/app_meetme.c (original)
+++ team/oej/tdd-sip/apps/app_meetme.c Wed Jan  9 15:09:52 2008
@@ -1796,7 +1796,7 @@
 		goto outrun;
 	}
 
-	retryzap = (strcasecmp(chan->tech->type, "Zap") || chan->audiohooks ? 1 : 0);
+	retryzap = (strcasecmp(chan->tech->type, "Zap") || (chan->audiohooks || chan->monitor) ? 1 : 0);
 	user->zapchannel = !retryzap;
 
  zapretry:
@@ -2240,14 +2240,14 @@
 				break;
 
 			if (c) {
-				if (c->fds[0] != origfd || (user->zapchannel && c->audiohooks)) {
+				if (c->fds[0] != origfd || (user->zapchannel && (c->audiohooks || c->monitor))) {
 					if (using_pseudo) {
 						/* Kill old pseudo */
 						close(fd);
 						using_pseudo = 0;
 					}
 					ast_debug(1, "Ooh, something swapped out under us, starting over\n");
-					retryzap = (strcasecmp(c->tech->type, "Zap") || c->audiohooks ? 1 : 0);
+					retryzap = (strcasecmp(c->tech->type, "Zap") || (c->audiohooks || c->monitor) ? 1 : 0);
 					user->zapchannel = !retryzap;
 					goto zapretry;
 				}

Modified: team/oej/tdd-sip/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/apps/app_queue.c?view=diff&rev=97628&r1=97627&r2=97628
==============================================================================
--- team/oej/tdd-sip/apps/app_queue.c (original)
+++ team/oej/tdd-sip/apps/app_queue.c Wed Jan  9 15:09:52 2008
@@ -352,7 +352,8 @@
 };
 
 struct member {
-	char interface[80];                 /*!< Technology/Location */
+	char interface[80];                 /*!< Technology/Location to dial to reach this member*/
+	char state_interface[80];           /*!< Technology/Location from which to read devicestate changes */
 	char membername[80];                /*!< Member name to use in queue logs */
 	int penalty;                        /*!< Are we a last resort? */
 	int calls;                          /*!< Number of calls serviced by this member */
@@ -496,6 +497,7 @@
 static void update_realtime_members(struct call_queue *q);
 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
 
+/*! \brief sets the QUEUESTATUS channel variable */
 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
 {
 	int i;
@@ -603,6 +605,12 @@
 	QUEUE_NORMAL
 };
 
+/*! \brief Check if members are available
+ *
+ * This function checks to see if members are available to be called. If any member
+ * is available, the function immediately returns QUEUE_NORMAL. If no members are available,
+ * the appropriate reason why is returned
+ */
 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty, int min_penalty)
 {
 	struct member *member;
@@ -644,7 +652,7 @@
 	int state;
 	char dev[0];
 };
-
+/*! \brief set a member's status based on device state of that member's state_interface*/
 static void *handle_statechange(struct statechange *sc)
 {
 	struct call_queue *q;
@@ -690,7 +698,7 @@
 		while ((cur = ao2_iterator_next(&mem_iter))) {
 			char *interface;
 			char *slash_pos;
-			interface = ast_strdupa(cur->interface);
+			interface = ast_strdupa(cur->state_interface);
 			if ((slash_pos = strchr(interface, '/')))
 				if ((slash_pos = strchr(slash_pos + 1, '/')))
 					*slash_pos = '\0';
@@ -747,6 +755,7 @@
 	.thread = AST_PTHREADT_NULL,
 };
 
+/*! \brief Consumer of the statechange queue */
 static void *device_state_thread(void *data)
 {
 	struct statechange *sc = NULL;
@@ -780,7 +789,7 @@
 
 	return NULL;
 }
-
+/*! \brief Producer of the statechange queue */
 static int statechange_queue(const char *dev, enum ast_device_state state)
 {
 	struct statechange *sc;
@@ -798,7 +807,6 @@
 
 	return 0;
 }
-
 static void device_state_cb(const struct ast_event *event, void *unused)
 {
 	enum ast_device_state state;
@@ -815,7 +823,8 @@
 	statechange_queue(device, state);
 }
 
-static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
+/*! \brief allocate space for new queue member and set fields based on parameters passed */
+static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
 {
 	struct member *cur;
 	
@@ -823,6 +832,10 @@
 		cur->penalty = penalty;
 		cur->paused = paused;
 		ast_copy_string(cur->interface, interface, sizeof(cur->interface));
+		if (!ast_strlen_zero(state_interface))
+			ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
+		else
+			ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
 		if (!ast_strlen_zero(membername))
 			ast_copy_string(cur->membername, membername, sizeof(cur->membername));
 		else
@@ -958,20 +971,20 @@
 {
 	struct call_queue *q;
 	struct member *mem, tmpmem;
-	struct ao2_iterator queue_iter;
+	struct ao2_iterator queue_iter, mem_iter;
 	int ret = 0;
 
 	ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
 	queue_iter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_iterator_next(&queue_iter))) {
-
 		ao2_lock(q);
-		if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
-			ao2_ref(mem, -1);
-			ao2_unlock(q);
-			queue_unref(q);
-			ret = 1;
-			break;
+		mem_iter = ao2_iterator_init(q->members, 0);
+		while ((mem = ao2_iterator_next(&mem_iter))) { 
+			if (!strcasecmp(mem->state_interface, interface)) {
+				ao2_ref(mem, -1);
+				ret = 1;
+				break;
+			}
 		}
 		ao2_unlock(q);
 		queue_unref(q);
@@ -991,7 +1004,7 @@
 				ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
 				AST_LIST_REMOVE_CURRENT(list);
 				ast_free(curint);
-			}
+			} 
 			break;
 		}
 	}
@@ -1256,7 +1269,7 @@
 	}
 }
 
-static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
+static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
 {
 	struct member *m, tmpmem;
 	int penalty = 0;
@@ -1280,10 +1293,10 @@
 
 	/* Create a new one if not found, else update penalty */
 	if (!m) {
-		if ((m = create_queue_member(interface, membername, penalty, paused))) {
+		if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
 			m->dead = 0;
 			m->realtime = 1;
-			add_to_interfaces(interface);
+			add_to_interfaces(state_interface);
 			ao2_link(q->members, m);
 			ao2_ref(m, -1);
 			m = NULL;
@@ -1293,6 +1306,11 @@
 		m->dead = 0;	/* Do not delete this one. */
 		if (paused_str)
 			m->paused = paused;
+		if (strcasecmp(state_interface, m->state_interface)) {
+			remove_from_interfaces(m->state_interface);
+			ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
+			add_to_interfaces(m->state_interface);
+		}
 		m->penalty = penalty;
 		ao2_ref(m, -1);
 	}
@@ -1307,7 +1325,7 @@
 	while ((cur = ao2_iterator_next(&mem_iter))) {
 		if (all || !cur->dynamic) {
 			ao2_unlink(q->members, cur);
-			remove_from_interfaces(cur->interface);
+			remove_from_interfaces(cur->state_interface);
 			q->membercount--;
 		}
 		ao2_ref(cur, -1);
@@ -1436,7 +1454,8 @@
 		rt_handle_member_record(q, interface,
 			ast_variable_retrieve(member_config, interface, "membername"),
 			ast_variable_retrieve(member_config, interface, "penalty"),
-			ast_variable_retrieve(member_config, interface, "paused"));
+			ast_variable_retrieve(member_config, interface, "paused"),
+			ast_variable_retrieve(member_config, interface, "state_interface"));
 	}
 
 	/* Delete all realtime members that have been deleted in DB. */
@@ -1444,9 +1463,7 @@
 	while ((m = ao2_iterator_next(&mem_iter))) {
 		if (m->dead) {
 			ao2_unlink(q->members, m);
-			ao2_unlock(q);
-			remove_from_interfaces(m->interface);
-			ao2_lock(q);
+			remove_from_interfaces(m->state_interface);
 			q->membercount--;
 		}
 		ao2_ref(m, -1);
@@ -1549,7 +1566,8 @@
 		rt_handle_member_record(q, interface,
 			S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
 			ast_variable_retrieve(member_config, interface, "penalty"),
-			ast_variable_retrieve(member_config, interface, "paused"));
+			ast_variable_retrieve(member_config, interface, "paused"),
+			ast_variable_retrieve(member_config, interface, "state_interface"));
 	}
 
 	/* Delete all realtime members that have been deleted in DB. */
@@ -1557,9 +1575,7 @@
 	while ((m = ao2_iterator_next(&mem_iter))) {
 		if (m->dead) {
 			ao2_unlink(q->members, m);
-			ao2_unlock(q);
-			remove_from_interfaces(m->interface);
-			ao2_lock(q);
+			remove_from_interfaces(m->state_interface);
 			q->membercount--;
 		}
 		ao2_ref(m, -1);
@@ -2013,6 +2029,11 @@
 	return vars;
 }
 
+/*! \brief Part 2 of ring_one
+ *
+ * Does error checking before attempting to request a channel and call a member. This
+ * function is only called from ring_one
+ */
 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
 {
 	int res;
@@ -2160,6 +2181,14 @@
 	return best;
 }
 
+/*! \brief Place a call to a queue member
+ *
+ * Once metrics have been calculated for each member, this function is used
+ * to place a call to the appropriate member (or members). The low-level
+ * channel-handling and error detection is handled in ring_entry
+ *
+ * Returns 1 if a member was called successfully, 0 otherwise
+ */
 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 {
 	int ret = 0;
@@ -2317,7 +2346,16 @@
 }
 
 #define AST_MAX_WATCHERS 256
-
+/*! \brief Wait for a member to answer the call
+ *
+ * \param[in] qe the queue_ent corresponding to the caller in the queue
+ * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
+ * \param[in] to the amount of time (in milliseconds) to wait for a response
+ * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
+ * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
+ * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
+ * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
+ */
 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
 {
 	const char *queue = qe->parent->name;
@@ -2564,7 +2602,15 @@
 
 	return peer;
 }
-
+/*! \brief Check if we should start attempting to call queue members
+ *
+ * The behavior of this function is dependent first on whether autofill is enabled
+ * and second on whether the ring strategy is ringall. If autofill is not enabled,
+ * then return true if we're the head of the queue. If autofill is enabled, then
+ * we count the available members and see if the number of available members is enough
+ * that given our position in the queue, we would theoretically be able to connect to
+ * one of those available members
+ */
 static int is_our_turn(struct queue_ent *qe)
 {
 	struct queue_ent *ch;
@@ -2629,7 +2675,6 @@
 
 	return res;
 }
-
 static void update_qe_rule(struct queue_ent *qe)
 {
 	int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
@@ -2652,6 +2697,16 @@
 	qe->pr = AST_LIST_NEXT(qe->pr, list);
 }
 
+/*! \brief The waiting areas for callers who are not actively calling members
+ *
+ * This function is one large loop. This function will return if a caller
+ * either exits the queue or it becomes that caller's turn to attempt calling
+ * queue members. Inside the loop, we service the caller with periodic announcements,
+ * holdtime announcements, etc. as configured in queues.conf
+ *
+ * \retval  0 if the caller's turn has arrived
+ * \retval -1 if the caller should exit the queue.
+ */
 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
 {
 	int res = 0;
@@ -2754,6 +2809,12 @@
 	return 0;
 }
 
+/*! \brief Calculate the metric of each member in the outgoing callattempts
+ *
+ * A numeric metric is given to each member depending on the ring strategy used
+ * by the queue. Members with lower metrics will be called before members with
+ * higher metrics
+ */
 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 {
 	if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty)))
@@ -2852,7 +2913,32 @@
 		(long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
 		qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
 }
-
+/*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
+ * 
+ * Here is the process of this function
+ * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
+ * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
+ *    iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
+ *    member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
+ *    during each iteration, we call calc_metric to determine which members should be rung when.
+ * 3. Call ring_one to place a call to the appropriate member(s)
+ * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
+ * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
+ * 6. Start the monitor or mixmonitor if the option is set
+ * 7. Remove the caller from the queue to allow other callers to advance
+ * 8. Bridge the call.
+ * 9. Do any post processing after the call has disconnected.
+ *
+ * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
+ * \param[in] options the options passed as the third parameter to the Queue() application
+ * \param[in] url the url passed as the fourth parameter to the Queue() application
+ * \param[in,out] tries the number of times we have tried calling queue members
+ * \param[out] noption set if the call to Queue() has the 'n' option set.
+ * \param[in] agi the agi passed as the fifth parameter to the Queue() application
+ * \param[in] macro the macro passed as the sixth parameter to the Queue() application
+ * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
+ * \param[in] ringing 1 if the 'r' option is set, otherwise 0
+ */
 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
 {
 	struct member *cur;
@@ -3578,6 +3664,7 @@
 				"MemberName: %s\r\n",
 				q->name, mem->interface, mem->membername);
 			ao2_unlink(q->members, mem);
+			remove_from_interfaces(mem->state_interface);
 			ao2_ref(mem, -1);
 
 			if (queue_persistent_members)
@@ -3591,14 +3678,11 @@
 		queue_unref(q);
 	}
 
-	if (res == RES_OKAY)
-		remove_from_interfaces(interface);
-
 	return res;
 }
 
 
-static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
+static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
 {
 	struct call_queue *q;
 	struct member *new_member, *old_member;
@@ -3613,8 +3697,8 @@
 
 	ao2_lock(q);
 	if ((old_member = interface_exists(q, interface)) == NULL) {
-		add_to_interfaces(interface);
-		if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
+		if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
+			add_to_interfaces(state_interface);
 			new_member->dynamic = 1;
 			ao2_link(q->members, new_member);
 			q->membercount++;
@@ -3797,6 +3881,7 @@
 	char *member;
 	char *interface;
 	char *membername = NULL;
+	char *state_interface;
 	char *penalty_tok;
 	int penalty = 0;
 	char *paused_tok;
@@ -3846,6 +3931,7 @@
 			penalty_tok = strsep(&member, ";");
 			paused_tok = strsep(&member, ";");
 			membername = strsep(&member, ";");
+			state_interface = strsep(&member, ";");
 
 			if (!penalty_tok) {
 				ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
@@ -3866,12 +3952,10 @@
 				ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
 				break;
 			}
-			if (ast_strlen_zero(membername))
-				membername = interface;
 
 			ast_debug(1, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
 			
-			if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
+			if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
 				ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
 				break;
 			}
@@ -4020,6 +4104,7 @@
 		AST_APP_ARG(penalty);
 		AST_APP_ARG(options);
 		AST_APP_ARG(membername);
+		AST_APP_ARG(state_interface);
 	);
 	int penalty = 0;
 
@@ -4046,7 +4131,7 @@
 		}
 	}
 
-	switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
+	switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
 	case RES_OKAY:
 		ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
 		ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
@@ -4133,6 +4218,18 @@
 	AST_LIST_UNLOCK(&rule_lists);
 }
 
+/*!\brief The starting point for all queue calls
+ *
+ * The process involved here is to 
+ * 1. Parse the options specified in the call to Queue()
+ * 2. Join the queue
+ * 3. Wait in a loop until it is our turn to try calling a queue member
+ * 4. Attempt to call a queue member
+ * 5. If 4. did not result in a bridged call, then check for between
+ *    call options such as periodic announcements etc.
+ * 6. Try 4 again uless some condition (such as an expiration time) causes us to 
+ *    exit the queue.
+ */
 static int queue_exec(struct ast_channel *chan, void *data)
 {
 	int res=-1;
@@ -4803,7 +4900,7 @@
 	int new;
 	const char *general_val = NULL;
 	char parse[80];
-	char *interface;
+	char *interface, *state_interface;
 	char *membername = NULL;
 	int penalty;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
@@ -4812,6 +4909,7 @@
 		AST_APP_ARG(interface);
 		AST_APP_ARG(penalty);
 		AST_APP_ARG(membername);
+		AST_APP_ARG(state_interface);
 	);
 
 	/*First things first. Let's load queuerules.conf*/
@@ -4880,8 +4978,10 @@
 				/* 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)
+					if (!new) {
 						ao2_unlock(q);
+						queue_unref(q);
+					}
 					continue;
 				}
 				/* Due to the fact that the "linear" strategy will have a different allocation
@@ -4933,11 +5033,22 @@
 							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);
+						/* Only attempt removing from interfaces list if the new state_interface is different than the old one */
+						if (cur && strcasecmp(cur->state_interface, state_interface)) {
+							remove_from_interfaces(cur->state_interface);
+						}
+						newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
+						if (!cur || (cur && strcasecmp(cur->state_interface, state_interface)))
+							add_to_interfaces(state_interface);
 						ao2_link(q->members, newm);
 						ao2_ref(newm, -1);
 						newm = NULL;
@@ -4945,8 +5056,6 @@
 						if (cur)
 							ao2_ref(cur, -1);
 						else {
-							/* Add them to the master int list if necessary */
-							add_to_interfaces(interface);
 							q->membercount++;
 						}
 					} else {
@@ -4961,16 +5070,16 @@
 						ao2_ref(cur, -1);
 						continue;
 					}
-
-					remove_from_interfaces(cur->interface);
+					ast_log(LOG_DEBUG, "%s in queue marked as delme, we should be deleting...\n", cur->interface);
 					q->membercount--;
 					ao2_unlink(q->members, cur);
+					remove_from_interfaces(cur->interface);
 					ao2_ref(cur, -1);
 				}
 
 				if (new) {
 					ao2_link(queues, q);
-				} else
+				} else 
 					ao2_unlock(q);
 				queue_unref(q);
 			}
@@ -5352,7 +5461,7 @@
 
 static int manager_add_queue_member(struct mansession *s, const struct message *m)
 {
-	const char *queuename, *interface, *penalty_s, *paused_s, *membername;
+	const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
 	int paused, penalty = 0;
 
 	queuename = astman_get_header(m, "Queue");
@@ -5360,6 +5469,7 @@
 	penalty_s = astman_get_header(m, "Penalty");
 	paused_s = astman_get_header(m, "Paused");
 	membername = astman_get_header(m, "MemberName");
+	state_interface = astman_get_header(m, "StateInterface");
 
 	if (ast_strlen_zero(queuename)) {
 		astman_send_error(s, m, "'Queue' not specified.");
@@ -5381,7 +5491,7 @@
 	else
 		paused = abs(ast_true(paused_s));
 
-	switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
+	switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
 	case RES_OKAY:
 		ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
 		astman_send_ack(s, m, "Added interface to queue");
@@ -5537,26 +5647,28 @@
 
 static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	char *queuename, *interface, *membername = NULL;
+	char *queuename, *interface, *membername = NULL, *state_interface = NULL;
 	int penalty;
 
 	switch ( cmd ) {
 	case CLI_INIT:
 		e->command = "queue add member";
 		e->usage =
-			"Usage: queue add member <channel> to <queue> [penalty <penalty>]\n"; 
+			"Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"; 
 		return NULL;
 	case CLI_GENERATE:
 		return complete_queue_add_member(a->line, a->word, a->pos, a->n);
 	}
 
-	if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10)) {
+	if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
 		return CLI_SHOWUSAGE;
 	} else if (strcmp(a->argv[4], "to")) {
 		return CLI_SHOWUSAGE;
-	} else if ((a->argc == 8) && strcmp(a->argv[6], "penalty")) {
+	} else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
 		return CLI_SHOWUSAGE;
-	} else if ((a->argc == 10) && strcmp(a->argv[8], "as")) {
+	} else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
+		return CLI_SHOWUSAGE;
+	} else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
 		return CLI_SHOWUSAGE;
 	}
 
@@ -5580,7 +5692,11 @@
 		membername = a->argv[9];
 	}
 
-	switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
+	if (a->argc >= 12) {
+		state_interface = a->argv[11];
+	}
+
+	switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
 	case RES_OKAY:
 		ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
 		ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);

Modified: team/oej/tdd-sip/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/apps/app_voicemail.c?view=diff&rev=97628&r1=97627&r2=97628
==============================================================================
--- team/oej/tdd-sip/apps/app_voicemail.c (original)
+++ team/oej/tdd-sip/apps/app_voicemail.c Wed Jan  9 15:09:52 2008
@@ -240,13 +240,15 @@
 	OPT_RECORDGAIN =       (1 << 3),
 	OPT_PREPEND_MAILBOX =  (1 << 4),
 	OPT_AUTOPLAY =         (1 << 6),
+	OPT_DTMFEXIT =         (1 << 7),
 } vm_option_flags;
 
 enum {
 	OPT_ARG_RECORDGAIN = 0,
 	OPT_ARG_PLAYFOLDER = 1,
+	OPT_ARG_DTMFEXIT   = 2,
 	/* This *must* be the last value in this enum! */
-	OPT_ARG_ARRAY_SIZE = 2,
+	OPT_ARG_ARRAY_SIZE = 3,
 } vm_option_args;
 
 AST_APP_OPTIONS(vm_app_options, {
@@ -254,6 +256,7 @@
 	AST_APP_OPTION('b', OPT_BUSY_GREETING),
 	AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
 	AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
+	AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
 	AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
 	AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
 });
@@ -496,12 +499,14 @@
 	"               application. The possible values are:\n"
 	"               SUCCESS | USEREXIT | FAILED\n\n"
 	"  Options:\n"
-	"    b    - Play the 'busy' greeting to the calling party.\n"
-	"    g(#) - Use the specified amount of gain when recording the voicemail\n"
-	"           message. The units are whole-number decibels (dB).\n"
-	"    s    - Skip the playback of instructions for leaving a message to the\n"
-	"           calling party.\n"
-	"    u    - Play the 'unavailable' greeting.\n";
+	"    b      - Play the 'busy' greeting to the calling party.\n"
+	"    d([c]) - Accept digits for a new extension in context c, if played during\n"
+	"             the greeting.  Context defaults to the current context.\n"
+	"    g(#)   - Use the specified amount of gain when recording the voicemail\n"
+	"             message. The units are whole-number decibels (dB).\n"
+	"    s      - Skip the playback of instructions for leaving a message to the\n"
+	"             calling party.\n"
+	"    u      - Play the 'unavailable' greeting.\n";
 
 static char *synopsis_vmain = "Check Voicemail messages";
 
@@ -2743,11 +2748,11 @@
 {
 	struct vm_state *sendvms = NULL, *destvms = NULL;
 	char messagestring[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/
-	if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 2))) {
+	if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
 		ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
 		return -1;
 	}
-	if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 2))) {
+	if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
 		ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
 		return -1;
 	}
@@ -2952,6 +2957,7 @@
 struct leave_vm_options {
 	unsigned int flags;
 	signed char record_gain;
+	char *exitcontext;
 };
 
 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
@@ -2983,11 +2989,11 @@
 	char ext_context[256] = "";
 	char fmt[80];
 	char *context;
-	char ecodes[16] = "#";
+	char ecodes[17] = "#";
 	char tmp[1024] = "", *tmpptr;
 	struct ast_vm_user *vmu;
 	struct ast_vm_user svm;
-	const char *category = NULL;
+	const char *category = NULL, *code, *alldtmf = "0123456789ABCD*#";
 
 	ast_copy_string(tmp, ext, sizeof(tmp));
 	ext = tmp;
@@ -3056,6 +3062,15 @@
 	else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
 		strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
 		ausemacro = 1;
+	}
+
+	if (ast_test_flag(options, OPT_DTMFEXIT)) {
+		for (code = alldtmf; *code; code++) {
+			char e[2] = "";
+			e[0] = *code;
+			if (strchr(ecodes, e[0]) == NULL && ast_canmatch_extension(chan, chan->context, e, 1, chan->cid.cid_num))
+				strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
+		}
 	}
 
 	/* Play the beginning intro if desired */
@@ -3102,7 +3117,7 @@
 		ast_stopstream(chan);
 	/* Check for a '*' here in case the caller wants to escape from voicemail to something
 	 other than the operator -- an automated attendant or mailbox login for example */
-	if (res == '*') {
+	if (!ast_strlen_zero(vmu->exit) && (res == '*')) {
 		chan->exten[0] = 'a';
 		chan->exten[1] = '\0';
 		if (!ast_strlen_zero(vmu->exit)) {
@@ -3117,7 +3132,7 @@
 	}
 
 	/* Check for a '0' here */
-	if (res == '0') {
+	if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
 	transfer:
 		if (ouseexten || ousemacro) {
 			chan->exten[0] = 'o';
@@ -3134,6 +3149,16 @@
 		}
 		return 0;
 	}
+
+	/* Allow all other digits to exit Voicemail and return to the dialplan */
+	if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
+		if (!ast_strlen_zero(options->exitcontext))
+			ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
+		free_user(vmu);
+		pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
+		return res;
+	}
+
 	if (res < 0) {
 		free_user(vmu);
 		pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
@@ -4936,7 +4961,7 @@
 		stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
 		if (stream == NIL) {
 			ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
-			return NIL;
+			return -1;
 		}
 		get_mailbox_delimiter(stream);
 		/* update delimiter in imapfolder */
@@ -7400,7 +7425,7 @@
 		if (args.argc == 2) {
 			if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
 				return -1;
-			ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING);
+			ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_DTMFEXIT);
 			if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
 				int gain;
 
@@ -7410,6 +7435,10 @@
 				} else {
 					leave_options.record_gain = (signed char) gain;
 				}
+			}
+			if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
+				if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
+					leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
 			}
 		}
 	} else {

Modified: team/oej/tdd-sip/channels/Makefile
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/channels/Makefile?view=diff&rev=97628&r1=97627&r2=97628
==============================================================================
--- team/oej/tdd-sip/channels/Makefile (original)
+++ team/oej/tdd-sip/channels/Makefile Wed Jan  9 15:09:52 2008
@@ -102,4 +102,4 @@
 
 chan_vpb.oo: ASTCFLAGS:=$(filter-out -Wdeclaration-after-statement,$(ASTCFLAGS))
 
-$(if $(filter chan_oss,$(EMBEDDED_MODS)),modules.link,chan_oss.so): console_video.o vgrabbers.o
+$(if $(filter chan_oss,$(EMBEDDED_MODS)),modules.link,chan_oss.so): console_video.o vgrabbers.o console_board.o

Modified: team/oej/tdd-sip/channels/chan_console.c
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/channels/chan_console.c?view=diff&rev=97628&r1=97627&r2=97628
==============================================================================
--- team/oej/tdd-sip/channels/chan_console.c (original)
+++ team/oej/tdd-sip/channels/chan_console.c Wed Jan  9 15:09:52 2008
@@ -29,7 +29,7 @@
  * 
  * \ingroup channel_drivers
  *
- * \arg http://www.portaudio.com/
+ * \extref Portaudio http://www.portaudio.com/
  *
  * To install portaudio v19 from svn, check it out using the following command:
  *  - svn co https://www.portaudio.com/repos/portaudio/branches/v19-devel

Modified: team/oej/tdd-sip/channels/chan_gtalk.c
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/channels/chan_gtalk.c?view=diff&rev=97628&r1=97627&r2=97628
==============================================================================
--- team/oej/tdd-sip/channels/chan_gtalk.c (original)
+++ team/oej/tdd-sip/channels/chan_gtalk.c Wed Jan  9 15:09:52 2008
@@ -896,6 +896,9 @@
 		return NULL;
 	}
 
+	/* Set CALLERID(name) to the full JID of the remote peer */
+	ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
+
 	if(strchr(tmp->us, '/')) {
 		data = ast_strdupa(tmp->us);
 		exten = strsep(&data, "/");
@@ -917,7 +920,6 @@
 	int fmt;
 	int what;
 	const char *n2;
-	char *data = NULL, *cid = NULL;
 
 	if (title)
 		n2 = title;
@@ -981,20 +983,7 @@
 	ast_module_ref(ast_module_info->self);
 	ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
 	ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
-	/* Don't use ast_set_callerid() here because it will
-	 * generate a needless NewCallerID event */
-	if (!strcasecmp(client->name, "guest")) {
-		data = ast_strdupa(i->them);
-		if (strchr(data, '/')) {
-			cid = strsep(&data, "/");
-		} else
-			cid = data;
-	} else {
-		data =  ast_strdupa(client->user);
-		cid = data;
-	}
-	cid = strsep(&cid, "@");
-	tmp->cid.cid_ani = ast_strdup(cid);
+
 	if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
 		tmp->cid.cid_dnid = ast_strdup(i->exten);
 	tmp->priority = 1;

Modified: team/oej/tdd-sip/channels/chan_mgcp.c
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/channels/chan_mgcp.c?view=diff&rev=97628&r1=97627&r2=97628
==============================================================================
--- team/oej/tdd-sip/channels/chan_mgcp.c (original)
+++ team/oej/tdd-sip/channels/chan_mgcp.c Wed Jan  9 15:09:52 2008
@@ -428,6 +428,7 @@
 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int mgcp_devicestate(void *data);
+static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp);
 
 static const struct ast_channel_tech mgcp_tech = {
 	.type = "MGCP",
@@ -1300,23 +1301,50 @@
 
 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit)
 {
-	/* Let asterisk play inband indications */
-	return -1;
+	struct mgcp_subchannel *sub = ast->tech_pvt;
+	struct mgcp_endpoint *p = sub->parent;
+	int res = 0;
+
+	ast_mutex_lock(&sub->lock);
+	if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
+		ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
+		res = -1; /* Let asterisk play inband indications */
+	} else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
+		ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
+		ast_rtp_senddigit_begin(sub->rtp, digit);
+	} else {
+		ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
+	}
+	ast_mutex_unlock(&sub->lock);
+
+	return res;
 }
 
 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
 	struct mgcp_subchannel *sub = ast->tech_pvt;
+	struct mgcp_endpoint *p = sub->parent;
+	int res = 0;
 	char tmp[4];
 
-	tmp[0] = 'D';
-	tmp[1] = '/';
-	tmp[2] = digit;
-	tmp[3] = '\0';
 	ast_mutex_lock(&sub->lock);
-	transmit_notify_request(sub, tmp);
+	if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
+		ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n");
+		res = -1; /* Tell Asterisk to stop inband indications */
+	} else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
+		ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n");
+		tmp[0] = 'D';
+		tmp[1] = '/';
+		tmp[2] = digit;
+		tmp[3] = '\0';
+		transmit_notify_request(sub, tmp);
+                ast_rtp_senddigit_end(sub->rtp, digit);
+	} else {
+		ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
+	}
 	ast_mutex_unlock(&sub->lock);
-	return -1; /* Return non-zero so that Asterisk will stop the inband indications */
+
+	return res;
 }
 
 /*!
@@ -2209,7 +2237,7 @@
 		add_header(&resp, "R", "L/hd(N)");
 		break;
 	case MGCP_OFFHOOK:
-		add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+		add_header_offhook(sub, &resp);
 		break;
 	}
 	if (!ast_strlen_zero(tone)) {
@@ -2251,7 +2279,7 @@
 		add_header(&resp, "R", "L/hd(N)");
 		break;
 	case MGCP_OFFHOOK:
-		add_header(&resp, "R",  (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+		add_header_offhook(sub, &resp);
 		break;
 	}
 	if (!ast_strlen_zero(tone2)) {
@@ -2292,7 +2320,7 @@
 		add_header(&resp, "R", "L/hd(N)");
 		break;
 	case MGCP_OFFHOOK:
-		add_header(&resp, "R",  (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N), L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+		add_header_offhook(sub, &resp);
 		break;
 	}
 	/* fill in new fields */
@@ -2301,6 +2329,16 @@

[... 1788 lines stripped ...]



More information about the asterisk-commits mailing list