[asterisk-commits] mmichelson: branch mmichelson/trunk-digiumphones r364768 - in /team/mmichelso...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue May 1 13:12:59 CDT 2012


Author: mmichelson
Date: Tue May  1 13:12:53 2012
New Revision: 364768

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=364768
Log:
Resolve conflicts and reset automerge property.


Modified:
    team/mmichelson/trunk-digiumphones/   (props changed)
    team/mmichelson/trunk-digiumphones/CHANGES
    team/mmichelson/trunk-digiumphones/addons/ooh323cDriver.c
    team/mmichelson/trunk-digiumphones/apps/app_dial.c
    team/mmichelson/trunk-digiumphones/apps/app_minivm.c
    team/mmichelson/trunk-digiumphones/apps/confbridge/conf_config_parser.c
    team/mmichelson/trunk-digiumphones/channels/chan_sip.c
    team/mmichelson/trunk-digiumphones/channels/sip/include/sip.h
    team/mmichelson/trunk-digiumphones/configs/sip.conf.sample
    team/mmichelson/trunk-digiumphones/configure
    team/mmichelson/trunk-digiumphones/configure.ac
    team/mmichelson/trunk-digiumphones/formats/format_g719.c
    team/mmichelson/trunk-digiumphones/formats/format_g723.c
    team/mmichelson/trunk-digiumphones/formats/format_g729.c
    team/mmichelson/trunk-digiumphones/formats/format_gsm.c
    team/mmichelson/trunk-digiumphones/formats/format_h263.c
    team/mmichelson/trunk-digiumphones/formats/format_h264.c
    team/mmichelson/trunk-digiumphones/formats/format_ilbc.c
    team/mmichelson/trunk-digiumphones/formats/format_pcm.c
    team/mmichelson/trunk-digiumphones/formats/format_siren14.c
    team/mmichelson/trunk-digiumphones/formats/format_siren7.c
    team/mmichelson/trunk-digiumphones/formats/format_sln.c
    team/mmichelson/trunk-digiumphones/formats/format_vox.c
    team/mmichelson/trunk-digiumphones/formats/format_wav.c
    team/mmichelson/trunk-digiumphones/formats/format_wav_gsm.c
    team/mmichelson/trunk-digiumphones/include/asterisk/autoconfig.h.in
    team/mmichelson/trunk-digiumphones/main/config.c
    team/mmichelson/trunk-digiumphones/main/features.c
    team/mmichelson/trunk-digiumphones/main/logger.c
    team/mmichelson/trunk-digiumphones/main/md5.c
    team/mmichelson/trunk-digiumphones/res/res_corosync.c
    team/mmichelson/trunk-digiumphones/tests/test_config.c

Propchange: team/mmichelson/trunk-digiumphones/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/mmichelson/trunk-digiumphones/
------------------------------------------------------------------------------
Binary property 'branch-10-merged' - no diff available.

Propchange: team/mmichelson/trunk-digiumphones/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue May  1 13:12:53 2012
@@ -1,1 +1,1 @@
-/trunk:1-364360
+/trunk:1-364767

Modified: team/mmichelson/trunk-digiumphones/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/trunk-digiumphones/CHANGES?view=diff&rev=364768&r1=364767&r2=364768
==============================================================================
--- team/mmichelson/trunk-digiumphones/CHANGES (original)
+++ team/mmichelson/trunk-digiumphones/CHANGES Tue May  1 13:12:53 2012
@@ -76,6 +76,9 @@
    the remote endpoint.
  * Adds an option send_diversion which can be disabled to prevent
    diversion headers from automatically being added to invites.
+ * Add support for lightweight NAT keepalive. If enabled a blank packet will
+   be sent to the remote host at a given interval to keep the NAT mapping open.
+   This can be enabled using the keepalive configuration option.
 
 Chan_local changes
 ------------------
@@ -141,6 +144,8 @@
    be supplied with arguments indicating where the callee should go after the caller
    is hung up, or without options specified, the priority after the Queue/Bridge
    will be used.
+ * Added 'b' and 'B' options to Dial that execute a Gosub on callee and caller
+   channels respectively before the callee channels are called.
 
 Parking
 ------------
@@ -207,6 +212,11 @@
    VM_INFO.
  * The REDIRECTING function now supports the redirecting original party id
    and reason.
+ * Two new functions have been added: FEATURE() and FEATUREMAP().  FEATURE()
+   lets you set some of the configuration options from the [general] section
+   of features.conf on a per-channel basis.  FEATUREMAP() lets you customize
+   the key sequence used to activate built-in features, such as blindxfer,
+   and automon.  See the built-in documentation for details.
 
 Followme changes
 -------------

Modified: team/mmichelson/trunk-digiumphones/addons/ooh323cDriver.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/trunk-digiumphones/addons/ooh323cDriver.c?view=diff&rev=364768&r1=364767&r2=364768
==============================================================================
--- team/mmichelson/trunk-digiumphones/addons/ooh323cDriver.c (original)
+++ team/mmichelson/trunk-digiumphones/addons/ooh323cDriver.c Tue May  1 13:12:53 2012
@@ -124,7 +124,7 @@
  free(mycthread);
  ast_module_unref(myself);
  ast_update_use_count();
