[asterisk-commits] qwell: trunk r100039 - in /trunk: ./ include/asterisk/ main/ res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jan 23 17:09:11 CST 2008


Author: qwell
Date: Wed Jan 23 17:09:11 2008
New Revision: 100039

URL: http://svn.digium.com/view/asterisk?view=rev&rev=100039
Log:
Move code from res_features into (new file) main/features.c

Added:
    trunk/main/features.c
      - copied, changed from r99976, trunk/res/res_features.c
Removed:
    trunk/res/res_features.c
Modified:
    trunk/.cleancount
    trunk/CHANGES
    trunk/include/asterisk/_private.h
    trunk/include/asterisk/features.h
    trunk/main/Makefile
    trunk/main/asterisk.c
    trunk/main/loader.c

Change Statistics:
 0 files changed

Modified: trunk/.cleancount
URL: http://svn.digium.com/view/asterisk/trunk/.cleancount?view=diff&rev=100039&r1=100038&r2=100039
==============================================================================
--- trunk/.cleancount (original)
+++ trunk/.cleancount Wed Jan 23 17:09:11 2008
@@ -1,1 +1,1 @@
-33
+34

Modified: trunk/CHANGES
URL: http://svn.digium.com/view/asterisk/trunk/CHANGES?view=diff&rev=100039&r1=100038&r2=100039
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Wed Jan 23 17:09:11 2008
@@ -409,6 +409,8 @@
   * Updated the ParkedCall application to allow you to not specify a parking
      extension.  If you don't specify a parking space to pick up, it will grab
      the first one available.
+  * Added cli command 'features reload' to reload call features from features.conf
+  * Moved into core asterisk binary.
 
 Language Support Changes
 ------------------------
@@ -498,4 +500,3 @@
      specifying which socket to use to connect to the running Asterisk daemon
      (-s)
   * Added logging to 'make update' command.  See update.log
-

Modified: trunk/include/asterisk/_private.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/_private.h?view=diff&rev=100039&r1=100038&r2=100039
==============================================================================
--- trunk/include/asterisk/_private.h (original)
+++ trunk/include/asterisk/_private.h Wed Jan 23 17:09:11 2008
@@ -32,6 +32,7 @@
 int ast_device_state_engine_init(void);	/*!< Provided by devicestate.c */
 int astobj2_init(void);			/*!< Provided by astobj2.c */
 int ast_file_init(void);		/*!< Provided by file.c */
+int ast_features_init(void);            /*!< Provided by features.c */
 
 /*!
  * \brief Reload asterisk modules.

Modified: trunk/include/asterisk/features.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/features.h?view=diff&rev=100039&r1=100038&r2=100039
==============================================================================
--- trunk/include/asterisk/features.h (original)
+++ trunk/include/asterisk/features.h Wed Jan 23 17:09:11 2008
@@ -109,4 +109,7 @@
 void ast_rdlock_call_features(void);
 void ast_unlock_call_features(void);
 
+/*! \brief Reload call features from features.conf */
+int ast_features_reload(void);
+
 #endif /* _AST_FEATURES_H */

Modified: trunk/main/Makefile
URL: http://svn.digium.com/view/asterisk/trunk/main/Makefile?view=diff&rev=100039&r1=100038&r2=100039
==============================================================================
--- trunk/main/Makefile (original)
+++ trunk/main/Makefile Wed Jan 23 17:09:11 2008
@@ -29,7 +29,8 @@
 	netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
 	cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
 	strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
-	astobj2.o hashtab.o global_datastores.o $(RESAMPLE_OBJS) version.o
+	astobj2.o hashtab.o global_datastores.o $(RESAMPLE_OBJS) version.o \
+	features.o
 
 # we need to link in the objects statically, not as a library, because
 # otherwise modules will not have them available if none of the static

Modified: trunk/main/asterisk.c
URL: http://svn.digium.com/view/asterisk/trunk/main/asterisk.c?view=diff&rev=100039&r1=100038&r2=100039
==============================================================================
--- trunk/main/asterisk.c (original)
+++ trunk/main/asterisk.c Wed Jan 23 17:09:11 2008
@@ -96,6 +96,7 @@
 #include "asterisk/network.h"
 #include "asterisk/cli.h"
 #include "asterisk/channel.h"
+#include "asterisk/features.h"
 #include "asterisk/ulaw.h"
 #include "asterisk/alaw.h"
 #include "asterisk/callerid.h"
@@ -3165,6 +3166,8 @@
 		exit(1);
 	}
 
