[svn-commits] trunk r36582 - /trunk/apps/app_meetme.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Sat Jul 1 16:54:44 MST 2006


Author: markster
Date: Sat Jul  1 18:54:43 2006
New Revision: 36582

URL: http://svn.digium.com/view/asterisk?rev=36582&view=rev
Log:
First pass at SLA support

Modified:
    trunk/apps/app_meetme.c

Modified: trunk/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_meetme.c?rev=36582&r1=36581&r2=36582&view=diff
==============================================================================
--- trunk/apps/app_meetme.c (original)
+++ trunk/apps/app_meetme.c Sat Jul  1 18:54:43 2006
@@ -58,6 +58,7 @@
 #include "asterisk/utils.h"
 #include "asterisk/translate.h"
 #include "asterisk/ulaw.h"
+#include "asterisk/astobj.h"
 #include "asterisk/devicestate.h"
 
 #include "enter.h"
@@ -179,13 +180,20 @@
 	AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
 });
 
+AST_APP_OPTIONS(sla_opts, {
+	/* Just a placeholder for now */
+});
 static const char *app = "MeetMe";
 static const char *app2 = "MeetMeCount";
 static const char *app3 = "MeetMeAdmin";
+static const char *appslas = "SLAS";
+static const char *appslat = "SLAT";
 
 static const char *synopsis = "MeetMe conference bridge";
 static const char *synopsis2 = "MeetMe participant count";
 static const char *synopsis3 = "MeetMe conference Administration";
+static const char *synopslas = "Shared Line Appearance - Station";
+static const char *synopslat = "Shared Line Appearance - Trunk";
 
 static const char *descrip =
 "  MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
@@ -263,6 +271,23 @@
 "      'V' -- Raise entire conference listening volume\n"
 "";
 
+static const char *descripslas =
+"  SLAS(sla[,options]): Run Shared Line Appearance for station\n"
+"Runs the share line appearance for a station calling in.  If there are no\n"
+"other participants in the conference, the trunk is called and is dumped into\n"
+"the bridge.\n";
+
+static const char *descripslat =
+"  SLAT(sla[,options]): Run Shared Line Appearance for trunk\n"
+"Runs the share line appearance for a trunk calling in.  If there are no\n"
+"other participants in the conference, all member stations are invited into\n"
+"the bridge.\n";
+
+#define CONFIG_FILE_NAME "meetme.conf"
+#define CONFIG_FILE_NAME_SLA "sla.conf"
+
+LOCAL_USER_DECL;
+
 struct ast_conference {
 	ast_mutex_t playlock;                   /*!< Conference specific lock (players) */
 	ast_mutex_t listenlock;                 /*!< Conference specific lock (listeners) */
@@ -313,6 +338,31 @@
 	AST_LIST_ENTRY(ast_conf_user) list;
 };
 
+struct ast_sla_station {
+	ASTOBJ_COMPONENTS(struct ast_sla_station);
+	char *dest;
+	char tech[0];
+};
+
+struct ast_sla_station_box {
+	ASTOBJ_CONTAINER_COMPONENTS(struct ast_sla_station);
+};
+
+struct ast_sla {
+	ASTOBJ_COMPONENTS (struct ast_sla);
+	struct ast_sla_station_box stations;
+	char confname[80];
+	char trunkdest[256];
+	char trunktech[20];
+};
+
+struct ast_sla_box {
+	ASTOBJ_CONTAINER_COMPONENTS(struct ast_sla);
+} slas;
+
+static int audio_buffers;			/* The number of audio buffers to be allocated on pseudo channels
+						   when in a conference
+						*/
 /*! The number of audio buffers to be allocated on pseudo channels
  *  when in a conference */
 static int audio_buffers;
@@ -501,6 +551,18 @@
 
 	if (!res) 
 		ast_autoservice_stop(chan);
+}
+
+static void station_destroy(struct ast_sla_station *station)
+{
+	free(station);
+}
+
+static void sla_destroy(struct ast_sla *sla)
+{
+	ASTOBJ_CONTAINER_DESTROYALL(&sla->stations, station_destroy);
+	ASTOBJ_CONTAINER_DESTROY(&sla->stations);
+	free(sla);
 }
 
 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
