[asterisk-commits] branch oej/managerstuff r31362 - in /team/oej/managerstuff: ./ apps/ channels...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Thu Jun 1 07:58:40 MST 2006


Author: oej
Date: Thu Jun  1 09:58:40 2006
New Revision: 31362

URL: http://svn.digium.com/view/asterisk?rev=31362&view=rev
Log:
Update

Modified:
    team/oej/managerstuff/   (props changed)
    team/oej/managerstuff/apps/app_dial.c
    team/oej/managerstuff/apps/app_hasnewvoicemail.c
    team/oej/managerstuff/apps/app_meetme.c
    team/oej/managerstuff/apps/app_osplookup.c
    team/oej/managerstuff/apps/app_sms.c
    team/oej/managerstuff/apps/app_sql_postgres.c
    team/oej/managerstuff/apps/app_voicemail.c
    team/oej/managerstuff/apps/app_waitforsilence.c
    team/oej/managerstuff/asterisk.c
    team/oej/managerstuff/channel.c
    team/oej/managerstuff/channels/chan_iax2.c
    team/oej/managerstuff/channels/chan_local.c
    team/oej/managerstuff/channels/chan_zap.c
    team/oej/managerstuff/codecs/gsm/Makefile
    team/oej/managerstuff/configs/extensions.conf.sample
    team/oej/managerstuff/configs/sip.conf.sample
    team/oej/managerstuff/dnsmgr.c
    team/oej/managerstuff/enum.c
    team/oej/managerstuff/include/asterisk/linkedlists.h
    team/oej/managerstuff/include/asterisk/lock.h
    team/oej/managerstuff/logger.c
    team/oej/managerstuff/pbx.c
    team/oej/managerstuff/res/res_agi.c
    team/oej/managerstuff/res/res_features.c
    team/oej/managerstuff/rtp.c
    team/oej/managerstuff/utils/smsq.c

Propchange: team/oej/managerstuff/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Jun  1 09:58:40 2006
@@ -1,1 +1,1 @@
-/branches/1.2:1-7496,7498-27338
+/branches/1.2:1-7496,7498-31354

Modified: team/oej/managerstuff/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/team/oej/managerstuff/apps/app_dial.c?rev=31362&r1=31361&r2=31362&view=diff
==============================================================================
--- team/oej/managerstuff/apps/app_dial.c (original)
+++ team/oej/managerstuff/apps/app_dial.c Thu Jun  1 09:58:40 2006
@@ -474,6 +474,8 @@
 						o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
 						if (!o->chan)
 							ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
+						else
+							ast_channel_inherit_variables(in, o->chan);
 					} else {
 						if (option_verbose > 2)
 							ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", o->chan->name);
@@ -942,20 +944,26 @@
 		}
 		
 		if( privdb_val == AST_PRIVACY_DENY ) {
+			strcpy(status, "NOANSWER");
 			ast_verbose( VERBOSE_PREFIX_3  "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
 			res=0;
 			goto out;
 		}
 		else if( privdb_val == AST_PRIVACY_KILL ) {
-			ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
+			strcpy(status, "DONTCALL");
+			if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
+				ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
+			}
 			res = 0;
 			goto out; /* Is this right? */
 		}
 		else if( privdb_val == AST_PRIVACY_TORTURE ) {
-			ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 301);
+			strcpy(status, "TORTURE");
+			if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
+				ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 301);
+			}
 			res = 0;
 			goto out; /* is this right??? */