+	ast_features_init();
+
 	if (init_framer()) {
 		printf(term_quit());
 		exit(1);

Copied: trunk/main/features.c (from r99976, trunk/res/res_features.c)
URL: http://svn.digium.com/view/asterisk/trunk/main/features.c?view=diff&rev=100039&p1=trunk/res/res_features.c&r1=99976&p2=trunk/main/features.c&r2=100039
==============================================================================
--- trunk/res/res_features.c (original)
+++ trunk/main/features.c Wed Jan 23 17:09:11 2008
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2006, Digium, Inc.
+ * Copyright (C) 1999 - 2008, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
  *
@@ -30,6 +30,8 @@
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/_private.h"
 
 #include <pthread.h>
 #include <sys/time.h>
@@ -126,7 +128,7 @@
 static unsigned int atxferloopdelay;
 static unsigned int atxfercallbackretries;
 
-static char *registrar = "res_features";		   /*!< Registrar for operations */
+static char *registrar = "features";		   /*!< Registrar for operations */
 
 /* module and CLI command definitions */
 static char *synopsis = "Answer a parked call";
@@ -599,9 +601,6 @@
 	struct ast_channel *parker;
         struct ast_channel *parkee;
 	int res = 0;
-	struct ast_module_user *u;
-
-	u = ast_module_user_add(chan);
 
 	set_peers(&parker, &parkee, peer, chan, sense);
 	/* Setup the exten/priority to be s/1 since we don't know
@@ -614,8 +613,6 @@
 		res = ast_safe_sleep(chan, 1000);
 	if (!res)
 		res = ast_park_call(parkee, parker, 0, NULL);
-
-	ast_module_user_remove(u);
 
 	if (!res) {
 		if (sense == FEATURE_SENSE_CHAN)
@@ -675,7 +672,7 @@
 	
 	if (callee_chan->monitor) {
 		ast_verb(4, "User hit '%s' to stop recording call.\n", code);
-		ast_monitor_stop(callee_chan, 1);
+		callee_chan->monitor->stop(callee_chan, 1);
 		return FEATURE_RETURN_SUCCESS;
 	}
 
@@ -2511,425 +2508,6 @@
 	return res;
 }
 
-/*!
- * \brief CLI command to list configured features
- * \param e
- * \param cmd
- * \param a
- *
- * \retval CLI_SUCCESS on success.
- * \retval NULL when tab completion is used.
- */
-static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) {
-	int i;
-	struct ast_call_feature *feature;
-	char format[] = "%-25s %-7s %-7s\n";
-
-	switch (cmd) {
-	
-	case CLI_INIT:
-		e->command = "features show";
-		e->usage =
-			"Usage: features show\n"
-			"       Lists configured features\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-        }
-
-	ast_cli(a->fd, format, "Builtin Feature", "Default", "Current");
-	ast_cli(a->fd, format, "---------------", "-------", "-------");
-
-	ast_cli(a->fd, format, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
-
-	ast_rwlock_rdlock(&features_lock);
-	for (i = 0; i < FEATURES_COUNT; i++)
-		ast_cli(a->fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
-	ast_rwlock_unlock(&features_lock);
-
-	ast_cli(a->fd, "\n");
-	ast_cli(a->fd, format, "Dynamic Feature", "Default", "Current");
-	ast_cli(a->fd, format, "---------------", "-------", "-------");
-	if (AST_LIST_EMPTY(&feature_list))
-		ast_cli(a->fd, "(none)\n");
-	else {
-		AST_LIST_LOCK(&feature_list);
-		AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
-			ast_cli(a->fd, format, feature->sname, "no def", feature->exten);
-		AST_LIST_UNLOCK(&feature_list);
-	}
-	ast_cli(a->fd, "\nCall parking\n");
-	ast_cli(a->fd, "------------\n");
-	ast_cli(a->fd,"%-20s:      %s\n", "Parking extension", parking_ext);
-	ast_cli(a->fd,"%-20s:      %s\n", "Parking context", parking_con);
-	ast_cli(a->fd,"%-20s:      %d-%d\n", "Parked call extensions", parking_start, parking_stop);
-	ast_cli(a->fd,"\n");
-
-	return CLI_SUCCESS;
-}
-
-static char mandescr_bridge[] =
-"Description: Bridge together two channels already in the PBX\n"
-"Variables: ( Headers marked with * are required )\n"
-"   *Channel1: Channel to Bridge to Channel2\n"
-"   *Channel2: Channel to Bridge to Channel1\n"
-"        Tone: (Yes|No) Play courtesy tone to Channel 2\n"
-"\n";
-
-/*!
- * \brief Actual bridge
- * \param chan
- * \param tmpchan
- * 
- * Stop hold music, lock both channels, masq channels,
- * after bridge return channel to next priority.
-*/
-static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
-{
-	ast_moh_stop(chan);
-	ast_channel_lock(chan);
-	ast_setstate(tmpchan, chan->_state);
-	tmpchan->readformat = chan->readformat;
-	tmpchan->writeformat = chan->writeformat;
-	ast_channel_masquerade(tmpchan, chan);
-	ast_channel_lock(tmpchan);
-	ast_do_masquerade(tmpchan);
-	/* when returning from bridge, the channel will continue at the next priority */
-	ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
-	ast_channel_unlock(tmpchan);
-	ast_channel_unlock(chan);
-}
-
-/*!
- * \brief Bridge channels together
- * \param s
- * \param m
- * 
- * Make sure valid channels were specified, 
- * send errors if any of the channels could not be found/locked, answer channels if needed,
- * create the placeholder channels and grab the other channels 
- * make the channels compatible, send error if we fail doing so 
- * setup the bridge thread object and start the bridge.
- * 
- * \retval 0 on success or on incorrect use.
- * \retval 1 on failure to bridge channels.
-*/
-static int action_bridge(struct mansession *s, const struct message *m)
-{
-	const char *channela = astman_get_header(m, "Channel1");
-	const char *channelb = astman_get_header(m, "Channel2");
-	const char *playtone = astman_get_header(m, "Tone");
-	struct ast_channel *chana = NULL, *chanb = NULL;
-	struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
-	struct ast_bridge_thread_obj *tobj = NULL;
-
-	/* make sure valid channels were specified */
-	if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
-		chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
-		chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
-		if (chana)
-			ast_channel_unlock(chana);
-		if (chanb)
-			ast_channel_unlock(chanb);
-
-		/* send errors if any of the channels could not be found/locked */
-		if (!chana) {
-			char buf[256];
-			snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
-			astman_send_error(s, m, buf);
-			return 0;
-		}
-		if (!chanb) {
-			char buf[256];
-			snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
-			astman_send_error(s, m, buf);
-			return 0;
-		}
-	} else {
-		astman_send_error(s, m, "Missing channel parameter in request");
-		return 0;
-	}
-
-	/* Answer the channels if needed */
-	if (chana->_state != AST_STATE_UP)
-		ast_answer(chana);
-	if (chanb->_state != AST_STATE_UP)
-		ast_answer(chanb);
-
-	/* create the placeholder channels and grab the other channels */
-	if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
-		NULL, NULL, 0, "Bridge/%s", chana->name))) {
-		astman_send_error(s, m, "Unable to create temporary channel!");
-		return 1;
-	}
-
-	if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
-		NULL, NULL, 0, "Bridge/%s", chanb->name))) {
-		astman_send_error(s, m, "Unable to create temporary channels!");
-		ast_channel_free(tmpchana);
-		return 1;
-	}
-
-	do_bridge_masquerade(chana, tmpchana);
-	do_bridge_masquerade(chanb, tmpchanb);
-	
-	/* make the channels compatible, send error if we fail doing so */
-	if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
-		ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
-		astman_send_error(s, m, "Could not make channels compatible for manager bridge");
-		ast_hangup(tmpchana);
-		ast_hangup(tmpchanb);
-		return 1;
-	}
-
-	/* setup the bridge thread object and start the bridge */
-	if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
-		ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
-		astman_send_error(s, m, "Unable to spawn a new bridge thread");
-		ast_hangup(tmpchana);
-		ast_hangup(tmpchanb);
-		return 1;
-	}
-
-	tobj->chan = tmpchana;
-	tobj->peer = tmpchanb;
-	tobj->return_to_pbx = 1;
-	
-	if (ast_true(playtone)) {
-		if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
-			if (ast_waitstream(tmpchanb, "") < 0)
-				ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
-		}
-	}
-
-	ast_bridge_call_thread_launch(tobj);
-
-	astman_send_ack(s, m, "Launched bridge thread with success");
-
-	return 0;
-}
-
-/*!
- * \brief CLI command to list parked calls
- * \param e 
- * \param cmd
- * \param a
- *  
- * Check right usage, lock parking lot, display parked calls, unlock parking lot list.
- * \retval CLI_SUCCESS on success.
- * \retval CLI_SHOWUSAGE on incorrect number of arguments.
- * \retval NULL when tab completion is used.
-*/
-static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	struct parkeduser *cur;
-	int numparked = 0;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "parkedcalls show";
-		e->usage =
-			"Usage: parkedcalls show\n"
-			"       List currently parked calls\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc > e->args)
-		return CLI_SHOWUSAGE;
-
-	ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
-		, "Context", "Extension", "Pri", "Timeout");
-
-	AST_LIST_LOCK(&parkinglot);
-	AST_LIST_TRAVERSE(&parkinglot, cur, list) {
-		ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
-			,cur->parkingexten, cur->chan->name, cur->context, cur->exten
-			,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
-
-		numparked++;
-	}
-	AST_LIST_UNLOCK(&parkinglot);
-	ast_cli(a->fd, "%d parked call%s.\n", numparked, ESS(numparked));
-
-
-	return CLI_SUCCESS;
-}
-
-static char *handle_parkedcalls_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	char *res = handle_parkedcalls(e, cmd, a);
-	if (cmd == CLI_INIT)
-		e->command = "show parkedcalls";
-	return res;
-}
-
-static struct ast_cli_entry cli_show_parkedcalls_deprecated = AST_CLI_DEFINE(handle_parkedcalls_deprecated, "List currently parked calls.");
-
-static struct ast_cli_entry cli_features[] = {
-	AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
-	AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls", .deprecate_cmd = &cli_show_parkedcalls_deprecated),
-};
-
-/*! 
- * \brief Dump parking lot status
- * \param s
- * \param m
- * 
- * Lock parking lot, iterate list and append parked calls status, unlock parking lot.
- * \return Always RESULT_SUCCESS 
-*/
-static int manager_parking_status(struct mansession *s, const struct message *m)
-{
-	struct parkeduser *cur;
-	const char *id = astman_get_header(m, "ActionID");
-	char idText[256] = "";
-
-	if (!ast_strlen_zero(id))
-		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
-
-	astman_send_ack(s, m, "Parked calls will follow");
-
-	AST_LIST_LOCK(&parkinglot);
-
-	AST_LIST_TRAVERSE(&parkinglot, cur, list) {
-		astman_append(s, "Event: ParkedCall\r\n"
-			"Exten: %d\r\n"
-			"Channel: %s\r\n"
-			"From: %s\r\n"
-			"Timeout: %ld\r\n"
-			"CallerIDNum: %s\r\n"
-			"CallerIDName: %s\r\n"
-			"%s"
-			"\r\n",
-			cur->parkingnum, cur->chan->name, cur->peername,
-			(long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
-			S_OR(cur->chan->cid.cid_num, ""),	/* XXX in other places it is <unknown> */
-			S_OR(cur->chan->cid.cid_name, ""),
-			idText);
-	}
-
-	astman_append(s,
-		"Event: ParkedCallsComplete\r\n"
-		"%s"
-		"\r\n",idText);
-
-	AST_LIST_UNLOCK(&parkinglot);
-
-	return RESULT_SUCCESS;
-}
-
-static char mandescr_park[] =
-"Description: Park a channel.\n"
-"Variables: (Names marked with * are required)\n"
-"	*Channel: Channel name to park\n"
-"	*Channel2: Channel to announce park info to (and return to if timeout)\n"
-"	Timeout: Number of milliseconds to wait before callback.\n";  
-
-/*!
- * \brief Create manager event for parked calls
- * \param s
- * \param m
- *
- * Get channels involved in park, create event.
- * \return Always 0
-*/
-static int manager_park(struct mansession *s, const struct message *m)
-{
-	const char *channel = astman_get_header(m, "Channel");
-	const char *channel2 = astman_get_header(m, "Channel2");
-	const char *timeout = astman_get_header(m, "Timeout");
-	char buf[BUFSIZ];
-	int to = 0;
-	int res = 0;
-	int parkExt = 0;
-	struct ast_channel *ch1, *ch2;
-
-	if (ast_strlen_zero(channel)) {
-		astman_send_error(s, m, "Channel not specified");
-		return 0;
-	}
-
-	if (ast_strlen_zero(channel2)) {
-		astman_send_error(s, m, "Channel2 not specified");
-		return 0;
-	}
-
-	ch1 = ast_get_channel_by_name_locked(channel);
-	if (!ch1) {
-		snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
-		astman_send_error(s, m, buf);
-		return 0;
-	}
-
-	ch2 = ast_get_channel_by_name_locked(channel2);
-	if (!ch2) {
-		snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
-		astman_send_error(s, m, buf);
-		ast_channel_unlock(ch1);
-		return 0;
-	}
-
-	if (!ast_strlen_zero(timeout)) {
-		sscanf(timeout, "%d", &to);
-	}
-
-	res = ast_masq_park_call(ch1, ch2, to, &parkExt);
-	if (!res) {
-		ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
-		astman_send_ack(s, m, "Park successful");
-	} else {
-		astman_send_error(s, m, "Park failure");
-	}
-
-	ast_channel_unlock(ch1);
-	ast_channel_unlock(ch2);
-
-	return 0;
-}
-
-/*!
- * \brief Pickup a call
- * \param chan channel that initiated pickup.
- *
- * Walk list of channels, checking it is not itself, channel is pbx one,
- * check that the callgroup for both channels are the same and the channel is ringing.
- * Answer calling channel, flag channel as answered on queue, masq channels together.
-*/
-int ast_pickup_call(struct ast_channel *chan)
-{
-	struct ast_channel *cur = NULL;
-	int res = -1;
-
-	while ((cur = ast_channel_walk_locked(cur)) != NULL) {
-		if (!cur->pbx && 
-			(cur != chan) &&
-			(chan->pickupgroup & cur->callgroup) &&
-			((cur->_state == AST_STATE_RINGING) ||
-			 (cur->_state == AST_STATE_RING))) {
-			 	break;
-		}
-		ast_channel_unlock(cur);
-	}
-	if (cur) {
-		ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
-		res = ast_answer(chan);
-		if (res)
-			ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
-		res = ast_queue_control(chan, AST_CONTROL_ANSWER);
-		if (res)
-			ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
-		res = ast_channel_masquerade(cur, chan);
-		if (res)
-			ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);		/* Done */
-		ast_channel_unlock(cur);
-	} else	{
-		ast_debug(1, "No call pickup possible...\n");
-	}
-	return res;
-}
-
 /*! 
  * \brief Add parking hints for all defined parking lots 
  * \param context
@@ -2948,7 +2526,6 @@
 		ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
 	}
 }
-
 
 static int load_config(void) 
 {
@@ -3005,7 +2582,7 @@
 	cfg = ast_config_load("features.conf", config_flags);
 	if (!cfg) {
 		ast_log(LOG_WARNING,"Could not load features.conf\n");
-		return AST_MODULE_LOAD_DECLINE;
+		return 0;
 	}
 	for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
 		if (!strcasecmp(var->name, "parkext")) {
@@ -3240,6 +2817,451 @@
 
 }
 
+/*!
+ * \brief CLI command to list configured features
+ * \param e
+ * \param cmd
+ * \param a
+ *
+ * \retval CLI_SUCCESS on success.
+ * \retval NULL when tab completion is used.
+ */
+static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int i;
+	struct ast_call_feature *feature;
+	char format[] = "%-25s %-7s %-7s\n";
+
+	switch (cmd) {
+	
+	case CLI_INIT:
+		e->command = "features show";
+		e->usage =
+			"Usage: features show\n"
+			"       Lists configured features\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+        }
+
+	ast_cli(a->fd, format, "Builtin Feature", "Default", "Current");
+	ast_cli(a->fd, format, "---------------", "-------", "-------");
+
+	ast_cli(a->fd, format, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
+
+	ast_rwlock_rdlock(&features_lock);
+	for (i = 0; i < FEATURES_COUNT; i++)
+		ast_cli(a->fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
+	ast_rwlock_unlock(&features_lock);
+
+	ast_cli(a->fd, "\n");
+	ast_cli(a->fd, format, "Dynamic Feature", "Default", "Current");
+	ast_cli(a->fd, format, "---------------", "-------", "-------");
+	if (AST_LIST_EMPTY(&feature_list))
+		ast_cli(a->fd, "(none)\n");
+	else {
+		AST_LIST_LOCK(&feature_list);
+		AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
+			ast_cli(a->fd, format, feature->sname, "no def", feature->exten);
+		AST_LIST_UNLOCK(&feature_list);
+	}
+	ast_cli(a->fd, "\nCall parking\n");
+	ast_cli(a->fd, "------------\n");
+	ast_cli(a->fd,"%-20s:      %s\n", "Parking extension", parking_ext);
+	ast_cli(a->fd,"%-20s:      %s\n", "Parking context", parking_con);
+	ast_cli(a->fd,"%-20s:      %d-%d\n", "Parked call extensions", parking_start, parking_stop);
+	ast_cli(a->fd,"\n");
+
+	return CLI_SUCCESS;
+}
+
+int ast_features_reload(void)
+{
+	load_config();
+
+	return RESULT_SUCCESS;
+}
+
+static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {	
+	case CLI_INIT:
+		e->command = "features reload";
+		e->usage =
+			"Usage: features reload\n"
+			"       Reloads configured call features from features.conf\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+        }
+	load_config();
+
+	return CLI_SUCCESS;
+}
+
+static char mandescr_bridge[] =
+"Description: Bridge together two channels already in the PBX\n"
+"Variables: ( Headers marked with * are required )\n"
+"   *Channel1: Channel to Bridge to Channel2\n"
+"   *Channel2: Channel to Bridge to Channel1\n"
+"        Tone: (Yes|No) Play courtesy tone to Channel 2\n"
+"\n";
+
+/*!
+ * \brief Actual bridge
+ * \param chan
+ * \param tmpchan
+ * 
+ * Stop hold music, lock both channels, masq channels,
+ * after bridge return channel to next priority.
+*/
+static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
+{
+	ast_moh_stop(chan);
+	ast_channel_lock(chan);
+	ast_setstate(tmpchan, chan->_state);
+	tmpchan->readformat = chan->readformat;
+	tmpchan->writeformat = chan->writeformat;
+	ast_channel_masquerade(tmpchan, chan);
+	ast_channel_lock(tmpchan);
+	ast_do_masquerade(tmpchan);
+	/* when returning from bridge, the channel will continue at the next priority */
+	ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
+	ast_channel_unlock(tmpchan);
+	ast_channel_unlock(chan);
+}
+
+/*!
+ * \brief Bridge channels together
+ * \param s
+ * \param m
+ * 
+ * Make sure valid channels were specified, 
+ * send errors if any of the channels could not be found/locked, answer channels if needed,
+ * create the placeholder channels and grab the other channels 
+ * make the channels compatible, send error if we fail doing so 
+ * setup the bridge thread object and start the bridge.
+ * 
+ * \retval 0 on success or on incorrect use.
+ * \retval 1 on failure to bridge channels.
+*/
+static int action_bridge(struct mansession *s, const struct message *m)
+{
+	const char *channela = astman_get_header(m, "Channel1");
+	const char *channelb = astman_get_header(m, "Channel2");
+	const char *playtone = astman_get_header(m, "Tone");
+	struct ast_channel *chana = NULL, *chanb = NULL;
+	struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
+	struct ast_bridge_thread_obj *tobj = NULL;
+
+	/* make sure valid channels were specified */
+	if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
+		chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
+		chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
+		if (chana)
+			ast_channel_unlock(chana);
+		if (chanb)
+			ast_channel_unlock(chanb);
+
+		/* send errors if any of the channels could not be found/locked */
+		if (!chana) {
+			char buf[256];
+			snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
+			astman_send_error(s, m, buf);
+			return 0;
+		}
+		if (!chanb) {
+			char buf[256];
+			snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
+			astman_send_error(s, m, buf);
+			return 0;
+		}
+	} else {
+		astman_send_error(s, m, "Missing channel parameter in request");
+		return 0;
+	}
+
+	/* Answer the channels if needed */
+	if (chana->_state != AST_STATE_UP)
+		ast_answer(chana);
+	if (chanb->_state != AST_STATE_UP)
+		ast_answer(chanb);
+
+	/* create the placeholder channels and grab the other channels */
+	if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
+		NULL, NULL, 0, "Bridge/%s", chana->name))) {
+		astman_send_error(s, m, "Unable to create temporary channel!");
+		return 1;
+	}
+
+	if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
+		NULL, NULL, 0, "Bridge/%s", chanb->name))) {
+		astman_send_error(s, m, "Unable to create temporary channels!");
+		ast_channel_free(tmpchana);
+		return 1;
+	}
+
+	do_bridge_masquerade(chana, tmpchana);
+	do_bridge_masquerade(chanb, tmpchanb);
+	
+	/* make the channels compatible, send error if we fail doing so */
+	if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
+		ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
+		astman_send_error(s, m, "Could not make channels compatible for manager bridge");
+		ast_hangup(tmpchana);
+		ast_hangup(tmpchanb);
+		return 1;
+	}
+
+	/* setup the bridge thread object and start the bridge */
+	if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
+		ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
+		astman_send_error(s, m, "Unable to spawn a new bridge thread");
+		ast_hangup(tmpchana);
+		ast_hangup(tmpchanb);
+		return 1;
+	}
+
+	tobj->chan = tmpchana;
+	tobj->peer = tmpchanb;
+	tobj->return_to_pbx = 1;
+	
+	if (ast_true(playtone)) {
+		if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
+			if (ast_waitstream(tmpchanb, "") < 0)
+				ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
+		}
+	}
+
+	ast_bridge_call_thread_launch(tobj);
+
+	astman_send_ack(s, m, "Launched bridge thread with success");
+
+	return 0;
+}
+
+/*!
+ * \brief CLI command to list parked calls
+ * \param e 
+ * \param cmd
+ * \param a
+ *  
+ * Check right usage, lock parking lot, display parked calls, unlock parking lot list.
+ * \retval CLI_SUCCESS on success.
+ * \retval CLI_SHOWUSAGE on incorrect number of arguments.
+ * \retval NULL when tab completion is used.
+*/
+static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct parkeduser *cur;
+	int numparked = 0;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "parkedcalls show";
+		e->usage =
+			"Usage: parkedcalls show\n"
+			"       List currently parked calls\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc > e->args)
+		return CLI_SHOWUSAGE;
+
+	ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
+		, "Context", "Extension", "Pri", "Timeout");
+
+	AST_LIST_LOCK(&parkinglot);
+	AST_LIST_TRAVERSE(&parkinglot, cur, list) {
+		ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
+			,cur->parkingexten, cur->chan->name, cur->context, cur->exten
+			,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
+
+		numparked++;
+	}
+	AST_LIST_UNLOCK(&parkinglot);
+	ast_cli(a->fd, "%d parked call%s.\n", numparked, ESS(numparked));
+
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_parkedcalls_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	char *res = handle_parkedcalls(e, cmd, a);
+	if (cmd == CLI_INIT)
+		e->command = "show parkedcalls";
+	return res;
+}
+
+static struct ast_cli_entry cli_show_parkedcalls_deprecated = AST_CLI_DEFINE(handle_parkedcalls_deprecated, "List currently parked calls.");
+
+static struct ast_cli_entry cli_features[] = {
+	AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
+	AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
+	AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls", .deprecate_cmd = &cli_show_parkedcalls_deprecated),
+};
+
+/*! 
+ * \brief Dump parking lot status
+ * \param s
+ * \param m
+ * 
+ * Lock parking lot, iterate list and append parked calls status, unlock parking lot.
+ * \return Always RESULT_SUCCESS 
+*/
+static int manager_parking_status(struct mansession *s, const struct message *m)
+{
+	struct parkeduser *cur;
+	const char *id = astman_get_header(m, "ActionID");
+	char idText[256] = "";
+
+	if (!ast_strlen_zero(id))
+		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+
+	astman_send_ack(s, m, "Parked calls will follow");
+
+	AST_LIST_LOCK(&parkinglot);
+
+	AST_LIST_TRAVERSE(&parkinglot, cur, list) {
+		astman_append(s, "Event: ParkedCall\r\n"
+			"Exten: %d\r\n"
+			"Channel: %s\r\n"
+			"From: %s\r\n"
+			"Timeout: %ld\r\n"
+			"CallerIDNum: %s\r\n"
+			"CallerIDName: %s\r\n"
+			"%s"
+			"\r\n",
+			cur->parkingnum, cur->chan->name, cur->peername,
+			(long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
+			S_OR(cur->chan->cid.cid_num, ""),	/* XXX in other places it is <unknown> */
+			S_OR(cur->chan->cid.cid_name, ""),
+			idText);
+	}
+
+	astman_append(s,
+		"Event: ParkedCallsComplete\r\n"
+		"%s"
+		"\r\n",idText);
+
+	AST_LIST_UNLOCK(&parkinglot);
+
+	return RESULT_SUCCESS;
+}
+
+static char mandescr_park[] =
+"Description: Park a channel.\n"
+"Variables: (Names marked with * are required)\n"
+"	*Channel: Channel name to park\n"
+"	*Channel2: Channel to announce park info to (and return to if timeout)\n"
+"	Timeout: Number of milliseconds to wait before callback.\n";  
+
+/*!
+ * \brief Create manager event for parked calls
+ * \param s
+ * \param m
+ *
+ * Get channels involved in park, create event.
+ * \return Always 0
+*/
+static int manager_park(struct mansession *s, const struct message *m)
+{
+	const char *channel = astman_get_header(m, "Channel");
+	const char *channel2 = astman_get_header(m, "Channel2");
+	const char *timeout = astman_get_header(m, "Timeout");
+	char buf[BUFSIZ];
+	int to = 0;
+	int res = 0;
+	int parkExt = 0;
+	struct ast_channel *ch1, *ch2;
+
+	if (ast_strlen_zero(channel)) {
+		astman_send_error(s, m, "Channel not specified");
+		return 0;
+	}
+
+	if (ast_strlen_zero(channel2)) {
+		astman_send_error(s, m, "Channel2 not specified");
+		return 0;
+	}
+
+	ch1 = ast_get_channel_by_name_locked(channel);
+	if (!ch1) {
+		snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
+		astman_send_error(s, m, buf);
+		return 0;
+	}
+
+	ch2 = ast_get_channel_by_name_locked(channel2);
+	if (!ch2) {
+		snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
+		astman_send_error(s, m, buf);
+		ast_channel_unlock(ch1);
+		return 0;
+	}
+
+	if (!ast_strlen_zero(timeout)) {
+		sscanf(timeout, "%d", &to);
+	}
+
+	res = ast_masq_park_call(ch1, ch2, to, &parkExt);
+	if (!res) {
+		ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
+		astman_send_ack(s, m, "Park successful");
+	} else {
+		astman_send_error(s, m, "Park failure");
+	}
+
+	ast_channel_unlock(ch1);
+	ast_channel_unlock(ch2);
+
+	return 0;
+}
+
+/*!
+ * \brief Pickup a call
+ * \param chan channel that initiated pickup.
+ *
+ * Walk list of channels, checking it is not itself, channel is pbx one,
+ * check that the callgroup for both channels are the same and the channel is ringing.
+ * Answer calling channel, flag channel as answered on queue, masq channels together.
+*/
+int ast_pickup_call(struct ast_channel *chan)
+{
+	struct ast_channel *cur = NULL;
+	int res = -1;
+
+	while ((cur = ast_channel_walk_locked(cur)) != NULL) {
+		if (!cur->pbx && 
+			(cur != chan) &&
+			(chan->pickupgroup & cur->callgroup) &&
+			((cur->_state == AST_STATE_RINGING) ||
+			 (cur->_state == AST_STATE_RING))) {
+			 	break;
+		}
+		ast_channel_unlock(cur);
+	}
+	if (cur) {
+		ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
+		res = ast_answer(chan);
+		if (res)
+			ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
+		res = ast_queue_control(chan, AST_CONTROL_ANSWER);
+		if (res)
+			ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
+		res = ast_channel_masquerade(cur, chan);
+		if (res)
+			ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);		/* Done */
+		ast_channel_unlock(cur);
+	} else	{
+		ast_debug(1, "No call pickup possible...\n");
+	}
+	return res;
+}
+
 static char *app_bridge = "Bridge";
 static char *bridge_synopsis = "Bridge two channels";
 static char *bridge_descrip =