@@ -584,7 +646,55 @@
 	return cnf;
 }
 
-static int conf_cmd(int fd, int argc, char **argv) {
+static int confs_show(int fd, int argc, char **argv)
+{
+	ast_cli(fd, "Deprecated! Please use 'meetme' instead.\n");
+
+	return RESULT_SUCCESS;
+}
+
+static int sla_show(int fd, int argc, char *argv[]) 
+{
+	struct ast_sla *sla;
+	if (argc != 2)
+		return RESULT_SHOWUSAGE;
+
+	ast_cli(fd, "Shared line appearances:\n");
+	ASTOBJ_CONTAINER_TRAVERSE(&slas, 1, {
+		ASTOBJ_RDLOCK(iterator);
+		ast_cli(fd, "SLA %s\n", iterator->name);
+		if (ast_strlen_zero(iterator->trunkdest) || ast_strlen_zero(iterator->trunktech))
+			ast_cli(fd, "Trunk => <unspecified>\n");
+		else
+			ast_cli(fd, "Trunk => %s/%s\n", iterator->trunktech, iterator->trunkdest);
+		sla = iterator;
+		ASTOBJ_CONTAINER_TRAVERSE(&sla->stations, 1, {
+			ast_cli(fd, "Station: %s/%s\n", iterator->tech, iterator->dest);
+		});
+		ASTOBJ_UNLOCK(iterator);
+	});
+
+	return RESULT_SUCCESS;
+}
+
+static char show_confs_usage[] =
+"Deprecated! Please use 'meetme' instead.\n";
+
+static struct ast_cli_entry cli_show_confs = {
+	{ "show", "conferences", NULL }, confs_show,
+	"Show status of conferences", show_confs_usage, NULL };
+
+
+static char sla_show_usage[] =
+"Usage: sla show\n"
+"       Lists status of all shared line appearances\n";
+
+static struct ast_cli_entry cli_sla_show = {
+	{ "sla", "show", NULL }, sla_show,
+	"Show status of Shared Line Appearances", sla_show_usage, NULL };
+
+static int conf_cmd(int fd, int argc, char **argv) 
+{
 	/* Process the command */
 	struct ast_conference *cnf;
 	struct ast_conf_user *user;
@@ -2222,6 +2332,152 @@
 	LOCAL_USER_REMOVE(u);
 	
 	return res;
+}
+
+struct sla_originate_helper {
+	char tech[100];
+	char data[200];
+	char app[20];
+	char appdata[100];
+	char cid_name[100];
+	char cid_num[100];
+};
+
+static void *sla_originate(void *data)
+{
+	struct sla_originate_helper *in = data;
+	int res;
+	int reason = 0;
+	struct ast_channel *chan = NULL;
+
+	ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, 99999, in->app, in->appdata, &reason, 1, 
+		S_OR(in->cid_num, NULL), 
+		S_OR(in->cid_name, NULL),
+		NULL, NULL, &chan);
+	/* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
+	if (chan)
+		ast_channel_unlock(chan);
+	free(in);
+	return NULL;
+}
+
+static void do_invite(struct ast_channel *orig, struct ast_sla *sla, const char *tech, const char *dest, const char *app)
+{
+	struct sla_originate_helper *slal = malloc(sizeof(struct sla_originate_helper));
+	pthread_attr_t attr;
+	pthread_t th;
+	if (slal) {
+		memset(slal, 0, sizeof(struct sla_originate_helper));
+		ast_copy_string(slal->tech, tech, sizeof(slal->tech));
+   		ast_copy_string(slal->data, dest, sizeof(slal->data));
+		ast_copy_string(slal->app, app, sizeof(slal->app));
+		ast_copy_string(slal->appdata, sla->name, sizeof(slal->appdata));
+		if (orig->cid.cid_num)
+			ast_copy_string(slal->cid_num, orig->cid.cid_num, sizeof(slal->cid_num));
+		if (orig->cid.cid_name)
+			ast_copy_string(slal->cid_name, orig->cid.cid_name, sizeof(slal->cid_name));
+		pthread_attr_init(&attr);
+		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+		ast_pthread_create(&th, &attr, sla_originate, slal);
+	}
+}
+
+static void invite_stations(struct ast_channel *orig, struct ast_sla *sla)
+{
+	ASTOBJ_CONTAINER_TRAVERSE(&sla->stations, 1, {
+		do_invite(orig, sla,iterator->tech, iterator->dest, "SLAS");
+	});
+}
+
+static void invite_trunk(struct ast_channel *orig, struct ast_sla *sla)
+{
+	do_invite(orig, sla,sla->trunktech, sla->trunkdest, "SLAT");
+}
+
+
+
+/*! \brief The slas()/slat() application */
+static int sla_exec(struct ast_channel *chan, void *data, int trunk)
+{
+	int res=-1;
+	struct localuser *u;
+	char confno[AST_MAX_EXTENSION] = "";
+	struct ast_sla *sla;
+	struct ast_conference *cnf;
+	char *info;
+	struct ast_flags confflags = {0};
+	int dynamic = 1;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(confno);
+		AST_APP_ARG(options);
+	);
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "SLA%c requires an argument (line)\n", trunk ? 'T' : 'S');
+		return -1;
+	}
+
+	info = ast_strdupa(data);
+
+	AST_STANDARD_APP_ARGS(args, info);	
+
+	if (ast_strlen_zero(args.confno)) {
+		ast_log(LOG_WARNING, "SLA%c requires an SLA line number\n", trunk ? 'T' : 'S');
+		return -1;
+	}
+	
+	LOCAL_USER_ADD(u);
+
+	if (chan->_state != AST_STATE_UP)
+		ast_answer(chan);
+
+	info = ast_strdupa(data);
+
+	
+	if (args.options)
+		ast_app_parse_options(sla_opts, &confflags, NULL, args.options);
+		
+	ast_set_flag(&confflags, CONFFLAG_QUIET|CONFFLAG_DYNAMIC);
+	if (trunk)
+		ast_set_flag(&confflags, CONFFLAG_WAITMARKED|CONFFLAG_MARKEDEXIT);
+	else
+		ast_set_flag(&confflags, CONFFLAG_MARKEDUSER);
+
+	sla = ASTOBJ_CONTAINER_FIND(&slas, args.confno);
+	if (sla) {
+		snprintf(confno, sizeof(confno), "sla-%s", args.confno);
+		cnf = find_conf(chan, confno, 1, dynamic, "", 1, &confflags);
+		if (cnf) {
+			if (!cnf->users) {
+				if (trunk)
+					invite_stations(chan, sla);
+				else
+					invite_trunk(chan, sla);
+			}
+			/* Run the conference */
+			res = conf_run(chan, cnf, confflags.flags);
+		} else
+			ast_log(LOG_WARNING, "SLA%c: Found SLA '%s' but unable to build conference!\n", trunk ? 'T' : 'S', args.confno);
+		ASTOBJ_UNREF(sla, sla_destroy);
+	} else {
+		ast_log(LOG_WARNING, "SLA%c: SLA '%s' not found!\n", trunk ? 'T' : 'S', args.confno);
+	}
+	
+	LOCAL_USER_REMOVE(u);
+	
+	return res;
+}
+
+/*! \brief The slas() wrapper */
+static int slas_exec(struct ast_channel *chan, void *data)
+{
+	return sla_exec(chan, data, 0);
+}
+
+/*! \brief The slat() wrapper */
+static int slat_exec(struct ast_channel *chan, void *data)
+{
+	return sla_exec(chan, data, 1);
 }
 
 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident) 
