--- ./asterisk/apps/app_meetme.c	2004-04-29 04:30:14.000000000 +0200
+++ ../new-asterisk/asterisk/apps/app_meetme.c	2004-05-13 19:05:43.000000000 +0200
@@ -37,9 +37,11 @@
 
 static char *app = "MeetMe";
 static char *app2 = "MeetMeCount";
+static char *app3 = "MeetMeAdmin";
 
 static char *synopsis = "Simple MeetMe conference bridge";
 static char *synopsis2 = "MeetMe participant count";
+static char *synopsis3 = "Send Admin Commands to a conference";
 
 static char *descrip =
 "  MeetMe(confno[,[options][,pin]]): Enters the user into a specified MeetMe conference.\n"
@@ -58,10 +60,10 @@
 "      'v' -- video mode\n"
 "      'q' -- quiet mode (don't play enter/leave sounds)\n"
 "      'M' -- enable music on hold when the conference has a single caller\n"
+"      'x' -- exit the conference if the last marked user left\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"
-"      Not implemented yet:\n"
 "      's' -- send user to admin/user menu if '*' is received\n"
 "      'a' -- set admin mode\n";
 
@@ -71,6 +73,8 @@
 "will be returned in the variable. Returns 0 on success or -1 on a hangup.\n"
 "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
 
+static char *descrip3 = "";
+
 STANDARD_LOCAL_USER;
 
 LOCAL_USER_DECL;
@@ -80,14 +84,35 @@
 	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 isdynamic;			/* Created on the fly? */
+        int locked;			  /* Is the conference locked? */
 	char pin[AST_MAX_EXTENSION];			/* If protected by a PIN */
 	struct ast_conference *next;
 } *confs;
 
+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 */
+	char usrvalue[50];		 /* Custom User Value */
+	time_t jointime;		 /* Time the user joined the conference */
+};
+
+#define ADMINFLAG_MUTED (1 << 1)	/* User is listening at the moment */
+#define ADMINFLAG_KICKME (1 << 2)	/* User is able to talk*/
+
+
 static ast_mutex_t conflock = AST_MUTEX_INITIALIZER;
 
+static int admin_exec(struct ast_channel *chan, void *data);
+
 #include "enter.h"
 #include "leave.h"
 
@@ -105,6 +130,7 @@
 #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 */
+#define CONFFLAG_ADMINEXIT (1 << 10)    /* If set the MeetMe will return if all marked with this flag left */
 
 
 static int careful_write(int fd, unsigned char *data, int len)
@@ -185,9 +211,13 @@
 				cnf = NULL;
 				goto cnfout;
 			}
+                        /* Fill the conference struct */
 			cnf->start = time(NULL);
 			cnf->zapconf = ztc.confno;
 			cnf->isdynamic = dynamic;
+                        cnf->firstuser = NULL;
+                        cnf->lastuser = NULL;
+                        cnf->locked = 0;
 			if (option_verbose > 2)
 				ast_verbose(VERBOSE_PREFIX_3 "Created ZapTel conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
 			cnf->next = confs;
@@ -241,9 +271,206 @@
 	{ "show", "conferences", NULL }, confs_show, 
 	"Show status of conferences", show_confs_usage, NULL };
 
