#include #include #include "ClearSilver.h" #include "global.h" #include "grade.h" #include "custom.h" #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_person_list.h" #include "manhat-lib/shared_grade_book_release.h" #include "manhat-lib/shared_cs_util.h" static void read_parameters (char *course, char *key) { cs_get_required_parameter("crs", course, MAX_PATH); cs_get_required_parameter("id", key, MAX_KEY); } static char *read_uploaded_file(CONFIG_STRUCT *conf) { char db_path[MAX_PATH +1]; FILE *fp; char *buf; struct stat file_stat; /* get size of the uploaded text file */ snprintf(db_path, MAX_PATH + 1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADES_NEW_TAB_FNAME); if(stat(db_path, &file_stat)) cs_critical_error( ERR_STAT_FAILED, db_path); /* allocate a buffer one byte larger than the length of the file */ buf = (char*)malloc(file_stat.st_size + 1); if(!buf) cs_critical_error( ERR_MALLOC_FAILED, ""); fp = fopen(db_path, "r"); if(!fp) return 0; /* can't open file */ if(get_shared_lock(fileno(fp), 0)) /* shared_lock.c */ { fclose(fp); return 0; } /* read the entire file into the buffer */ if(fread(buf, file_stat.st_size, 1, fp) != 1) cs_critical_error(ERR_FREAD_FAILED, db_path); release_lock(fileno(fp)); /* shared_lock.c */ fclose(fp); *(buf + file_stat.st_size) = '\0'; /* null terminate the buf string */ return buf; } static int contains_digits(const char *id) { int i, len; len = strlen(id); for(i =0; inext) { if( (ptr->data.group != FACULTY) && !strcmp(ptr->data.id, id) && (*(ptr->data.realname) != '*')) { if(ptr->data.team == 1) /* if not already found in uploaded file */ find = -1; /* means this person is duplicated in file */ else { ptr->data.team = 1; /* mark this person as included in uploaded file */ find = 1; } break; } } if(find == 0) /* person was listed in file, but not in our classroom */ { snprintf(stdname, MAX_NAME +1, "extra.%d.id", *extra_count); cs_set_value(stdname, id); (*extra_count)++; return 0; } else if(find == -1) { snprintf(stdname, MAX_NAME +1, "dup.%d.id", *dup_count); cs_set_value( stdname, id); (*dup_count)++; return 0; } return 1; } static int all_students_have_grades(P_NODE *head) { P_NODE *ptr; int i =0; char name[MAX_NAME +1]; for(ptr = head; ptr; ptr = ptr->next) { if(ptr->data.group != FACULTY && *(ptr->data.realname) != '*') { if(ptr->data.team != 1) { snprintf(name, MAX_NAME +1, "miss.%d.id", i); cs_set_value( name, ptr->data.id); snprintf(name, MAX_NAME +1, "miss.%d.name", i); cs_set_value(name, ptr->data.realname); i++; } } } if(i ==0) return 1; return 0; } /* we'll use the 'team' field in the linked list to record * ** whether or not that person is listed in the uploaded tab file * ** This function sets the team to 0 for all nodes, meaning that * ** the person is not yet found in the tab file * */ static P_NODE * clear_team_fields(P_NODE *head) { P_NODE *ptr; for(ptr = head; ptr; ptr=ptr->next) ptr -> data.team = 0; return head; } static P_NODE *build_grade_receiver_list( CONFIG_STRUCT *conf, int *error) { P_NODE *head; int len =0, ss, done, i; char *grades_line = 0, *buf, *ptrID, id[MAX_ID +1 ]; int big = MAX_GRADES_LINELEN; int extra_count = 0, /* count of records in uploaded file,with no matching students in classroom */ dup_count = 0; /* count of records in uploaded file, which were duplicates */ head = build_option_person_list(conf); /* shared_person_list.c */ head = clear_team_fields(head); buf = read_uploaded_file(conf); grades_line = (char*)malloc(sizeof(char) * (MAX_GRADES_LINELEN + 1)); if(!grades_line) cs_critical_error(ERR_MALLOC_FAILED, ""); *grades_line = '\0'; len = strlen(buf); for(ss =0; ss < len; ss++) { i = 0; while( (ss < len) && (buf[ss] != '\n')) /* handle one line at a time */ { if((int)strlen(grades_line) >= big) { grades_line = realloc(grades_line, (big * 2) + 1); big = big * 2; } grades_line[i] = buf[ss]; grades_line[i + 1] = '\0'; i++; ss++; } if(*grades_line) /* if the line contains characters */ { done = 0; /* find a tab character */ ptrID = strchr(grades_line, '\t'); if(ptrID) *ptrID ='\0'; else done = 1; if(!done) { /* first field is an ID number */ strncpy(id, grades_line, MAX_ID + 1); *(id + MAX_ID) = '\0'; if(contains_digits(id)) { if(!mark_this_student(head, id, &extra_count, &dup_count)) (*error)++; } } free(grades_line); grades_line =0; big = MAX_GRADES_LINELEN; grades_line = (char*)malloc(sizeof(char) * MAX_GRADES_LINELEN +1); if(!grades_line) cs_critical_error(ERR_MALLOC_FAILED, ""); *grades_line = '\0'; } /* if(*grades_line) */ } /* for each character in the file */ free(buf); if(!all_students_have_grades(head)) (*error)++; return head; } static void deliver_new_file_to_students(CONFIG_STRUCT *conf, P_NODE *head) { P_NODE *ptr; for(ptr = head; ptr; ptr = ptr->next) { if(ptr->data.team == 1) write_student_newfile (ptr->data.username, conf); /* shared_grade_book_release.c */ } } static int has_newlines (char *buffer, int bytes_read, int *tab) { char *ptr; int i; int has_new_line =0; for (ptr = buffer, i = 1; i <= bytes_read; ptr++, i++) { if (*ptr == 10) has_new_line++; if(*ptr == '\t') (*tab)++; } if(has_new_line) return 1; return 0; } static void cr_to_nl (char *buffer, int bytes_read) { char *ptr; int i; for (ptr = buffer, i = 1; i <= bytes_read; ptr++, i++) if (*ptr == 13) *ptr = 10; } static void rename_temp_tab_file(CONFIG_STRUCT *conf) { char old_fname[MAX_PATH + 1]; char new_fname[MAX_PATH + 1 ]; snprintf(old_fname, MAX_PATH +1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADES_NEW_TAB_FNAME); snprintf(new_fname, MAX_PATH +1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADES_TAB_FNAME); if(rename(old_fname, new_fname)) cs_critical_error(ERR_RENAME_FAILED, old_fname); } static int write_temporary_tab_file (FILE *fp, CONFIG_STRUCT *conf) { #define CHUNKSIZE 2048 FILE *out; int bytes_read; int bytes_left; char buffer[CHUNKSIZE]; char file[MAX_PATH + 1]; int newlines = -1; /* does this file contain at least one newline ASCII 10 a Macintosh kludge */ int no_tabs_found = 0; struct stat file_stat; struct stat dir_stat; if(fstat(fileno(fp), &file_stat)) cs_critical_error(ERR_NO_FILE, ""); /* create a directory for the grade book within the courses directory, ** if it doesn't already exist */ snprintf(file, MAX_PATH +1, "%s%s", conf->course_path, GRADE_BOOK_DIR); if(stat(file, &dir_stat)) if(mkdir(file, 0770)) cs_critical_error(ERR_MKDIR_FAILED,file); snprintf(file, MAX_PATH +1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADES_NEW_TAB_FNAME); out = fopen(file, "w"); if (!out) cs_critical_error(ERR_FOPEN_WRITE_FAILED, file); bytes_left = file_stat.st_size; bytes_read = CHUNKSIZE; while (bytes_left) { if (bytes_left < CHUNKSIZE) bytes_read = bytes_left; if (fread (buffer, bytes_read, 1, fp) != 1) cs_critical_error(ERR_FREAD_FAILED, file); if (newlines == -1) newlines = has_newlines (buffer, bytes_read, &no_tabs_found); /* do this once */ if (!newlines) /* assume it's a macintosh file and convert */ cr_to_nl (buffer, bytes_read); bytes_left -= bytes_read; if (fwrite (buffer, bytes_read, 1, out) != 1) cs_critical_error(ERR_FWRITE_FAILED, file); } fclose (out); if(no_tabs_found) return 1; return 0; #undef CHUNKSIZE } static void delete_upload_file(CONFIG_STRUCT *conf) { char file[MAX_PATH +1]; snprintf(file, MAX_PATH +1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADES_NEW_TAB_FNAME); unlink(file); } int main () { char course[MAX_PATH + 1]; char key[MAX_KEY + 1]; SESSION user; CONFIG_STRUCT conf; FILE *fp; int error = 0; P_NODE *head =0; cs_cgi_init(); /* shared_cs_util.c */ read_parameters (course, key); read_configuration_file (course, &conf); /* shared_util.c */ validate_key (key, &user, &conf); /* shared_util.c */ if(user.group != FACULTY) cs_critical_error(ERR_REQUEST_DENIED, ""); /* shared_cs_util.h */ cs_set_course_info(&conf); /* shared_cs_util.h */ cs_set_current_time(); /* shared_cs_util.h */ cs_set_back_url( course, key, "grades_fac_menu"); /* shared_cs_util.h */ fp = cgi_filehandle (global_cgi, "grades_file"); /* ClearSilver library */ if(!fp) cs_critical_error(ERR_UPLOAD_FILE, ""); /* shared_cs_util.h */ if(!write_temporary_tab_file(fp,&conf)) cs_critical_error(ERR_GRADES_UPLOAD_FORMAT, ""); /** shared_cs_util.h */ head = build_grade_receiver_list( &conf, &error); if(error) { cs_set_back_url( course, key, "grades_upload_form"); delete_upload_file(&conf); cs_cgi_display ("grade_upload_error", 1); } else { delete_redfiles (head, &conf); /* shared_grade_book_release.c */ deliver_new_file_to_students(&conf, head); rename_temp_tab_file(&conf); printf("Location: %s?crs=%s&id=%s&released=1\n\n", "grades_view", course, key); } cs_cgi_destroy(); return 0; /* exit successfully */ }