- return dummy;
+ return NULL;
 }
 
 int ooh323c_start_call_thread(ooCallData *call) {

Modified: team/mmichelson/trunk-digiumphones/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/trunk-digiumphones/apps/app_dial.c?view=diff&rev=364768&r1=364767&r2=364768
==============================================================================
--- team/mmichelson/trunk-digiumphones/apps/app_dial.c (original)
+++ team/mmichelson/trunk-digiumphones/apps/app_dial.c Tue May  1 13:12:53 2012
@@ -107,6 +107,27 @@
 					announcement) are completed.  This option can be used to answer the calling
 					channel before doing anything on the called channel. You will rarely need to use
 					this option, the default behavior is adequate in most cases.</para>
+				</option>
+				<option name="b" argsep="^">
+					<para>Before initiating the actual call, Gosub to the specified
+					location using the newly created channel(s).  The Gosub will be
+					executed for each destination channel.</para>
+					<argument name="context" required="false" />
+					<argument name="exten" required="false" />
+					<argument name="priority" required="true" hasparams="optional" argsep="^">
+						<argument name="arg1" multiple="true" required="true" />
+						<argument name="argN" />
+					</argument>
+				</option>
+				<option name="B" argsep="^">
+					<para>Before initiating the actual call, Gosub to the specified
+					location using the current channel.</para>
+					<argument name="context" required="false" />
+					<argument name="exten" required="false" />
+					<argument name="priority" required="true" hasparams="optional" argsep="^">
+						<argument name="arg1" multiple="true" required="true" />
+						<argument name="argN" />
+					</argument>
 				</option>
 				<option name="C">
 					<para>Reset the call detail record (CDR) for this call.</para>
@@ -587,6 +608,8 @@
 #define OPT_FORCE_CID_TAG    (1LLU << 38)
 #define OPT_FORCE_CID_PRES   (1LLU << 39)
 #define OPT_CALLER_ANSWER    (1LLU << 40)
+#define OPT_PREDIAL_CALLEE   (1LLU << 41)
+#define OPT_PREDIAL_CALLER   (1LLU << 42)
 
 enum {
 	OPT_ARG_ANNOUNCE = 0,
@@ -606,6 +629,8 @@
 	OPT_ARG_FORCECLID,
 	OPT_ARG_FORCE_CID_TAG,
 	OPT_ARG_FORCE_CID_PRES,
+	OPT_ARG_PREDIAL_CALLEE,
+	OPT_ARG_PREDIAL_CALLER,
 	/* note: this entry _MUST_ be the last one in the enum */
 	OPT_ARG_ARRAY_SIZE,
 };
@@ -613,6 +638,8 @@
 AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
 	AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
 	AST_APP_OPTION('a', OPT_CALLER_ANSWER),
+	AST_APP_OPTION_ARG('b', OPT_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLEE),
+	AST_APP_OPTION_ARG('B', OPT_PREDIAL_CALLER, OPT_ARG_PREDIAL_CALLER),
 	AST_APP_OPTION('C', OPT_RESETCDR),
 	AST_APP_OPTION('c', OPT_CANCEL_ELSEWHERE),
 	AST_APP_OPTION('d', OPT_DTMF_EXIT),
@@ -640,9 +667,9 @@
 	AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
 	AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
 	AST_APP_OPTION_ARG('s', OPT_FORCE_CID_TAG, OPT_ARG_FORCE_CID_TAG),
-	AST_APP_OPTION_ARG('u', OPT_FORCE_CID_PRES, OPT_ARG_FORCE_CID_PRES),
 	AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
 	AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+	AST_APP_OPTION_ARG('u', OPT_FORCE_CID_PRES, OPT_ARG_FORCE_CID_PRES),
 	AST_APP_OPTION_ARG('U', OPT_CALLEE_GOSUB, OPT_ARG_CALLEE_GOSUB),
 	AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
 	AST_APP_OPTION('W', OPT_CALLER_MONITOR),
@@ -662,15 +689,25 @@
  * The list of active channels
  */
 struct chanlist {
-	struct chanlist *next;
+	AST_LIST_ENTRY(chanlist) node;
 	struct ast_channel *chan;
+	/*! Channel interface dialing string (is tech/number).  (Stored in stuff[]) */
+	const char *interface;
+	/*! Channel technology name.  (Stored in stuff[]) */
+	const char *tech;
+	/*! Channel device addressing.  (Stored in stuff[]) */
+	const char *number;
 	uint64_t flags;
 	/*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
 	struct ast_party_connected_line connected;
 	/*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
 	unsigned int pending_connected_update:1;
 	struct ast_aoc_decoded *aoc_s_rate_list;
+	/*! The interface, tech, and number strings are stuffed here. */
+	char stuff[0];
 };
+
+AST_LIST_HEAD_NOLOCK(dial_head, chanlist);
 
 static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode);
 
@@ -681,11 +718,12 @@
 	ast_free(outgoing);
 }
 
