#include #include #include #include #include #include "global.h" #include "custom.h" #include "manhat-lib/shared_cs_util.h" #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_roster_xml_parser.h" #include "manhat-lib/shared_survey_string.h" #include "manhat-lib/shared_authenticate.h" #include "manhat-lib/shared_central_user.h" #include "manhat-lib/shared_file_util.h" #include "manhat-lib/shared_server_string.h" #include "manhat-lib/shared_encrypt.h" #include "manhat-lib/shared_user_index.h" #include "manhat-lib/shared_super_util.h" #include "manhat-lib/shared_strtrm.h" #include "manhat-lib/shared_new_course_lock.h" #include "manhat-lib/shared_add_util.h" #include "manhat-lib/shared_authenticate.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_person_list.h" #include "manhat-lib/shared_update_user_info.h" #include "manhat-lib/shared_delete.h" /* The administrator is given a chance to alter the following data items found in the XML ** file before the course is created. ** ** The name of the directory where the course is stored (the 'internal course name') ** The name of the subdirectory (under the standard 'courses' directory) where the course will ** be stored. ** ** This data structure keeps track of these data items for each course created. */ typedef struct directory_name_node { char name[MAX_COURSE_NO +1]; /* the original internal name of the course, as stored in the XML file */ char dir_id[MAX_COURSE_ID +1]; /* the new internal name of the course, as modified by the user */ char subdir[MAX_COURSE_SUBDIR + 1]; /* the new internal subdirectory for the course */ COURSE_TYPE course_type; /* Standalone, Normal or Template */ struct directory_name_node *next; } DIRECTORY_NAME_NODE; typedef enum user_state{NEW, /* this is a new user */ NEW_1, EXISTS, /* this is an existing user */ ERROR_UID, /* couldn't derive a username */ ERROR_NAME /* name in xml file didn't match existing name */ }USER_STATE; typedef enum user_add_state{FINISH, /* user was successfully added */ FAILED, /* error occurred while creating user */ USEREXISTS /* user was already in the course */ }USER_ADD_STATE; typedef enum user_central_state{C_ERROR, /* an error occurred while adding user to central database */ SUCCESS, /* user was successfully added to central database */ UN_CHANGE /* user was already in database, no changes required */ }USER_CENTRAL_STATE; typedef struct user { char first[MAX_NAME +1]; char last[MAX_NAME +1]; char id[MAX_ID +1]; char username[MAX_USERNAME +1]; char password[MAX_PASSWORD +1]; GROUP_TYPE group; USER_STATE is_new; USER_ADD_STATE add_state; USER_CENTRAL_STATE central_state; }USER; typedef struct user_node { USER user; struct user_node *next; }USER_NODE; typedef enum course_state{UPDATE, /* course already existed, this is an update */ C_NEW, /* this is a completely new course */ DIR_ERR, /* couldn't create course directory */ MSG_ERR, /* couldn't create chat message file */ CONFIG_ERR, /* couldn't write config.dat */ COURSE_ERR, /* general error? */ TYPE_CONFLICT /* course type conflict */ } COURSE_STATE; /* adding teacher to a course */ typedef enum t_pass_state{OPEN_ERR, /* error appending to password file */ T_SUCCESS /* all teachers added successfully */ }T_PASS_STATE; typedef struct master_course_list { char course_subdir[MAX_COURSE_SUBDIR + 1]; char course_dir[MAX_COURSE_ID + 1]; char course_path[MAX_PATH + 1]; char course_no[MAX_COURSE_NO + 1]; char course_title[MAX_COURSE_TITLE + 1]; char course_semester[MAX_SEMESTER + 1]; COURSE_TYPE course_type; COURSE_STATE exists; T_PASS_STATE t_state; USER_NODE *head; /* list of teachers only */ USER_NODE *add_head; /* complete list of people who have been added to the course */ USER_NODE *add_current; struct master_course_list *next; } CREATED_COURSE_NODE; typedef struct course_group { char course_subdir[MAX_COURSE_SUBDIR + 1]; char course_dir[MAX_COURSE_NO +1]; COURSE_TYPE course_type; GROUP_TYPE group; struct course_group *next; }COURSE_GROUP; typedef struct user_group_info { USER user; COURSE_GROUP *head; COURSE_GROUP *current; struct user_group_info *next; }USER_GROUP_INFO; typedef struct user_group_info_list { USER_GROUP_INFO *head; USER_GROUP_INFO *current; }USER_GROUP_INFO_LIST; USER_NODE * find_all_teachers(XML_COURSE_INFO *info) { USER_NODE *head =0, *ptr, *current=0; for(info->user_current = info->user_head; info->user_current; info->user_current=info->user_current->next) { if(info->user_current->data.group == FACULTY) { ptr = (USER_NODE*)malloc(sizeof(USER_NODE)); if(!ptr) cs_critical_error(ERR_MALLOC_FAILED, "find_all_teachers()"); ptr->next = 0; strncpy(ptr->user.first, info->user_current->data.realname, MAX_NAME + 1); strncpy(ptr->user.last, info->user_current->data.lastname, MAX_NAME + 1); strncpy(ptr->user.id, info->user_current->data.id, MAX_ID +1); strncpy(ptr->user.username, info->user_current->data.username, MAX_USERNAME +1); ptr->user.group = FACULTY; ptr->user.central_state = UN_CHANGE; /* assume this to start */ if(!head) head = ptr; else current->next = ptr; current = ptr; } } return head; } USER_NODE * find_all_users_in_standalone(XML_COURSE_INFO *info) { USER_NODE *head =0, *ptr, *current=0; for(info->user_current = info->user_head; info->user_current; info->user_current=info->user_current->next) { ptr = (USER_NODE*)malloc(sizeof(USER_NODE)); if(!ptr) cs_critical_error(ERR_MALLOC_FAILED, "find_all_uses_in_standalone()"); ptr->next =0; strncpy(ptr->user.first, info->user_current->data.realname, MAX_NAME +1); strncpy(ptr->user.last, info->user_current->data.lastname, MAX_NAME +1); strncpy(ptr->user.id, info->user_current->data.id, MAX_ID +1); strncpy(ptr->user.username, info->user_current->data.username, MAX_USERNAME +1); ptr->user.group = info->user_current->data.group; ptr->user.central_state = UN_CHANGE; if(!head) head = ptr; else current->next = ptr; current = ptr; } return head; } USER_GROUP_INFO * find_exist_users(USER_GROUP_INFO_LIST *list, P_NODE* info) { USER_GROUP_INFO *ptr; for(ptr=list->head; ptr; ptr = ptr->next) { if(strcmp(ptr->user.id, info->data.id) ==0) return ptr; } return 0; } USER_GROUP_INFO_LIST * process_one_course(USER_GROUP_INFO_LIST *list, XML_COURSE_INFO *info) { USER_GROUP_INFO *ptr, *find; /* for each user in the course */ for(info->user_current=info->user_head; info->user_current; info->user_current=info->user_current->next) { if(info->user_current->data.group != FACULTY) { find = find_exist_users(list, info->user_current); if(!find) { ptr = (USER_GROUP_INFO*)malloc(sizeof(USER_GROUP_INFO)); strncpy(ptr->user.first, info->user_current->data.realname,MAX_NAME +1); strncpy(ptr->user.last, info->user_current->data.lastname,MAX_NAME +1); strncpy(ptr->user.id, info->user_current->data.id,MAX_ID +1); if(strlen(info->user_current->data.username)>0) strncpy(ptr->user.username, info->user_current->data.username,MAX_USERNAME +1); else ptr->user.username[0]='\0'; ptr->user.is_new =NEW; ptr->user.central_state =UN_CHANGE; ptr->user.group=info->user_current->data.group; ptr->next =0; /** add a new course for this user */ ptr->head = (COURSE_GROUP*)malloc(sizeof(COURSE_GROUP)); /* There is a bug here if the subdir name is longer than MAX_COURSE_NO. The malloc above is uninitialized. So when the sub_dir name is longer than the above constant, the string is not null terminated. The next line assures that the above structure is intialized to 0, so the string will be null terminated. DFP 6/21/2005*/ memset(ptr->head, '\0', sizeof(COURSE_GROUP)); ptr->current = ptr->head; ptr->head->next =0; strncpy(ptr->head->course_subdir, info->subdir, MAX_COURSE_NO +1); strncpy(ptr->head->course_dir, info->dir_id, MAX_COURSE_NO +1); ptr->head->course_type = info->course_type; ptr->head->group=info->user_current->data.group; if(!list->head) list->head = ptr; else list->current->next = ptr; list->current = ptr; } else /* user was already listed */ { find->user.central_state =UN_CHANGE; find->current->next=(COURSE_GROUP*)malloc(sizeof(COURSE_GROUP)); /* There is a bug here if the subdir name is longer than MAX_COURSE_NO. The malloc above is uninitialized. So when the sub_dir name is longer than the above constant, the string is not null terminated. The next line assures that the above structure is intialized to 0, so the string will be null terminated. DFP 6/21/2005*/ memset(find->current->next, '\0', sizeof(COURSE_GROUP)); find->current = find->current->next; strncpy(find->current->course_subdir, info->subdir, MAX_COURSE_NO +1); strncpy(find->current->course_dir, info->dir_id, MAX_COURSE_NO +1); find->current->course_type = info->course_type; find->current->group = info->user_current->data.group; find->current->next =0; } } } return list; } USER_GROUP_INFO_LIST * build_user_list(XML_COURSE_INFO_LIST *list) { USER_GROUP_INFO_LIST *head; /* start with an empty user list */ head = (USER_GROUP_INFO_LIST *)malloc(sizeof(USER_GROUP_INFO_LIST)); if(!head) cs_critical_error(ERR_MALLOC_FAILED, "build_user_list()"); head->head =0; head->current =0; /* for each course */ for(list->current=list->head; list->current; list->current = list->current->next) { if(list->current->course_type != STANDALONE) head = process_one_course(head, list->current); } return head; } /* start list with normal and template courses ** and only teacher info */ CREATED_COURSE_NODE* build_normal_template_course_list(XML_COURSE_INFO_LIST *list) { USER_NODE *teacher_head; /*char error[300];*/ CREATED_COURSE_NODE *head = 0, *ptr, *current = 0; for(list->current=list->head; list->current; list->current = list->current->next) { /* if NOT Standalone course */ if(list->current->course_type != STANDALONE) { teacher_head = find_all_teachers(list->current); if(!teacher_head) { /* cs_critical_error(ERR_COURSE_X_Y_HAS_NO_TEACHER, list->current->course_code);*/ } ptr = (CREATED_COURSE_NODE *)malloc(sizeof(CREATED_COURSE_NODE)); if(!ptr) cs_critical_error(ERR_MALLOC_FAILED, "build_normal_template_course_list()"); strncpy(ptr->course_subdir, list->current->subdir, MAX_COURSE_SUBDIR + 1); strncpy(ptr->course_dir, list->current->dir_id, MAX_COURSE_ID +1); strncpy(ptr->course_no, list->current->course_code, MAX_COURSE_NO +1); strncpy(ptr->course_title, list->current->title, MAX_COURSE_TITLE +1); ptr->course_type = list->current->course_type; /*DFP 6/27/2005. Set state */ ptr->t_state = T_SUCCESS; if(ptr->course_type == TEMPLATE) { snprintf(ptr->course_path, MAX_PATH + 1, "%s%s/%s", TEMPLATE_PATH, ptr->course_subdir, ptr->course_dir); } else { snprintf(ptr->course_path, MAX_PATH + 1, "%s%s/%s", COURSE_PATH, ptr->course_subdir, ptr->course_dir); } /* change semester to a standard value for course templates */ if(list->current->course_type == TEMPLATE) strncpy(ptr->course_semester, "Course Template", MAX_SEMESTER + 1); else strncpy(ptr->course_semester, list->current->semester, MAX_SEMESTER + 1); ptr->next = 0; ptr->head = teacher_head; ptr->add_head = 0; ptr->add_current = 0; if(!head) head = ptr; else current-> next = ptr; current = ptr; } } return head; } int find_this_username(USER_NODE *all, const char *username) { USER_NODE *ptr; for(ptr = all; ptr; ptr = ptr->next) { if(strlen(ptr->user.username) > 0 && strcmp(ptr->user.username, username) ==0) return 1; } return 0; } static void process_standalone_username(USER_NODE *one, USER_NODE *all) { char username[MAX_USERNAME +1]; int try; one->user.is_new = NEW; /* assume this to start */ if(!strlen(one->user.username)) /* if username wasn't supplied in XML file */ { derive_username (one->user.first, one->user.last, one->user.id, username, MAX_USERNAME+1); for(try = 1; (try <= MAX_USERNAME_TRIES) && (find_this_username(all, username)); try++) { derive_another_username(one->user.first, one->user.last, one->user.id, username, MAX_USERNAME + 1, try); } if(try > MAX_USERNAME_TRIES) one->user.is_new = ERROR_UID; } else /* username was supplied in XML file */ { strncpy(username, one->user.username, MAX_USERNAME + 1); *(username + MAX_USERNAME) = '\0'; if(find_this_username(all, username)) one->user.is_new = ERROR_UID; } if(one->user.is_new != ERROR_UID) { one->user.is_new = NEW; strncpy(one->user.username, username, MAX_USERNAME + 1); derive_password (one->user.username, one->user.first,one->user.last, one->user.id, one->user.password, MAX_PASSWORD +1); /* shared_authenticate.c */ } } USER_NODE * find_teacher_in_course_head(USER_NODE *head, const char *id) { USER_NODE *ptr; for(ptr = head; ptr; ptr = ptr->next) { if(strcmp(ptr->user.id, id) ==0) return ptr; } return 0; } void update_standalone_username(CREATED_COURSE_NODE *sta_list) { CREATED_COURSE_NODE *ptr; USER_NODE *t_node, *t_ptr; for(ptr = sta_list; ptr; ptr = ptr->next) { for(t_node = ptr->add_head; t_node; t_node = t_node->next) { process_standalone_username(t_node, ptr->add_head); if(t_node->user.group == FACULTY) { t_ptr =find_teacher_in_course_head(ptr->head, t_node->user.id); if(t_ptr) { strncpy(t_ptr->user.username, t_node->user.username, MAX_USERNAME +1); strncpy(t_ptr->user.password, t_node->user.password, MAX_PASSWORD +1); t_ptr->user.is_new = t_node->user.is_new; } } } } } /* build list of standalone courses with teachers and students */ CREATED_COURSE_NODE * standalone_course_list(XML_COURSE_INFO_LIST *list) { CREATED_COURSE_NODE *head =0, *ptr, *current=0; for(list->current=list->head; list->current; list->current = list->current->next) { if(list->current->course_type == STANDALONE) { ptr = (CREATED_COURSE_NODE *)malloc(sizeof(CREATED_COURSE_NODE)); strncpy(ptr->course_subdir, list->current->subdir, MAX_COURSE_SUBDIR +1); strncpy(ptr->course_dir, list->current->dir_id, MAX_COURSE_ID +1); snprintf(ptr->course_path, MAX_PATH + 1, "%s%s/%s", COURSE_PATH, ptr->course_subdir, ptr->course_dir); strncpy(ptr->course_no, list->current->course_code, MAX_COURSE_NO +1); strncpy(ptr->course_title, list->current->title, MAX_COURSE_TITLE +1); ptr->course_type = list->current->course_type; strncpy(ptr->course_semester, list->current->semester, MAX_SEMESTER +1); ptr->next = 0; ptr->head = find_all_teachers(list->current); ptr->add_head =find_all_users_in_standalone(list->current); ptr->add_current = ptr->add_head; if(!head) head = ptr; else current->next = ptr; current = ptr; } } return head; } static void print_heading() { printf("%s%s\n", "Course List", ""); } static void print_course_table(CREATED_COURSE_NODE *head, const char *title) { CREATED_COURSE_NODE *ptr; USER_NODE *t_node; int course_count =0; int people_count; char c_color[9] = "#C7C5FF"; char t_color[9] = "#A4FFE5"; char s_color[9] = "#F6FFCD"; printf("