+static char *complete_confno(char *line, char *word, int pos, int state)
+{
+	struct ast_conference *cnf;
+	int which=0;
+	
+	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;
+}
+
+static int conf_show(int fd, int argc, char **argv) {
+	struct ast_conference *cnf;
+	struct ast_conf_user *user;
+	
+	if (argc != 3)
+		return RESULT_SHOWUSAGE;
+	
+	ast_mutex_lock(&conflock);
+	if (!confs) {
+		ast_cli(fd, "No active conferences.\n");
+		return RESULT_SUCCESS;	
+	}
+	cnf = confs;
+	/* Find the right conference */
+	while(cnf) {
+		if (strcmp(cnf->confno, argv[2]))
+			ast_log(LOG_WARNING, "CONF FOUND\n");
+			break;
+		if (cnf->next) {
+			cnf = cnf->next;	
+		} else {
+			ast_cli(fd, "No such conference: %s.\n",argv[2]);
+			ast_mutex_unlock(&conflock);
+			return RESULT_SUCCESS;
+		}
+	}
+	/* Show all the users */
+	user = cnf->firstuser;
+	while(user) {
+		ast_cli(fd, "User Number: %i  on Channel: %s\n", user->user_no, user->chan->name);
+		user = user->nextuser;
+	}
+	ast_mutex_unlock(&conflock);
+        return RESULT_SUCCESS;
+}
+        
+static char show_conf_usage[] =
+"Usage: show conference number\n"
+"       Provides information of users in the specified conference\n";
+
+static struct ast_cli_entry cli_show_conf = {
+        { "show", "conference", NULL }, conf_show,
+        "Show users in conference", show_conf_usage, complete_confno };
+        
+        
+static int conf_cmd(int fd, int argc, char **argv) {
+	/* Process the command */
+	char cmdline[1024] = "";
+	int i = 0;
+	for (i = 0; i < argc; i++) {
+		strcat(cmdline, argv[i]);
+		strcat(cmdline, "|");
+	}
+	if (argc < 3)
+		return RESULT_SHOWUSAGE;
+	strncpy(cmdline, argv[1], 800);
+	if (strstr(argv[2], "lock")) {
+		if (strcmp(argv[2], "lock") == 0) {
+			/* Lock */
+			strcat(cmdline, "|L");
+		} else {
+			/* Unlock */
+			strcat(cmdline, "|l");
+		}
+	} else if (strstr(argv[2], "mute")) {
+		if (argc < 4)
+			return RESULT_SHOWUSAGE;
+		if (strcmp(argv[2], "mute") == 0) {
+			/* Mute */
+			strcat(cmdline, "|M|");	
+			strcat(cmdline, argv[3]);
+		} else {
+			/* Unmute */
+			strcat(cmdline, "|m|");
+			strcat(cmdline, argv[3]);
+		}	
+	} else if (strcmp(argv[2], "kick") == 0) {
+		if (argc < 4)
+			return RESULT_SHOWUSAGE;
+		if (strcmp(argv[3], "all") == 0) {
+			/* Kick all */
+			strcat(cmdline, "|K");
+		} else {
+			/* Kick a single user */
+			strcat(cmdline, "|k|");
+			strcat(cmdline, argv[3]);
+		}	
+	} else 
+		return RESULT_SHOWUSAGE;
+	admin_exec(NULL, cmdline);
+	return 0;
+}
+
+static char *complete_confcmd(char *line, char *word, int pos, int state) {
+	#define CONF_COMMANDS 5
+	int which = 0, x = 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"};
+	char *myline;
+	
+	if (pos == 1) {
+		/* 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;
+	} else if (pos == 2) {
+		/* 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 == 3) {
+		/* User Number || Conf Command option*/
+		if (strstr(line, "mute") || strstr(line, "kick")) {
+			if ((state == 0) && (strstr(line, "kick")) && !(strncasecmp(word, "all", strlen(word)))) {
+				return strdup("all");
+			}
+			which++;
+			ast_mutex_lock(&conflock);
+			cnf = confs;
+			
+			/* TODO: Find the conf number from the cmdline (ignore spaces) <- test this! */
+			myline = strdupa(line);
+			if (strsep(&myline, " ") && !confno) {
+				while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
+					;
+			}
+			
+			while(cnf) {
+				if (strcmp(confno, cnf->confno) == 0) {
+					break;
+				}
+				cnf = cnf->next;
+			}
+			if (cnf) {
+				/* Search for the user */
+				usr = cnf->firstuser;
+				while(usr) {
+					sprintf(usrno, "%i", usr->user_no);
+					if (!strncasecmp(word, usrno, strlen(word))) {
+						if (++which > state)
+							break;
+					}
+					usr = usr->nextuser;
+				}
+			}
+			ast_mutex_unlock(&conflock);
+			return usr ? strdup(usrno) : NULL;
+		}
+	}
+	return NULL;
+}
+        
+static char conf_usage[] =
+"Usage: conf confnumber (un)lock|(un)mute|kick usernumber\n"
+"       Executes a command for the conference or on a conferee\n"
+"	conf confnunber (un)lock\n"
+"	conf confnumber (un)mute usernumber\n"
+"	conf confnumber kick usernumber|all\n";
+
+static struct ast_cli_entry cli_conf = {
+        { "conf", NULL, NULL }, conf_cmd,
+        "Execute a command on a conference or conferee", conf_usage, complete_confcmd };
+        
 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags)
 {
 	struct ast_conference *prev=NULL, *cur;
+        struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user));
 	int fd;
 	struct zt_confinfo ztc;
 	struct ast_frame *f;