-static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere)
+static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int answered_elsewhere)
 {
 	/* Hang up a tree of stuff */
-	struct chanlist *oo;
-	while (outgoing) {
+	struct chanlist *outgoing;
+
+	while ((outgoing = AST_LIST_REMOVE_HEAD(out_chans, node))) {
 		/* Hangup any existing lines we have open */
 		if (outgoing->chan && (outgoing->chan != exception)) {
 			if (answered_elsewhere) {
@@ -696,9 +734,7 @@
 			}
 			ast_hangup(outgoing->chan);
 		}
-		oo = outgoing;
-		outgoing = outgoing->next;
-		chanlist_free(oo);
+		chanlist_free(outgoing);
 	}
 }
 
@@ -1004,7 +1040,7 @@
 };
 
 static struct ast_channel *wait_for_answer(struct ast_channel *in,
-	struct chanlist *outgoing, int *to, struct ast_flags64 *peerflags,
+	struct dial_head *out_chans, int *to, struct ast_flags64 *peerflags,
 	char *opt_args[],
 	struct privacy_args *pa,
 	const struct cause_args *num_in, int *result, char *dtmf_progress,
@@ -1015,13 +1051,14 @@
 	int prestart = num.busy + num.congestion + num.nochan;
 	int orig = *to;
 	struct ast_channel *peer = NULL;
-	/* single is set if only one destination is enabled */
-	int single = outgoing && !outgoing->next;
-	int caller_entertained = outgoing
-		&& ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
 #ifdef HAVE_EPOLL
 	struct chanlist *epollo;
 #endif
+	struct chanlist *outgoing = AST_LIST_FIRST(out_chans);
+	/* single is set if only one destination is enabled */
+	int single = outgoing && !AST_LIST_NEXT(outgoing, node);
+	int caller_entertained = outgoing
+		&& ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
 	struct ast_party_connected_line connected_caller;
 	struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1);
 	int cc_recall_core_id;
@@ -1064,8 +1101,9 @@
 	is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL);
 
 #ifdef HAVE_EPOLL
-	for (epollo = outgoing; epollo; epollo = epollo->next)
+	AST_LIST_TRAVERSE(out_chans, epollo, node) {
 		ast_poll_channel_add(in, epollo->chan);
+	}
 #endif
 
 	while (*to && !peer) {
@@ -1076,7 +1114,7 @@
 		struct ast_channel *watchers[AST_MAX_WATCHERS];
 
 		watchers[pos++] = in;
-		for (o = outgoing; o; o = o->next) {
+		AST_LIST_TRAVERSE(out_chans, o, node) {
 			/* Keep track of important channels */
 			if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan)
 				watchers[pos++] = o->chan;
@@ -1101,7 +1139,7 @@
 			return NULL;
 		}
 		winner = ast_waitfor_n(watchers, pos, to);
-		for (o = outgoing; o; o = o->next) {
+		AST_LIST_TRAVERSE(out_chans, o, node) {
 			struct ast_frame *f;
 			struct ast_channel *c = o->chan;
 
@@ -1486,7 +1524,7 @@
 			}
 
 			/* Send the frame from the in channel to all outgoing channels. */
-			for (o = outgoing; o; o = o->next) {
+			AST_LIST_TRAVERSE(out_chans, o, node) {
 				if (!o->chan || !ast_test_flag64(o, DIAL_STILLGOING)) {
 					/* This outgoing channel has died so don't send the frame to it. */
 					continue;
@@ -1575,7 +1613,7 @@
 	}
 
 #ifdef HAVE_EPOLL
-	for (epollo = outgoing; epollo; epollo = epollo->next) {
+	AST_LIST_TRAVERSE(out_chans, epollo, node) {
 		if (epollo->chan)
 			ast_poll_channel_del(in, epollo->chan);
 	}
@@ -1918,12 +1956,13 @@
 {
 	int res = -1; /* default: error */
 	char *rest, *cur; /* scan the list of destinations */
-	struct chanlist *outgoing = NULL; /* list of destinations */
+	struct dial_head out_chans = AST_LIST_HEAD_NOLOCK_INIT_VALUE; /* list of destinations */
+	struct chanlist *outgoing;
+	struct chanlist *tmp;
 	struct ast_channel *peer;
 	int to; /* timeout */
 	struct cause_args num = { chan, 0, 0, 0 };
 	int cause;
-	char numsubst[256];
 
 	struct ast_bridge_config config = { { 0, } };
 	struct timeval calldurationlimit = { 0, };
@@ -1983,7 +2022,7 @@
 	pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
 
 	if (ast_strlen_zero(data)) {
-		ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
+		ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
 		pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
 		return -1;
 	}
@@ -1999,7 +2038,7 @@
 	}
 
 	if (ast_strlen_zero(args.peers)) {
-		ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
+		ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
 		pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
 		goto done;
 	}
@@ -2154,34 +2193,60 @@
 
 	ast_channel_lock(chan);
 	if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) {
-		outbound_group = ast_strdupa(outbound_group);	
+		outbound_group = ast_strdupa(outbound_group);
 		pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL);
 	} else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) {
 		outbound_group = ast_strdupa(outbound_group);
 	}
-	ast_channel_unlock(chan);	
+	ast_channel_unlock(chan);
 	ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE |
 			 OPT_CANCEL_TIMEOUT | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB | OPT_FORCECLID);
+
+	/* PREDIAL: Run gosub on the caller's channel */
+	if (ast_test_flag64(&opts, OPT_PREDIAL_CALLER)
+		&& !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
+		ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLER]);
+		ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER]);
+	}
 
 	/* loop through the list of dial destinations */
 	rest = args.peers;
 	while ((cur = strsep(&rest, "&")) ) {
-		struct chanlist *tmp;
 		struct ast_channel *tc; /* channel for this destination */
-		/* Get a technology/[device:]number pair */
+		/* Get a technology/resource pair */
 		char *number = cur;
-		char *interface = ast_strdupa(number);
 		char *tech = strsep(&number, "/");
+		size_t tech_len;
+		size_t number_len;
 		/* find if we already dialed this interface */
 		struct ast_dialed_interface *di;
 		AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
+
 		num_dialed++;
 		if (ast_strlen_zero(number)) {
-			ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
+			ast_log(LOG_WARNING, "Dial argument takes format (technology/resource)\n");
 			goto out;
 		}
-		if (!(tmp = ast_calloc(1, sizeof(*tmp))))
+
+		tech_len = strlen(tech) + 1;
+		number_len = strlen(number) + 1;
+		tmp = ast_calloc(1, sizeof(*tmp) + (2 * tech_len) + number_len);
+		if (!tmp) {
 			goto out;
+		}
+
+		/* Save tech, number, and interface. */
+		cur = tmp->stuff;
+		strcpy(cur, tech);
+		tmp->tech = cur;
+		cur += tech_len;
+		strcpy(cur, tech);
+		cur[tech_len - 1] = '/';
+		tmp->interface = cur;
+		cur += tech_len;
+		strcpy(cur, number);
+		tmp->number = cur;
+
 		if (opts.flags) {
 			ast_copy_flags64(tmp, &opts,
 				OPT_CANCEL_ELSEWHERE |
@@ -2193,7 +2258,7 @@
 				OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
 			ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);
 		}
-		ast_copy_string(numsubst, number, sizeof(numsubst));
+
 		/* Request the peer */
 
 		ast_channel_lock(chan);
@@ -2215,7 +2280,6 @@
 				chanlist_free(tmp);
 				goto out;
 			}
