#include #include #include #include #include #include #include "global.h" #include "custom.h" #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_cs_util.h" #include "manhat-lib/shared_news_util.h" #include "manhat-lib/shared_clipboard_util.h" #include "manhat-lib/shared_potato_util.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_copy_file.h" #include "manhat-lib/shared_server_string.h" #include "manhat-lib/shared_hotpot_exam_util.h" static void read_parameters (char *course, char *key, char *sender, char *info_fname, int *grp, int *read, long *offset, char *from, char *team, int *inbox, char *student, int *no_frame) { char astring[25]; cs_get_required_parameter ("crs", course, MAX_FILENAME); /* shared_cgi_util.c */ cs_get_required_parameter ("id", key, MAX_KEY); cs_get_required_parameter ("read", astring, 5); /* expecting 0 or 1 */ *read = atoi (astring); cs_get_required_parameter ("sender", sender, MAX_USERNAME); cs_get_required_parameter ("from", from, MAX_FROM); cs_set_value("from", from); cs_get_required_parameter ("grp", astring, 5); *grp = atoi (astring); /* the MAIL group may be sending zero, or one other parameters which indicate ** whether the person is reading the INBOX, INBOX ATTIC, OUTBOX, or OUTBOX ATTIC ** just check for presence or absence of the next two fields */ if (*grp == MAIL) { cs_get_optional_parameter("inbox", astring, 10); *inbox = strlen(astring); } cs_get_required_parameter ("inf", info_fname, MAX_FILENAME); cs_get_required_parameter ("loc", astring, 15); *offset = atol (astring); cs_get_optional_parameter("team", astring, 5); if(strlen(astring)) *team = astring[0]; else *team =0; cs_get_optional_parameter("student", student, MAX_USERNAME); cs_get_optional_parameter("noframe", astring, 5); if(strlen(astring)) *no_frame = 1; } static void mark_as_read (long offset, int grp, CONFIG_STRUCT *conf, SESSION *user) { FILE *fp; int fd; char inbox_path[MAX_PATH + 1]; /* full path to inbox.dat */ CENTRAL_INBOX_RECORD inbox; snprintf (inbox_path, MAX_PATH + 1, "%s%s", central_discussion_path, INBOX_FNAME); fp = fopen (inbox_path, "r+"); if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, ""); fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ if (fseek (fp, offset, SEEK_SET)) cs_critical_error (ERR_FSEEK_FAILED, ""); if (fread (&inbox, sizeof (CENTRAL_INBOX_RECORD), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); release_lock(fd); /* shared_lock.c */ fclose(fp); mark_msg_as_read(&inbox, conf, user); /*shared_news_util.c */ } static void read_inf_file (int grp, const char *sender, const char *info_fname, char *dirname, char *html_index, CONFIG_STRUCT *conf) { char infopath[MAX_PATH + 1]; NEWS_INFO info; INFO post_info; ATTACHMENT attach; FILE *fp; int fd; snprintf (infopath, MAX_PATH + 1, "%speople/%s/%s/%s", conf->course_path, sender, discussion_fname, info_fname); fp = fopen (infopath, "r"); if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, ""); fd = fileno(fp); get_shared_lock(fd,1); /*shared_lock.c */ /** the data structure for the POST office is different *** from that of other groups **/ if(grp == MAIL) { if (fread (&post_info, sizeof (INFO), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); } else { if (fread (&info, sizeof (NEWS_INFO), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); } if (fread (&attach, sizeof (ATTACHMENT), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); release_lock(fd); /* shared_lock.c */ fclose (fp); strncpy (dirname, attach.unique_fname, MAX_FILENAME + 1); strncpy (html_index, attach.orig_fname, MAX_FILENAME + 1); } static void read_clipboard_inf_file (char *clipboard_path, char *dirname, char *html_index, SESSION *user) { char infopath[MAX_PATH + 1]; CLIPBOARD_INFO info; ATTACHMENT attach; FILE *fp; snprintf (clipboard_path, MAX_PATH + 1, "%s%s/", CLIPBOARD_PATH, user->id); snprintf (infopath, MAX_PATH + 1, "%s%s/%s", CLIPBOARD_PATH, user->id, CLIPBOARD_INF_FNAME); fp = fopen (infopath, "r"); if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, ""); if (fread (&info, sizeof (CLIPBOARD_INFO), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); if (fread (&attach, sizeof (ATTACHMENT), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); fclose (fp); strncpy (dirname, attach.unique_fname, MAX_FILENAME + 1); strncpy (html_index, attach.orig_fname, MAX_FILENAME + 1); } static int create_potato_symlink(const char *sender, const char *dirname, const char *html_index, char *symlink_fname, const char *info_fname, const char *course, const char *key, CONFIG_STRUCT *conf, SESSION *user) { char source_base[MAX_PATH + 1]; char dest_base[MAX_PATH + 1]; char html_path[MAX_PATH + 1]; char new_html_path[MAX_PATH + 1]; char temp_path[MAX_PATH + 1]; char oldname[MAX_PATH + 1]; char newname[MAX_PATH + 1]; FILE *fp; struct stat buf; char *buffer; /* the source_base is the teacher's selftest directory */ snprintf (source_base, MAX_PATH + 1, "%speople/%s/%s/", conf->course_path, sender, discussion_fname); /* the dest_base is THIS person's selftest directory */ snprintf (dest_base, MAX_PATH + 1, "%speople/%s/%s/", conf->course_path, user->username, discussion_fname); /* path to original HTML file stored in the teacher's selftest directory */ snprintf (html_path, MAX_PATH + 1, "%s%s/%s", source_base, dirname, html_index); /* path to temporary file we'll write now in this user's directory */ snprintf (temp_path, MAX_PATH + 1, "%s%s", dest_base, HOTPOT_TMP_FNAME); /* how large is the html file ? */ if (stat (html_path, &buf)) cs_critical_error (ERR_STAT_FAILED, ""); /* allocate an extra byte for a terminating null */ buffer = (char *) malloc( (buf.st_size + 1) * sizeof(char)); if(!buffer) cs_critical_error (ERR_MALLOC_FAILED, ""); fp = fopen (html_path, "r"); if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, ""); /* read the whole html file in one gulp */ if (fread (buffer, buf.st_size, 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); fclose(fp); /* now open the temporary file for writing */ fp = fopen (temp_path, "w"); if(!fp) cs_critical_error (ERR_FOPEN_WRITE_FAILED , ""); /* this function will write the modified html file, if the original ** file meets the CGI enabled hot potato criteria */ if(!process_cgi_enabled_potato(buffer,buf.st_size, course, key, sender, info_fname, html_index, "AttachedWebsite", ALIAS, fp)) /* ALIAS is #defined in custom.h */ { fclose(fp); unlink(temp_path); free(buffer); return 0; } /* still here? then the html file was a CGI-enabled hot potato quiz ** and the modified html file has been written to the temporary file **/ fclose(fp); free(buffer); kill_hotpotato_directory(user->username, conf); /* shared_potato_util.c */ copy_dir(source_base, dest_base, /* shared_copy_file.c */ dirname, HOTPOT_TMP_DIRNAME); snprintf(new_html_path,MAX_PATH + 1, "%s%s/%s", dest_base, HOTPOT_TMP_DIRNAME, html_index); copy_file(temp_path,new_html_path); /* shared_copy_file.c */ unlink(temp_path); /* oldname must be expressed relative to the images/links directory ** thus, the leading ../ */ snprintf (oldname, MAX_PATH + 1, "../%s%s", dest_base, HOTPOT_TMP_DIRNAME); get_symlink_fname(course, symlink_fname, user); /* shared_util.c */ /* note next that the path for 'newname' is relative to the bin directory */ snprintf (newname, MAX_PATH + 1, "../images/links/%s", symlink_fname); remove_stale_symlinks (user->username, course, conf->access); if (symlink (oldname, newname)) cs_critical_error (ERR_SYMLINK_FAILED, ""); return 1; } static void create_symlink (const char *crs, const char *sender, const char *key, const char *info_fname, char *html_index, char *symlink_fname, int grp, CONFIG_STRUCT *conf, SESSION *user) { char dirname[MAX_FILENAME + 1]; char oldname[MAX_PATH + 1]; char newname[MAX_PATH + 1]; int done = 0; read_inf_file (grp, sender, info_fname, dirname, html_index, conf); /* Next is to protect against students trying to use this ** program to view the source XML for a Hot Potatoes exam. ** If this is a hot potatoes exam, and the user is not a teacher, ** print an obscure error message and exit **/ if( (strstr(dirname, HOTPOT_EXAM_DIR_PREFIX) == dirname) /* test for hot pot exam */ && (user->group != FACULTY)) cs_critical_error(ERR_GENERAL_ERROR, ""); if (grp == SELFTEST) done = create_potato_symlink(sender,dirname,html_index,symlink_fname, info_fname, crs, key, conf, user); else if(grp == ASSIGNMENTS) { create_hotpot_exam_symlink(conf->course_path, sender, dirname, user, crs, symlink_fname, conf->access); /*shared_hotpot_exam_util.c */ done = 1; } if(!done) /* do ordinary symlink */ { /* oldname must be expressed relative to the images/links directory ** thus, the leading ../ */ snprintf (oldname, MAX_PATH + 1, "../%s%s", discussion_path, dirname); get_symlink_fname(crs, symlink_fname, user); /* note next that the path for 'newname' is relative to the bin directory */ snprintf (newname, MAX_PATH + 1, "../images/links/%s", symlink_fname); remove_stale_symlinks (user->username, crs, conf->access); if (symlink (oldname, newname)) cs_critical_error (ERR_SYMLINK_FAILED, ""); } } static void create_clipboard_symlink (const char *crs, const char *sender, const char *key, const char *info_fname, char *html_index, char *symlink_fname, int grp, SESSION *user, int access) { char clipboard_path[MAX_PATH + 1]; char dirname[MAX_FILENAME + 1]; char oldname[MAX_PATH + 1]; char newname[MAX_PATH + 1]; read_clipboard_inf_file (clipboard_path, dirname, html_index, user); /* oldname must be expressed relative to the images/links directory ** thus, the leading ../ */ snprintf (oldname, MAX_PATH + 1, "../%s%s", clipboard_path, dirname); get_symlink_fname( crs, symlink_fname, user); /* note next that the path for 'newname' is relative to the bin directory */ snprintf (newname, MAX_PATH + 1, "../images/links/%s", symlink_fname); remove_stale_symlinks (user->username, crs, access); if (symlink (oldname, newname)) cs_critical_error (ERR_SYMLINK_FAILED, ""); } void send_frameset (const char *symlink_fname, const char *html_index, const char *course, const char *key, long offset, int grp, const char *from, char team, int inbox, const char *student, int no_frame) { char server_string[MAX_PATH + 1]; char url[MAX_PATH + 1]; get_server_string(server_string, MAX_PATH + 1); /* shared_server_string.c */ cs_set_value("server_name", server_string); if (team) snprintf (url, MAX_PATH +1, "%s?crs=%s&id=%s&loc=%ld&grp=%d&from=%s&team=%c%s", "web_page_back", course, key, offset, grp, from, team, no_frame == 1 ? "&noframe=1":""); else if (grp == MAIL) snprintf (url, MAX_PATH +1, "%s?crs=%s&id=%s&loc=%ld&grp=%d&from=%s%s", "web_page_back", course, key, offset, grp, from, inbox ? "&inbox=yes" : ""); else if(strlen(student)) snprintf (url, MAX_PATH +1, "%s?crs=%s&id=%s&loc=%ld&grp=%d&student=%s&from=%s%s", "web_page_back", course, key, offset, grp, student, from, no_frame==1 ? "&noframe=1":""); else snprintf (url, MAX_PATH +1, "%s?crs=%s&id=%s&loc=%ld&grp=%d&from=%s%s", "web_page_back", course, key, offset, grp, from, no_frame==1?"&noframe=1":""); cs_set_value("top_url", url); /** bottom_url is the content. Need to check for special case. If the "html_index" is set *** to the value ZIP_LECTERN_START_FNAME, this is a Lectern II RealAudio lecture. The bottom *** frame must point to the CGI program "lectern_handler" to deliver this content ***/ if(!strcmp(html_index,ZIP_LECTERN_START_FNAME)) snprintf(url, MAX_PATH + 1, "%s?link=%s", "lectern_handler", symlink_fname); else snprintf(url, MAX_PATH +1, "%s%slinks/%s/%s", server_string, IMAGE_PATH, symlink_fname, html_index); cs_set_value("bottom_url", url); } int main (void) { char course[MAX_PATH + 1]; /* from crs=? command line */ char key[MAX_KEY + 1]; /* from id=? command line */ char sender[MAX_USERNAME + 1]; /* from sender=? command line */ char info_fname[MAX_FILENAME + 1]; /* from inf=? command line */ int grp; /* from grp=? command line */ int read; /* from read=? command line */ long offset; /* from loc=? command line */ char from[MAX_FROM]; /* from from=? command line .. this is different than usual because ** this time 'from' indicates where the caller is from, not where ** the caller is... */ char team; /* optional parameter sent here when faculty is reading a msg * in the team_teach module */ char student[MAX_USERNAME + 1]; /* optional parameter sent when person is reading a msg via assign_read */ int inbox = 0, no_frame=0; /* this might appear on cmd line if grp == MAIL * */ char html_index[MAX_FILENAME + 1]; /*name of html file to start */ char symlink_fname[MAX_FILENAME + 1]; SESSION user; CONFIG_STRUCT conf; /* the configuration read from config file */ cs_cgi_init(); read_parameters (course, key, sender, info_fname, &grp, &read, &offset, from, &team, &inbox, student, &no_frame); read_configuration_file (course, &conf); /* shared_util.c */ validate_key (key, &user, &conf); /* shared_util.c */ set_discussion_names (conf.course_path, sender, grp); /* shared_news_util.c */ if(grp == CLIPBOARD) create_clipboard_symlink (course, sender, key, info_fname, html_index, symlink_fname, grp, &user, conf.access); else create_symlink (course, sender, key, info_fname, html_index, symlink_fname, grp, &conf, &user); if ((grp != CLIPBOARD) && (grp != MAIL) && !read) mark_as_read (offset, grp, &conf, &user); cs_set_int_value("grp", grp); cs_set_course_info(&conf); send_frameset (symlink_fname, html_index, course, key, offset, grp, from, team, inbox,student, no_frame); cs_cgi_display("web_page_start", 1); cs_cgi_destroy(); return 0; }