--- app_meetme.c.orig	2004-07-03 12:41:02.000000000 -0400
+++ app_meetme.c	2004-07-03 15:56:51.000000000 -0400
@@ -66,12 +66,13 @@
 "      '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"
-"      'w' -- wait until a marked user has entered the conference\n"
+"      'x' -- exit the conference if the last admin user left\n"
+"      'w' -- wait until a admin user has entered the conference\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"
+"         (Note: This does not work with non-Zap channels in the same conference)\n"
 "      's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
+"      'r' -- Allow retry on wrong PIN\n"
 "      'a' -- set admin mode\n";
 
 static char *descrip2 =
@@ -100,7 +101,7 @@
 	int fd;				/* Announcements fd */
 	int zapconf;			/* Zaptel Conf # */
 	int users;			/* Number of active users */
-	int markedusers;		  /* Number of marked users */
+	int admins;		  	/* Number of admin 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) */
@@ -136,6 +137,7 @@
 #define LEAVE	1
 
 #define CONF_SIZE 320
+#define MAXRETRY 3
 
 #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 */
@@ -146,8 +148,8 @@
 #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_ADMINEXIT (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_ADMINEXIT (1 << 10)    /* If set the MeetMe will return if all admin with this flag left */
+#define CONFFLAG_WAITADMIN (1 << 11)		/* If set, the MeetMe will wait until a admin user enters */
 
 
 static int careful_write(int fd, unsigned char *data, int len)
@@ -213,7 +215,7 @@
 			memset(cnf, 0, sizeof(struct ast_conference));
 			strncpy(cnf->confno, confno, sizeof(cnf->confno) - 1);
 			strncpy(cnf->pin, pin, sizeof(cnf->pin) - 1);
-			cnf->markedusers = -1;
+			cnf->admins = 0;
 			cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo");
 			if (cnf->chan) {
 				cnf->fd = cnf->chan->fds[0];	/* for use by conf_play() */
@@ -273,7 +275,7 @@
 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;
@@ -294,18 +296,20 @@
 	}
 	if (argc == 1) {
 		/* 'MeetMe': List all the conferences */	
-	now = time(NULL);
+		now = time(NULL);
 		cnf = confs;
 		if (!cnf) {
-		ast_cli(fd, "No active MeetMe conferences.\n");
-		return RESULT_SUCCESS;
-	}
-	ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
+			ast_cli(fd, "No active MeetMe conferences.\n");
+			return RESULT_SUCCESS;
+		}
+
+		ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
+
 		while(cnf) {
-			if (cnf->markedusers < 0)
+			if (cnf->admins < 0)
 				strcpy(cmdline, "N/A ");
 			else 
-				snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
+				snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->admins);
 			hr = (now - cnf->start) / 3600;
 			min = ((now - cnf->start) % 3600) / 60;
 			sec = (now - cnf->start) % 60;
@@ -320,6 +324,7 @@
 	}
 	if (argc < 3)
 		return RESULT_SHOWUSAGE;
+
 	strncpy(cmdline, argv[2], 100);	/* Argv 2: conference number */
 	if (strstr(argv[1], "lock")) {	
 		if (strcmp(argv[1], "lock") == 0) {
@@ -471,7 +476,7 @@
 	struct ast_conference *conf = ptr;
 	int res;
 	ast_mutex_lock(&conflock);
-	res = (conf->markedusers < 0);
+	res = (conf->admins < 0);
 	ast_mutex_unlock(&conflock);
 	return res;
 }
@@ -493,6 +498,7 @@
 	int retryzap;
 	int origfd;
 	int musiconhold = 0;
+	int lastadmin = 0;
 	int firstpass = 0;
 	int origquiet;
 	int ret = -1;
@@ -518,14 +524,9 @@
 		goto outrun;
 	}
 	conf->users++;