-
 			datastore->inheritance = DATASTORE_INHERIT_FOREVER;
 
 			if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
@@ -2234,14 +2298,13 @@
 
 		AST_LIST_LOCK(dialed_interfaces);
 		AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
-			if (!strcasecmp(di->interface, interface)) {
+			if (!strcasecmp(di->interface, tmp->interface)) {
 				ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n",
 					di->interface);
 				break;
 			}
 		}
 		AST_LIST_UNLOCK(dialed_interfaces);
-
 		if (di) {
 			fulldial++;
 			chanlist_free(tmp);
@@ -2252,45 +2315,47 @@
 		 * which "real" interfaces have been dialed.  The Local channel will
 		 * inherit this list so that if it ends up dialing a real interface,
 		 * it won't call one that has already been called. */
-		if (strcasecmp(tech, "Local")) {
-			if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) {
-				AST_LIST_UNLOCK(dialed_interfaces);
+		if (strcasecmp(tmp->tech, "Local")) {
+			if (!(di = ast_calloc(1, sizeof(*di) + strlen(tmp->interface)))) {
 				chanlist_free(tmp);
 				goto out;
 			}
-			strcpy(di->interface, interface);
+			strcpy(di->interface, tmp->interface);
 
 			AST_LIST_LOCK(dialed_interfaces);
 			AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
 			AST_LIST_UNLOCK(dialed_interfaces);
 		}
 
-		tc = ast_request(tech, ast_channel_nativeformats(chan), chan, numsubst, &cause);
+		tc = ast_request(tmp->tech, ast_channel_nativeformats(chan), chan, tmp->number, &cause);
 		if (!tc) {
 			/* If we can't, just go on to the next call */
 			ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n",
-				tech, cause, ast_cause2str(cause));
+				tmp->tech, cause, ast_cause2str(cause));
 			handle_cause(cause, &num);
-			if (!rest) /* we are on the last destination */
+			if (!rest) {
+				/* we are on the last destination */
 				ast_channel_hangupcause_set(chan, cause);
+			}
+			if (!ignore_cc && (cause == AST_CAUSE_BUSY || cause == AST_CAUSE_CONGESTION)) {
+				if (!ast_cc_callback(chan, tmp->tech, tmp->number, ast_cc_busy_interface)) {
+					ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, "");
+				}
+			}
 			chanlist_free(tmp);
-			if (!ignore_cc && (cause == AST_CAUSE_BUSY || cause == AST_CAUSE_CONGESTION)) {
-				if (!ast_cc_callback(chan, tech, numsubst, ast_cc_busy_interface)) {
-					ast_cc_extension_monitor_add_dialstring(chan, interface, "");
-				}
-			}
 			continue;
 		}
 		ast_channel_get_device_name(tc, device_name, sizeof(device_name));
 		if (!ignore_cc) {
-			ast_cc_extension_monitor_add_dialstring(chan, interface, device_name);
-		}
-		pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
+			ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, device_name);
+		}
+		pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", tmp->number);
 
 		ast_channel_lock_both(tc, chan);
 
 		/* Setup outgoing SDP to match incoming one */