-
 		}
 		else if( privdb_val == AST_PRIVACY_UNKNOWN ) {
 			/* Get the user's intro, store it in priv-callerintros/$CID, 
@@ -1065,6 +1073,8 @@
 				tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
 				if (!tmp->chan)
 					ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
+				else
+					ast_channel_inherit_variables(chan, tmp->chan);
 			} else {
 				if (option_verbose > 2)
 					ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", tmp->chan->name);
@@ -1314,6 +1324,7 @@
 								     opt_args[OPT_ARG_PRIVACY], privcid);
 						ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_DENY);
 					}
+					strcpy(status,"NOANSWER");
 					if (ast_test_flag(&opts, OPT_MUSICBACK)) {
 						ast_moh_stop(chan);
 					} else if (ast_test_flag(&opts, OPT_RINGBACK)) {

Modified: team/oej/managerstuff/apps/app_hasnewvoicemail.c
URL: http://svn.digium.com/view/asterisk/team/oej/managerstuff/apps/app_hasnewvoicemail.c?rev=31362&r1=31361&r2=31362&view=diff
==============================================================================
--- team/oej/managerstuff/apps/app_hasnewvoicemail.c (original)
+++ team/oej/managerstuff/apps/app_hasnewvoicemail.c Thu Jun  1 09:58:40 2006
@@ -52,6 +52,12 @@
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
 #include "asterisk/options.h"
+#ifdef USE_ODBC_STORAGE
+#include "asterisk/res_odbc.h"
+
+static char odbc_database[80];
+static char odbc_table[80];
+#endif
 
 static char *tdesc = "Indicator for whether a voice mailbox has messages in a given folder.";
 static char *app_hasvoicemail = "HasVoicemail";
@@ -82,25 +88,93 @@
 
 LOCAL_USER_DECL;
 
-static int hasvoicemail_internal(char *context, char *box, char *folder)
-{
-	char vmpath[256];
-	DIR *vmdir;
-	struct dirent *vment;
-	int count=0;
-
-	snprintf(vmpath,sizeof(vmpath), "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR, context, box, folder);
-	if ((vmdir = opendir(vmpath))) {
-		/* No matter what the format of VM, there will always be a .txt file for each message. */
-		while ((vment = readdir(vmdir))) {
-			if (!strncmp(vment->d_name + 7, ".txt", 4)) {
-				count++;
-			}
-		}
-		closedir(vmdir);
-	}
+#ifdef USE_ODBC_STORAGE
+static int hasvoicemail_internal(const char *context, const char *mailbox, const char *folder)
+{
+	int nummsgs = 0;
+	int res;
+	SQLHSTMT stmt;
+	char sql[256];
+	char rowdata[20];
+
+	if (!folder)
+		folder = "INBOX";
+	/* If no mailbox, return immediately */
+	if (ast_strlen_zero(mailbox))
+		return 0;
+	if (ast_strlen_zero(context))
+		context = "default";
+
+	odbc_obj *obj;
+	obj = fetch_odbc_obj(odbc_database, 0);
+	if (obj) {
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
+			goto yuck;
+		}
+		snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s/voicemail/%s/%s/%s'", odbc_table, ast_config_AST_SPOOL_DIR, context, mailbox, folder);
+		res = SQLPrepare(stmt, sql, SQL_NTS);
+		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {  
+			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
+			SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+			goto yuck;
+		}
+		res = odbc_smart_execute(obj, stmt);
+		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
+			SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+			goto yuck;
+		}
+		res = SQLFetch(stmt);
+		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+			ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
+			SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+			goto yuck;
+		}
+		res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
+		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+			ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
+			SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+			goto yuck;
+		}
+		nummsgs = atoi(rowdata);
+		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+	} else
+		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
+
+yuck:
+	return nummsgs;
+}
+
+#else
+
+static int hasvoicemail_internal(const char *context, const char *mailbox, const char *folder)
+{
+	DIR *dir;
+	struct dirent *de;
+	char fn[256];
+	int count = 0;
+
+	if (ast_strlen_zero(folder))
+		folder = "INBOX";
+	if (ast_strlen_zero(context))
+		context = "default";
+	/* If no mailbox, return immediately */
+	if (ast_strlen_zero(mailbox))
+		return 0;
+	snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/%s", ast_config_AST_SPOOL_DIR, context, mailbox, folder);
+	dir = opendir(fn);
+	if (!dir)
+		return 0;
+	while ((de = readdir(dir))) {
+		if (!strncasecmp(de->d_name, "msg", 3) && !strcasecmp(de->d_name + 8, "txt"))
+			count++;
+	}
+	closedir(dir);
 	return count;
 }
+#endif
 
 static int hasvoicemail_exec(struct ast_channel *chan, void *data)
 {
@@ -230,6 +304,31 @@
 	.read = acf_vmcount_exec,
 };
 