%s

\n", title); for(ptr = head; ptr; ptr = ptr->next) { if(ptr->course_type == CENTRAL) printf("\n", c_color); else if(ptr->course_type == STANDALONE) printf("
\n", s_color); else printf("
\n", t_color); printf("\n", "Group", ptr->course_subdir); printf("\n", "Internal Course Name", ptr->course_dir); printf("\n", "Course Code", ptr->course_no); printf("\n", "Course Title", ptr->course_title); printf("\n", "Semester", ptr->course_semester); printf("\n", "Course Type", ptr->course_type == STANDALONE? "Standalone": ptr->course_type == TEMPLATE? "Template": "Normal"); printf(""); printf("", "Success?", ptr->t_state == OPEN_ERR ? "No": "Yes"); printf("
%s %s
%s %s
%s %s
%s %s
%s %s
%s %s
%s", "Status"); if(ptr->exists == C_NEW) puts("New Course"); else if(ptr->exists == UPDATE) puts("Updated Course"); else if(ptr->exists == DIR_ERR) puts("Dir Error"); else if(ptr->exists == CONFIG_ERR) puts("Config Error"); else if(ptr->exists == COURSE_ERR) puts("Course Error"); else if(ptr->exists == TYPE_CONFLICT) puts("Course type conflict"); puts("
%s %s
\n"); printf("
\n"); course_count++; people_count =0; printf("\n"); printf("\n", ptr->course_no); printf("\n", "Full Name", "ID", "Username", "Central Status", "User Type", "Course Status", "Central Status" ); for(t_node = ptr->add_head; t_node; t_node = t_node->next) { people_count++ ; printf("\n", (t_node->user.is_new == ERROR_NAME) || (t_node->user.is_new == ERROR_UID)? "#ff9999" : "#ffffff"); printf( "", t_node->user.first, t_node->user.last); printf("", t_node->user.id); printf("", t_node->user.username); printf("", ptr->course_type == STANDALONE? "N/A":(t_node->user.is_new == NEW) || (t_node->user.is_new == NEW_1) ? "New User" : (t_node->user.is_new == EXISTS)? "Existing User": (t_node->user.is_new == ERROR_NAME)? "Name Mismatch": "Username Error"); printf("", (t_node->user.group == FACULTY) ? "faculty": "student"); printf("", (t_node->user.add_state == FINISH)? "Delete Successful": (t_node->user.add_state == USEREXISTS)? "Existing User": "Delete Failed"); printf("\n\n", ptr->course_type == STANDALONE? "N/A":t_node->user.central_state == C_ERROR? "Failed": t_node->user.central_state == SUCCESS? "Success": "Unchanged"); } printf("\n", "Total Users", people_count); printf("
%s
%s%s%s%s%s%s%s
%s %s %s %s%s %s%s%s
%s %d