-		if (!outgoing && !rest && CAN_EARLY_BRIDGE(peerflags, chan, tc)) {
+		if (!AST_LIST_FIRST(&out_chans) && !rest && CAN_EARLY_BRIDGE(peerflags, chan, tc)) {
+			/* We are on the only destination. */
 			ast_rtp_instance_early_bridge_make_compatible(tc, chan);
 		}
 		
@@ -2389,44 +2454,74 @@
 
 		ast_channel_unlock(tc);
 		ast_channel_unlock(chan);
-		res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */
+
+		/* Put channel in the list of outgoing thingies. */
+		tmp->chan = tc;
+		AST_LIST_INSERT_TAIL(&out_chans, tmp, node);
+	}
+
+	/*
+	 * PREDIAL: Run gosub on all of the callee channels
+	 *
+	 * We run the callee predial before ast_call() in case the user
+	 * wishes to do something on the newly created channels before
+	 * the channel does anything important.
+	 *
+	 * Inside the target gosub we will be able to do something with
+	 * the newly created channel name ie: now the calling channel
+	 * can know what channel will be used to call the destination
+	 * ex: now we will know that SIP/abc-123 is calling SIP/def-124
+	 */
+	if (ast_test_flag64(&opts, OPT_PREDIAL_CALLEE)
+		&& !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])
+		&& !AST_LIST_EMPTY(&out_chans)) {
+		ast_autoservice_start(chan);
+		ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLEE]);
+		AST_LIST_TRAVERSE(&out_chans, tmp, node) {
+			ast_app_exec_sub(NULL, tmp->chan, opt_args[OPT_ARG_PREDIAL_CALLEE]);
+		}
+		ast_autoservice_stop(chan);
+	}
+
+	/* Start all outgoing calls */
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&out_chans, tmp, node) {
+		res = ast_call(tmp->chan, tmp->number, 0); /* Place the call, but don't wait on the answer */
 		ast_channel_lock(chan);
 
 		/* Save the info in cdr's that we called them */
 		if (ast_channel_cdr(chan))
-			ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(tc));
+			ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(tmp->chan));
 
 		/* check the results of ast_call */
 		if (res) {
 			/* Again, keep going even if there's an error */
 			ast_debug(1, "ast call on peer returned %d\n", res);
-			ast_verb(3, "Couldn't call %s/%s\n", tech, numsubst);
-			if (ast_channel_hangupcause(tc)) {
-				ast_channel_hangupcause_set(chan, ast_channel_hangupcause(tc));
+			ast_verb(3, "Couldn't call %s\n", tmp->interface);
+			if (ast_channel_hangupcause(tmp->chan)) {
+				ast_channel_hangupcause_set(chan, ast_channel_hangupcause(tmp->chan));
 			}
 			ast_channel_unlock(chan);
-			ast_cc_call_failed(chan, tc, interface);
-			ast_hangup(tc);
-			tc = NULL;
+			ast_cc_call_failed(chan, tmp->chan, tmp->interface);
+			ast_hangup(tmp->chan);
+			tmp->chan = NULL;
+			AST_LIST_REMOVE_CURRENT(node);
 			chanlist_free(tmp);
 			continue;
-		} else {
-			senddialevent(chan, tc, numsubst);
-			ast_verb(3, "Called %s/%s\n", tech, numsubst);
-			ast_channel_unlock(chan);
-		}
-		/* Put them in the list of outgoing thingies...  We're ready now.
-		   XXX If we're forcibly removed, these outgoing calls won't get
-		   hung up XXX */
+		}
+
+		senddialevent(chan, tmp->chan, tmp->number);
+		ast_channel_unlock(chan);
+
+		ast_verb(3, "Called %s\n", tmp->interface);
 		ast_set_flag64(tmp, DIAL_STILLGOING);
-		tmp->chan = tc;
-		tmp->next = outgoing;
-		outgoing = tmp;
+
 		/* If this line is up, don't try anybody else */
-		if (ast_channel_state(outgoing->chan) == AST_STATE_UP)
+		if (ast_channel_state(tmp->chan) == AST_STATE_UP) {
 			break;
-	}
-	
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
 	if (ast_strlen_zero(args.timeout)) {
 		to = -1;
 	} else {
@@ -2439,6 +2534,7 @@
 		}
 	}
 
+	outgoing = AST_LIST_FIRST(&out_chans);
 	if (!outgoing) {
 		strcpy(pa.status, "CHANUNAVAIL");
 		if (fulldial == num_dialed) {
@@ -2474,7 +2570,7 @@
 		}
 	}
 
-	peer = wait_for_answer(chan, outgoing, &to, peerflags, opt_args, &pa, &num, &result,
+	peer = wait_for_answer(chan, &out_chans, &to, peerflags, opt_args, &pa, &num, &result,
 		dtmf_progress, ignore_cc, &forced_clid, &stored_clid);
 
 	/* The ast_channel_datastore_remove() function could fail here if the
@@ -2508,8 +2604,7 @@
 		/* 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.  */
-		hanguptree(outgoing, peer, 1);
-		outgoing = NULL;
+		hanguptree(&out_chans, peer, 1);
 		/* If appropriate, log that we have a destination channel and set the answer time */
 		if (ast_channel_cdr(chan)) {
 			ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
@@ -2519,11 +2614,14 @@
 			pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ast_channel_name(peer));
 		
 		ast_channel_lock(peer);
-		number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); 
-		if (!number)
-			number = numsubst;
+		number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
+		if (ast_strlen_zero(number)) {
+			number = NULL;
+		} else {
+			number = ast_strdupa(number);
+		}
+		ast_channel_unlock(peer);
 		pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
-		ast_channel_unlock(peer);
 
 		if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
 			ast_debug(1, "app_dial: sendurl=%s.\n", args.url);
@@ -2618,7 +2716,7 @@
 			ast_channel_exten_set(peer, ast_channel_exten(chan));
 			ast_channel_priority_set(peer, ast_channel_priority(chan) + 2);
 			ast_pbx_start(peer);
-			hanguptree(outgoing, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0);
+			hanguptree(&out_chans, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0);
 			if (continue_exec)
 				*continue_exec = 1;
 			res = 0;
@@ -2903,7 +3001,7 @@
 	}
 
 	ast_channel_early_bridge(chan, NULL);
-	hanguptree(outgoing, NULL, 0); /* In this case, there's no answer anywhere */
+	hanguptree(&out_chans, NULL, 0); /* In this case, there's no answer anywhere */
 	pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
 	senddialendevent(chan, pa.status);
 	ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);

Modified: team/mmichelson/trunk-digiumphones/apps/app_minivm.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/trunk-digiumphones/apps/app_minivm.c?view=diff&rev=364768&r1=364767&r2=364768
==============================================================================
--- team/mmichelson/trunk-digiumphones/apps/app_minivm.c (original)
+++ team/mmichelson/trunk-digiumphones/apps/app_minivm.c Tue May  1 13:12:53 2012
@@ -2085,7 +2085,7 @@
 	char *domain;
 	char *tmpptr;
 	struct minivm_account *vmu;
