Index: apps/app_meetme.c =================================================================== --- apps/app_meetme.c (revision 68158) +++ apps/app_meetme.c (working copy) @@ -74,8 +74,17 @@ #define SLA_CONFIG_FILE "sla.conf" /*! each buffer is 20ms, so this is 640ms total */ -#define DEFAULT_AUDIO_BUFFERS 32 +#define DEFAULT_AUDIO_BUFFERS 32 +/*! Column names for RealTime storage of conferences */ +#define DEFAULT_CONF_COL "confno" +#define DEFAULT_USER_PIN_COL "pin" +#define DEFAULT_ADMIN_PIN_COL "adminpin" +#define DEFAULT_USER_OPTS_COL "" +#define DEFAULT_MOD_OPTS_COL "" +/*! String format for scheduled conferences */ +#define DATE_FORMAT "%Y-%m-%d %H:%M:%S" + enum { ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */ ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */ @@ -209,6 +218,26 @@ static const char *slastation_synopsis = "Shared Line Appearance Station"; static const char *slatrunk_synopsis = "Shared Line Appearance Trunk"; +/* RealTime database column names */ +static char rt_conf_column[AST_MAX_EXTENSION]; +static char rt_user_pin_column[AST_MAX_EXTENSION]; +static char rt_admin_pin_column[AST_MAX_EXTENSION]; +static char rt_user_opts_column[AST_MAX_EXTENSION]; +static char rt_admin_opts_column[AST_MAX_EXTENSION]; +static char rt_maxusers_column[AST_MAX_EXTENSION]; +static char rt_starttime_column[AST_MAX_EXTENSION]; +static char rt_endtime_column[AST_MAX_EXTENSION]; +static char rt_members_column[AST_MAX_EXTENSION]; + +/* Lookup RealTime conferences based on confno and current time */ +static int rt_schedule; +static int fuzzystart; +static int earlyalert; +static int endalert; + +/* Log participant count to the RealTime backend */ +static int rt_log_members; + static const char *descrip = " 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" @@ -317,6 +346,8 @@ int zapconf; /*!< Zaptel Conf # */ int users; /*!< Number of active users */ int markedusers; /*!< Number of marked users */ + int maxusers; /*!< Participant limit if scheduled */ + int endalert; /*!< When to play conf ending message */ time_t start; /*!< Start time (s) */ int refcount; /*!< reference count of usage */ enum recording_state recording:2; /*!< recording status */ @@ -328,6 +359,7 @@ char pin[MAX_PIN]; /*!< If protected by a PIN */ char pinadmin[MAX_PIN]; /*!< If protected by a admin PIN */ char uniqueid[32]; + char endtime[19]; /*!< When to end the conf if scheduled */ struct ast_frame *transframe[32]; struct ast_frame *origframe; struct ast_trans_pvt *transpath[32]; @@ -787,6 +819,7 @@ /* Fill the conference struct */ cnf->start = time(NULL); cnf->zapconf = ztc.confno; + cnf->maxusers = 0; /* 0 means unlimited */ 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); @@ -1379,6 +1412,8 @@ int duration=20; int hr, min, sec; int sent_event = 0; + int checked = 0; + int announcement_played = 0; time_t now; struct ast_dsp *dsp=NULL; struct ast_app *app; @@ -1456,6 +1491,14 @@ else user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1; + if (rt_schedule && conf->maxusers) + if (user->user_no > conf->maxusers){ + /* Sorry, but this confernce has reached the participant limit! */ + if (!ast_streamfile(chan, "conf-full", chan->language)) + ast_waitstream(chan, ""); + goto outrun; + } + AST_LIST_INSERT_TAIL(&conf->userlist, user, list); user->chan = chan; @@ -1463,10 +1506,11 @@ user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0; user->talking = -1; conf->users++; - /* Update table */ - snprintf(members, sizeof(members), "%d", conf->users); - ast_update_realtime("meetme", "confno", conf->confno, "members", members , NULL); - + if (rt_log_members) { + /* Update table */ + snprintf(members, sizeof(members), "%d", conf->users); + ast_update_realtime("meetme", rt_conf_column, conf->confno, rt_members_column, members , NULL); + } /* This device changed state now - if this is the first user */ if (conf->users == 1) ast_device_state_changed("meetme:%s", conf->confno); @@ -1715,6 +1759,42 @@ for(;;) { int menu_was_active = 0; + if (rt_schedule){ + char currenttime[32]=""; + struct tm *l_time; + + now = time(NULL); + if (!(now % 60)){ + if (!checked){ + l_time = localtime(&now); + strftime(currenttime, sizeof(currenttime), DATE_FORMAT, l_time); + if (strcmp(currenttime, conf->endtime) > 0){ + ast_verbose("Quitting time...\n"); + goto outrun; + } + + if (!announcement_played && conf->endalert){ + now += conf->endalert; + l_time = localtime(&now); + strftime(currenttime, sizeof(currenttime), DATE_FORMAT, l_time); + if (strcmp(currenttime, conf->endtime) > 0){ + if(!ast_streamfile(chan, "conf-will-end-in", chan->language)) + ast_waitstream(chan, ""); + ast_say_digits(chan, (conf->endalert/60), "", chan->language); + if(!ast_streamfile(chan, "minutes", chan->language)) + ast_waitstream(chan, ""); + announcement_played = 1; + + } + } + checked = 1; + + } + } else { + checked = 0; + } + } + outfd = -1; ms = -1; @@ -2262,9 +2342,11 @@ } conf->users--; - /* Update table */ - snprintf(members, sizeof(members), "%d", conf->users); - ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL); + if (rt_log_members){ + /* Update table */ + snprintf(members, sizeof(members), "%d", conf->users); + ast_update_realtime("meetme", rt_conf_column, conf->confno, rt_members_column, members, NULL); + } if (confflags & CONFFLAG_MARKEDUSER) conf->markedusers--; /* Remove ourselves from the list */ @@ -2285,7 +2367,7 @@ } static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic, - char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags) + char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags, char *optargs[], int *too_early) { struct ast_variable *var; struct ast_conference *cnf; @@ -2303,25 +2385,87 @@ if (!cnf) { char *pin = NULL, *pinadmin = NULL; /* For temp use */ - - var = ast_load_realtime("meetme", "confno", confno, NULL); + int maxusers = 0; + time_t now; + char currenttime[19]=""; + char startTime[19]=""; + char endtime[19]=""; + char eatime[19]=""; + char userOpts[32]=""; + char adminOpts[32]=""; + struct tm *l_time, *ea_time; + if (rt_schedule){ + time(&now); + + if (fuzzystart) + now += fuzzystart; + + l_time = localtime(&now); + strftime(currenttime, sizeof(currenttime), DATE_FORMAT, l_time); + + if (earlyalert){ + now += earlyalert; + ea_time = localtime(&now); + strftime(eatime, sizeof(eatime), DATE_FORMAT, ea_time); + } else { + ea_time = localtime(&now); + strftime(eatime, sizeof(eatime), DATE_FORMAT, ea_time); + } + + if (option_debug) + ast_log(LOG_DEBUG, "Looking for conference %s that starts after %s\n", confno, eatime); + + var = ast_load_realtime("meetme", rt_conf_column, + confno, "startTime<= ", eatime, "endtime>= ", + currenttime, NULL); + } else + var = ast_load_realtime("meetme", rt_conf_column , confno, NULL); + if (!var) return NULL; while (var) { - if (!strcasecmp(var->name, "pin")) { + if (!strcasecmp(var->name, rt_user_pin_column)) { pin = ast_strdupa(var->value); - } else if (!strcasecmp(var->name, "adminpin")) { + } else if (!strcasecmp(var->name, rt_admin_pin_column)) { pinadmin = ast_strdupa(var->value); + } else if (!strcasecmp(var->name, rt_user_opts_column)) { + ast_copy_string(userOpts, var->value, sizeof(userOpts)); + } else if (!strcasecmp(var->name, rt_maxusers_column)) { + maxusers = atoi(var->value); + } else if (!strcasecmp(var->name, rt_admin_opts_column)) { + ast_copy_string(adminOpts, var->value, sizeof(adminOpts)); + } else if (!strcasecmp(var->name, rt_endtime_column)) { + ast_copy_string(endtime, var->value, sizeof(endtime)); + } else if (!strcasecmp(var->name, rt_starttime_column)) { + ast_copy_string(startTime, var->value, sizeof(startTime)); } + var = var->next; } ast_variables_destroy(var); + if (earlyalert){ + if (strcmp(startTime, currenttime) > 0){ + /* Announce that the caller is early and exit */ + if (!ast_streamfile(chan, "conf-has-not-started", chan->language)) + ast_waitstream(chan, ""); + *too_early = 1; + return NULL; + } + } + cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan); + + if (cnf) { + cnf->maxusers = maxusers; + cnf->endalert = endalert; + ast_copy_string(cnf->endtime, endtime, sizeof(cnf->endtime)); + } } + if (cnf) { if (confflags && !cnf->chan && !ast_test_flag(confflags, CONFFLAG_QUIET) && @@ -2405,7 +2549,8 @@ } } if (!var) { - ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno); + if (option_debug) + ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno); } ast_config_destroy(cfg); } @@ -2644,17 +2789,21 @@ cnf = find_conf(chan, confno, 1, dynamic, the_pin, sizeof(the_pin), 1, &confflags); if (!cnf) { + int too_early = 0; cnf = find_conf_realtime(chan, confno, 1, dynamic, - the_pin, sizeof(the_pin), 1, &confflags); + the_pin, sizeof(the_pin), 1, &confflags, optargs, &too_early); + if (rt_schedule && too_early) + allowretry = 0; } if (!cnf) { - res = ast_streamfile(chan, "conf-invalid", chan->language); - if (!res) - ast_waitstream(chan, ""); - res = -1; - if (allowretry) + if (allowretry){ confno[0] = '\0'; + res = ast_streamfile(chan, "conf-invalid", chan->language); + if (!res) + ast_waitstream(chan, ""); + res = -1; + } } else { if ((!ast_strlen_zero(cnf->pin) && !ast_test_flag(&confflags, CONFFLAG_ADMIN)) || @@ -3139,8 +3288,24 @@ struct ast_config *cfg; const char *val; - audio_buffers = DEFAULT_AUDIO_BUFFERS; + audio_buffers = DEFAULT_AUDIO_BUFFERS; + /* Set RT column names to their defaults */ + ast_copy_string(rt_conf_column, DEFAULT_CONF_COL, sizeof(rt_conf_column)); + ast_copy_string(rt_user_pin_column, DEFAULT_CONF_COL, sizeof(rt_user_pin_column)); + ast_copy_string(rt_admin_pin_column, DEFAULT_CONF_COL, sizeof(rt_admin_pin_column)); + ast_copy_string(rt_user_opts_column, DEFAULT_CONF_COL, sizeof(rt_user_opts_column)); + ast_copy_string(rt_admin_opts_column, DEFAULT_CONF_COL, sizeof(rt_admin_opts_column)); + + /* Scheduling support is off by default */ + rt_schedule = 0; + fuzzystart = 0; + earlyalert = 0; + endalert = 0; + + /* Logging of participants defaults to ON for compatibility reasons */ + rt_log_members = 1; + if (!(cfg = ast_config_load(CONFIG_FILE_NAME))) return; @@ -3156,6 +3321,57 @@ if (audio_buffers != DEFAULT_AUDIO_BUFFERS) ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers); } + if ((val = ast_variable_retrieve(cfg, "general", "rt_confno"))) { + ast_copy_string(rt_conf_column, val, sizeof(rt_conf_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "rt_upin"))) { + ast_copy_string(rt_user_pin_column, val, sizeof(rt_user_pin_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "rt_mpin"))) { + ast_copy_string(rt_admin_pin_column, val, sizeof(rt_admin_pin_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "rt_uflags"))) { + ast_copy_string(rt_user_opts_column, val, sizeof(rt_user_opts_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "rt_mflags"))) { + ast_copy_string(rt_admin_opts_column, val, sizeof(rt_admin_opts_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "rt_starttime"))) { + ast_copy_string(rt_starttime_column, val, sizeof(rt_starttime_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "rt_endtime"))) { + ast_copy_string(rt_endtime_column, val, sizeof(rt_endtime_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "rt_maxusers"))) { + ast_copy_string(rt_maxusers_column, val, sizeof(rt_maxusers_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "rt_members"))) { + ast_copy_string(rt_members_column, val, sizeof(rt_members_column)); + } + if ((val = ast_variable_retrieve(cfg, "general", "schedule"))) { + rt_schedule = ast_true(val) ? 1 : 0; + } + if ((val = ast_variable_retrieve(cfg, "general", "logmembercount"))) { + rt_log_members = ast_true(val) ? 1 : 0; + } + if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) { + if ((sscanf(val, "%d", &fuzzystart) != 1)) { + ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val); + fuzzystart = 0; + } + } + if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) { + if ((sscanf(val, "%d", &earlyalert) != 1)) { + ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val); + earlyalert = 0; + } + } + if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) { + if ((sscanf(val, "%d", &endalert) != 1)) { + ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val); + endalert = 0; + } + } ast_config_destroy(cfg); }