@@ -3388,16 +3410,11 @@
 	return 0;
 }
 
-static int reload(void)
-{
-	return load_config();
-}
-
-static int load_module(void)
+int ast_features_init(void)
 {
 	int res;
 
-	ast_register_application(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip);	
+	ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
 
 	memset(parking_ext, 0, sizeof(parking_ext));
 	memset(parking_con, 0, sizeof(parking_con));
@@ -3406,9 +3423,9 @@
 		return res;
 	ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
 	ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
-	res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
+	res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
 	if (!res)
-		res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
+		res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
 	if (!res) {
 		ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
 		ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
@@ -3420,29 +3437,3 @@
 
 	return res;
 }
-
-
-static int unload_module(void)
-{
-	struct ast_context *con;
-	ast_manager_unregister("ParkedCalls");
-	ast_manager_unregister("Bridge");
-	ast_manager_unregister("Park");
-	ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
-	ast_unregister_application(parkcall);
-	ast_unregister_application(app_bridge);
-	ast_devstate_prov_del("Park");
-	con = ast_context_find(parking_con);
-	if (con)
-		ast_context_destroy(con, registrar);
-	con = ast_context_find(parking_con_dial);
-	if (con)
-		ast_context_destroy(con, registrar); 	
-	return ast_unregister_application(parkedcall);
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
-		.load = load_module,
-		.unload = unload_module,
-		.reload = reload,
-	      );

Modified: trunk/main/loader.c
URL: http://svn.digium.com/view/asterisk/trunk/main/loader.c?view=diff&rev=100039&r1=100038&r2=100039
==============================================================================
--- trunk/main/loader.c (original)
+++ trunk/main/loader.c Wed Jan 23 17:09:11 2008
@@ -46,6 +46,7 @@
 #include "asterisk/rtp.h"
 #include "asterisk/http.h"
 #include "asterisk/lock.h"
+#include "asterisk/features.h"
 
 #ifdef DLFCNCOMPAT
 #include "asterisk/dlfcn-compat.h"
@@ -247,6 +248,7 @@
 	{ "rtp",	ast_rtp_reload },
 	{ "http",	ast_http_reload },
 	{ "logger",	logger_reload },
+	{ "features",	ast_features_reload },
 	{ NULL, 	NULL }
 };
 




More information about the asterisk-commits mailing list