-	char *username = argv[0];
+	char *username;
 	const char *template = "";
 	const char *filename;
 	const char *format;
@@ -2457,7 +2457,7 @@
 	char *domain;
 	char *tmpptr = NULL;
 	struct minivm_account *vmu;
-	char *username = argv[0];
+	char *username;
 	struct ast_flags flags = { 0 };
 	char *opts[OPT_ARG_ARRAY_SIZE];
 	int error = FALSE;

Modified: team/mmichelson/trunk-digiumphones/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/trunk-digiumphones/apps/confbridge/conf_config_parser.c?view=diff&rev=364768&r1=364767&r2=364768
==============================================================================
--- team/mmichelson/trunk-digiumphones/apps/confbridge/conf_config_parser.c (original)
+++ team/mmichelson/trunk-digiumphones/apps/confbridge/conf_config_parser.c Tue May  1 13:12:53 2012
@@ -241,6 +241,8 @@
 		ast_string_field_set(sounds, placeintoconf, sound_file);
 	} else if (!strcasecmp(sound_name, "sound_wait_for_leader")) {
 		ast_string_field_set(sounds, waitforleader, sound_file);
+	} else if (!strcasecmp(sound_name, "sound_leader_has_left")) {
+		ast_string_field_set(sounds, leaderhasleft, sound_file);
 	} else if (!strcasecmp(sound_name, "sound_get_pin")) {
 		ast_string_field_set(sounds, getpin, sound_file);
 	} else if (!strcasecmp(sound_name, "sound_invalid_pin")) {
@@ -334,6 +336,7 @@
 		ast_string_field_set(sounds, otherinparty, tmp->sounds->otherinparty);
 		ast_string_field_set(sounds, placeintoconf, tmp->sounds->placeintoconf);
 		ast_string_field_set(sounds, waitforleader, tmp->sounds->waitforleader);
+		ast_string_field_set(sounds, leaderhasleft, tmp->sounds->leaderhasleft);
 		ast_string_field_set(sounds, getpin, tmp->sounds->getpin);
 		ast_string_field_set(sounds, invalidpin, tmp->sounds->invalidpin);
 		ast_string_field_set(sounds, locked, tmp->sounds->locked);
@@ -1038,6 +1041,7 @@
 	ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds));
 	ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds));
 	ast_cli(a->fd,"sound_wait_for_leader:       %s\n", conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, b_profile.sounds));
+	ast_cli(a->fd,"sound_leader_has_left:       %s\n", conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, b_profile.sounds));
 	ast_cli(a->fd,"sound_get_pin:        %s\n", conf_get_sound(CONF_SOUND_GET_PIN, b_profile.sounds));
 	ast_cli(a->fd,"sound_invalid_pin:    %s\n", conf_get_sound(CONF_SOUND_INVALID_PIN, b_profile.sounds));
 	ast_cli(a->fd,"sound_locked:         %s\n", conf_get_sound(CONF_SOUND_LOCKED, b_profile.sounds));

Modified: team/mmichelson/trunk-digiumphones/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/trunk-digiumphones/channels/chan_sip.c?view=diff&rev=364768&r1=364767&r2=364768
==============================================================================
--- team/mmichelson/trunk-digiumphones/channels/chan_sip.c (original)
+++ team/mmichelson/trunk-digiumphones/channels/chan_sip.c Tue May  1 13:12:53 2012
@@ -703,6 +703,7 @@
 static char default_notifymime[AST_MAX_EXTENSION]; /*!< Default MIME media type for MWI notify messages */
 static char default_vmexten[AST_MAX_EXTENSION];    /*!< Default From Username on MWI updates */
 static int default_qualify;                        /*!< Default Qualify= setting */
+static int default_keepalive;                      /*!< Default keepalive= setting */
 static char default_mohinterpret[MAX_MUSICCLASS];  /*!< Global setting for moh class to use when put on hold */
 static char default_mohsuggest[MAX_MUSICCLASS];    /*!< Global setting for moh class to suggest when putting
                                                     *   a bridged channel on hold */
@@ -1402,6 +1403,7 @@
 static void sip_peer_hold(struct sip_pvt *p, int hold);
 static void mwi_event_cb(const struct ast_event *, void *);
 static void network_change_event_cb(const struct ast_event *, void *);
+static void sip_keepalive_all_peers(void);
 
 /*--- Applications, functions, CLI and manager command helpers */
 static const char *sip_nat_mode(const struct sip_pvt *p);
@@ -2903,6 +2905,10 @@
 	if (peer->expire != -1) {
 		AST_SCHED_DEL_UNREF(sched, peer->expire,
 				sip_unref_peer(peer, "remove register expire ref"));
+	}
+	if (peer->keepalivesend != -1) {
+		AST_SCHED_DEL_UNREF(sched, peer->keepalivesend,
+				    sip_unref_peer(peer, "remove keepalive peer ref"));
 	}
 }
 