-	if (confflags & CONFFLAG_ADMINEXIT) {
-		if (conf->markedusers == -1) {
-			conf->markedusers = 1;
-		} else {
-			conf->markedusers++;
-		}
-	}
-      
+	if (confflags & CONFFLAG_ADMIN) 
+		conf->admins++;
+
    	ast_mutex_lock(&conflock);
 	if (conf->firstuser == NULL) {
 		/* Fill the first new User struct */
@@ -554,36 +555,16 @@
 	user->adminflags = 0;
 	ast_mutex_unlock(&conflock);
 	origquiet = confflags & CONFFLAG_QUIET;
-	while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers < 0)) {
-		confflags &= ~CONFFLAG_QUIET;
-		confflags |= origquiet;
-		/* XXX Announce that we're waiting on the conference lead to join */
-		if (!(confflags & CONFFLAG_QUIET)) {
-			res = ast_streamfile(chan, "vm-dialout", chan->language);
-			if (!res)
-				res = ast_waitstream(chan, "");
-		} else
-			res = 0;
-		/* If we're waiting with hold music, set to silent mode */
-		if (!res) {
-			confflags |= CONFFLAG_QUIET;
-			ast_moh_start(chan, NULL);
-			res = ast_safe_sleep_conditional(chan, 60000, confnonzero, conf);
-			ast_moh_stop(chan);
-		}
-		if (res < 0) {
-			ast_log(LOG_DEBUG, "Got hangup on '%s' already\n", chan->name);
-			goto outrun;
-		}
-	}
-	
-	if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) {
-		if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
-			if (ast_waitstream(chan, "") < 0)
-				goto outrun;
-		} else
-			goto outrun;
-	}
+	if (confflags & CONFFLAG_QUIET) {
+	} else {
+		if (conf->users == 1 && ! (confflags & CONFFLAG_WAITADMIN))
+			if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
+				ast_waitstream(chan, "");
+
+		if (confflags & CONFFLAG_WAITADMIN && conf->admins == 0)
+			if (!ast_streamfile(chan, "conf-waitforchairman", chan->language))
+				ast_waitstream(chan, "");
+ 	}
 
 	/* Set it into linear mode (write) */
 	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
@@ -659,7 +640,7 @@
 		}
 	}
 	memset(&ztc, 0, sizeof(ztc));
-	/* Add us to the conference */
+
 	ztc.chan = 0;	
 	ztc.confno = conf->zapconf;
 	if (confflags & CONFFLAG_MONITOR)
@@ -724,11 +705,67 @@
 		for(;;) {
 			outfd = -1;
 			ms = -1;
+			lastadmin = conf->admins;
+
 			c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
 			
 			/* Update the struct with the actual confflags */
 			user->userflags = confflags;
 			
+			if (confflags & CONFFLAG_WAITADMIN) {
+				if(conf->admins == 0) {
+					if (lastadmin != 0) {
+						if (!(confflags & CONFFLAG_QUIET))
+							if (!ast_streamfile(chan, "conf-adminhasleft", chan->language))
+								ast_waitstream(chan, "");
+						if(confflags & CONFFLAG_ADMINEXIT)
+							break;
+						else {
+							ztc.confmode = ZT_CONF_CONF;
+							if (ioctl(fd, ZT_SETCONF, &ztc)) {
+								ast_log(LOG_WARNING, "Error setting conference\n");
+								close(fd);
+								goto outrun;
+							}
+						}
+					}
+					if (musiconhold == 0 && confflags & CONFFLAG_MOH) {
+						ast_moh_start(chan, NULL);
+						musiconhold = 1;
+					} else {
+						ztc.confmode = ZT_CONF_CONF;
+						if (ioctl(fd, ZT_SETCONF, &ztc)) {
+							ast_log(LOG_WARNING, "Error setting conference\n");
+							close(fd);
+							goto outrun;
+						}
+					}
+				} else if(conf->admins >= 1 && lastadmin == 0) {
+					if (confflags & CONFFLAG_MONITOR)
+						ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
+					else if (confflags & CONFFLAG_TALKER)
+						ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
+					else
+						ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
+					if (ioctl(fd, ZT_SETCONF, &ztc)) {
+						ast_log(LOG_WARNING, "Error setting conference\n");
+						close(fd);
+						goto outrun;
+					}
+					if (musiconhold && confflags & CONFFLAG_MOH) {
+						ast_moh_stop(chan);
+						musiconhold = 0;
+					}
+					if ( !(confflags & CONFFLAG_QUIET)) {
+						if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
+							ast_waitstream(chan, "");
+						conf_play(conf, ENTER);
+					}
+				}
+			}					
+
+
+
 			/* trying to add moh for single person conf */
 			if (confflags & CONFFLAG_MOH) {
 				if (conf->users == 1) {
@@ -744,8 +781,13 @@
 				}
 			}
 			
-			/* Leave if the last marked user left */
-			if (conf->markedusers == 0) {
+			/* Leave if the last admin user left */
+			if (confflags & CONFFLAG_ADMINEXIT && conf->admins == 0) {
+				if (!(confflags & CONFFLAG_QUIET)) {
+					res = ast_streamfile(chan, "conf-adminhasleft", chan->language);
+					if (!res)
+						res = ast_waitstream(chan, "");
+				}
 				ret = -1;
 				break;
 			}
@@ -770,7 +812,7 @@
 					}
 				}
 				if (user->adminflags & ADMINFLAG_KICKME) {
-					//You have been kicked.
+					/* You have been kicked. */
 					if (!ast_streamfile(chan, "conf-kicked", chan->language))
 						ast_waitstream(chan, "");
 					ret = 0;
@@ -954,8 +996,8 @@
 			chan->name, chan->uniqueid, conf->confno);
 		prev = NULL;
 		conf->users--;