\n"); } printf("

%s %d

\n", "Total Courses", course_count); } void read_parameters(char *roster_path) { cs_get_required_parameter ("roster_path", roster_path, MAX_PATH); /* shared_cs_util.c */ } void free_directory_name_list(DIRECTORY_NAME_NODE *head) { DIRECTORY_NAME_NODE *ptr; while(head) { ptr = head->next; free(head); head = ptr; } } static void check_invalid_chars(const char *string) { const char *cptr; /* check for invalid characters */ for(cptr = string; *cptr; cptr++) { if((*cptr != '_') && !isdigit(*cptr) && !isalpha(*cptr)) { cs_critical_error(ERR_COURSE_X_HAS_INVALID_CHARS, string); } } } /* assumes strings have been trimmed ** in read_parameters() */ static void check_internal_course_names(XML_COURSE_INFO_LIST *list) { for(list->current=list->head; list->current; list->current=list->current->next) { if(!strlen(list->current->dir_id) || !strlen(list->current->subdir) ) cs_critical_error(ERR_COURSE_NAMES_EMPTY, ""); /* Central or Standalone Course subdir names can't start with a 'T' */ if( (list->current->course_type == CENTRAL) || (list->current->course_type == STANDALONE)) { if(*(list->current->subdir) == 'T') cs_critical_error(ERR_COURSE_CANT_START_WITH_T, list->current->subdir); } check_invalid_chars(list->current->dir_id); check_invalid_chars(list->current->subdir); } /* for each course ... */ } /* parses the xml file into a linked list of ** course nodes */ XML_COURSE_INFO_LIST * parse_xml_file(const char *xml_file_path) { XML_COURSE_INFO_LIST *list; /* shared_roster_xml_parser.h */ FILE *fp; struct stat file_stat; char *buf; if(stat(xml_file_path, &file_stat)) { cs_critical_error(ERR_FILE_X_NOT_FOUND, xml_file_path); } buf = (char*)malloc( (file_stat.st_size + 1) * sizeof(char)); /* allocate an additional byte for terminating NULL */ if(!buf) cs_critical_error(ERR_MALLOC_FAILED, "parse_xml_file()"); fp = fopen(xml_file_path, "r"); if(!fp) cs_critical_error(ERR_FOPEN_READ_FAILED, xml_file_path); if(fread(buf, file_stat.st_size, 1, fp) != 1) cs_critical_error(ERR_FREAD_FAILED, xml_file_path); fclose(fp); *(buf + file_stat.st_size) = '\0'; /* null terminate the buf string */ list = xml_course_data_parser(buf); /*shared_roster_xml_parser.c */ free(buf); return list; } /** adds correct internal name and course type to *** the master course list **/ static void update_xml_info_list(XML_COURSE_INFO_LIST *list) { if(list->head) { for(list->current=list->head; list->current; list->current=list->current->next) list->current->course_type = CENTRAL; } else cs_critical_error(ERR_NO_DATA_FOUND, ""); } static void free_teacher_node(USER_NODE *t_head) { USER_NODE *ptr; while(t_head) { ptr = t_head->next; free(t_head); t_head = ptr; } } static void free_course_f_list(CREATED_COURSE_NODE *head) { CREATED_COURSE_NODE *ptr; while(head) { ptr = head->next; if(head->head) free_teacher_node(head->head); if(head->add_head) free_teacher_node(head->add_head); free(head); head = ptr; } } static void free_user_group_info_list(USER_GROUP_INFO_LIST *list) { USER_GROUP_INFO *ptr; while(list->head) { ptr = list->head->next; free(list->head); list->head = ptr; } free(list); } INDEX_USER * find_this_user_from_index(INDEX_USER_LIST *list, USER *node) { INDEX_USER *ptr; for(ptr = list->head; ptr;ptr = ptr->next) { if(strcmp(ptr->id, node->id) ==0) return ptr; } return 0; } int username_exist(INDEX_USER_LIST *index_list, const char *username) { INDEX_USER *ptr; for(ptr = index_list->head; ptr; ptr = ptr->next) { if(strcmp(ptr->username, username) ==0) return 1; } return 0; } INDEX_USER_LIST * process_one_username(USER *ptr, INDEX_USER_LIST *index_list) { INDEX_USER *a_user; char realname[MAX_NAME +1]; char username[MAX_USERNAME +1]; int try; ptr->is_new = NEW ; /* assume this to start */ a_user = find_this_user_from_index(index_list, ptr); if(!a_user) { if(!strlen(ptr->username)) /* if username wasn't supplied in XML file */ { derive_username (ptr->first, ptr->last, ptr->id, username, MAX_USERNAME+1); /* shared_authenticate.c */ for(try = 1; (try <= MAX_USERNAME_TRIES) && ( username_invalid(username) /* shared_authenticate.c */ || username_exist (index_list, username ) ); try++) { derive_another_username(ptr->first, ptr->last, ptr->id, username, MAX_USERNAME + 1, try); /* shared_authenticate.c */ } if(try > MAX_USERNAME_TRIES) ptr->is_new = ERROR_UID; /* couldn't derive username */ } else /* a username was supplied in the XML file */ { strncpy(username, ptr->username, MAX_USERNAME + 1); *(username + MAX_USERNAME) = '\0'; strtrm(username); /* shared_strtrm.c */ if(username_invalid(username) /* shared_authenticate.c */ || username_exist(index_list, username)) ptr->is_new = ERROR_UID; } if(ptr->is_new != ERROR_UID) { ptr->is_new = NEW; strncpy(ptr->username, username, MAX_USERNAME + 1); derive_password (ptr->username, ptr->first,ptr->last,ptr->id, ptr->password, MAX_PASSWORD +1); /* shared_authenticate.c */ snprintf(realname, MAX_NAME+1, "%s %s", ptr->first,ptr->last); index_list = add_to_index_list(index_list, ptr->username, ptr->id, realname); /* shared_user_index.c */ } } else /* person already has a central account */ { strncpy(ptr->username, a_user->username, MAX_USERNAME +1); derive_password (ptr->username, ptr->first,ptr->last,ptr->id, ptr->password, MAX_PASSWORD +1); /* shared_authenticate.c */ snprintf(realname, MAX_NAME+1, "%s %s", ptr->first,ptr->last); if(strcmp(realname, a_user->realname) == 0) ptr->is_new = EXISTS; else { /* copy correct real name into first, last fields */ get_first_last_names(a_user->realname, ptr->first, ptr->last); /* shared_authenticate.c */ ptr->is_new = ERROR_NAME; /* user exists, but they had a different real name on Manhattan */ } } return index_list; } INDEX_USER_LIST * derive_teacher_username_password(CREATED_COURSE_NODE *course_head, INDEX_USER_LIST *index_list) { CREATED_COURSE_NODE *course; USER_NODE *ptr; for(course = course_head; course; course = course->next) { for(ptr = course->head; ptr; ptr = ptr->next) index_list = process_one_username(&(ptr->user), index_list); } return index_list; } INDEX_USER_LIST * derive_student_username_password(USER_GROUP_INFO_LIST *user_list, INDEX_USER_LIST *index_list) { for(user_list->current = user_list->head; user_list->current; user_list->current = user_list->current->next) { index_list = process_one_username (&(user_list->current->user), index_list); } return index_list; } int create_course_dir(CREATED_COURSE_NODE *course) { char path[MAX_PATH + 1]; /* create subdir, if necessary */ snprintf(path, MAX_PATH + 1, "%s%s", course->course_type == TEMPLATE? TEMPLATE_PATH : COURSE_PATH, course->course_subdir); if(!file_exists(path)) { if(mkdir (path, 0777)) return 0; } if(mkdir(course->course_path, 0777)) return 0; return 1; } static void get_config_default_value(CREATED_COURSE_NODE *course, CONFIG_STRUCT *conf) { char professor[MAX_INSTRUCTOR +1]; strncpy(conf->course_no, course->course_no, MAX_COURSE_NO+1); strncpy(conf->title, course->course_title, MAX_COURSE_TITLE+1); strncpy(conf->semester, course->course_semester, MAX_SEMESTER+1); snprintf(professor, MAX_INSTRUCTOR +1, "%s %s", "Prof.", course->head->user.last); strncpy(conf->instructor, professor, MAX_INSTRUCTOR +1); conf->login_expire = 0; conf -> key_expire = MAX_KEY_EXPIRE; conf -> mail_attachments = MAX_ATTACHMENTS; conf -> assignments = 0; conf -> syllabus = 0; conf -> discussion = 0; conf -> postoffice = 0; conf -> internet = 0; conf -> lounge = 0; conf -> chat = 0; conf -> anonymous = 0; conf -> team = 0; conf -> team_teach = 0; conf -> grades = 0; conf -> selftest = 0; conf -> lectures = 0; conf -> people = 0; conf -> surveys = 0; conf->access = ACCESS_ALL; /*Full access for teachers and students */ conf ->standalone = (course->course_type == STANDALONE)? 1 : 0; conf -> template = (course->course_type == TEMPLATE)? 1 : 0; conf->misc = 0; conf->podcasts = 0; conf->future6 = 0; conf->theme = 0; } static int write_config_file(const char *course, CONFIG_STRUCT *conf) { FILE *fp; char file_path[MAX_PATH +1]; snprintf(file_path, MAX_PATH +1, "%s/%s", course, CONFIG_FNAME); fp = fopen(file_path,"w"); if(!fp) return 0; if(fwrite(conf, sizeof(CONFIG_STRUCT), 1, fp) != 1) { fclose(fp); return 0; } fclose(fp); return 1; } static int create_inboxes_directory (const char *crs ) { char path[MAX_PATH + 1]; snprintf (path, MAX_PATH + 1, "%s/%s", crs, INBOXES_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR ,ANONYMOUS_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, ASSIGNMENTS_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, DISCUSSION_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, TEAM_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, INET_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, LOUNGE_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, MAIL_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, HANDOUTS_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, TEAM_TEACH_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, GRADES_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, SELFTEST_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, LECTURES_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, SURVEYS_DIR); if(mkdir (path, 0777)) return 0; return 1; } int create_key_people(const char *course_path) { char path[MAX_PATH +1]; snprintf (path, MAX_PATH + 1, "%s/%s", course_path, KEY_DIR); if(mkdir (path, 0777)) return 0; snprintf (path, MAX_PATH + 1, "%s/%s", course_path, PEOPLE_DIR); if(mkdir (path, 0777)) return 0; return 1; } static int write_chat_message_log(const char *course) { FILE *fp; char log_fname[MAX_PATH +1]; snprintf(log_fname, MAX_PATH + 1, "%s/%s", course, CHAT_MSG_LOG); fp = fopen (log_fname, "w"); if(!fp) return 0; fclose(fp); return 1; } int write_logout_html (const char *crs) { FILE *fp; char fname[MAX_PATH +1]; snprintf(fname, MAX_PATH + 1, "%s/%s", crs, EXIT_FILE); fp = fopen (fname, "w"); if(!fp) return 0; fprintf (fp, "
%s
", EXIT_URL, EXIT_URL); fclose (fp); return 1; } int create_one_person_dir (const char *course_path, const char *username) { char basedir [MAX_PATH + 1]; snprintf (basedir, MAX_PATH + 1, "%s/", course_path); return create_directories(basedir,username); /* shared_add_util.c */ } int no_error_mark_passwd_file (const char *username, const CONFIG_STRUCT *conf) { FILE *fp; int fd; int found = 0; long offset = 0; char line[200]; char *ptr; char qmark = '?'; char passwd_fname[MAX_PATH + 1]; snprintf (passwd_fname, MAX_PATH + 1, "%s%s", conf->course_path, PASSWD_FNAME); fp = fopen (passwd_fname, "r+"); /* open for reading and writing */ if (!fp) return 0; fd = fileno(fp); get_exclusive_lock(fd, 1); /* shared_lock.c */ while (!found && fgets (line, 199, fp)) { if (*line != '?') /* skip usernames that start with ? */ { ptr = strchr (line, ':'); if (!ptr) cs_critical_error (ERR_PASSWD_PARSE_ERROR, line); *ptr = '\0'; if (!strcmp (line, username)) { fseek (fp, offset, SEEK_SET); if (fwrite (&qmark, sizeof (char), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, passwd_fname); found = 1; } } offset = ftell (fp); } release_lock(fd); fclose (fp); return found? 1: 0; } CREATED_COURSE_NODE * delete_user_from_course_list(CREATED_COURSE_NODE *course, USER *ptr) { int deleted; /* was the user's directory removed? */ char dirname[MAX_PATH + 1]; int exists; CONFIG_STRUCT conf; read_configuration_file (course->course_path, &conf); /* shared_util.c */ #ifdef DEBUGPRINT printf("

