#include #include #include #include #include "global.h" #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_super_util.h" #include "manhat-lib/shared_strtrm.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_access.h" #include "manhat-lib/shared_news_util.h" #include "manhat-lib/shared_file_util.h" #include "manhat-lib/shared_person_list.h" #include "manhat-lib/shared_cs_util.h" #include "manhat-lib/shared_super_menu.h" typedef struct access_node { CONFIG_STRUCT conf; char dirname[MAX_FILENAME + 1]; int orig_access; /* value of the original access setting */ int read_ok; /* were we able to read the configuration file? */ struct access_node *next; } ACCESS_NODE; ACCESS_NODE * get_access_node(char *str) { ACCESS_NODE *ptr; ptr = (ACCESS_NODE*)malloc(sizeof(ACCESS_NODE)); strncpy(ptr->dirname, str, MAX_FILENAME + 1); strtrm(ptr->dirname); /* shared_strtrm.c */ ptr->next = 0; return ptr; } ACCESS_NODE * build_access_course_list() { #define MAX_TMP_NAME 50 ACCESS_NODE *head = 0, *current =0, *ptr; char *str; HDF *obj; str = hdf_get_value(global_cgi->hdf, "Query.crs.0", 0); if(str) { obj = hdf_get_child(global_cgi->hdf, "Query.crs"); while(obj) { str = obj->value; if(str && strlen(str)) { ptr = get_access_node(str); if(!head) head = ptr; else current->next = ptr; current = ptr; } obj = obj->next; } } else { str = hdf_get_value(global_cgi->hdf, "Query.crs", 0); if(!str) cs_critical_error(ERR_PARAM_MISSING, "crs"); head = get_access_node(str); } return head; #undef MAX_TMP_NAME } void free_access_course_list(ACCESS_NODE *head) { ACCESS_NODE *ptr; while(head) { ptr = head; head = head->next; free(ptr); } } ACCESS_NODE* read_parameters (char *key, int *access) { ACCESS_NODE *head; char tmp[10 + 1]; cs_get_required_parameter ("id", key, MAX_KEY); /* shared_cs_util.c */ cs_get_required_parameter ("access", tmp,10);/* shared_cs_util.c */ *access = atoi(tmp); head = build_access_course_list(); return head; } void set_results(ACCESS_NODE *head, const char *key) { #define MAX_TMP_NAME 50 ACCESS_NODE *ptr; char url[MAX_PATH +1]; char name[MAX_TMP_NAME]; int i =0; snprintf(url, MAX_PATH +1, "%s?id=%s", "super_config_course_list", key); cs_set_value("back_url", url); for(ptr=head; ptr; ptr=ptr->next) { snprintf(name, MAX_TMP_NAME, "chg_course.%d.dirname", i); cs_set_value(name, ptr->dirname); if(ptr->read_ok) { snprintf(name, MAX_TMP_NAME, "chg_course.%d.read_ok", i); cs_set_int_value(name, 1); snprintf(name, MAX_TMP_NAME, "chg_course.%d.course_no", i); cs_set_value(name, ptr->conf.course_no); snprintf(name, MAX_TMP_NAME, "chg_course.%d.title", i); cs_set_value(name, ptr->conf.title); snprintf(name, MAX_TMP_NAME, "chg_course.%d.instructor", i); cs_set_value(name, ptr->conf.instructor); snprintf(name, MAX_TMP_NAME, "chg_course.%d.semester", i); cs_set_value(name, ptr->conf.semester); snprintf(name, MAX_TMP_NAME, "chg_course.%d.orig_access", i); cs_set_int_value(name, ptr->orig_access); snprintf(name, MAX_TMP_NAME, "chg_course.%d.access", i); cs_set_int_value(name, ptr->conf.access); } i++; } #undef MAX_TMP_NAME } ACCESS_NODE * read_configs(ACCESS_NODE *head) { ACCESS_NODE *ptr; for(ptr=head; ptr; ptr=ptr->next) { ptr->read_ok = read_configuration_file_ok(ptr->dirname, &(ptr->conf)); /* shared_util.c */ if(ptr->read_ok) ptr->orig_access = ptr->conf.access; } return head; } static void write_new_config_file(const char *fname, CONFIG_STRUCT *conf, const char *extension) { FILE *fp; int fd; char fullpath[MAX_PATH + 1]; /* if the first letter of the course fname starts with a 'T', ** then this is a course template and the config file will be ** located in the TEMPLATE_PATH directory instead of the ** COURSE_PATH directory */ snprintf (fullpath, MAX_PATH + 1, "%s%s/%s%s", (*fname == 'T')? TEMPLATE_PATH : COURSE_PATH, fname, CONFIG_FNAME, extension); fp = fopen (fullpath, "w"); if (fp) { fd = fileno(fp); get_exclusive_lock(fd, 1); /* shared_lock.c */ fwrite (conf, sizeof (CONFIG_STRUCT), 1, fp); release_lock(fd); /* shared_lock.c */ fclose (fp); } } /** ** this is just like read_configuration_file() in shared_util.c ** except it's reading from config.dat.orig ** and that config.dat.orig is DELETED after a successful read ** ** this could (should) be improved so that only the modules that ** are activated are updated, not the entire configuration */ int read_orig_config (const char *fname, CONFIG_STRUCT * config) { FILE *fp; int fd; char fullpath[MAX_PATH + 1]; int is_template; /* if the first letter of the course fname starts with a 'T', ** then this is a course template and the config file will be ** located in the TEMPLATE_PATH directory instead of the ** COURSE_PATH directory */ is_template = (*fname == 'T'); snprintf (fullpath, MAX_PATH + 1, "%s%s/%s.orig", is_template ? TEMPLATE_PATH : COURSE_PATH, fname, CONFIG_FNAME); fp = fopen (fullpath, "r"); if (!fp) return 0; /* the config file can be changed by a teacher or administrator ** so we use advisory file locking */ fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ if (fread (config, sizeof (CONFIG_STRUCT), 1, fp) != 1) { release_lock(fd); fclose(fp); return 0; } release_lock(fd); /* shared_lock.c */ fclose (fp); /* whether the course is a template or not is NOT stored in the file.. ** instead it is set here based on the course name */ config->template = is_template; /* the course_path data item used to be saved in the file since the ** addition of the course templates idea, it is more convenient to set ** it here */ snprintf (config->course_path, MAX_PATH + 1, "%s%s/", is_template ? TEMPLATE_PATH : COURSE_PATH, fname); unlink(fullpath); /* we're done with the backup file */ return 1; /* success */ } /* just check to see if the inbox.dat file exists ** This means at least one message was sent. ** This should be improved to check to make sure there's ** at least one undeleted message in the inbox file */ int has_content(const char *course_path, int group) { char inbox_fname[MAX_PATH + 1]; /* we're only interested in the 'central_discussion_path' value, ** so we can send set_discussion_names() a phony username **/ set_discussion_names(course_path, "bogus_name", group); /* shared_news_util.c */ snprintf(inbox_fname,MAX_PATH + 1,"%s%s",central_discussion_path,INBOX_FNAME); if(file_exists(inbox_fname)) /* shared_file_util.c */ return 1; else return 0; } int has_chat_transcripts(const char *course_path) { char path[MAX_PATH + 1]; struct stat buf; snprintf (path, MAX_PATH + 1, "%s/%s", course_path, CHAT_MSG_LOG); if (!stat (path, &buf) && buf.st_size) /* file exists and is not empty */ return 1; else return 0; } int grades_posted(CONFIG_STRUCT *conf) { P_NODE *person_head = 0; P_NODE *ptr; char teacher_username[MAX_USERNAME + 1]; char fname[MAX_PATH + 1]; *teacher_username = '\0'; /* find a teacher */ person_head = build_option_person_list(conf); /* shared_person_list.c */ for(ptr = person_head; ptr; ptr=ptr->next) if(ptr->data.group == FACULTY) { strncpy(teacher_username, ptr->data.username, MAX_USERNAME + 1); break; } free_option_person_list(person_head); /* shared_person_list.c */ if(*teacher_username) { snprintf (fname, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR,teacher_username, GRADES_DIR, GRADES_HTML_FNAME); if(file_exists(fname)) /* shared_file_util.c */ return 1; else return 0; } else return 1; /* no teacher - should never happen, but we'll activate the module to be safe */ return 1; } static void activate_modules_with_content(CONFIG_STRUCT *conf) { conf->assignments = has_content(conf->course_path, ASSIGNMENTS); conf->syllabus = has_content(conf->course_path, HANDOUTS_NOTICES); conf->discussion = has_content(conf->course_path, CLASS_DISCUSSION); conf->postoffice = 1; /* don't know which user we'll be capturing, best we can do is to always enable the Post Office */ conf->internet = has_content(conf->course_path, INTERNET_RESOURCES); conf->lounge = has_content(conf->course_path, STUDENT_LOUNGE); conf->chat = has_chat_transcripts(conf->course_path); conf->anonymous = has_content(conf->course_path, ANONYMOUS_DISCUSSION); conf->team = has_content(conf->course_path, TEAM_DISCUSSION); conf->team_teach = has_content(conf->course_path, TEAM_TEACH); conf->grades = grades_posted(conf); conf->selftest = has_content(conf->course_path, SELFTEST); conf->lectures = has_content(conf->course_path, LECTURES); } ACCESS_NODE * write_new_configs(ACCESS_NODE *head, int access) { ACCESS_NODE *ptr; for(ptr=head; ptr; ptr=ptr->next) { if(ptr->read_ok) { if( (access == ACCESS_CAPTURE) && (ptr->orig_access != ACCESS_CAPTURE)) /* if changing TO capture mode */ { write_new_config_file(ptr->dirname, &(ptr->conf), ".orig"); /* backup original configuration to config.dat.orig */ activate_modules_with_content( &(ptr->conf)); /* turn on all modules that have messages */ } else if( (access != ACCESS_CAPTURE) && (ptr->orig_access == ACCESS_CAPTURE)) /* if changing FROM capture mode */ read_orig_config(ptr->dirname, &(ptr->conf)); /* restore original module selections from config.dat.orig file ** and delete the config.dat.orig backup file */ ptr->conf.access = access; write_new_config_file(ptr->dirname, &(ptr->conf), ""); } } return head; } int main () { char key[MAX_KEY + 1]; /* from id=? command line */ ACCESS_NODE *head; int access; /*from access=? command line */ SESSION user; cs_cgi_init(); head = read_parameters (key, &access); validate_super_key (key, &user); /* shared_super_util.c */ set_admin_page(&user, key, 0, "super_config_course_list"); /* shared_super_menu.c */ head = read_configs(head); /* read the configuration file for each course */ head = write_new_configs(head, access); set_results(head, key); free_access_course_list(head); cs_cgi_display("super_chg_crs_access", 1); cs_cgi_destroy(); return 0; }