@@ -13195,8 +13201,6 @@
 		if ((data->state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) {
 			const char *local_display = exten;
 			char *local_target = ast_strdupa(mto);
-			const char *remote_display = exten;
-			char *remote_target = ast_strdupa(mfrom);
 
 			/* There are some limitations to how this works.  The primary one is that the
 			   callee must be dialing the same extension that is being monitored.  Simply dialing
@@ -13206,28 +13210,16 @@
 
 				if ((caller = ast_channel_callback(find_calling_channel, NULL, p, 0))) {
 					char *cid_num;
-					char *connected_num;
 					int need;
 
 					ast_channel_lock(caller);
 					cid_num = S_COR(ast_channel_caller(caller)->id.number.valid,
 						ast_channel_caller(caller)->id.number.str, "");
 					need = strlen(cid_num) + strlen(p->fromdomain) + sizeof("sip:@");
-					remote_target = alloca(need);
-					snprintf(remote_target, need, "sip:%s@%s", cid_num, p->fromdomain);
-
-					remote_display = ast_strdupa(S_COR(ast_channel_caller(caller)->id.name.valid,
+					local_target = alloca(need);
+					snprintf(local_target, need, "sip:%s@%s", cid_num, p->fromdomain);
+					local_display = ast_strdupa(S_COR(ast_channel_caller(caller)->id.name.valid,
 						ast_channel_caller(caller)->id.name.str, ""));
-
-					connected_num = S_COR(ast_channel_connected(caller)->id.number.valid,
-						ast_channel_connected(caller)->id.number.str, "");
-					need = strlen(connected_num) + strlen(p->fromdomain) + sizeof("sip:@");
-					local_target = alloca(need);
-					snprintf(local_target, need, "sip:%s@%s", connected_num, p->fromdomain);
-
-					local_display = ast_strdupa(S_COR(ast_channel_connected(caller)->id.name.valid,
-						ast_channel_connected(caller)->id.name.str, ""));
-
 					ast_channel_unlock(caller);
 					caller = ast_channel_unref(caller);
 				}
@@ -13249,10 +13241,10 @@
 						"<target uri=\"%s\"/>\n"
 						"</remote>\n"
 						"<local>\n"
-						"<identity display=\"%s\">%s</identity>\n"
+						"<identity>%s</identity>\n"
 						"<target uri=\"%s\"/>\n"
 						"</local>\n",
-						remote_display, remote_target, remote_target, local_display, local_target, local_target);
+						local_display, local_target, local_target, mto, mto);
 			} else {
 				ast_str_append(tmp, 0, "<dialog id=\"%s\" direction=\"recipient\">\n", exten);
 			}
@@ -18427,6 +18419,7 @@
 		ast_cli(fd, "  Useragent    : %s\n", peer->useragent);
 		ast_cli(fd, "  Reg. Contact : %s\n", peer->fullcontact);
 		ast_cli(fd, "  Qualify Freq : %d ms\n", peer->qualifyfreq);
+		ast_cli(fd, "  Keepalive    : %d ms\n", peer->keepalive * 1000);
 		if (peer->chanvars) {
 			ast_cli(fd, "  Variables    :\n");
 			for (v = peer->chanvars ; v ; v = v->next)
@@ -19100,6 +19093,7 @@
 	ast_cli(a->fd, "  Force rport:            %s\n", force_rport_string(global_flags));
 	ast_cli(a->fd, "  DTMF:                   %s\n", dtmfmode2str(ast_test_flag(&global_flags[0], SIP_DTMF)));
 	ast_cli(a->fd, "  Qualify:                %d\n", default_qualify);
+	ast_cli(a->fd, "  Keepalive:              %d\n", default_keepalive);
 	ast_cli(a->fd, "  Use ClientCode:         %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_USECLIENTCODE)));
 	ast_cli(a->fd, "  Progress inband:        %s\n", (ast_test_flag(&global_flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER) ? "Never" : (AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROG_INBAND) != SIP_PROG_INBAND_NO)));
 	ast_cli(a->fd, "  Language:               %s\n", default_language);
@@ -27451,6 +27445,56 @@
 	return global_st_mode;
 }
 
+/*! \brief Send keep alive packet to peer */
+static int sip_send_keepalive(const void *data)
+{
+	struct sip_peer *peer = (struct sip_peer*) data;
+	int res = 0;
+	const char keepalive[] = "\r\n";
+
+	peer->keepalivesend = -1;
+
+	if (!peer->keepalive || ast_sockaddr_isnull(&peer->addr)) {
+		sip_unref_peer(peer, "release keepalive peer ref");
+		return 0;
+	}
+
+	/* Send the packet out using the proper method for this peer */
+	if ((peer->socket.fd != -1) && (peer->socket.type == SIP_TRANSPORT_UDP)) {
+		res = ast_sendto(peer->socket.fd, keepalive, sizeof(keepalive), 0, &peer->addr);
+	} else if ((peer->socket.type & (SIP_TRANSPORT_TCP | SIP_TRANSPORT_TLS)) &&
+		   (peer->socket.tcptls_session) &&
+		   (peer->socket.tcptls_session->fd != -1)) {
+		res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, sizeof(keepalive));
+	} else if (peer->socket.type == SIP_TRANSPORT_UDP) {
+		res = ast_sendto(sipsock, keepalive, sizeof(keepalive), 0, &peer->addr);
+	}
+
+	if (res == -1) {
+		switch (errno) {
+		case EBADF:             /* Bad file descriptor - seems like this is generated when the host exist, but doesn't accept the UDP packet */
+		case EHOSTUNREACH:      /* Host can't be reached */
+		case ENETDOWN:          /* Interface down */
+		case ENETUNREACH:       /* Network failure */
+		case ECONNREFUSED:      /* ICMP port unreachable */
+			res = XMIT_ERROR;       /* Don't bother with trying to transmit again */
+		}
+	}
+
+	if (res != sizeof(keepalive)) {
+		ast_log(LOG_WARNING, "sip_send_keepalive to %s returned %d: %s\n", ast_sockaddr_stringify(&peer->addr), res, strerror(errno));
+	}
+
+	AST_SCHED_REPLACE_UNREF(peer->keepalivesend, sched,
+				peer->keepalive * 1000, sip_send_keepalive, peer,
+				sip_unref_peer(_data, "removing keepalive peer ref"),
+				sip_unref_peer(peer, "removing keepalive peer ref"),
+				sip_ref_peer(peer, "adding keepalive peer ref"));
+
+	sip_unref_peer(peer, "release keepalive peer ref");
+
+	return 0;
+}
 
 /*! \brief React to lack of answer to Qualify poke */
 static int sip_poke_noanswer(const void *data)
@@ -28314,6 +28358,7 @@
 		*/
 		peer->expire = -1;
 		peer->pokeexpire = -1;
+		peer->keepalivesend = -1;
 		set_socket_transport(&peer->socket, SIP_TRANSPORT_UDP);
 	}
 	peer->type = SIP_TYPE_PEER;