Read configuration file. conf.standalone = %d

", (int) conf.standalone); #endif if(!conf.standalone) { #ifdef DEBUGPRINT printf("

About to call delete_course.

"); #endif snprintf(dirname, MAX_PATH+1, "%s/%s", course->course_subdir, course->course_dir); delete_course(ptr->username, dirname ); /* delete course in central course list file - shared_delete.c */ } exists = no_error_mark_passwd_file (ptr->username, &conf); if (exists) { deleted = !user_contributed (ptr->username, &conf); /* shared_delete.c */ if (deleted) { snprintf (dirname, MAX_PATH + 1, "%s%s/%s", conf.course_path, PEOPLE_DIR, ptr->username); kill_directory(dirname); /* shared_file_util.c */ } } return course; } CREATED_COURSE_NODE * add_user_to_course_list(CREATED_COURSE_NODE *course, USER *ptr) { USER_NODE *target; target = (USER_NODE *)malloc(sizeof(USER_NODE)); if(!target) cs_critical_error(ERR_MALLOC_FAILED, "add_user_to_course_list()"); strncpy(target->user.username, ptr->username, MAX_USERNAME + 1); strncpy(target->user.first, ptr->first, MAX_NAME +1); strncpy(target->user.password, ptr->password, MAX_PASSWORD + 1); strncpy(target->user.last, ptr->last, MAX_NAME +1); strncpy(target->user.id, ptr->id, MAX_ID +1); target->user.is_new = ptr->is_new; target->user.group = ptr->group; target->user.add_state = ptr->add_state; target->user.central_state = ptr->central_state; target->next =0; if(!course->add_head) { course->add_head = target; course->add_current = course->add_head; } else { course->add_current->next = target; course->add_current = course->add_current->next; } return course; } static void update_central_info(CREATED_COURSE_NODE *course, USER *user_ptr) { char realname[MAX_NAME +1]; char course_name[MAX_PATH + 1]; snprintf(realname, MAX_NAME +1, "%s %s", user_ptr->first, user_ptr->last); snprintf(course_name, MAX_PATH + 1, "%s/%s", course->course_subdir, course->course_dir); if( (user_ptr->is_new == NEW) && (user_ptr->add_state == FINISH) && ( (course->exists == C_NEW) || (course->exists == UPDATE)) && (user_ptr->central_state != SUCCESS) ) { /* create_central_letter_dir is in shared_central_user.c */ /* sub_dir_name is in shared_authenticate.c */ if(!create_central_letter_dir (sub_dir_name(user_ptr->username))) user_ptr->central_state = C_ERROR; if(!create_central_user_dir(user_ptr->username)) /* shared_central_user.c */ user_ptr->central_state = C_ERROR; if(!write_central_id_file (realname,user_ptr->username, user_ptr->id)) /* shared_central_user.c */ user_ptr->central_state = C_ERROR; if(!write_central_password_file (user_ptr->username, user_ptr->password)) /* shared_central_user.c */ user_ptr->central_state = C_ERROR; if(!add_course(user_ptr->username,course_name)) /* shared_central_user.c */ user_ptr->central_state = C_ERROR; else { user_ptr->central_state = SUCCESS; user_ptr->is_new = NEW_1; /* central records already updated for this user */ } } else if((user_ptr->is_new != ERROR_UID || user_ptr->is_new != NEW) && user_ptr->add_state == FINISH) { if(course->exists == C_NEW || course->exists == UPDATE) { if(!add_course(user_ptr->username,course_name)) /* shared_central_user.c */ user_ptr->central_state = C_ERROR; else user_ptr->central_state = SUCCESS; } } else user_ptr->central_state = UN_CHANGE; } CREATED_COURSE_NODE * add_teachers(CREATED_COURSE_NODE *course) { USER_NODE *ptr; char file_path[MAX_PATH +1]; if(course->exists == C_NEW) { for(ptr = course->head; ptr; ptr=ptr->next) /* for each teacher */ { if(create_one_person_dir (course->course_path, ptr->user.username)) ptr->user.add_state = FINISH; else ptr->user.add_state = FAILED; if(course->course_type != STANDALONE) { update_central_info(course, &(ptr->user)); course =add_user_to_course_list(course, &(ptr->user)); } } } else if(course->exists == UPDATE) { for(ptr = course->head; ptr; ptr =ptr->next) { snprintf(file_path, MAX_PATH +1, "%s/%s/%s", course->course_path, PEOPLE_DIR, ptr->user.username); if(!file_exists(file_path)) { if(create_one_person_dir (course->course_path, ptr->user.username)) ptr->user.add_state = FINISH; else ptr->user.add_state = FAILED; if(course->course_type != STANDALONE) update_central_info(course, &(ptr->user)); } else ptr->user.add_state = USEREXISTS; if(course->course_type != STANDALONE) course =add_user_to_course_list(course, &(ptr->user)); } } return course; } int write_passwd_file(CREATED_COURSE_NODE *course, USER_NODE *head) { USER_NODE *ptr; char file_path[MAX_PATH +1]; FILE *fp; if( (course->exists != C_NEW) && (course->exists != UPDATE) ) return 0; snprintf(file_path, MAX_PATH +1, "%s/%s", course->course_path, PASSWORD_FNAME); fp = fopen(file_path, "a+"); if(!fp) return -1; get_exclusive_lock(fileno(fp),1); /* shared_lock.c */ for(ptr = head; ptr; ptr = ptr->next) { if( (course->course_type == STANDALONE) && ptr->user.add_state == FINISH) { fprintf(fp, "%s:x:%s %s:%s:anonymous:Z:%s\n", ptr->user.username, ptr->user.first, ptr->user.last, "faculty", ptr->user.id); write_password(ptr->user.username, ptr->user.password, course->course_path); /* shared_encrypt.c */ } else if(ptr->user.add_state == FINISH && ptr->user.central_state == SUCCESS) { fprintf(fp, "%s:x:%s %s:%s:anonymous:Z:%s\n", ptr->user.username, ptr->user.first, ptr->user.last, "faculty", ptr->user.id); } } release_lock(fileno(fp)); /* shared_lock.c */ fclose(fp); return 1; } CREATED_COURSE_NODE * find_this_course(CREATED_COURSE_NODE *course_head, const char *dir, const char *subdir) { CREATED_COURSE_NODE *ptr; for(ptr = course_head; ptr; ptr = ptr->next) { if(!strcmp(ptr->course_dir, dir) && !strcmp(ptr->course_subdir, subdir)) return ptr; } return 0; } int find_user_in_this_course(CREATED_COURSE_NODE *course, const char *username) { USER_NODE *ptr; for(ptr = course->add_head; ptr; ptr = ptr->next) { #ifdef DEBUGPRINT printf("