+static int load_config(void)
+{
+#ifdef USE_ODBC_STORAGE
+	struct ast_config *cfg;
+	char *tmp;
+	cfg = ast_config_load("voicemail.conf");
+	if (cfg) {
+		if (! (tmp = ast_variable_retrieve(cfg, "general", "odbcstorage")))
+			tmp = "asterisk";
+		ast_copy_string(odbc_database, tmp, sizeof(odbc_database));
+
+		if (! (tmp = ast_variable_retrieve(cfg, "general", "odbctable")))
+			tmp = "voicemessages";
+		ast_copy_string(odbc_table, tmp, sizeof(odbc_table));
+		ast_config_destroy(cfg);
+	}
+#endif
+	return 0;
+}
+
+int reload(void)
+{
+	return load_config();
+}
+
 int unload_module(void)
 {
 	int res;
@@ -246,7 +345,7 @@
 int load_module(void)
 {
 	int res;
-
+	load_config();
 	res = ast_custom_function_register(&acf_vmcount);
 	res |= ast_register_application(app_hasvoicemail, hasvoicemail_exec, hasvoicemail_synopsis, hasvoicemail_descrip);
 	res |= ast_register_application(app_hasnewvoicemail, hasvoicemail_exec, hasnewvoicemail_synopsis, hasnewvoicemail_descrip);

Modified: team/oej/managerstuff/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/team/oej/managerstuff/apps/app_meetme.c?rev=31362&r1=31361&r2=31362&view=diff
==============================================================================
--- team/oej/managerstuff/apps/app_meetme.c (original)
+++ team/oej/managerstuff/apps/app_meetme.c Thu Jun  1 09:58:40 2006
@@ -25,6 +25,10 @@
  * \ingroup applications
  */
 
+/*** MODULEINFO
+	<depend>zaptel</depend>
+ ***/
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -59,7 +63,124 @@
 #include "asterisk/translate.h"
 #include "asterisk/ulaw.h"
 
-static const char *tdesc = "MeetMe conference bridge";
+#include "enter.h"
+#include "leave.h"
+
+LOCAL_USER_DECL;
+
+#define CONFIG_FILE_NAME "meetme.conf"
+
+/*! each buffer is 20ms, so this is 640ms total */
+#define DEFAULT_AUDIO_BUFFERS  32
+
+enum {
+	ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
+	ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
+	ADMINFLAG_KICKME =    (1 << 3)  /*!< User has been kicked */
+};
+
+#define MEETME_DELAYDETECTTALK     300
+#define MEETME_DELAYDETECTENDTALK  1000
+
+#define AST_FRAME_BITS  32
+
+enum volume_action {
+	VOL_UP,
+	VOL_DOWN
+};
+
+enum entrance_sound {
+	ENTER,
+	LEAVE
+};
+
+enum recording_state {
+	MEETME_RECORD_OFF,
+	MEETME_RECORD_STARTED,
+	MEETME_RECORD_ACTIVE,
+	MEETME_RECORD_TERMINATE
+};
+
+#define CONF_SIZE  320
+
+enum {
+	/*! user has admin access on the conference */
+	CONFFLAG_ADMIN = (1 << 0),
+	/*! If set the user can only receive audio from the conference */
+	CONFFLAG_MONITOR = (1 << 1),
+	/*! If set asterisk will exit conference when '#' is pressed */
+	CONFFLAG_POUNDEXIT = (1 << 2),
+	/*! If set asterisk will provide a menu to the user when '*' is pressed */
+	CONFFLAG_STARMENU = (1 << 3),
+	/*! If set the use can only send audio to the conference */
+	CONFFLAG_TALKER = (1 << 4),
+	/*! If set there will be no enter or leave sounds */
+	CONFFLAG_QUIET = (1 << 5),
+	/*! If set, when user joins the conference, they will be told the number 
+	 *  of users that are already in */
+	CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
+	/*! Set to run AGI Script in Background */
+	CONFFLAG_AGI = (1 << 7),
+	/*! Set to have music on hold when user is alone in conference */
+	CONFFLAG_MOH = (1 << 8),
+	/*! If set the MeetMe will return if all marked with this flag left */
+	CONFFLAG_MARKEDEXIT = (1 << 9),
+	/*! If set, the MeetMe will wait until a marked user enters */
+	CONFFLAG_WAITMARKED = (1 << 10),
+	/*! If set, the MeetMe will exit to the specified context */
+	CONFFLAG_EXIT_CONTEXT = (1 << 11),
+	/*! If set, the user will be marked */
+	CONFFLAG_MARKEDUSER = (1 << 12),
+	/*! If set, user will be ask record name on entry of conference */
+	CONFFLAG_INTROUSER = (1 << 13),
+	/*! If set, the MeetMe will be recorded */
+	CONFFLAG_RECORDCONF = (1<< 14),
+	/*! If set, the user will be monitored if the user is talking or not */
+	CONFFLAG_MONITORTALKER = (1 << 15),
+	CONFFLAG_DYNAMIC = (1 << 16),
+	CONFFLAG_DYNAMICPIN = (1 << 17),
+	CONFFLAG_EMPTY = (1 << 18),
+	CONFFLAG_EMPTYNOPIN = (1 << 19),
+	CONFFLAG_ALWAYSPROMPT = (1 << 20),
+	/*! If set, treats talking users as muted users */
+	CONFFLAG_OPTIMIZETALKER = (1 << 21),
+	/*! If set, won't speak the extra prompt when the first person 
+	 *  enters the conference */
+	CONFFLAG_NOONLYPERSON = (1 << 22),
+	CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
+	/*! If set, user will be asked to record name on entry of conference 
+	 *  without review */
+	CONFFLAG_STARTMUTED = (1 << 24)
+	/*! If set, the user will be initially self-muted */
+};
+
+AST_APP_OPTIONS(meetme_opts, {
+	AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
+	AST_APP_OPTION('a', CONFFLAG_ADMIN ),
+	AST_APP_OPTION('b', CONFFLAG_AGI ),
+	AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
+	AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
+	AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
+	AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
+	AST_APP_OPTION('e', CONFFLAG_EMPTY ),
+	AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
+	AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
+	AST_APP_OPTION('M', CONFFLAG_MOH ),
+	AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
+	AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
+	AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
+	AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ),
+	AST_APP_OPTION('q', CONFFLAG_QUIET ),
+	AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
+	AST_APP_OPTION('s', CONFFLAG_STARMENU ),
+	AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
+	AST_APP_OPTION('l', CONFFLAG_MONITOR ),
+	AST_APP_OPTION('t', CONFFLAG_TALKER ),
+	AST_APP_OPTION('w', CONFFLAG_WAITMARKED ),
+	AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
+	AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
+	AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
+});
 
 static const char *app = "MeetMe";
 static const char *app2 = "MeetMeCount";
@@ -70,10 +191,10 @@
 static const char *synopsis3 = "MeetMe conference Administration";
 
 static const char *descrip =
-"  MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe conference.\n"
-"If the conference number is omitted, the user will be prompted to enter\n"
-"one. \n"
-"User can exit the conference by hangup, or if the 'p' option is specified, by pressing '#'.\n"
+"  MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
+"conference.  If the conference number is omitted, the user will be prompted\n"
+"to enter one.  User can exit the conference by hangup, or if the 'p' option\n"
+"is specified, by pressing '#'.\n"
 "Please note: The Zaptel kernel modules and at least one hardware driver (or ztdummy)\n"
 "             must be present for conferencing to operate properly. In addition, the chan_zap\n"
 "             channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
@@ -81,41 +202,45 @@
 "      'a' -- set admin mode\n"
 "      'A' -- set marked mode\n"
 "      'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
-"             Default: conf-background.agi\n"
-"             (Note: This does not work with non-Zap channels in the same conference)\n"
+"             Default: conf-background.agi  (Note: This does not work with\n"
+"             non-Zap channels in the same conference)\n"
 "      'c' -- announce user(s) count on joining a conference\n"
 "      'd' -- dynamically add conference\n"
 "      'D' -- dynamically add conference, prompting for a PIN\n"
 "      'e' -- select an empty conference\n"
 "      'E' -- select an empty pinless conference\n"
-"      'i' -- announce user join/leave\n"
-"      'm' -- set monitor only mode (Listen only, no talking)\n"
+"      'i' -- announce user join/leave with review\n"
+"      'I' -- announce user join/leave without review\n"
+"      'l' -- set listen only mode (Listen only, no talking)\n"
+"      'm' -- set initially muted\n"
 "      'M' -- enable music on hold when the conference has a single caller\n"
+"      'o' -- set talker optimization - treats talkers who aren't speaking as\n"
+"             being muted, meaning (a) No encode is done on transmission and\n"
+"             (b) Received audio that is not registered as talking is omitted\n"
+"             causing no buildup in background noise\n"
 "      'p' -- allow user to exit the conference by pressing '#'\n"
 "      'P' -- always prompt for the pin even if it is specified\n"
 "      'q' -- quiet mode (don't play enter/leave sounds)\n"
 "      'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
 "             using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
-"             meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is wav.\n"
+"             meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
+"             wav.\n"
 "      's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
 "      't' -- set talk only mode. (Talk only, no listening)\n"
 "      'T' -- set talker detection (sent to manager interface and meetme list)\n"
-"      'o' -- set talker optimization - treats talkers who aren't speaking as\n"
-"             being muted, meaning (a) No encode is done on transmission and\n"
-"             (b) Received audio that is not registered as talking is omitted\n"
-"             causing no buildup in background noise\n"
-"      'v' -- video mode\n"
 "      'w' -- wait until the marked user enters the conference\n"
 "      'x' -- close the conference when last marked user exits\n"
 "      'X' -- allow user to exit the conference by entering a valid single\n"
 "             digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
-"             if that variable is not defined.\n";
+"             if that variable is not defined.\n"
+"      '1' -- do not play message when first person enters\n";
 
 static const char *descrip2 =
 "  MeetMeCount(confno[|var]): Plays back the number of users in the specified\n"
 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
-"will be returned in the variable. Upon app completion, MeetMeCount will hangup the\n"
-"channel, unless priority n+1 exists, in which case priority progress will continue.\n"
+"will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
+"the channel, unless priority n+1 exists, in which case priority progress will\n"
+"continue.\n"
 "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
 
 static const char *descrip3 = 
@@ -125,154 +250,99 @@
 "      'K' -- Kick all users out of conference\n"
 "      'l' -- Unlock conference\n"
 "      'L' -- Lock conference\n"
-"      'm' -- Unmute conference\n"
-"      'M' -- Mute conference\n"
-"      'n' -- Unmute entire conference (except admin)\n"
-"      'N' -- Mute entire conference (except admin)\n"
+"      'm' -- Unmute one user\n"
+"      'M' -- Mute one user\n"
+"      'n' -- Unmute all users in the conference\n"
+"      'N' -- Mute all non-admin users in the conference\n"
+"      'r' -- Reset one user's volume settings\n"
+"      'R' -- Reset all users volume settings\n"
+"      's' -- Lower entire conference speaking volume\n"
+"      'S' -- Raise entire conference speaking volume\n"
+"      't' -- Lower one user's talk volume\n"
+"      'T' -- Lower all users talk volume\n"
+"      'u' -- Lower one user's listen volume\n"
+"      'U' -- Lower all users listen volume\n"
+"      'v' -- Lower entire conference listening volume\n"
+"      'V' -- Raise entire conference listening volume\n"
 "";
 
-#define CONFIG_FILE_NAME "meetme.conf"
-
-STANDARD_LOCAL_USER;
-
-LOCAL_USER_DECL;
-
-static struct ast_conference {
-	ast_mutex_t playlock;				/* Conference specific lock (players) */
-	ast_mutex_t listenlock;				/* Conference specific lock (listeners) */
-	char confno[AST_MAX_EXTENSION];		/* Conference */
-	struct ast_channel *chan;		/* Announcements channel */
-	struct ast_channel *lchan;		/* Listen/Record channel */
-	int fd;					/* Announcements fd */
-	int zapconf;				/* Zaptel Conf # */
-	int users;				/* Number of active users */
-	int markedusers;			/* Number of marked users */
-	struct ast_conf_user *firstuser;	/* Pointer to the first user struct */
-	struct ast_conf_user *lastuser;		/* Pointer to the last user struct */
-	time_t start;				/* Start time (s) */
-	int recording;				/* recording status */
-	int isdynamic;				/* Created on the fly? */
-	int locked;				/* Is the conference locked? */
-	pthread_t recordthread;			/* thread for recording */
-	pthread_attr_t attr;			/* thread attribute */
-	const char *recordingfilename;		/* Filename to record the Conference into */
-	const char *recordingformat;			/* Format to record the Conference in */
-	char pin[AST_MAX_EXTENSION];		/* If protected by a PIN */
-	char pinadmin[AST_MAX_EXTENSION];	/* If protected by a admin PIN */
+struct ast_conference {
+	ast_mutex_t playlock;                   /*!< Conference specific lock (players) */
+	ast_mutex_t listenlock;                 /*!< Conference specific lock (listeners) */
+	char confno[AST_MAX_EXTENSION];         /*!< Conference */
+	struct ast_channel *chan;               /*!< Announcements channel */
+	struct ast_channel *lchan;              /*!< Listen/Record channel */
+	int fd;                                 /*!< Announcements fd */
+	int zapconf;                            /*!< Zaptel Conf # */
+	int users;                              /*!< Number of active users */
+	int markedusers;                        /*!< Number of marked users */
+	time_t start;                           /*!< Start time (s) */
+	int refcount;                           /*!< reference count of usage */
+	enum recording_state recording:2;               /*!< recording status */
+	unsigned int isdynamic:1;               /*!< Created on the fly? */
+	unsigned int locked:1;                  /*!< Is the conference locked? */
+	pthread_t recordthread;                 /*!< thread for recording */
+	pthread_attr_t attr;                    /*!< thread attribute */
+	const char *recordingfilename;          /*!< Filename to record the Conference into */
+	const char *recordingformat;            /*!< Format to record the Conference in */
+	char pin[AST_MAX_EXTENSION];            /*!< If protected by a PIN */
+	char pinadmin[AST_MAX_EXTENSION];       /*!< If protected by a admin PIN */
 	struct ast_frame *transframe[32];
 	struct ast_frame *origframe;
 	struct ast_trans_pvt *transpath[32];
-	struct ast_conference *next;
-} *confs;
+	AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
+	AST_LIST_ENTRY(ast_conference) list;
+};
+
+static AST_LIST_HEAD_STATIC(confs, ast_conference);
 
 struct volume {
-	int desired;				/* Desired volume adjustment */
-	int actual;				/* Actual volume adjustment (for channels that can't adjust) */
+	int desired;                            /*!< Desired volume adjustment */
+	int actual;                             /*!< Actual volume adjustment (for channels that can't adjust) */
 };
 
 struct ast_conf_user {
-	int user_no;				/* User Number */
-	struct ast_conf_user *prevuser;		/* Pointer to the previous user */
-	struct ast_conf_user *nextuser;		/* Pointer to the next user */
-	int userflags;				/* Flags as set in the conference */
-	int adminflags;				/* Flags set by the Admin */
-	struct ast_channel *chan;		/* Connected channel */
-	int talking;				/* Is user talking */
-	int zapchannel;				/* Is a Zaptel channel */
-	char usrvalue[50];			/* Custom User Value */
-	char namerecloc[AST_MAX_EXTENSION];	/* Name Recorded file Location */
-	time_t jointime;			/* Time the user joined the conference */
+	int user_no;                            /*!< User Number */
+	int userflags;                          /*!< Flags as set in the conference */
+	int adminflags;                         /*!< Flags set by the Admin */
+	struct ast_channel *chan;               /*!< Connected channel */
+	int talking;                            /*!< Is user talking */
+	int zapchannel;                         /*!< Is a Zaptel channel */
+	char usrvalue[50];                      /*!< Custom User Value */
+	char namerecloc[PATH_MAX];		/*!< Name Recorded file Location */
+	time_t jointime;                        /*!< Time the user joined the conference */
 	struct volume talk;
 	struct volume listen;
+	AST_LIST_ENTRY(ast_conf_user) list;
 };
 
-static int audio_buffers;			/* The number of audio buffers to be allocated on pseudo channels
-						   when in a conference
-						*/
-
-#define DEFAULT_AUDIO_BUFFERS 32		/* each buffer is 20ms, so this is 640ms total */
-
-#define ADMINFLAG_MUTED (1 << 1)		/* User is muted */
-#define ADMINFLAG_KICKME (1 << 2)		/* User is kicked */
-#define MEETME_DELAYDETECTTALK 		300
-#define MEETME_DELAYDETECTENDTALK 	1000
-
-#define AST_FRAME_BITS 32
-
-enum volume_action {
-	VOL_UP,
-	VOL_DOWN,
+/*! The number of audio buffers to be allocated on pseudo channels
+ *  when in a conference */
+static int audio_buffers;
+
+/*! Map 'volume' levels from -5 through +5 into
+ *  decibel (dB) settings for channel drivers
+ *  Note: these are not a straight linear-to-dB
+ *  conversion... the numbers have been modified
+ *  to give the user a better level of adjustability
+ */
+static signed char gain_map[] = {
+	-15,
+	-13,
+	-10,
+	-6,
+	0,
+	0,
+	0,
+	6,
+	10,
+	13,
+	15,
 };
 
-AST_MUTEX_DEFINE_STATIC(conflock);
 
 static int admin_exec(struct ast_channel *chan, void *data);
-static struct ast_frame null_frame = { AST_FRAME_NULL, };
-
 static void *recordthread(void *args);
-
-#include "enter.h"
-#include "leave.h"
-
-#define ENTER	0
-#define LEAVE	1
-
-#define MEETME_RECORD_OFF	0
-#define MEETME_RECORD_STARTED	1
-#define MEETME_RECORD_ACTIVE	2
-#define MEETME_RECORD_TERMINATE	3
-
-#define CONF_SIZE 320
-
-#define CONFFLAG_ADMIN	(1 << 1)		/* If set the user has admin access on the conference */
-#define CONFFLAG_MONITOR (1 << 2)		/* If set the user can only receive audio from the conference */
-#define CONFFLAG_POUNDEXIT (1 << 3)		/* If set asterisk will exit conference when '#' is pressed */
-#define CONFFLAG_STARMENU (1 << 4)		/* If set asterisk will provide a menu to the user when '*' is pressed */
-#define CONFFLAG_TALKER (1 << 5)		/* If set the use can only send audio to the conference */
-#define CONFFLAG_QUIET (1 << 6)			/* If set there will be no enter or leave sounds */
-#define CONFFLAG_VIDEO (1 << 7)			/* Set to enable video mode */
-#define CONFFLAG_AGI (1 << 8)			/* Set to run AGI Script in Background */
-#define CONFFLAG_MOH (1 << 9)			/* Set to have music on hold when user is alone in conference */
-#define CONFFLAG_MARKEDEXIT (1 << 10)		/* If set the MeetMe will return if all marked with this flag left */
-#define CONFFLAG_WAITMARKED (1 << 11)		/* If set, the MeetMe will wait until a marked user enters */
-#define CONFFLAG_EXIT_CONTEXT (1 << 12)		/* If set, the MeetMe will exit to the specified context */
-#define CONFFLAG_MARKEDUSER (1 << 13)		/* If set, the user will be marked */
-#define CONFFLAG_INTROUSER (1 << 14)		/* If set, user will be ask record name on entry of conference */
-#define CONFFLAG_RECORDCONF (1<< 15)		/* If set, the MeetMe will be recorded */
-#define CONFFLAG_MONITORTALKER (1 << 16)	/* If set, the user will be monitored if the user is talking or not */
-#define CONFFLAG_DYNAMIC (1 << 17)
-#define CONFFLAG_DYNAMICPIN (1 << 18)
-#define CONFFLAG_EMPTY (1 << 19)
-#define CONFFLAG_EMPTYNOPIN (1 << 20)
-#define CONFFLAG_ALWAYSPROMPT (1 << 21)
-#define CONFFLAG_ANNOUNCEUSERCOUNT (1 << 22)	/* If set, when user joins the conference, they will be told the number of users that are already in */
-#define CONFFLAG_OPTIMIZETALKER (1 << 23)	/* If set, treats talking users as muted users */
-
-
-AST_APP_OPTIONS(meetme_opts, {
-	AST_APP_OPTION('a', CONFFLAG_ADMIN ),
-	AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
-	AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
-	AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
-	AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
-	AST_APP_OPTION('m', CONFFLAG_MONITOR ),
-	AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ),
-	AST_APP_OPTION('s', CONFFLAG_STARMENU ),
-	AST_APP_OPTION('t', CONFFLAG_TALKER ),
-	AST_APP_OPTION('q', CONFFLAG_QUIET ),
-	AST_APP_OPTION('M', CONFFLAG_MOH ),
-	AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
-	AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
-	AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
-	AST_APP_OPTION('b', CONFFLAG_AGI ),
-	AST_APP_OPTION('w', CONFFLAG_WAITMARKED ),
-	AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
-	AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
-	AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
-	AST_APP_OPTION('e', CONFFLAG_EMPTY ),
-	AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
-	AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
-});
 
 static char *istalking(int x)
 {
@@ -311,26 +381,6 @@
 	return 0;
 }
 
-/* Map 'volume' levels from -5 through +5 into
-   decibel (dB) settings for channel drivers
-   Note: these are not a straight linear-to-dB
-   conversion... the numbers have been modified
-   to give the user a better level of adjustability
-*/
-static signed char gain_map[] = {
-	-15,
-	-13,
-	-10,
-	-6,
-	0,
-	0,
-	0,
-	6,
-	10,
-	13,
-	15,
-};
-
 static int set_talk_volume(struct ast_conf_user *user, int volume)
 {
 	signed char gain_adjust;
@@ -422,18 +472,16 @@
 	ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
 }
 
-static void conf_play(struct ast_channel *chan, struct ast_conference *conf, int sound)
+static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
 {
 	unsigned char *data;
 	int len;
 	int res = -1;
-	short *data2;
-	int x;
 
 	if (!chan->_softhangup)
 		res = ast_autoservice_start(chan);
 
-	ast_mutex_lock(&conflock);
+	AST_LIST_LOCK(&confs);
 
 	switch(sound) {
 	case ENTER:
@@ -449,39 +497,36 @@
 		len = 0;
 	}
 	if (data) {
-		data2 = alloca(len * 2);
-		for (x=0;x<len;x++)
-			data2[x] = AST_MULAW(data[x]);
-		careful_write(conf->fd, (unsigned char *)data2, len << 1, 1);
-	}
-
-	ast_mutex_unlock(&conflock);
+		careful_write(conf->fd, data, len, 1);
+	}
+
+	AST_LIST_UNLOCK(&confs);
 
 	if (!res) 
 		ast_autoservice_stop(chan);
 }
 
