#include #include #include #include #include "global.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_read_infofile.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_translate_url.h" #include "manhat-lib/shared_access.h" #include "manhat-lib/shared_spelling_util.h" #include "manhat-lib/shared_teamstring.h" #include "manhat-lib/shared_podcast_util.h" #include "manhat-lib/shared_msg_line.h" #define NOTEAM '!' int find_num_lines( char *buf); static void read_parameters (char *course, char *key, long *offset, int *grp, int *topic, int *reply_to, char *team, int *paste, char *from, char *recipient) { char msg[MAX_FILENAME + 1]; cs_get_required_parameter ("crs", course, MAX_PATH); /* shared_cs_util.c */ cs_get_required_parameter ("id", key, MAX_KEY); /* shared_cs_util.c */ cs_get_required_parameter ("from", from, MAX_PATH); /* shared_cs_util.c */ cs_get_required_parameter ("grp", msg, MAX_FILENAME); /* shared_cs_util.c */ *grp = atoi (msg); if (!group_uses_topic (*grp)) /* shared_news_util.c */ { *topic = -1; *reply_to = -1; cs_set_value("no_topic_type","1"); } else { cs_get_required_parameter ("topic", msg, MAX_FILENAME); /* shared_cs_util.c */ *topic = atoi (msg); cs_get_required_parameter ("reply_to", msg, MAX_FILENAME); /* shared_cs_util.c */ *reply_to = atoi (msg); } /** now get the optional parameters */ cs_get_optional_parameter ("loc", msg, MAX_FILENAME); /* shared_cs_util.c */ if (!*msg) /* loc param not found, assume not a reply */ *offset = -1; /* -1 means this is not a reply */ else *offset = atol (msg); cs_get_optional_parameter ("paste", msg, MAX_FILENAME); /* shared_cs_util.c */ if (!*msg) *paste = 0; /* not pasting */ else *paste = 1; /* we are pasting from clipboard */ cs_get_optional_parameter ("team", msg, MAX_FILENAME); /* shared_cs_util.c */ if (!*msg) *team = NOTEAM; else *team = *msg; cs_get_optional_parameter ("to", recipient, MAX_USERNAME); /* shared_cs_util.c */ } static void get_topic_subject (int topic, char *subject, char *topic_sender, char *topic_realname) { int fd; FILE *fp; char inbox_path[MAX_PATH + 1]; int found = 0; CENTRAL_INBOX_RECORD msg; *subject = '\0'; *topic_sender = '\0'; *topic_realname = '\0'; snprintf (inbox_path, MAX_PATH + 1, "%s/%s", central_discussion_path, INBOX_FNAME); fp = fopen(inbox_path,"r"); if(!fp) return; fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ while(!found && (fread(&msg,sizeof(CENTRAL_INBOX_RECORD),1,fp) == 1)) if ((msg.info.reply_to == -1) && (msg.info.msg_id == topic)) { found = 1; strncpy (subject, msg.info.subject, MAX_SUBJECT + 1); strncpy (topic_sender, msg.info.sender, MAX_USERNAME + 1); strncpy (topic_realname, msg.info.sender_realname, MAX_NAME + 1); } release_lock(fd); /* shared_lock.c */ fclose(fp); } static void set_basic_new_memo_data (char *course, char *key, int grp, int topic, int reply_to, char team, char *from, char *recipient, CONFIG_STRUCT *conf, SESSION *user) { int empty_clipboard; char topic_subject[MAX_SUBJECT + 1]; char translated_from[MAX_PATH + 1]; char topic_author_username[MAX_USERNAME + 1]; /* username of person who started topic */ char topic_author_realname[MAX_NAME + 1]; /* real name "" "" */ char temp[20]; char *realname; cs_set_course_info(conf); /* shared_cs_util.c */ cs_set_current_time(); /* shared_cs_util.c */ /** clipboard_empty() is in shared_clipboard_utils.c */ empty_clipboard = (user->group != FACULTY) || clipboard_empty (user->username, conf->course_path, user); /*** for use in the back button *****/ translate_url_substitutes (translated_from, from, MAX_PATH + 1, 1); /* shared_translate_url.c */ cs_set_value("back_url", translated_from); /* shared_cs_util.c */ if (topic != -1) get_topic_subject (topic, topic_subject, topic_author_username, topic_author_realname); insert_spell_check_button(conf); /* shared_spelling_util.c */ cs_set_int_value("emoticons_disabled", EMOTICONS_DISABLED(conf->misc)? 1 : 0); cs_set_value("crs", course); cs_set_value("id", key); cs_set_int_value("grp", grp); cs_set_int_value("topic", topic); cs_set_int_value("reply_to", reply_to); cs_set_value("from", from); cs_set_int_value("msg.textarea.hard_wrap", USE_TEXTAREA_HARD_WRAP); /* custom.h */ if (team != NOTEAM) { snprintf(temp, 2, "%c", team); cs_set_value("team", temp); get_team_name(team, temp); /* shared_teamstring.c */ cs_set_value("team_name", temp); } if(strlen(recipient)) cs_set_value("to", recipient); else if ((grp == ASSIGNMENTS) && (topic != -1)) cs_set_value("to", topic_author_username); if (!empty_clipboard) cs_set_int_value("content_clipboard", 1); /* shared_cs_util.c */ if (topic == -1) cs_set_int_value("topic_assign", grp == ASSIGNMENTS? 1: 0); /* shared_cs_util.c */ else { if ((grp == ASSIGNMENTS) && (user->group == FACULTY) && strlen(recipient) ) { realname = hdf_get_value(global_cgi->hdf, "Query.realname", 0); if(realname) cs_set_value("feedbackto_realname", realname); /* shared_cs_util.c */ cs_set_value("feedbackto_recipient", recipient); /* shared_cs_util.c */ } cs_set_value("topic_subject", topic_subject); /* shared_cs_util.c */ cs_set_value("topic_author_realname", topic_author_realname); /* shared_cs_util.c */ cs_set_value("topic_author_username", topic_author_username); /* shared_cs_util.c */ } } static void set_new_memo_attachments (int add_note, CONFIG_STRUCT *conf, int allow_hotpot_exam) { if (add_note) cs_set_int_value("attach.add_note", 1); /* shared_cs_util.c */ if(allow_hotpot_exam) cs_set_int_value("attach.allow_hotpot_exam", 1); /* shared_cs_util.c */ cs_set_int_value("attach.max_files", conf->mail_attachments); /* shared_cs_util.c */ } /** reads the message data for msg at offset into CENTRAL_INBOX_RECORD *msg ***/ static void read_inbox_record (long offset, CENTRAL_INBOX_RECORD *msg) { int fd; FILE *fp; char inbox_path[MAX_PATH + 1]; snprintf (inbox_path, MAX_PATH + 1, "%s/%s", central_discussion_path, INBOX_FNAME); *(inbox_path + MAX_PATH) = '\0'; fp = fopen(inbox_path,"r"); if(!fp) cs_critical_error(ERR_FOPEN_READ_FAILED, inbox_path); fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ if (fseek (fp, offset, SEEK_SET)) cs_critical_error (ERR_FSEEK_FAILED, inbox_path); /* shared_cs_util.c */ if (fread(msg, sizeof(CENTRAL_INBOX_RECORD),1,fp) != 1) cs_critical_error (ERR_FREAD_FAILED, inbox_path); /* shared_cs_util.c */ release_lock(fd); /* shared_lock.c */ fclose(fp); } /* creates a textarea field which is one char wider than the longest line ** of the message to allow for insertion of > char */ static void set_reply_textarea (const char *sender_username, const char *msg_fname, int grp, CONFIG_STRUCT *conf) { FILE *fp; char fullpath[MAX_PATH + 1]; struct stat file_stat; char *buf = 0, *add_reply_mark = 0; int longest; snprintf (fullpath, MAX_PATH + 1, "%s/%s/%s/%s/%s", conf->course_path, PEOPLE_DIR,sender_username, discussion_fname, msg_fname); *(fullpath + MAX_PATH) = '\0'; if(stat(fullpath, &file_stat)) cs_critical_error(ERR_STAT_FAILED, fullpath); /* shared_cs_util.c */ buf = (char*)malloc( (file_stat.st_size + 1) * sizeof(char) ); if(!buf) cs_critical_error( ERR_MALLOC_FAILED, "set_reply_textarea()"); /* shared_cs_util.c */ if(file_stat.st_size) /* if the file is not empty */ { fp = fopen (fullpath, "r"); if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, fullpath); /* shared_cs_util.c */ if(fread(buf, file_stat.st_size, 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, fullpath); /* shared_cs_util.c */ fclose (fp); } *(buf + file_stat.st_size) = '\0'; remove_smart_quotes(buf); /* shared_msg_line.c */ longest = find_longest_line(buf, conf); /* shared_news_util.c */ cs_set_int_value("msg.textarea.cols", longest + 1); /* shared_cs_util.c */ longest = find_num_lines(buf); /* shared_news_util.c */ add_reply_mark = add_mark_to_msg(buf, longest); /* shared_news_util.c */ cs_set_value("msg.textarea.body", add_reply_mark); /* shared_cs_util.c */ if(buf) free(buf); if(add_reply_mark) free(add_reply_mark); } void handle_podcast_attached_files() { #define MAX_TMP_NAME 50 ATTACHMENT_NODE *aptr; int attachment_count = 0; char extension[MAX_FILENAME +1], name[MAX_TMP_NAME +1], value[MAX_PATH]; for ( aptr = attachment_head; aptr; aptr = aptr->next) { get_extension(aptr->data.orig_fname, extension); /* shared_news_util.c */ if(is_valid_podcast_file_extension(extension)) { snprintf(name, MAX_TMP_NAME + 1, "attach.file.%d.value", attachment_count); snprintf(value, MAX_PATH, "%s::%s", aptr->data.orig_fname, aptr->data.unique_fname); cs_set_value(name, value); snprintf(name, MAX_TMP_NAME + 1, "attach.file.%d.orig", attachment_count); cs_set_value(name, aptr->data.orig_fname); /* shared_cs_util.c */ attachment_count++; } } if(attachment_count) { cs_set_int_value("has_attach", 1); /* shared_cs_util.c */ cs_set_value("attach.type", "pasted_files"); /* shared_cs_util.c */ } #undef MAX_TMP_NAME } static int do_paste (int topic, int *files_attached, SESSION *user, int grp, CONFIG_STRUCT *conf) { #define MAX_TMP_NAME 30 char name[MAX_TMP_NAME + 1]; char value[MAX_PATH + 1]; CLIPBOARD_INFO clipboard_info; char clipboard_path[MAX_PATH + 1]; ATTACHMENT_NODE *aptr; int i; int hotpot_exam; /* are we trying to paste a Hot Potatoes exam? */ char *clip_subject = 0; *files_attached = 0; /* assume this to start */ if (user->group != FACULTY) cs_critical_error (ERR_REQUEST_DENIED, ""); /* shared_cs_util.c */ if (get_clipboard_info (&clipboard_info, clipboard_path, user)) /* shared_read_infofile.c */ return 1; /* clipboard is empty */ cs_set_int_value("do_clipboard", 1); /* shared_cs_util.c */ *files_attached = clipboard_info.attachments; /* print clipboard subject but must replace quotes " with " */ clip_subject = replace_quot(clipboard_info.subject); /* shared_news_util.c */ cs_set_value("msg.subject.value", clip_subject); /* shared_cs_util.c */ if(clip_subject) free(clip_subject); /* handle textarea - shared_news_util.c */ do_paste_textarea (clipboard_path, clipboard_info.msg_fname, clipboard_info.sender_username, clipboard_info.sender_realname, user, conf); if (attachment_head) { if(grp == PODCASTS) handle_podcast_attached_files(); else { cs_set_int_value("has_attach", 1); /* shared_cs_util.c */ hotpot_exam = clipboard_info.website_attached && is_hotpot_exam_dir(attachment_head->data.unique_fname); /* shared_news_util.c */ if(hotpot_exam && !allow_hotpot_exam_post(user,grp,topic)) /* shared_news_util.c */ cs_set_int_value("attach.not_allow", 1); /* shared_cs_util.c */ else { if(clipboard_info.website_attached) { cs_set_value("attach.type", "pasted_website"); /* shared_cs_util.c */ cs_set_int_value("attach.website", 1); /* shared_cs_util.c */ cs_set_int_value("attach.value", 1); /* shared_cs_util.c */ } else { cs_set_value("attach.type", "pasted_files"); /* shared_cs_util.c */ cs_set_int_value("attach.value", clipboard_info.attachments); /* shared_cs_util.c */ } } for (i = 1, aptr = attachment_head; aptr; aptr = aptr->next, i++) { snprintf(name, MAX_TMP_NAME + 1, "attach.file.%d.value", i-1); snprintf(value, MAX_PATH, "%s::%s", aptr->data.orig_fname, aptr->data.unique_fname); cs_set_value(name, value); if( (i == 1) && clipboard_info.website_attached ) { snprintf(name, MAX_TMP_NAME + 1, "attach.file.%d.type", i-1); if(hotpot_exam) cs_set_int_value(name, 0); /* lang.news_new_memo.attach.type.0 = attached hot potato exam */ else cs_set_int_value(name, 1); /* lang.news_new_memo.attach.type.1 = attached website */ } else { snprintf(name, MAX_TMP_NAME + 1, "attach.file.%d.orig", i-1); cs_set_value(name, aptr->data.orig_fname); /* shared_cs_util.c */ } } } } free_attachment_list (); return 0; /* paste successful */ #undef MAX_TMP_NAME } static void set_new_memo_form_data (char *course, char *key, long offset, int grp, int topic, int reply_to, char team, int paste, char *from, char *recipient, CONFIG_STRUCT *conf, SESSION *user) { CENTRAL_INBOX_RECORD inbox; char reply_subject[MAX_SUBJECT + 1]; int paste_failed = 0; int files_attached = 0; int allow_hotpot_exam; /* should form allow attachment of a Hot Potatoes exam? */ char *subject = 0; set_basic_new_memo_data (course, key, grp, topic, reply_to, team, from, recipient, conf, user); /* If this is a teacher posting a new topic, put in ** a 'hide message' checkbox */ if ( (user->group == FACULTY) && (topic == -1) ) cs_set_int_value("include_mark_hidden_option", 1); /* shared_cs_util.c */ /* handle subject */ cs_set_int_value("msg.subject.max", MAX_SUBJECT-1); if (paste) paste_failed = do_paste (topic, &files_attached, user, grp, conf); if (!paste || paste_failed) { if ((offset == -1) || paste_failed) /* i.e. if this is not a reply */ cs_set_int_value("msg.textarea.cols", editor_width_config(conf->misc)); /* shared_news_util.c */ else /* this is a reply */ { /* read the data for this message */ read_inbox_record (offset, &inbox); /* handle subject */ cs_set_int_value("msg.subject.add_re", 1); strncpy (reply_subject, inbox.info.subject, MAX_SUBJECT - 1); /* Internet Explorer has a problem since it ignores the maxlength=xxx value for an field if the length of value is > maxlength. The following chops off three characters from the end of the string to allow for the addition of "Re:" to the beginning of the string */ *(reply_subject + MAX_SUBJECT - 1 - 3) = '\0'; cs_set_int_value("msg.subject.max", MAX_SUBJECT -1); cs_set_int_value("msg.subject.size", MAX_SUBJECT -1); /* print subject but must replace quotes " with " */ subject = replace_quot(reply_subject); /* shared_news_util.c */ cs_set_value("msg.subject.value", subject); if(subject) free(subject); /* handle textarea */ set_reply_textarea (inbox.info.sender, inbox.info.msg_fname, grp, conf); cs_set_value("msg.textarea.feedback", inbox.info.sender_realname); cs_set_value("msg.textarea.feedback_newline", "\n \n"); } /* else: this is a reply */ } /* deal with the attachment area */ allow_hotpot_exam = allow_hotpot_exam_post(user,grp, topic); /* shared_news_util.c */ set_new_memo_attachments (files_attached, conf, allow_hotpot_exam); } /* Faculty using the team teach module must send along the 'team' parameter so we know who to send the ** msgs to. Others who send the 'team' parameter are imposters and should be stopped ** ** also, only FACULTY can post to some groups **/ static void check_imposter (char team, int grp, SESSION *user, int topic, const char *recipient) { /** only FACULTY can create new topics in the assignments module */ if((topic == -1) && (grp == ASSIGNMENTS) && (user->group != FACULTY)) cs_critical_error (ERR_REQUEST_DENIED, ""); /** non-blank recipient is OK only for FACULTY in ASSIGNMENTS module and non-topic */ if(strlen(recipient) && ((grp != ASSIGNMENTS) || (topic == -1)) ) cs_critical_error (ERR_REQUEST_DENIED, ""); if (faculty_only_group (grp) /* shared_news_util.c */ && user->group != FACULTY) cs_critical_error (ERR_REQUEST_DENIED, ""); if ((user->group == FACULTY) && (grp == TEAM_TEACH)) { if (team == NOTEAM) cs_critical_error (ERR_PARAM_MISSING, "team"); } else if (team != NOTEAM) cs_critical_error (ERR_REQUEST_DENIED, ""); } 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=? optional cmd line */ int grp; /* from grp=? cmd line */ int topic; /* from topic=? command line */ int reply_to; /* from reply_to=? command line */ char from[MAX_PATH + 1]; /* from from=? command line */ char team; /* from [optional] team=? command line */ int paste; /* from [optional] paste=? command line */ char recipient[MAX_USERNAME + 1]; /* from [optional] to=? command line */ SESSION user; CONFIG_STRUCT conf; cs_cgi_init(); /* shared_cs_util.c */ read_parameters (course, key, &offset, &grp, &topic, &reply_to, &team, &paste, from, recipient); read_configuration_file (course, &conf); /* shared_util.c */ validate_key (key, &user, &conf); /* shared_util.c */ if(!has_write_permission(&user, &conf)) /* shared_access.c */ access_denied_error(); /* only FACULTY can address a message to someone other than themselves ** that happens in the assignments module */ if(strlen(recipient) && (user.group != FACULTY) && strcmp(recipient,user.username)) cs_critical_error(ERR_REQUEST_DENIED, ""); set_discussion_names (conf.course_path, user.username, grp); /* shared_news_util.c */ cs_set_int_value("grp", grp); /* shared_cs_util.c */ check_imposter (team, grp, &user, topic, recipient); set_new_memo_form_data (course, key, offset, grp, topic, reply_to, team, paste, from, recipient, &conf, &user); cs_cgi_display("news_new_memo", 1); /* shared_cs_util.c */ cs_cgi_destroy(); /* shared_cs_util.c */ return 0; }