Looking for %s, looking at %s

", username, ptr->user.username); #endif if(!strcmp(ptr->user.username, username)) return 1; } return 0; } CREATED_COURSE_NODE * add_students_to_courses(CREATED_COURSE_NODE *course_head, USER_GROUP_INFO_LIST *user_list) { CREATED_COURSE_NODE *course_ptr; USER_GROUP_INFO *user_ptr; char file_path[MAX_PATH +1]; for(user_ptr = user_list->head; user_ptr; user_ptr = user_ptr->next) { for(user_ptr->current = user_ptr->head; user_ptr->current; user_ptr->current = user_ptr->current->next) { course_ptr = find_this_course(course_head, user_ptr->current->course_dir, user_ptr->current->course_subdir); if(course_ptr && (course_ptr->t_state == T_SUCCESS) && (course_ptr->course_type != TEMPLATE)) { snprintf(file_path, MAX_PATH +1, "%s/%s/%s", course_ptr->course_path, PEOPLE_DIR, user_ptr->user.username); if(!file_exists(file_path)) { if(user_ptr->user.is_new != ERROR_UID) { if(create_one_person_dir(course_ptr->course_path, user_ptr->user.username)) user_ptr->user.add_state = FINISH; else user_ptr->user.add_state = FAILED; if(course_ptr->course_type != STANDALONE) update_central_info(course_ptr, &(user_ptr->user)); } } else user_ptr->user.add_state = USEREXISTS; /* but he may not be in the password file! */ if(!find_user_in_this_course(course_ptr, user_ptr->user.username)) course_ptr = add_user_to_course_list(course_ptr, &(user_ptr->user)); } } } return course_head; } CREATED_COURSE_NODE * drop_students_from_courses(CREATED_COURSE_NODE *course_head, USER_GROUP_INFO_LIST *user_list) { CREATED_COURSE_NODE *course_ptr; USER_GROUP_INFO *user_ptr; char file_path[MAX_PATH +1]; #ifdef DEBUGPRINT printf("

