app_meetme: Use new prompts for administrator menu
[asterisk/asterisk.git] / apps / app_meetme.c
index e63a4b3..9fb0e06 100644 (file)
@@ -2375,6 +2375,428 @@ static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
        return 0;
 }
 
+enum menu_modes {
+       MENU_DISABLED = 0,
+       MENU_NORMAL,
+       MENU_ADMIN,
+       MENU_ADMIN_EXTENDED,
+};
+
+/*! \internal
+ * \brief Processes menu options for the standard menu (accessible through the 's' option for app_meetme)
+ *
+ * \param menu_mode a pointer to the currently active menu_mode.
+ * \param dtmf a pointer to the dtmf value currently being processed against the menu.
+ * \param conf the active conference for which the user has called the menu from.
+ * \param confflags flags used by conf for various options
+ * \param chan ast_channel belonging to the user who called the menu
+ * \param user which meetme conference user invoked the menu
+ */
+static void meetme_menu_normal(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
+{
+       switch (*dtmf) {
+       case '1': /* Un/Mute */
+               *menu_mode = MENU_DISABLED;
+
+               /* user can only toggle the self-muted state */
+               user->adminflags ^= ADMINFLAG_SELFMUTED;
+
+               /* they can't override the admin mute state */
+               if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
+                       if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               } else {
+                       if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               }
+               break;
+
+       case '2':
+               *menu_mode = MENU_DISABLED;
+               if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
+                       user->adminflags |= ADMINFLAG_T_REQUEST;
+               }
+
+               if (user->adminflags & ADMINFLAG_T_REQUEST) {
+                       if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               }
+               break;
+
+       case '4':
+               tweak_listen_volume(user, VOL_DOWN);
+               break;
+       case '5':
+               /* Extend RT conference */
+               if (rt_schedule) {
+                       rt_extend_conf(conf->confno);
+               }
+               *menu_mode = MENU_DISABLED;
+               break;
+
+       case '6':
+               tweak_listen_volume(user, VOL_UP);
+               break;
+
+       case '7':
+               tweak_talk_volume(user, VOL_DOWN);
+               break;
+
+       case '8':
+               *menu_mode = MENU_DISABLED;
+               break;
+
+       case '9':
+               tweak_talk_volume(user, VOL_UP);
+               break;
+
+       default:
+               *menu_mode = MENU_DISABLED;
+               if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
+                       ast_waitstream(chan, "");
+               }
+               break;
+       }
+}
+
+/*! \internal
+ * \brief Processes menu options for the adminstrator menu (accessible through the 's' option for app_meetme)
+ *
+ * \param menu_mode a pointer to the currently active menu_mode.
+ * \param dtmf a pointer to the dtmf value currently being processed against the menu.
+ * \param conf the active conference for which the user has called the menu from.
+ * \param confflags flags used by conf for various options
+ * \param chan ast_channel belonging to the user who called the menu
+ * \param user which meetme conference user invoked the menu
+ */
+static void meetme_menu_admin(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
+{
+       switch(*dtmf) {
+       case '1': /* Un/Mute */
+               *menu_mode = MENU_DISABLED;
+               /* for admin, change both admin and use flags */
+               if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
+                       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
+               } else {
+                       user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
+               }
+
+               if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
+                       if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               } else {
+                       if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               }
+               break;
+
+       case '2': /* Un/Lock the Conference */
+               *menu_mode = MENU_DISABLED;
+               if (conf->locked) {
+                       conf->locked = 0;
+                       if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               } else {
+                       conf->locked = 1;
+                       if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               }
+               break;
+
+       case '3': /* Eject last user */
+       {
+               struct ast_conf_user *usr = NULL;
+               int max_no = 0;
+               ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
+               *menu_mode = MENU_DISABLED;
+               usr = ao2_find(conf->usercontainer, &max_no, 0);
+               if ((ast_channel_name(usr->chan) == ast_channel_name(chan)) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
+                       if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               } else {
+                       usr->adminflags |= ADMINFLAG_KICKME;
+               }
+               ao2_ref(usr, -1);
+               ast_stopstream(chan);
+               break;
+       }
+
+       case '4':
+               tweak_listen_volume(user, VOL_DOWN);
+               break;
+
+       case '5':
+               /* Extend RT conference */
+               if (rt_schedule) {
+                       if (!rt_extend_conf(conf->confno)) {
+                               if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
+                                       ast_waitstream(chan, "");
+                               }
+                       } else {
+                               if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
+                                       ast_waitstream(chan, "");
+                               }
+                       }
+                       ast_stopstream(chan);
+               }
+               *menu_mode = MENU_DISABLED;
+               break;
+
+       case '6':
+               tweak_listen_volume(user, VOL_UP);
+               break;
+
+       case '7':
+               tweak_talk_volume(user, VOL_DOWN);
+               break;
+
+       case '8':
+               if (!ast_streamfile(chan, "conf-adminmenu-menu8", ast_channel_language(chan))) {
+                       /* If the user provides DTMF while playing the sound, we want to drop right into the extended menu function with new DTMF once we get out of here. */
+                       *dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
+                       ast_stopstream(chan);
+               }
+               *menu_mode = MENU_ADMIN_EXTENDED;
+               break;
+
+       case '9':
+               tweak_talk_volume(user, VOL_UP);
+               break;
+       default:
+               menu_mode = MENU_DISABLED;
+               /* Play an error message! */
+               if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
+                       ast_waitstream(chan, "");
+               }
+               break;
+       }
+
+}
+
+/*! \internal
+ * \brief Processes menu options for the extended administrator menu (accessible through option 8 on the administrator menu)
+ *
+ * \param menu_mode a pointer to the currently active menu_mode.
+ * \param dtmf a pointer to the dtmf value currently being processed against the menu.
+ * \param conf the active conference for which the user has called the menu from.
+ * \param confflags flags used by conf for various options
+ * \param chan ast_channel belonging to the user who called the menu
+ * \param user which meetme conference user invoked the menu
+ * \param recordingtmp character buffer which may hold the name of the conference recording file
+ * \param dahdic dahdi configuration info used by the main conference loop
+ */
+static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, struct dahdi_confinfo *dahdic, struct ast_format_cap *cap_slin)
+{
+       int keepplaying;
+       int playednamerec;
+       int res;
+       struct ao2_iterator user_iter;
+       struct ast_conf_user *usr = NULL;
+
+       switch(*dtmf) {
+       case '1': /* *81 Roll call */
+               keepplaying = 1;
+               playednamerec = 0;
+               if (conf->users == 1) {
+                       if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
+                               res = ast_waitstream(chan, AST_DIGIT_ANY);
+                               ast_stopstream(chan);
+                               if (res > 0) {
+                                       keepplaying = 0;
+                               }
+                       }
+               } else if (conf->users == 2) {
+                       if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
+                               res = ast_waitstream(chan, AST_DIGIT_ANY);
+                               ast_stopstream(chan);
+                               if (res > 0) {
+                                       keepplaying = 0;
+                               }
+                       }
+               } else {
+                       if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
+                               res = ast_waitstream(chan, AST_DIGIT_ANY);
+                               ast_stopstream(chan);
+                               if (res > 0) {
+                                       keepplaying = 0;
+                               }
+                       }
+                       if (keepplaying) {
+                               res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
+                               ast_stopstream(chan);
+                               if (res > 0) {
+                                       keepplaying = 0;
+                               }
+                       }
+                       if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
+                               res = ast_waitstream(chan, AST_DIGIT_ANY);
+                               ast_stopstream(chan);
+                               if (res > 0) {
+                                       keepplaying = 0;
+                               }
+                       }
+               }
+               user_iter = ao2_iterator_init(conf->usercontainer, 0);
+               while((usr = ao2_iterator_next(&user_iter))) {
+                       if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
+                               if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
+                                       res = ast_waitstream(chan, AST_DIGIT_ANY);
+                                       ast_stopstream(chan);
+                                       if (res > 0) {
+                                               keepplaying = 0;
+                                       }
+                               }
+                               playednamerec = 1;
+                       }
+                       ao2_ref(usr, -1);
+               }
+               ao2_iterator_destroy(&user_iter);
+               if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
+                       res = ast_waitstream(chan, AST_DIGIT_ANY);
+                       ast_stopstream(chan);
+                       if (res > 0) {
+                               keepplaying = 0;
+                       }
+               }
+
+               *menu_mode = MENU_DISABLED;
+               break;
+
+       case '2': /* *82 Eject all non-admins */
+               if (conf->users == 1) {
+                       if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               } else {
+                       ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
+               }
+               ast_stopstream(chan);
+               *menu_mode = MENU_DISABLED;
+               break;
+
+       case '3': /* *83 (Admin) mute/unmute all non-admins */
+               if(conf->gmuted) {
+                       conf->gmuted = 0;
+                       ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
+                       if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               } else {
+                       conf->gmuted = 1;
+                       ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
+                       if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               }
+               ast_stopstream(chan);
+               *menu_mode = MENU_DISABLED;
+               break;
+
+       case '4': /* *84 Record conference */
+               if (conf->recording != MEETME_RECORD_ACTIVE) {
+                       ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
+                       if (!conf->recordingfilename) {
+                               const char *var;
+                               ast_channel_lock(chan);
+                               if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
+                                       conf->recordingfilename = ast_strdup(var);
+                               }
+                               if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
+                                       conf->recordingformat = ast_strdup(var);
+                               }
+                               ast_channel_unlock(chan);
+                               if (!conf->recordingfilename) {
+                                       snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
+                                       conf->recordingfilename = ast_strdup(recordingtmp);
+                               }
+                               if (!conf->recordingformat) {
+                                       conf->recordingformat = ast_strdup("wav");
+                               }
+                               ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
+                               conf->confno, conf->recordingfilename, conf->recordingformat);
+                       }
+
+                       ast_mutex_lock(&conf->recordthreadlock);
+                       if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL)))) {
+                               ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
+                               ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
+                               dahdic->chan = 0;
+                               dahdic->confno = conf->dahdiconf;
+                               dahdic->confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
+                               if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, dahdic)) {
+                                       ast_log(LOG_WARNING, "Error starting listen channel\n");
+                                       ast_hangup(conf->lchan);
+                                       conf->lchan = NULL;
+                               } else {
+                                       ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
+                               }
+                       }
+                       ast_mutex_unlock(&conf->recordthreadlock);
+                       if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan))) {
+                               ast_waitstream(chan, "");
+                       }
+               }
+
+               ast_stopstream(chan);
+               *menu_mode = MENU_DISABLED;
+               break;
+
+       case '8': /* *88 Exit the menu and return to the conference... without an error message */
+               ast_stopstream(chan);
+               *menu_mode = MENU_DISABLED;
+               break;
+
+       default:
+               if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
+                       ast_waitstream(chan, "");
+               }
+               ast_stopstream(chan);
+               *menu_mode = MENU_DISABLED;
+               break;
+       }
+}
+
+/*! \internal
+ * \brief Processes menu options for the various menu types (accessible through the 's' option for app_meetme)
+ *
+ * \param menu_mode a pointer to the currently active menu_mode.
+ * \param dtmf a pointer to the dtmf value currently being processed against the menu.
+ * \param conf the active conference for which the user has called the menu from.
+ * \param confflags flags used by conf for various options
+ * \param chan ast_channel belonging to the user who called the menu
+ * \param user which meetme conference user invoked the menu
+ * \param recordingtmp character buffer which may hold the name of the conference recording file
+ * \param dahdic dahdi configuration info used by the main conference loop
+ */
+
+static void meetme_menu(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, struct dahdi_confinfo *dahdic, struct ast_format_cap *cap_slin)
+{
+       switch (*menu_mode) {
+       case MENU_DISABLED:
+               break;
+       case MENU_NORMAL:
+               meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
+               break;
+       case MENU_ADMIN:
+               meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
+               /* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
+               if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
+                       break;
+               }
+       case MENU_ADMIN_EXTENDED:
+               meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user, recordingtmp, dahdic, cap_slin);
+               break;
+       }
+}
+
 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
 {
        struct ast_conf_user *user = NULL;
@@ -2395,8 +2817,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
        int currentmarked = 0;
        int ret = -1;
        int x;
-       int menu_active = 0;
-       int menu8_active = 0;
+       enum menu_modes menu_mode = MENU_DISABLED;
        int talkreq_manager = 0;
        int using_pseudo = 0;
        int duration = 20;
@@ -2412,7 +2833,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
        char exitcontext[AST_MAX_CONTEXT] = "";
        char recordingtmp[AST_MAX_EXTENSION] = "";
        char members[10] = "";
-       int dtmf, opt_waitmarked_timeout = 0;
+       int dtmf = 0, opt_waitmarked_timeout = 0;
        time_t timeout = 0;
        struct dahdi_bufferinfo bi;
        char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
@@ -2994,7 +3415,8 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
                        /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
                        x = 1;
                        ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
-               }       
+               }
+
                for (;;) {
                        int menu_was_active = 0;
 
@@ -3157,11 +3579,11 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
                        /* if we have just exited from the menu, and the user had a channel-driver
                           volume adjustment, restore it
                        */
-                       if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) {
+                       if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
                                set_talk_volume(user, user->listen.desired);
                        }
 
-                       menu_was_active = menu_active;
+                       menu_was_active = menu_mode;
 
                        currentmarked = conf->markedusers;
                        if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
@@ -3471,7 +3893,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
                                                        careful_write(fd, f->data.ptr, f->datalen, 0);
                                                }
                                        }