-		if (confflags & CONFFLAG_ADMINEXIT) 
-			conf->markedusers--;
+		if (confflags & CONFFLAG_ADMIN) 
+			conf->admins--;
 		cur = confs;
 		if (!conf->users) {
 			/* No more users -- close this one out */
@@ -1122,6 +1164,7 @@
 	int res=-1;
 	struct localuser *u;
 	char confno[AST_MAX_EXTENSION] = "";
+	char originconfno[AST_MAX_EXTENSION] = "";
 	int allowretry = 0;
 	int retrycnt = 0;
 	struct ast_conference *cnf;
@@ -1147,6 +1190,8 @@
 		strncpy(confno, tmp, sizeof(confno));
 		if (ast_strlen_zero(confno)) {
 			allowretry = 1;
+		} else {
+			strncpy(originconfno,confno,sizeof(confno));
 		}
 	}
 	if (info)
@@ -1176,7 +1221,9 @@
 		if (strchr(inflags, 'b'))
 			confflags |= CONFFLAG_AGI;
 		if (strchr(inflags, 'w'))
-			confflags |= CONFFLAG_WAITMARKED;
+			confflags |= CONFFLAG_WAITADMIN;
+		if (strchr(inflags, 'r'))
+			allowretry = 1;
 		if (strchr(inflags, 'd'))
 			dynamic = 1;
 		if (strchr(inflags, 'D')) {
@@ -1194,7 +1241,7 @@
 	}
 
 	do {
-		if (retrycnt > 3)
+		if (retrycnt > MAXRETRY)
 			allowretry = 0;
 		if (empty) {
 			int i, map[1024];
@@ -1296,7 +1343,7 @@
 				}
 			}
 		}
-		while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
+		while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt <= MAXRETRY)) {
 			/* Prompt user for conference number */
 			res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
 			if (res < 0) {
@@ -1325,7 +1372,9 @@
 						res = 0;
 					} else {
 						/* Prompt user for pin if pin is required */
-						res = ast_app_getdata(chan, "conf-getpin", pin, sizeof(pin) - 1, 0);
+						if (++retrycnt <= MAXRETRY)
+							res = ast_app_getdata(chan, "conf-getpin", pin, sizeof(pin) - 1, 0);
+
 					}
 					if (res >= 0) {
 						if (!strcasecmp(pin, cnf->pin)) {
@@ -1339,7 +1388,7 @@
 							if (!res)
 								ast_waitstream(chan, "");
 							res = -1;
-							if (allowretry)
+							if (allowretry  && sizeof(originconfno) == 0)
 								strcpy(confno, "");
 						}
 					} else {