@@ -2542,7 +2798,7 @@
 	return AST_DEVICE_INUSE;
 }
 
-static void load_config(void)
+static void load_config_meetme(void)
 {
 	struct ast_config *cfg;
 	char *val;
@@ -2568,11 +2824,90 @@
 	ast_config_destroy(cfg);
 }
 
+static void append_station(struct ast_sla *sla, const char *station)
+{
+	struct ast_sla_station *s;
+	char *c;
+	s = ast_calloc(1, sizeof(struct ast_sla_station) + strlen(station) + 2);
+	if (s) {
+		ASTOBJ_INIT(s);
+		strcpy(s->tech, station);
+		c = strchr(s->tech, '/');
+		if (c) {
+			*c = '\0';
+			s->dest = c + 1;
+			ASTOBJ_CONTAINER_LINK(&sla->stations, s);
+		} else {
+			ast_log(LOG_WARNING, "station '%s' should be in tech/destination format! Ignoring!\n", station);
+			free(s);
+		}
+	}
+}
+
+static void parse_sla(const char *cat, struct ast_variable *v)
+{
+	struct ast_sla *sla;
+	sla = ASTOBJ_CONTAINER_FIND(&slas, cat);
+	if (!sla) {
+		sla = ast_calloc(1, sizeof(struct ast_sla));
+		if (sla) {
+			ASTOBJ_INIT(sla);
+			ast_copy_string(sla->name, cat, sizeof(sla->name));
+			snprintf(sla->confname, sizeof(sla->confname), "sla-%s", sla->name);
+			ASTOBJ_CONTAINER_LINK(&slas, sla);
+		}
+	}
+	if (sla) {
+		ASTOBJ_UNMARK(sla);
+		ASTOBJ_WRLOCK(sla);
+		while (v) {
+			if (!strcasecmp(v->name, "trunk")) {
+				char *c;
+				c = strchr(v->value, '/');
+				if (c) {
+					ast_copy_string(sla->trunktech, v->value, (c - v->value) + 1);
+					ast_copy_string(sla->trunkdest, c + 1, sizeof(sla->trunkdest));
+				}
+			} else if (!strcasecmp(v->name, "station")) {
+				append_station(sla, v->value);
+			}
+			v = v->next;
+		}
+		ASTOBJ_UNLOCK(sla);
+	}
+}
+
+static void load_config_sla(void)
+{
+	char *cat;
+	struct ast_config *cfg;
+	if (!(cfg = ast_config_load(CONFIG_FILE_NAME_SLA)))
+		return;
+
+	ASTOBJ_CONTAINER_MARKALL(&slas);
+	cat = ast_category_browse(cfg, NULL);
+	while(cat) {
+		if (strcasecmp(cat, "general")) 
+			parse_sla(cat, ast_variable_browse(cfg, cat));
+		cat = ast_category_browse(cfg, cat);
+	}
+	ast_config_destroy(cfg);
+	ASTOBJ_CONTAINER_PRUNE_MARKED(&slas, sla_destroy);
+}
+
+static void load_config(void)
+{
+	load_config_meetme();
+	load_config_sla();
+}
+
 static int unload_module(void *mod)
 {
 	int res;
 	
-	res = ast_cli_unregister(&cli_conf);
+	res = ast_cli_unregister(&cli_show_confs);
+	res |= ast_cli_unregister(&cli_sla_show);
+	res |= ast_cli_unregister(&cli_conf);
 	res |= ast_manager_unregister("MeetmeMute");
 	res |= ast_manager_unregister("MeetmeUnmute");
 	res |= ast_unregister_application(app3);
@@ -2590,13 +2925,17 @@
 	int res;
 
 	load_config();
-
-	res = ast_cli_register(&cli_conf);
+	ASTOBJ_CONTAINER_INIT(&slas);
+	res = ast_cli_register(&cli_show_confs);
+	res |= ast_cli_register(&cli_sla_show);
+	res |= ast_cli_register(&cli_conf);
 	res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute, "Mute a Meetme user");
 	res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute, "Unmute a Meetme user");
 	res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
 	res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
 	res |= ast_register_application(app, conf_exec, synopsis, descrip);
+	res |= ast_register_application(appslas, slas_exec, synopslas, descripslas);
+	res |= ast_register_application(appslat, slat_exec, synopslat, descripslat);
 
 	res |= ast_devstate_prov_add("Meetme", meetmestate);
 	return res;



More information about the svn-commits mailing list