-                               } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
+                               } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
                                        if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
                                                conf_queue_dtmf(conf, user, f);
                                        }
@@ -3485,345 +3907,37 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
                                        /* if we are entering the menu, and the user has a channel-driver
                                           volume adjustment, clear it
                                        */
-                                       if (!menu_active && user->talk.desired && !user->talk.actual) {
+                                       if (!menu_mode && user->talk.desired && !user->talk.actual) {
                                                set_talk_volume(user, 0);
                                        }
 
                                        if (musiconhold) {
                                                ast_moh_stop(chan);
-                                       }
-                                       if (menu8_active) {
-                                               /* *8 Submenu */
-                                               dtmf = f->subclass.integer;
-                                               if (dtmf > 0) {
-                                                       int keepplaying;
-                                                       int playednamerec;
-                                                       struct ao2_iterator user_iter;
-                                                       struct ast_conf_user *usr = NULL;
-                                                       switch(dtmf) {
-                                                       case '1': /* *81 Roll call */
-                                                               keepplaying = 1;
-                                                               playednamerec = 0;
-                                                               if (conf->users == 1) {
-                                                                       if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
-                                                                               res = ast_waitstream(chan, AST_DIGIT_ANY);
-                                                                               ast_stopstream(chan);
-                                                                               if (res > 0)
-                                                                                       keepplaying = 0;
-                                                                       }
-                                                               } else if (conf->users == 2) {
-                                                                       if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
-                                                                               res = ast_waitstream(chan, AST_DIGIT_ANY);
-                                                                               ast_stopstream(chan);
-                                                                               if (res > 0)
-                                                                                       keepplaying = 0;
-                                                                       }
-                                                               } else {
-                                                                       if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
-                                                                               res = ast_waitstream(chan, AST_DIGIT_ANY);
-                                                                               ast_stopstream(chan);
-                                                                               if (res > 0)
-                                                                                       keepplaying = 0;
-                                                                       }
-                                                                       if (keepplaying) {
-                                                                               res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
-                                                                               if (res > 0)
-                                                                                       keepplaying = 0;
-                                                                       }
-                                                                       if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
-                                                                               res = ast_waitstream(chan, AST_DIGIT_ANY);
-                                                                               ast_stopstream(chan);
-                                                                               if (res > 0)
-                                                                                       keepplaying = 0;
-                                                                       }
-                                                               }
-                                                               user_iter = ao2_iterator_init(conf->usercontainer, 0);
-                                                               while((usr = ao2_iterator_next(&user_iter))) {
-                                                                       if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
-                                                                               if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
-                                                                                       res = ast_waitstream(chan, AST_DIGIT_ANY);
-                                                                                       ast_stopstream(chan);
-                                                                                       if (res > 0)
-                                                                                               keepplaying = 0;
-                                                                               }
-                                                                               playednamerec = 1;
-                                                                       }
-                                                                       ao2_ref(usr, -1);
-                                                               }
-                                                               ao2_iterator_destroy(&user_iter);
-                                                               if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
-                                                                       res = ast_waitstream(chan, AST_DIGIT_ANY);
-                                                                       ast_stopstream(chan);
-                                                                       if (res > 0)
-                                                                               keepplaying = 0;
-                                                               }
-                                                               break;
-                                                       case '2': /* *82 Eject all non-admins */
-                                                               if (conf->users == 1) {
-                                                                       if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan)))
-                                                                               ast_waitstream(chan, "");
-                                                               } else {
-                                                                       ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
-                                                               }
-                                                               ast_stopstream(chan);
-                                                               break;
-                                                       case '3': /* *83 (Admin) mute/unmute all non-admins */
-                                                               if(conf->gmuted) {
-                                                                       conf->gmuted = 0;
-                                                                       ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
-                                                                       if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan)))
-                                                                               ast_waitstream(chan, "");
-                                                               } else {
-                                                                       conf->gmuted = 1;
-                                                                       ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
-                                                                       if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan)))
-                                                                               ast_waitstream(chan, "");
-                                                               }
-                                                               ast_stopstream(chan);
-                                                               break;
-                                                       case '4': /* *84 Record conference */
-                                                               if (conf->recording != MEETME_RECORD_ACTIVE) {
-                                                                       ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
-
-                                                                       if (!conf->recordingfilename) {
-                                                                               const char *var;
-                                                                               ast_channel_lock(chan);
-                                                                               if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
-                                                                                       conf->recordingfilename = ast_strdup(var);
-                                                                               }
-                                                                               if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
-                                                                                       conf->recordingformat = ast_strdup(var);
-                                                                               }
-                                                                               ast_channel_unlock(chan);
-                                                                               if (!conf->recordingfilename) {
-                                                                                       snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
-                                                                                       conf->recordingfilename = ast_strdup(recordingtmp);
-                                                                               }
-                                                                               if (!conf->recordingformat) {
-                                                                                       conf->recordingformat = ast_strdup("wav");
-                                                                               }
-                                                                               ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
-                                                                                       conf->confno, conf->recordingfilename, conf->recordingformat);
-                                                                       }
-
-                                                                       ast_mutex_lock(&conf->recordthreadlock);
-                                                                       if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL)))) {
-                                                                               ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
-                                                                               ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
-                                                                               dahdic.chan = 0;
-                                                                               dahdic.confno = conf->dahdiconf;
-                                                                               dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
-                                                                               if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
-                                                                                       ast_log(LOG_WARNING, "Error starting listen channel\n");
-                                                                                       ast_hangup(conf->lchan);
-                                                                                       conf->lchan = NULL;
-                                                                               } else {
-                                                                                       ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
-                                                                               }
-                                                                       }
-                                                                       ast_mutex_unlock(&conf->recordthreadlock);
-
-                                                                       if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan)))
-                                                                               ast_waitstream(chan, "");
-
-                                                               }
-
-                                                               ast_stopstream(chan);
-                                                               break;
-                                                       default:
-                                                               if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan)))
-                                                                       ast_waitstream(chan, "");
-                                                               ast_stopstream(chan);
-                                                               break;
-                                                       }
-                                               }
-
-                                               menu8_active = 0;
-                                               menu_active = 0;
-                                       } else if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
-                                               /* Admin menu */
-                                               if (!menu_active) {
-                                                       menu_active = 1;
-                                                       /* Record this sound! */
-                                                       if (!ast_streamfile(chan, "conf-adminmenu-162", ast_channel_language(chan))) {
-                                                               dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
-                                                               ast_stopstream(chan);
-                                                       } else {
-                                                               dtmf = 0;
-                                                       }
+                                       } else if (!menu_mode) {
+                                               char *menu_to_play;
+                                               if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
+                                                       menu_mode = MENU_ADMIN;
+                                                       menu_to_play = "conf-adminmenu-18";
                                                } else {
-                                                       dtmf = f->subclass.integer;
+                                                       menu_mode = MENU_NORMAL;
+                                                       menu_to_play = "conf-usermenu-162";
                                                }