In drop students from courses.

"); #endif for(user_ptr = user_list->head; user_ptr; user_ptr = user_ptr->next) { #ifdef DEBUGPRINT printf ("

In first for loop.

"); #endif for(user_ptr->current = user_ptr->head; user_ptr->current; user_ptr->current = user_ptr->current->next) { #ifdef DEBUGPRINT printf("

In second for loop.

"); #endif course_ptr = find_this_course(course_head, user_ptr->current->course_dir, user_ptr->current->course_subdir); if(course_ptr && (course_ptr->t_state == T_SUCCESS) && (course_ptr->course_type != TEMPLATE)) { snprintf(file_path, MAX_PATH +1, "%s/%s/%s", course_ptr->course_path, PEOPLE_DIR, user_ptr->user.username); if(file_exists(file_path)) { /* Student in course */ #ifdef DEBUGPRINT printf("

User %s exists!

", user_ptr->user.username); #endif user_ptr->user.add_state = USEREXISTS; /* but he may not be in the password file! */ course_ptr = delete_user_from_course_list(course_ptr, &(user_ptr->user)); user_ptr->user.add_state = FINISH; } else { user_ptr->user.add_state = FAILED; #ifdef DEBUGPRINT printf("

Did not find user %s in course.

", user_ptr->user.username); #endif } course_ptr = add_user_to_course_list(course_ptr, &(user_ptr->user)); } #ifdef DEBUGPRINT else { printf("