@@ -28356,6 +28401,7 @@
 	peer->callgroup = 0;
 	peer->pickupgroup = 0;
 	peer->maxms = default_qualify;
+	peer->keepalive = default_keepalive;
 	peer->prefs = default_prefs;
 	ast_string_field_set(peer, zone, default_zone);
 	peer->stimer.st_mode_oper = global_st_mode;	/* Session-Timers */
@@ -28955,6 +29001,15 @@
 				ast_log(LOG_WARNING, "Qualify is incompatible with dynamic uncached realtime.  Please either turn rtcachefriends on or turn qualify off on peer '%s'\n", peer->name);
 				peer->maxms = 0;
 			}
+		} else if (!strcasecmp(v->name, "keepalive")) {
+			if (!strcasecmp(v->value, "no")) {
+				peer->keepalive = 0;
+			} else if (!strcasecmp(v->value, "yes")) {
+				peer->keepalive = DEFAULT_KEEPALIVE_INTERVAL;
+			} else if (sscanf(v->value, "%30d", &peer->keepalive) != 1) {
+				ast_log(LOG_WARNING, "Keep alive of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of sip.conf\n", peer->name, v->lineno);
+				peer->keepalive = 0;
+			}
 		} else if (!strcasecmp(v->name, "callcounter")) {
 			peer->call_limit = ast_true(v->value) ? INT_MAX : 0;
 		} else if (!strcasecmp(v->name, "call-limit")) {
@@ -29419,6 +29474,7 @@
 	default_fromdomain[0] = '\0';
 	default_fromdomainport = 0;
 	default_qualify = DEFAULT_QUALIFY;
+	default_keepalive = DEFAULT_KEEPALIVE;
 	default_zone[0] = '\0';
 	default_maxcallbitrate = DEFAULT_MAX_CALL_BITRATE;
 	ast_copy_string(default_mohinterpret, DEFAULT_MOHINTERPRET, sizeof(default_mohinterpret));
@@ -29894,6 +29950,15 @@
 			} else if (sscanf(v->value, "%30d", &default_qualify) != 1) {
 				ast_log(LOG_WARNING, "Qualification default should be 'yes', 'no', or a number of milliseconds at line %d of sip.conf\n", v->lineno);
 				default_qualify = 0;
+			}
+		} else if (!strcasecmp(v->name, "keepalive")) {
+			if (!strcasecmp(v->value, "no")) {
+				default_keepalive = 0;
+			} else if (!strcasecmp(v->value, "yes")) {
+				default_keepalive = DEFAULT_KEEPALIVE_INTERVAL;
+			} else if (sscanf(v->value, "%30d", &default_keepalive) != 1) {
+				ast_log(LOG_WARNING, "Keep alive default should be 'yes', 'no', or a number of milliseconds at line %d of sip.conf\n", v->lineno);
+				default_keepalive = 0;
 			}
 		} else if (!strcasecmp(v->name, "qualifyfreq")) {
 			int i;
@@ -30901,6 +30966,29 @@
 	ao2_iterator_destroy(&i);
 }
 
+/*! \brief Send a keepalive to all known peers */
+static void sip_keepalive_all_peers(void)
+{
+	struct ao2_iterator i;
+	struct sip_peer *peer;
+
+	if (!speerobjs) {       /* No peers, just give up */
+		return;
+	}
+
+	i = ao2_iterator_init(peers, 0);
+	while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
+		ao2_lock(peer);
+		AST_SCHED_REPLACE_UNREF(peer->keepalivesend, sched, 0, sip_send_keepalive, peer,
+					sip_unref_peer(_data, "removing poke peer ref"),
+					sip_unref_peer(peer, "removing poke peer ref"),
+					sip_ref_peer(peer, "adding poke peer ref"));
+		ao2_unlock(peer);
+		sip_unref_peer(peer, "toss iterator peer ptr");
+	}
+	ao2_iterator_destroy(&i);
+}
+
 /*! \brief Send all known registrations */
 static void sip_send_all_registers(void)
 {
@@ -31005,6 +31093,9 @@
 
 	/* Send qualify (OPTIONS) to all peers */
 	sip_poke_all_peers();
+
+	/* Send keepalive to all peers */
+	sip_keepalive_all_peers();
 
 	/* Register with all services */
 	sip_send_all_registers();
@@ -31771,7 +31862,8 @@
 	ast_manager_register_xml("SIPqualifypeer", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_sip_qualify_peer);

[... 1371 lines stripped ...]



More information about the asterisk-commits mailing list