@@ -260,16 +487,63 @@
 	int firstpass = 0;
 	int ret = -1;
 	int x;
+        int menu_active = 0;
 
 	struct ast_app *app;
 	char *agifile;
 	char *agifiledefault = "conf-background.agi";
+        char choice[2] = "";
+        char meetmesecs[30];
 
 	ZT_BUFFERINFO bi;
 	char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
 	char *buf = __buf + AST_FRIENDLY_OFFSET;
 	
+        user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */
+	
+	if (conf->locked) {
+		/* Sorry, but this confernce is locked! (TODO: Record this file!) */	
+		if (!ast_streamfile(chan, "conf-locked", chan->language))
+			ast_waitstream(chan, "");
+		goto outrun;
+	}
+	
 	conf->users++;
+        if (confflags & CONFFLAG_ADMINEXIT) {
+        	if (conf->markedusers == -1) {
+        		conf->markedusers = 1;
+        	} else {
+        		conf->markedusers++;
+        	}
+        }
+      
+      	ast_mutex_lock(&conflock);
+        if (conf->firstuser == NULL) {
+		/* Fill the first new User struct */
+                user->user_no = 1;
+                user->nextuser = NULL;
+                user->prevuser = NULL;
+        	conf->firstuser = user;
+        	conf->lastuser = user;
+        } else {
+        	/* Fill the new user struct */	
+        	user->user_no = conf->lastuser->user_no + 1; 
+                user->prevuser = conf->lastuser;
+                user->nextuser = NULL;
+                if (conf->lastuser->nextuser != NULL) {
+                	ast_log(LOG_WARNING, "Error in User Management!\n");
+                      	goto outrun;
+                } else {
+                	conf->lastuser->nextuser = user;
+                	conf->lastuser = user;
+                }
+        }
+        strncpy(user->usrvalue, "test", sizeof(user->usrvalue));
+	user->chan = chan;
+	user->userflags = confflags;
+	user->adminflags = 0;
+	ast_mutex_unlock(&conflock);
+        
 	if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) {
 		if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
 			ast_waitstream(chan, "");
@@ -417,6 +691,10 @@
 		outfd = -1;
 		ms = -1;
 		c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
+                
+                /* Update the struct with the actual confflags */
+                user->userflags = confflags;
+                
 		/* trying to add moh for single person conf */
 		if (confflags & CONFFLAG_MOH) {
 			if (conf->users == 1) {
@@ -431,7 +709,47 @@
 				}
 			}
 		}