-static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic)
+static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
 {
 	struct ast_conference *cnf;
 	struct zt_confinfo ztc;
 
-	ast_mutex_lock(&conflock);
-
-	for (cnf = confs; cnf; cnf = cnf->next) {
+	AST_LIST_LOCK(&confs);
+
+	AST_LIST_TRAVERSE(&confs, cnf, list) {
 		if (!strcmp(confno, cnf->confno)) 
 			break;
 	}
 
 	if (!cnf && (make || dynamic)) {
 		/* Make a new one */
-		cnf = calloc(1, sizeof(*cnf));
-		if (cnf) {
+		if ((cnf = ast_calloc(1, sizeof(*cnf)))) {
 			ast_mutex_init(&cnf->playlock);
 			ast_mutex_init(&cnf->listenlock);
 			ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
 			ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
 			ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
+			cnf->refcount = 0;
 			cnf->markedusers = 0;
 			cnf->chan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
 			if (cnf->chan) {
@@ -528,36 +573,20 @@
 			/* Fill the conference struct */
 			cnf->start = time(NULL);
 			cnf->zapconf = ztc.confno;
-			cnf->isdynamic = dynamic;
-			cnf->firstuser = NULL;
-			cnf->lastuser = NULL;
-			cnf->locked = 0;
+			cnf->isdynamic = dynamic ? 1 : 0;
 			if (option_verbose > 2)
 				ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
-			cnf->next = confs;
-			confs = cnf;
-		} else	
-			ast_log(LOG_WARNING, "Out of memory\n");
+			AST_LIST_INSERT_HEAD(&confs, cnf, list);
+		} 
 	}
  cnfout:
-	ast_mutex_unlock(&conflock);
+	if (cnf){ 
+		cnf->refcount += refcount;
+	}
+	AST_LIST_UNLOCK(&confs);
 	return cnf;
 }
 
-static int confs_show(int fd, int argc, char **argv)
-{
-	ast_cli(fd, "Deprecated! Please use 'meetme' instead.\n");
-
-	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 int conf_cmd(int fd, int argc, char **argv) {
 	/* Process the command */
 	struct ast_conference *cnf;
@@ -579,13 +608,12 @@
 	if (argc == 1) {
 		/* 'MeetMe': List all the conferences */	
 		now = time(NULL);
-		cnf = confs;
-		if (!cnf) {
+		if (AST_LIST_EMPTY(&confs)) {
 			ast_cli(fd, "No active MeetMe conferences.\n");
 			return RESULT_SUCCESS;
 		}
 		ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
-		while(cnf) {
+		AST_LIST_TRAVERSE(&confs, cnf, list) {
 			if (cnf->markedusers == 0)
 				strcpy(cmdline, "N/A ");
 			else 
@@ -597,7 +625,6 @@
 			ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
 
 			total += cnf->users; 	
-			cnf = cnf->next;
 		}
 		ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
 		return RESULT_SUCCESS;
@@ -645,35 +672,53 @@
 			strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
 		}	
 	} else if(strcmp(argv[1], "list") == 0) {
+		int concise = ( 4 == argc && ( !strcasecmp(argv[3], "concise") ) );
 		/* List all the users in a conference */
-		if (!confs) {
-			ast_cli(fd, "No active conferences.\n");
+		if (AST_LIST_EMPTY(&confs)) {
+			if ( !concise )
+				ast_cli(fd, "No active conferences.\n");
 			return RESULT_SUCCESS;	
 		}
-		cnf = confs;
 		/* Find the right conference */
-		while(cnf) {
+		AST_LIST_TRAVERSE(&confs, cnf, list) {
 			if (strcmp(cnf->confno, argv[2]) == 0)
 				break;
-			if (cnf->next) {
-				cnf = cnf->next;	
-			} else {
+		}
+		if (!cnf) {
+			if ( !concise )
 				ast_cli(fd, "No such conference: %s.\n",argv[2]);
-				return RESULT_SUCCESS;
-			}
+			return RESULT_SUCCESS;
 		}
 		/* Show all the users */
-		for (user = cnf->firstuser; user; user = user->nextuser)
-			ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s\n",
-				user->user_no,
-				user->chan->cid.cid_num ? user->chan->cid.cid_num : "<unknown>",
-				user->chan->cid.cid_name ? user->chan->cid.cid_name : "<no name>",
-				user->chan->name,
-				user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
-				user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
-				user->adminflags & ADMINFLAG_MUTED ? "(Admn Muted)" : "",
-				istalking(user->talking));
-		ast_cli(fd,"%d users in that conference.\n",cnf->users);
+		AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
+			now = time(NULL);
+			hr = (now - user->jointime) / 3600;
+			min = ((now - user->jointime) % 3600) / 60;
+			sec = (now - user->jointime) % 60;
+			if ( !concise )
+				ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %02d:%02d:%02d\n",
+					user->user_no,
+					S_OR(user->chan->cid.cid_num, "<unknown>"),
+					S_OR(user->chan->cid.cid_name, "<no name>"),
+					user->chan->name,
+					user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
+					user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
+					user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
+					istalking(user->talking), hr, min, sec);
+			else 
+				ast_cli(fd, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
+					user->user_no,
+					S_OR(user->chan->cid.cid_num, ""),
+					S_OR(user->chan->cid.cid_name, ""),
+					user->chan->name,
+					user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
+					user->userflags  & CONFFLAG_MONITOR ? "1" : "",
+					user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)  ? "1" : "",
+					user->talking, hr, min, sec);
+			
+		}
+		if ( !concise )
+			ast_cli(fd,"%d users in that conference.\n",cnf->users);
 
 		return RESULT_SUCCESS;
 	} else 
@@ -684,46 +729,38 @@
 	return 0;
 }
 
-static char *complete_confcmd(char *line, char *word, int pos, int state) {
-#define CONF_COMMANDS 6
-	int which = 0, x = 0;
+static char *complete_confcmd(const char *line, const char *word, int pos, int state)
+{
+	static char *cmds[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL};
+
+	int len = strlen(word);
+	int which = 0;
 	struct ast_conference *cnf = NULL;
 	struct ast_conf_user *usr = NULL;
 	char *confno = NULL;
 	char usrno[50] = "";
-	char cmds[CONF_COMMANDS][20] = {"lock", "unlock", "mute", "unmute", "kick", "list"};
-	char *myline;
+	char *myline, *ret = NULL;
 	
-	if (pos == 1) {
-		/* Command */
-		for (x = 0;x < CONF_COMMANDS; x++) {
-			if (!strncasecmp(cmds[x], word, strlen(word))) {
-				if (++which > state) {
-					return strdup(cmds[x]);
-				}
-			}
-		}
-	} else if (pos == 2) {
-		/* Conference Number */
-		ast_mutex_lock(&conflock);
-		cnf = confs;
-		while(cnf) {
-			if (!strncasecmp(word, cnf->confno, strlen(word))) {
-				if (++which > state)
-					break;
-			}
-			cnf = cnf->next;
-		}
-		ast_mutex_unlock(&conflock);
-		return cnf ? strdup(cnf->confno) : NULL;
+	if (pos == 1) {		/* Command */
+		return ast_cli_complete(word, cmds, state);
+	} else if (pos == 2) {	/* Conference Number */
+		AST_LIST_LOCK(&confs);
+		AST_LIST_TRAVERSE(&confs, cnf, list) {
+			if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
+				ret = cnf->confno;
+				break;
+			}
+		}
+		ret = ast_strdup(ret); /* dup before releasing the lock */
+		AST_LIST_UNLOCK(&confs);
+		return ret;
 	} else if (pos == 3) {
 		/* User Number || Conf Command option*/
 		if (strstr(line, "mute") || strstr(line, "kick")) {
-			if ((state == 0) && (strstr(line, "kick") || strstr(line,"mute")) && !(strncasecmp(word, "all", strlen(word)))) {
+			if (state == 0 && (strstr(line, "kick") || strstr(line,"mute")) && !strncasecmp(word, "all", len))
 				return strdup("all");
-			}
 			which++;
-			ast_mutex_lock(&conflock);
+			AST_LIST_LOCK(&confs);
 
 			/* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
 			myline = ast_strdupa(line);
@@ -732,31 +769,30 @@
 					;
 			}
 			
-			for (cnf = confs; cnf; cnf = cnf->next) {
+			AST_LIST_TRAVERSE(&confs, cnf, list) {
 				if (!strcmp(confno, cnf->confno))
 				    break;
 			}
 
 			if (cnf) {
 				/* Search for the user */
-				for (usr = cnf->firstuser; usr; usr = usr->nextuser) {
+				AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
 					snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
-					if (!strncasecmp(word, usrno, strlen(word))) {
-						if (++which > state)
-							break;
-					}
+					if (!strncasecmp(word, usrno, len) && ++which > state)
+						break;
 				}
 			}
-			ast_mutex_unlock(&conflock);
+			AST_LIST_UNLOCK(&confs);
 			return usr ? strdup(usrno) : NULL;
-		}
+		} else if ( strstr(line, "list") && ( 0 == state ) )
+			return strdup("concise");
 	}
 
 	return NULL;
 }
 	
 static char conf_usage[] =
-"Usage: meetme  (un)lock|(un)mute|kick|list <confno> <usernumber>\n"
+"Usage: meetme  (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
 "       Executes a command for the conference or on a conferee\n";
 
 static struct ast_cli_entry cli_conf = {
@@ -796,32 +832,18 @@
    We assume that this was called while holding conflock. */
 static int conf_free(struct ast_conference *conf)
 {
-	struct ast_conference *prev = NULL, *cur = confs;
 	int x;
 	
-	while (cur) {
-		if (cur == conf) {
-			if (prev)
-				prev->next = conf->next;
-			else
-				confs = conf->next;
-			break;
-		}
-		prev = cur;
-		cur = cur->next;
-	}
-
-	if (!cur)
-		ast_log(LOG_WARNING, "Conference not found\n");

[... 3990 lines stripped ...]


More information about the asterisk-commits mailing list