#include #include #include #include /* for tolower() */ #include "global.h" #include "custom.h" /* for date FORMAT strings */ #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_cs_util.h" #include "manhat-lib/shared_news_util.h" #include "manhat-lib/shared_msg_line.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_translate_url.h" #include "manhat-lib/shared_access.h" #include "manhat-lib/shared_bio.h" SESSION user; CONFIG_STRUCT conf; ATTACHMENT_NODE *attachment_head = 0; /* linked list of file info */ static void read_parameters (char *course, char *key, long *offset, char *from_prog, char *student, int *del_link, int *printer_friendly, int *fixed_font) { char off_set[MAX_FILENAME + 1]; /* for holding the long value, length should be long enough, don't you think? */ cs_get_required_parameter ("crs", course, MAX_PATH); cs_get_required_parameter ("id", key, MAX_KEY); cs_get_required_parameter ("loc", off_set, MAX_FILENAME); *offset = atol (off_set); cs_get_optional_parameter ("from", from_prog, MAX_PATH); cs_get_optional_parameter ("student", student, MAX_USERNAME); cs_get_optional_parameter ("del_link", off_set, 5); *del_link = strlen(off_set); /* provide printer-friendly version? */ cs_get_optional_parameter ("print", off_set, 5); /* shared_cs_util.c */ *printer_friendly = *off_set? 1: 0; /* provide preformatted text (instead of proportional) ? */ cs_get_optional_parameter ("fixed", off_set, 5); /* shared_cs_util.c */ *fixed_font = *off_set? (atoi(off_set)? 1 : 0) : 0; } MSG_TREE_NODE *find_last_node(MSG_TREE_NODE *root) { MSG_TREE_NODE *ptr; ptr = root; for(;;) { for(;ptr->next;ptr=ptr->next); if(!ptr->reply) return ptr; ptr=ptr->reply; } } static void get_previous_msg_offset(MSG_TREE_NODE *msg_ptr, long *offset) { MSG_TREE_NODE *leaf; if(msg_ptr->data.info.reply_to == -1) /* msg is the topic */ *offset = -1; else if( (msg_ptr->prev->reply == msg_ptr) || /* msg was first reply to another msg */ (!msg_ptr->prev->reply)) /* prev. message had no replies */ *offset = msg_ptr->prev->offset; else { leaf = find_last_node(msg_ptr->prev->reply); *offset = leaf->offset; } } static void get_next_msg_offset(MSG_TREE_NODE *msg_ptr, long *offset) { MSG_TREE_NODE *ptr,*last; int done; if(msg_ptr->data.info.reply_to == -1) /* msg is the topic */ *offset = msg_ptr->reply? msg_ptr->reply->offset: - 1; else if(msg_ptr->reply) *offset = msg_ptr->reply->offset; else if(msg_ptr->next) *offset = msg_ptr->next->offset; /* message is a leaf */ else { for(ptr = msg_ptr->prev, last = msg_ptr, done = 0; !done; last=ptr, ptr=ptr->prev) { done = (ptr->data.info.reply_to == -1) || ((ptr->reply == last) && (ptr->next)); if(done) break; } if(ptr->data.info.reply_to == -1) *offset = -1; else *offset = ptr->next->offset; } } static void get_offsets (MSG_TREE_NODE *msg_ptr, long *next_msg_offset, long *prev_msg_offset) { get_previous_msg_offset(msg_ptr,prev_msg_offset); get_next_msg_offset(msg_ptr, next_msg_offset); } static void set_command_urls (MSG_TREE_NODE *msg_ptr, MSG_TREE_NODE *topic_ptr, char *course, char *key, char *from, char *fac_username, char *student, int can_write) { #define LONG_STRING 512 long next_offset, prev_offset; char temp[LONG_STRING + 1]; /*** back button *****/ translate_url_substitutes (temp, from, LONG_STRING + 1, 1); /* shared_translate_url.c */ cs_set_value("back_button_url", temp); /* Main menu */ snprintf (temp, LONG_STRING +1, "%s?crs=%s&id=%s", "main_menu", course, key); cs_set_value("main_menu_url", temp); /**** Back to Topic Index */ snprintf (temp, LONG_STRING +1, "%s?crs=%s&id=%s&grp=%d", "news_topic", course, key, ASSIGNMENTS ); cs_set_value("news_topic_url", temp); /* Data for 'Reply' button */ if ( (msg_ptr == topic_ptr) || !can_write) cs_set_value("reply_url", ""); else { snprintf(temp, LONG_STRING +1, "%s?crs=%s&id=%s&grp=%d&topic=%d&loc=%ld&reply_to=%d&to=%s&from=%s", "news_new_memo", course, key, ASSIGNMENTS, msg_ptr->data.info.topic_id, msg_ptr->offset, msg_ptr->data.info.msg_id,student,from); cs_set_value("reply_url", temp); } /* find next, previous messages */ get_offsets (msg_ptr, &next_offset, &prev_offset); /**** data for read next msg****/ if (next_offset != -1) { snprintf(temp, LONG_STRING +1, "%s?crs=%s&id=%s&loc=%ld&student=%s&from=%s", "assign_read", course, key, next_offset, student, from); cs_set_value("next_msg_url", temp); } /* data for read previous msg */ if (prev_offset != -1) { snprintf (temp, LONG_STRING +1, "%s?crs=%s&id=%s&loc=%ld&student=%s&from=%s", "assign_read", course, key, prev_offset, student, from); cs_set_value("prev_msg_url", temp); } snprintf (temp, LONG_STRING +1, "%s?crs=%s&id=%s&loc=%ld&grp=%d","news_info", course, key, msg_ptr->offset, ASSIGNMENTS); cs_set_value("info_url", temp); /** set flag value and url */ cs_set_int_value("flagged", msg_ptr->user_data.flagged? 1:0); snprintf(temp, LONG_STRING + 1, "%s?crs=%s&id=%s&grp=%d&msg_id=%d&from=assign_read%ccrs%c%s%cid%c%s%cloc%c%ld%cstudent%c%s&from_from=%s", "news_flag", course, key, ASSIGNMENTS, msg_ptr->data.info.msg_id, QMARK_SUB, EQUAL_SUB, course, AMP_SUB, EQUAL_SUB, key, AMP_SUB, EQUAL_SUB, msg_ptr->offset, AMP_SUB, EQUAL_SUB, student, from); cs_set_value("flag_url", temp); #undef LONG_STRING } static void process_msg_node (MSG_TREE_NODE *msg_ptr, int *website_attached, CONFIG_STRUCT *conf, SESSION *user) { FILE *fp; int fd; char infopath[MAX_PATH + 1]; int i; NEWS_INFO infofile_info; ATTACHMENT_NODE *aptr = 0; if(!msg_ptr->user_data.time_read && (conf->access != ACCESS_CAPTURE)) /* if msg is unread and not in capture mode */ { mark_msg_as_read(&(msg_ptr->data),conf,user); /*shared_news_util.c */ } /*** if there are attachments, read the info file to **** build the attachment list ***/ *website_attached = 0; /* assume this to start */ if(msg_ptr->data.info.attachments) { snprintf(infopath,MAX_PATH + 1,"%s%s/%s/%s/%s",conf->course_path,PEOPLE_DIR, msg_ptr->data.info.sender,discussion_fname,msg_ptr->data.info_fname); fp = fopen(infopath,"r"); if(!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, infopath); fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ if(fread( &infofile_info, sizeof(NEWS_INFO), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, infopath); /* process attachments, build linked list */ *website_attached = (infofile_info.attachments == -1); if (*website_attached) infofile_info.attachments = 1; /* since we have to pick up the dirname */ for (i = 1; i <= infofile_info.attachments; i++) { if (!attachment_head) { attachment_head = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE)); if (!attachment_head) cs_critical_error (ERR_MALLOC_FAILED, infopath); aptr = attachment_head; } else { aptr->next = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE)); if (!aptr->next) cs_critical_error (ERR_MALLOC_FAILED, infopath); aptr = aptr->next; } if (fread(&aptr->data, sizeof (ATTACHMENT), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, infopath); aptr->next = 0; } /* for .. */ release_lock(fd); /* shared_lock.c */ fclose (fp); } /* if attachments */ } static void free_attachment_list () { ATTACHMENT_NODE *aptr; while (attachment_head) { aptr = attachment_head; attachment_head = attachment_head->next; free (aptr); } } static void set_news_msg_values (char *course, char *key, long offset, char *from, char *student, CONFIG_STRUCT *conf, SESSION *user, int can_write) { MSG_TREE_NODE *msg_ptr; MSG_TREE_NODE *topic_ptr; int website_attached; int msg_count; time_t current_time; int teacher_hidden; int read_only; char msg_path[MAX_PATH + 1]; char url[MAX_PATH + 1]; build_fac_assign_read_tree(user, offset, student, &msg_ptr, &topic_ptr, &msg_count, ¤t_time); /* shared_news_util.c */ if(!msg_ptr || !tree_head) cs_critical_error(ERR_CANT_FIND_THIS_OFFSET, "set_news_msg_values()"); /* an empty 'from' string indicates that we need to return to the "assign_fac_expand" * program */ if (!strlen (from)) snprintf (from, MAX_PATH + 1, "%s%ccrs%c%s%cid%c%s%ctopic%c%d%cloc%c%ld", "assign_fac_expand", QMARK_SUB,EQUAL_SUB,course, AMP_SUB, EQUAL_SUB,key,AMP_SUB, EQUAL_SUB, msg_ptr->data.info.topic_id,AMP_SUB, EQUAL_SUB, topic_ptr->offset); cs_set_value("from", from); teacher_hidden = is_teacher_hidden (topic_ptr->data.status, topic_ptr->data.release_time, /* shared_news_util.c */ topic_ptr->data.unrelease_time, current_time); read_only = BASIC_STATUS(topic_ptr->data.status) == READ_ONLY ? 1 : 0; /* see global.h */ process_msg_node (msg_ptr, &website_attached, conf, user); /* shared_news_util.c */ set_assign_read_heading_data (msg_ptr, "msg.", topic_ptr, course, key, conf, teacher_hidden, can_write, read_only); set_command_urls (msg_ptr, topic_ptr, course, key, from, user->username, student, can_write); cs_set_bio_link( msg_ptr->data.info.sender,course, conf, key, ASSIGNMENTS, 0, "user", 30); /* shared_bio.c */ /* shared_news_util.c */ set_news_attachment_data (msg_ptr, topic_ptr->data.info.subject, course, key, ASSIGNMENTS, website_attached, "assign_read", user->team, /* but it doesn't really matter */ 0, /* is_fac_teamteach */ student, conf, 0, user->username, attachment_head, ""); /* name prefix is blank */ snprintf (msg_path, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, msg_ptr->data.info.sender, discussion_fname, msg_ptr->data.info.msg_fname); set_msg_body_data(msg_path, "", ""); /* shared_msg_line.c */ /*** The teacher can delete an assignment if no one has yet submitted **** work for the assignment. The teacher can delete other messages **** sent TO students at any time. (this allows him/her to retrieve **** feedback sent to the wrong student. Messages sent by the student **** to the teacher cannot be deleted ***/ if ( (msg_count < 2) || ((msg_ptr->data.info.reply_to != -1) && strcmp(msg_ptr->data.info.sender, msg_ptr->data.info.receiver_username))) { if(can_write) { cs_set_value("insert_kill_form", "1"); } } if(website_attached) { snprintf(url, MAX_PATH + 1, "%s?crs=%s&id=%s&sender=%s&dir=%s&grp=%d", "web_page_zip", course, key, msg_ptr->data.info.sender, attachment_head->data.unique_fname, ASSIGNMENTS); cs_set_value("website_zip_download_url", url); /* shared_cs_util.h */ cs_set_value("website_dirname", attachment_head->data.unique_fname); /* shared_cs_util.h */ } free_msg_tree(tree_head); /*shared_news_util.c */ free_attachment_list (); } int main (void) { char course[MAX_PATH + 1]; /* from crs=? command line */ char key[MAX_KEY + 1]; /* from id=? command line */ long offset; /* from loc=? command line */ char from_prog[MAX_PATH + 1]; /* from from=? command line */ char student_username[MAX_USERNAME + 1]; /* optional command line */ int can_write; int del_link; /* from del_link=?command line do we need to rm a symbolic link ** to an attached web page? */ int printer_friendly; /* from print=? command line provide "printer friendly" version? */ int fixed_font; /* from fixed=? command line print body as fixed font? */ cs_cgi_init(); /* shared_cs_util.c */ read_parameters (course, key, &offset, from_prog, student_username, &del_link, &printer_friendly, &fixed_font); 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.c */ cs_set_value("is_faculty","1"); if(conf.access == ACCESS_CAPTURE) cs_set_value("capture_mode", "1"); /* shared_cs_util.h */ cs_set_int_value("printer_friendly", printer_friendly); cs_set_int_value("fixed_font", fixed_font); can_write = has_write_permission(&user, &conf); /* shared_access.c */ if(can_write) cs_set_value("can_write", "1"); cs_set_course_info(&conf); /* shared_cs_util.c */ cs_set_value("crs", course); /* shared_cs_util.h */ cs_set_int_value("grp", ASSIGNMENTS); /* shared_cs_util.c */ cs_set_value("key", key); /* shared_cs_util.h */ cs_set_value("username",user.username); /* shared_cs_util.h */ if(*student_username) cs_set_value("student_username", student_username); set_discussion_names (conf.course_path, user.username, ASSIGNMENTS); /* shared_news_util.c */ set_news_msg_values (course, key, offset, from_prog, student_username, &conf, &user, can_write); if (del_link) remove_stale_symlinks (user.username, course, conf.access); /*shared_news_util.c */ /* NOTE: this program uses the same lang file as news_read.c **/ cs_load_lang("news_read"); cs_cgi_display("assign_read", 1); /* shared_cs_util.c */ cs_cgi_destroy(); /* shared_cs_util.c */ return 0; }