-                                               if (dtmf > 0) {
-                                                       switch(dtmf) {
-                                                       case '1': /* Un/Mute */
-                                                               menu_active = 0;
-
-                                                               /* for admin, change both admin and use flags */
-                                                               if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
-                                                                       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
-                                                               } else {
-                                                                       user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
-                                                               }
 
-                                                               if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
-                                                                       if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
-                                                                               ast_waitstream(chan, "");
-                                                                       }
-                                                               } else {
-                                                                       if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
-                                                                               ast_waitstream(chan, "");
-                                                                       }
-                                                               }
-                                                               break;
-                                                       case '2': /* Un/Lock the Conference */
-                                                               menu_active = 0;
-                                                               if (conf->locked) {
-                                                                       conf->locked = 0;
-                                                                       if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
-                                                                               ast_waitstream(chan, "");
-                                                                       }
-                                                               } else {
-                                                                       conf->locked = 1;
-                                                                       if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
-                                                                               ast_waitstream(chan, "");
-                                                                       }
-                                                               }
-                                                               break;
-                                                       case '3': /* Eject last user */
-                                                       {
-                                                               struct ast_conf_user *usr = NULL;
-                                                               int max_no = 0;
-                                                               ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
-                                                               menu_active = 0;
-                                                               usr = ao2_find(conf->usercontainer, &max_no, 0);
-                                                               if ((ast_channel_name(usr->chan) == ast_channel_name(chan)) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
-                                                                       if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
-                                                                               ast_waitstream(chan, "");
-                                                                       }
-                                                               } else {
-                                                                       usr->adminflags |= ADMINFLAG_KICKME;
-                                                               }
-                                                               ao2_ref(usr, -1);
-                                                               ast_stopstream(chan);
-                                                               break;  
-                                                       }
-                                                       case '4':
-                                                               tweak_listen_volume(user, VOL_DOWN);
-                                                               break;
-                                                       case '5':
-                                                               /* Extend RT conference */
-                                                               if (rt_schedule) {
-                                                                       if (!rt_extend_conf(conf->confno)) {
-                                                                               if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
-                                                                                       ast_waitstream(chan, "");
-                                                                               }
-                                                                       } else {
-                                                                               if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
-                                                                                       ast_waitstream(chan, "");
-                                                                               }
-                                                                       }
-                                                                       ast_stopstream(chan);
-                                                               }
-                                                               menu_active = 0;
-                                                               break;
-                                                       case '6':
-                                                               tweak_listen_volume(user, VOL_UP);
-                                                               break;
-                                                       case '7':
-                                                               tweak_talk_volume(user, VOL_DOWN);
-                                                               break;
-                                                       case '8':
-                                                               menu8_active = 1;
-                                                               break;
-                                                       case '9':
-                                                               tweak_talk_volume(user, VOL_UP);
-                                                               break;
-                                                       default:
-                                                               menu_active = 0;
-                                                               /* Play an error message! */
-                                                               if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
-                                                                       ast_waitstream(chan, "");
-                                                               }
-                                                               break;
-                                                       }
-                                               }
-                                       } else {
-                                               /* User menu */
-                                               if (!menu_active) {
-                                                       menu_active = 1;
-                                                       if (!ast_streamfile(chan, "conf-usermenu-162", ast_channel_language(chan))) {
-                                                               dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
-                                                               ast_stopstream(chan);
-                                                       } else {
-                                                               dtmf = 0;
-                                                       }
+                                               if (!ast_streamfile(chan, menu_to_play, ast_channel_language(chan))) {
+                                                       dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
+                                                       ast_stopstream(chan);
                                                } else {
-                                                       dtmf = f->subclass.integer;
-                                               }
-                                               if (dtmf > 0) {
-                                                       switch (dtmf) {
-                                                       case '1': /* Un/Mute */
-                                                               menu_active = 0;
-
-                                                               /* user can only toggle the self-muted state */
-                                                               user->adminflags ^= ADMINFLAG_SELFMUTED;
-
-                                                               /* they can't override the admin mute state */
-                                                               if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
-                                                                       if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
-                                                                               ast_waitstream(chan, "");
-                                                                       }
-                                                               } else {
-                                                                       if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
-                                                                               ast_waitstream(chan, "");
-                                                                       }
-                                                               }
-                                                               break;
-                                                       case '2':
-                                                               menu_active = 0;
-                                                               if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
-                                                                       user->adminflags |= ADMINFLAG_T_REQUEST;
-                                                               }
-                                                                       
-                                                               if (user->adminflags & ADMINFLAG_T_REQUEST) {
-                                                                       if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
-                                                                               ast_waitstream(chan, "");
-                                                                       }
-                                                               }
-                                                               break;
-                                                       case '4':
-                                                               tweak_listen_volume(user, VOL_DOWN);
-                                                               break;
-                                                       case '5':
-                                                               /* Extend RT conference */
-                                                               if (rt_schedule) {
-                                                                       rt_extend_conf(conf->confno);
-                                                               }
-                                                               menu_active = 0;
-                                                               break;
-                                                       case '6':
-                                                               tweak_listen_volume(user, VOL_UP);
-                                                               break;
-                                                       case '7':
-                                                               tweak_talk_volume(user, VOL_DOWN);
-                                                               break;
-                                                       case '8':
-                                                               menu_active = 0;
-                                                               break;
-                                                       case '9':
-                                                               tweak_talk_volume(user, VOL_UP);
-                                                               break;
-                                                       default:
-                                                               menu_active = 0;
-                                                               if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
-                                                                       ast_waitstream(chan, "");
-                                                               }
-                                                               break;
-                                                       }
+                                                       dtmf = 0;
                                                }
+                                       } else {
+                                               dtmf = f->subclass.integer;
+                                       }
+
+                                       if (dtmf > 0) {
+                                               meetme_menu(&menu_mode, &dtmf, conf, confflags, chan, user, recordingtmp, &dahdic, cap_slin);
                                        }
-                                       if (musiconhold && !menu_active) {
+
+                                       if (musiconhold && !menu_mode) {
                                                conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
                                        }