-		/* end modifications */
+                
+                /* Leave if the last marked user left */
+                if ((confflags & CONFFLAG_ADMINEXIT) && (conf->markedusers == 0)) {
+                	ret = 0;
+                	break;
+                }
+
+		/* Check if the admin changed my modes */
+		if (user->adminflags) {			
+			/* Set the new modes */
+			if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) {
+				ztc.confmode ^= ZT_CONF_TALKER;
+				if (ioctl(fd, ZT_SETCONF, &ztc)) {
+                			ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
+                			ret = -1;
+                			break;
+        			}
+			}
+			if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
+				ast_log(LOG_WARNING, "Unmuting!");
+				ztc.confmode |= ZT_CONF_TALKER;
+				if (ioctl(fd, ZT_SETCONF, &ztc)) {
+                			ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
+                			ret = -1;
+                			break;
+        			}
+			}
+			if (user->adminflags & ADMINFLAG_KICKME) {
+				//TODO: Message -> You have been kicked.
+				ret = 0;
+                		break;
+			}
+		} else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
+			ast_log(LOG_WARNING, "Unmuting!");
+			ztc.confmode |= ZT_CONF_TALKER;
+			if (ioctl(fd, ZT_SETCONF, &ztc)) {
+                		ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
+				ret = -1;
+				break;
+        		}
+		}
 
 		if (c) {
 			if (c->fds[0] != origfd) {
@@ -449,13 +767,72 @@
 			if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
 				ret = 0;
 				break;
-			} else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) {
+                        } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || menu_active) {
+                        		if (musiconhold) {
+			   	        	ast_moh_stop(chan);
+			                }
+			                if(!menu_active)
++						menu_active=1;
 					if ((confflags & CONFFLAG_ADMIN)) {
-					/* Do admin stuff here */
+                                        	/* Admin menu */
+                                        	/* TODO: Record this sound! */
+                                        	//ast_app_getdata(chan, "conf-adminmenu", choice, 1, 1000);
+                                        	ast_log(LOG_WARNING, "Playing beep\n");
+                                        	ast_app_getdata(chan, "beep", choice, 1, 0);
+                                        	switch(atoi(choice)) {
+                                        		case 1: /* Un/Mute */
+                                        			menu_active = 0;
+         							if (ztc.confmode & ZT_CONF_TALKER) {
+         						       		ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
+         						       		confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
 					} else {
-					/* Do user menu here */
+        						        	ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
+        						        	confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
+        						        }
+        							if (ioctl(fd, ZT_SETCONF, &ztc)) {
+                							ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
+                							ret = -1;
+                							break;
+        							}
+                                        			break;
+                                        		case 2: /* Lock the Conference */
+                                        			menu_active = 0;
+                                        			conf->locked = 1;
+                                        			break;
+                                        	}
+                                        } else {
+                                        	/* User menu */
+                                        	ast_log(LOG_WARNING, "GOT TO THE USER MENU");
+                                        	//ast_app_getdata(chan, "conf-usermenu", choice, 1, 0);
+                                        	ast_app_getdata(chan, "beep", choice, 1, 0);
+                                       		switch(atoi(choice)) {
+                                       			case 1: /* Un/Mute */
+                                       				if (user->adminflags & ADMINFLAG_MUTED) {
+                                       					/* TODO: Record this soundfile! */
+                                       					menu_active = 0;
+                                       					if (!ast_streamfile(chan, "conf-notallowed", chan->language))
+                        							ast_waitstream(chan, "");
+                                       				} else {
+                                       					menu_active = 0;
+	       								if (ztc.confmode & ZT_CONF_TALKER) {
+	       							       		ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
+	       							       		confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
+	       								} else {
+	       							        	ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
+	       							        	confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
+	       							        }
+	       								if (ioctl(fd, ZT_SETCONF, &ztc)) {
+	               								ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
+	               								ret = -1;
+	               								break;
+	       								}
+	       							}
+                                       				break;
+                                       		}
+                                        }
+					if (musiconhold) {
+			   	        	ast_moh_start(chan, NULL);
 					}
-
 			} else if (fd != chan->fds[0]) {
 				if (f->frametype == AST_FRAME_VOICE) {
 					if (f->subclass == AST_FORMAT_ULAW) {
@@ -501,13 +878,12 @@
 		conf_play(conf, LEAVE);
 
 outrun:
-
+        if (user->user_no) { /* Only cleanup users who really joined! */
 	ast_mutex_lock(&conflock);
-	/* Clean up */
 	conf->users--;
+	        cur = confs;
 	if (!conf->users) {
 		/* No more users -- close this one out */
-		cur = confs;
 		while(cur) {
 			if (cur == conf) {
 				if (prev)
@@ -523,7 +899,27 @@
 			ast_log(LOG_WARNING, "Conference not found\n");
 		close(conf->fd);
 		free(conf);
+	        } else {
+	        	/* Remove the user struct */ 
+	        	if (user == cur->firstuser) {
+	        		ast_log(LOG_WARNING, "Removing first user\n");
+	        		cur->firstuser->nextuser->prevuser = NULL;
+	        		cur->firstuser = cur->firstuser->nextuser;
+	        	} else if (user == cur->lastuser){
+	        		ast_log(LOG_WARNING, "Removing last user\n");
+	        		cur->lastuser->prevuser->nextuser = NULL;
+	        		cur->lastuser = cur->lastuser->prevuser;
+	        	} else {
+	        		ast_log(LOG_WARNING, "Removing middle user\n");
+	        		user->nextuser->prevuser = user->prevuser;
+	        		user->prevuser->nextuser = user->nextuser;
 	}
+	        	/* Return the number of seconds the user was in the conf */
+	        	sprintf(meetmesecs, "%i", (int) (user->jointime - time(NULL)));
+	        	pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
+	        }
+	}
+	free(user);
 	ast_mutex_unlock(&conflock);
 	return ret;
 }
@@ -681,6 +1077,8 @@
 			confflags |= CONFFLAG_QUIET;
 		if (strchr(inflags, 'M'))
 			confflags |= CONFFLAG_MOH;
+                if (strchr(inflags, 'x'))
+                        confflags |= CONFFLAG_ADMINEXIT;
 		if (strchr(inflags, 'b'))
 			confflags |= CONFFLAG_AGI;
 		if (strchr(inflags, 'd'))
@@ -854,10 +1252,103 @@
 	return res;
 }
 
+static struct ast_conf_user* find_user(struct ast_conference *conf, char *callerident) {
+	struct ast_conf_user *user = NULL;
+	char usrno[1024] = "";
+	if (conf && callerident) {
+		user = conf->firstuser;
+		while(user) {
+			sprintf(usrno, "%i", user->user_no);
+			if (strcmp(usrno, callerident) == 0)
+				return user;
+			user = user->nextuser;
+		}
+	}
+	return NULL;
+}
+
+static int admin_exec(struct ast_channel *chan, void *data) {
+	/* MeetMeAdmin(confno, command, caller) */
+	char *params, *command = NULL, *caller = NULL, *conf = NULL;
+	struct ast_conference *cnf;
+	struct ast_conf_user *user = NULL;
+
+	ast_mutex_lock(&conflock);
+	/* The param has the conference number the user and the command to execute */
+	if (data && strlen(data)) {		
+		params = ast_strdupa((char *) data);
+		conf = strsep(&params, "|");
+		command = strsep(&params, "|");
+		caller = strsep(&params, "|");
+		
+		ast_mutex_lock(&conflock);
+                cnf = confs;
+                while (cnf) {
+                        if (strcmp(cnf->confno, conf) == 0) 
+                        	break;
+                	cnf = cnf->next;
+                }
+                ast_mutex_unlock(&conflock);
+                
+                if (caller)
+                	user = find_user(cnf, caller);
+                
+		if (cnf) {
+			switch((int) (*command)) {
+				case 76: /* L: Lock */ 
+					cnf->locked = 1;
+					break;
+				case 108: /* l: Unlock */ 
+					cnf->locked = 0;
+					break;
+				case 75: /* K: kick all users*/
+					user = cnf->firstuser;
+					while(user) {
+						user->adminflags |= ADMINFLAG_KICKME;
+						if (user->nextuser) {
+							user = user->nextuser;
+						} else {
+							break;
+						}
+					}
+					break;
+				case 77: /* M: Mute */ 
+					if (user) {
+						user->adminflags |= ADMINFLAG_MUTED;
+					} else {
+						ast_log(LOG_NOTICE, "Specified User not found!");
+					}
+					break;
+				case 109: /* m: Unmute */ 
+					if (user && (user->adminflags & ADMINFLAG_MUTED)) {
+						user->adminflags ^= ADMINFLAG_MUTED;
+					} else {
+						ast_log(LOG_NOTICE, "Specified User not found!");
+					}
+					break;
+				case 107: /* k: Kick user */ 
+					if (user) {
+						user->adminflags |= ADMINFLAG_KICKME;
+					} else {
+						ast_log(LOG_NOTICE, "Specified User not found!");
+					}
+					break;
+			}
+		} else {
+			ast_log(LOG_NOTICE, "Conference Number not found\n");
+		}
+	}
+	ast_mutex_unlock(&conflock);
+	return 0;
+}
+
 int unload_module(void)
 {
 	STANDARD_HANGUP_LOCALUSERS;
 	ast_cli_unregister(&cli_show_confs);
+        ast_cli_unregister(&cli_show_conf);
+        ast_cli_unregister(&cli_conf);
+        ast_unregister_application(app3);
 	ast_unregister_application(app2);
 	return ast_unregister_application(app);
 }
@@ -865,6 +1356,9 @@
 int load_module(void)
 {
 	ast_cli_register(&cli_show_confs);
+        ast_cli_register(&cli_show_conf);
+        ast_cli_register(&cli_conf);
+        ast_register_application(app3, admin_exec, synopsis3, descrip3);
 	ast_register_application(app2, count_exec, synopsis2, descrip2);
 	return ast_register_application(app, conf_exec, synopsis, descrip);
 }