Did not find course %s/%s.

", user_ptr->current->course_subdir, user_ptr->current->course_dir ); if(!course_ptr) { printf("

Course ptr null.

"); } else { printf("

Course state = %d, course_type = %d

", course_ptr->t_state, course_ptr->course_type); } } #endif } } return course_head; } static P_NODE* build_password_list(const char *subdir, const char *dir) { char course_name[MAX_PATH + 1]; CONFIG_STRUCT conf; P_NODE *head = 0; snprintf(course_name, MAX_PATH + 1, "%s/%s", subdir, dir); if(read_configuration_file_ok(course_name,&conf)) head=build_option_person_list(&conf); return head; } static int listed_in_password(const char *username, P_NODE *person_head) { P_NODE *p_ptr; for(p_ptr = person_head; p_ptr; p_ptr=p_ptr->next) if(!strcmp(username,p_ptr->data.username)) return 1; return 0; } void write_students_to_password_file(CREATED_COURSE_NODE *courses) { CREATED_COURSE_NODE *course_ptr; char file_path[MAX_PATH +1]; FILE *fp; P_NODE *person_head; for(course_ptr = courses; course_ptr; course_ptr = course_ptr->next) { /* students are NOT added to course templates! */ if(course_ptr->course_type != TEMPLATE) { person_head = build_password_list( course_ptr->course_subdir, course_ptr->course_dir); snprintf(file_path, MAX_PATH +1, "%s/%s", course_ptr->course_path,PASSWORD_FNAME); fp = fopen(file_path, "a"); if(!fp) { course_ptr->t_state = OPEN_ERR; break; } get_exclusive_lock(fileno(fp), 0); /* shared_lock.c */ for(course_ptr->add_current = course_ptr->add_head; course_ptr->add_current; course_ptr->add_current = course_ptr->add_current->next) { if( (course_ptr->add_current->user.group != FACULTY) && ( (course_ptr->add_current->user.add_state == FINISH) || ((course_ptr->add_current->user.add_state == USEREXISTS) && !listed_in_password(course_ptr->add_current->user.username,person_head)) ) ) { fprintf(fp, "%s:x:%s %s:%s:anonymous:A:%s\n", course_ptr->add_current->user.username, course_ptr->add_current->user.first, course_ptr->add_current->user.last, "student", course_ptr->add_current->user.id); if(course_ptr->course_type == STANDALONE) { write_password(course_ptr->add_current->user.username, course_ptr->add_current->user.password, course_ptr->course_path); /* shared_encrypt.c */ } } } release_lock(fileno(fp)); /* shared_lock.c */ fclose(fp); free_option_person_list(person_head); /* shared_person_list.c */ } } /* for... */ } int check_course_type(CREATED_COURSE_NODE *course) { CONFIG_STRUCT conf; char file[MAX_PATH +1]; snprintf(file, MAX_PATH +1, "%s/%s", course->course_subdir, course->course_dir); read_configuration_file (file, &conf); if(conf.standalone && course->course_type == STANDALONE) return 1; else if((!conf.standalone) && course->course_type == CENTRAL) return 1; else return 0; } CREATED_COURSE_NODE * create_course_with_teachers(CREATED_COURSE_NODE *course_head) { CREATED_COURSE_NODE *ptr; CONFIG_STRUCT conf; for(ptr = course_head; ptr; ptr = ptr->next) { if(ptr->course_type == TEMPLATE) { /* the first teacher's username is used as the course_subdir within the templates directory */ snprintf(ptr->course_subdir, MAX_COURSE_SUBDIR + 1, "T%s", ptr->head->user.username); *(ptr->course_subdir + MAX_COURSE_SUBDIR) = '\0'; snprintf(ptr->course_path, MAX_PATH + 1, "%s%s/%s", TEMPLATE_PATH, ptr->course_subdir, ptr->course_dir); } else snprintf(ptr->course_path, MAX_PATH + 1, "%s%s/%s", COURSE_PATH, ptr->course_subdir, ptr->course_dir); if(file_exists(ptr->course_path)) /* shared_file_util.c */ { if(ptr->course_type == TEMPLATE) ptr->exists = UPDATE; /* Course already exists */ else { if(check_course_type(ptr)) { ptr->exists = UPDATE; /* Course already exists */ ptr =add_teachers(ptr); } else ptr->exists = TYPE_CONFLICT; } } else { ptr->exists = C_NEW; /* new course */ if(create_course_dir(ptr)) { get_config_default_value(ptr, &conf); if(write_config_file(ptr->course_path, &conf)) { if(!create_inboxes_directory (ptr->course_path) ) ptr->exists = DIR_ERR; //can't create inbox, key, or people dirs if(!create_key_people(ptr->course_path)) ptr->exists = DIR_ERR; //can't create inbox, key, or people dirs else { if(conf.standalone && !write_logout_html(ptr->course_path)) ptr->exists = MSG_ERR; //can't write logout html file for standalone course or chat log if( !write_chat_message_log(ptr->course_path)) ptr->exists = MSG_ERR; // chat log else ptr =add_teachers(ptr); } } else ptr->exists = CONFIG_ERR; // can't write conf file } else { ptr->exists = COURSE_ERR; // can't create course dir } } ptr->t_state = write_passwd_file(ptr, ptr->head) == 1? T_SUCCESS : OPEN_ERR; } return course_head; } void create_standalone_with_students(CREATED_COURSE_NODE *stand_head) { CREATED_COURSE_NODE *ptr; char file_path[MAX_PATH +1]; for(ptr = stand_head; ptr; ptr = ptr->next) { if(ptr && (ptr->t_state == T_SUCCESS)) { for(ptr->add_current = ptr->add_head; ptr->add_current; ptr->add_current = ptr->add_current->next) { if(ptr->add_current->user.group != FACULTY) { snprintf(file_path, MAX_PATH +1, "%s/%s/%s", ptr->course_path,PEOPLE_DIR, ptr->add_current->user.username); if(!file_exists(file_path)) { if(ptr->add_current->user.is_new != ERROR_UID) { if(create_one_person_dir(ptr->course_path, ptr->add_current->user.username)) ptr->add_current->user.add_state = FINISH; else ptr->add_current->user.add_state = FAILED; } } else ptr->add_current->user.add_state = USEREXISTS; } else { if(ptr->exists == C_NEW) ptr->add_current->user.add_state = FINISH; else ptr->add_current->user.add_state = USEREXISTS; } } } } } /* for debugging only */ void dump_xml_list(XML_COURSE_INFO_LIST *list) { int students = 0; send_content_type(); puts("
\n");
 for(list->current = list->head; list->current; list->current=list->current->next)
  {
   printf("\n\nCourse Code: %s\n", list->current->course_code);
   printf("Title: %s\n", list->current->title);
   printf("Semester: %s\n", list->current->semester);   
   printf("subdir: %s\n", list->current->subdir);   
   printf("dir_id: %s\n", list->current->dir_id);   
   for(list->current->user_current = list->current->user_head, students = 0; 
                   list->current->user_current;
                      list->current->user_current = list->current->user_current->next, students++)
                      
    {
     printf("real name: %s
\n", list->current->user_current->data.realname); printf("last name: %s
\n", list->current->user_current->data.lastname); printf("id number: %s
\n", list->current->user_current->data.id); } printf("Total users: %d

\n", students); } // puts(""); // exit(1); } /*** for debugging only ***/ void dump_user_list(USER_GROUP_INFO_LIST *user_list) { USER_GROUP_INFO *ptr; COURSE_GROUP *course_ptr; for(ptr=user_list->head; ptr; ptr = ptr->next) { printf("lastname= %s
\n", ptr->user.last); printf("id = %s
\n", ptr->user.id); for(course_ptr = ptr->head; course_ptr; course_ptr=course_ptr->next) { printf("subdir : %s
\n", course_ptr->course_subdir); printf("coursedir : %s
\n", course_ptr->course_dir); } } } int main() { XML_COURSE_INFO_LIST *xml_info_list; /* shared_roster_xml_parser.h */ CREATED_COURSE_NODE *course_head = 0; USER_GROUP_INFO_LIST *user_list = 0; INDEX_USER_LIST *index_list = 0; char roster_path[MAX_PATH + 1]; /* full (relative) path to xml file */ cs_cgi_init(); /* shared_cs_util.c */ /* build a linked list of directory names assigned to each course by the user */ read_parameters(roster_path); /** NEXT COMMENTED OUT - no authentication is done in this version *** *** validate_super_key(key, &user); *** **/ /* parse the xml file into a linked list */ xml_info_list = parse_xml_file(roster_path); /* parse xml file */ /* incorporate any directory name changes made by the user into the xml_info_list */ update_xml_info_list(xml_info_list); /* add correct course type and internal name to list */ /* make sure the directory names provided are reasonable */ check_internal_course_names(xml_info_list); send_content_type(); print_heading(); /* only one admin can create a course at a time */ get_new_course_lock(); /* shared_new_course_lock.c */ /* start list with normal and template courses ** and only teacher info */ course_head = build_normal_template_course_list(xml_info_list); if(course_head) { index_list = (INDEX_USER_LIST *)malloc(sizeof(INDEX_USER_LIST)); index_list->current =0; index_list->head =0; index_list = build_index_user_list(index_list); /* shared_user_index.c */ /* DFP 6/24/2005 Don't need to do the next two steps. */ /* index_list = derive_teacher_username_password(course_head,index_list); course_head =create_course_with_teachers(course_head); */ user_list = build_user_list(xml_info_list); /* list contains all students, with their courses */ if(user_list) { index_list=derive_student_username_password(user_list,index_list); /* DFP 6/24/2005 */ /*This will become drop students from courses */ /*course_head = add_students_to_courses(course_head, user_list);*/ course_head = drop_students_from_courses(course_head, user_list); /*write_students_to_password_file(course_head);*/ reindex_users("../users"); /* shared_user_index.c */ print_course_table(course_head, "Normal and Template Courses"); } } else printf("

%s

", "(No Central Courses)"); free_xml_data_list(xml_info_list); if(index_list) free_index_user_list(index_list); /* shared_user_index.c */ if(course_head) free_course_f_list(course_head); if(user_list) free_user_group_info_list(user_list); free_new_course_lock(); /* shared_new_course_lock.c */ unlink(roster_path); cs_cgi_destroy(); /* shared_cs_util.c */ return 0; }