#include #include #include #include /* for tolower() */ #include #include #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_post_inbox.h" #include "manhat-lib/shared_translate_url.h" /* for AMP_SUB, et. al */ #include "manhat-lib/shared_access.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_post_outbox.h" #include "manhat-lib/shared_msg_line.h" #define GATHER_ALL "_all_" #define GATHER_UNREAD "_unread_" #define GATHER_LAST "_last_" typedef struct msg_node { INBOX_RECORD inbox; INFO infofile_info; ATTACHMENT_NODE *attachment_head; PERSON_NODE *person_head; int number_recipients; int website_attached; long offset; struct msg_node *next; } MSG_NODE; MSG_NODE *msg_head = 0; typedef enum gather_type { UNREAD, ALL, USERNAME, LAST } GATHER_TYPE; typedef struct gather_struct { char username[MAX_USERNAME + 1]; char realname[MAX_NAME + 1]; GATHER_TYPE target; } GATHER_STRUCT; static void read_parameters (char *course, char *key, char *gather, int *del_link, char *topic_prog, int *printer_friendly, int *fixed_font) { char tmp[MAX_FILENAME + 1]; /* the long offset value,etc */ cs_get_required_parameter ("crs", course, MAX_FILENAME); cs_get_required_parameter ("id", key, MAX_KEY); cs_get_optional_parameter ("gather", gather, MAX_PATH); if( !strlen(gather)) strncpy (gather, GATHER_LAST, MAX_PATH + 1); snprintf (topic_prog, MAX_PATH + 1, "%s?crs=%s&id=%s", "post_inbox", course, key); /* just check if the "del_link" parameter is there */ cs_get_optional_parameter ("del_link", tmp, 5); *del_link = strlen(tmp); /* provide printer-friendly version? */ cs_get_optional_parameter ("print", tmp, 5); /* shared_cs_util.c */ *printer_friendly = *tmp? (atoi(tmp)? 1 : 0) : 0; /* provide preformatted text (instead of proportional) ? */ cs_get_optional_parameter ("fixed", tmp, 5); /* shared_cs_util.c */ *fixed_font = *tmp? (atoi(tmp)? 1 : 0) : 0; } static void parse_gather_string (char *gather, GATHER_STRUCT * gather_target) { char *ptr; *gather_target->username = '\0'; *gather_target->realname = '\0'; if (!strcmp (gather, GATHER_ALL)) gather_target->target = ALL; else if (!strcmp (gather, GATHER_UNREAD)) gather_target->target = UNREAD; else if (!strcmp (gather, GATHER_LAST)) gather_target->target = LAST; else { ptr = strchr (gather, ':'); if (ptr) { *ptr = '\0'; strncpy (gather_target->username, gather, MAX_USERNAME); strncpy (gather_target->realname, ptr + 1, MAX_NAME); *ptr = ':'; gather_target->target = USERNAME; } else cs_critical_error (ERR_GATHER_PARSE_ERROR, gather); } } static int meets_gather_criteria (GATHER_STRUCT * criteria, INBOX_RECORD * msg) { switch (criteria->target) { case UNREAD: return (msg->time_read == 0); break; case ALL: return 1; break; case USERNAME: return (!strcmp (msg->newfile_info.sender, criteria->username)); break; case LAST: default: cs_critical_error (ERR_UNKNOWN_GATHER_TYPE, ""); break; } return 0; } static void memory_error () { cs_critical_error (ERR_MALLOC_FAILED, ""); } static void read_inf_file (MSG_NODE * msg, CONFIG_STRUCT *conf) { FILE *fp; char infopath[MAX_PATH + 1]; int i; ATTACHMENT_NODE *aptr = 0; PERSON_NODE *pptr = 0; PERSON person_buffer; snprintf (infopath, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, msg->inbox.newfile_info.sender, discussion_fname, msg->inbox.newfile_info.info_fname); fp = fopen (infopath, "r"); if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, ""); get_shared_lock(fileno(fp), 1); /* shared_lock.c */ if (fread (&msg->infofile_info, sizeof (INFO), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); /* process attachments, build linked list */ msg->website_attached = (msg->infofile_info.no_attachments == -1); if (msg->website_attached) msg->infofile_info.no_attachments = 1; /* since we have to pick up the dirname */ for (i = 1; i <= msg->infofile_info.no_attachments; i++) { if (!msg->attachment_head) { msg->attachment_head = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE)); if (!msg->attachment_head) memory_error (); aptr = msg->attachment_head; } else { aptr->next = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE)); if (!aptr->next) memory_error (); aptr = aptr->next; } if (fread (&aptr->data, sizeof (ATTACHMENT), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, ""); aptr->next = 0; } /* for .. */ /* process list of people msg was sent to */ msg->number_recipients = 0; while (fread (&person_buffer, sizeof (PERSON), 1, fp) == 1) { if (!msg->person_head) { msg->person_head = (PERSON_NODE *) malloc (sizeof (PERSON_NODE)); if (!msg->person_head) memory_error (); pptr = msg->person_head; } else { pptr->next = (PERSON_NODE *) malloc (sizeof (PERSON_NODE)); if (!pptr->next) memory_error (); pptr = pptr->next; } msg->number_recipients++; pptr->data = person_buffer; pptr->next = 0; } release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); } static void build_new_list (GATHER_STRUCT * gather_criteria, CONFIG_STRUCT *conf, SESSION *user) { FILE *fp; char inbox_path[MAX_PATH + 1]; INBOX_RECORD msg; MSG_NODE *msg_ptr = 0; long offset = 0; snprintf (inbox_path, MAX_PATH + 1, "%s/%s", discussion_path, INBOX_FNAME); fp = fopen (inbox_path, "r+"); if (fp) { get_exclusive_lock(fileno(fp), 1); while (fread (&msg, sizeof (INBOX_RECORD), 1, fp) == 1) { if ( (msg.newfile_info.how_sent != DELETED) && meets_gather_criteria (gather_criteria, &msg)) { if (!msg_head) { msg_head = (MSG_NODE *) malloc (sizeof (MSG_NODE)); if (!msg_head) memory_error (); msg_ptr = msg_head; } else { msg_ptr->next = (MSG_NODE *) malloc (sizeof (MSG_NODE)); if (!msg_ptr->next) memory_error (); msg_ptr = msg_ptr->next; } msg_ptr->inbox = msg; msg_ptr->offset = offset; msg_ptr->next = 0; msg_ptr->attachment_head = 0; msg_ptr->person_head = 0; read_inf_file (msg_ptr, conf); if (!msg_ptr->inbox.time_read) { msg_ptr->inbox.time_read = time (NULL); mark_sender_files_read (&(msg_ptr->inbox), conf, user); /* shared_post_outbox.c */ if (fseek (fp, offset, SEEK_SET)) cs_critical_error (ERR_FSEEK_FAILED, ""); if (fwrite (&(msg_ptr->inbox), sizeof (INBOX_RECORD), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, ""); } } /* if meets_gather_criteria ... */ offset = ftell (fp); } /* while fread(... */ release_lock(fileno(fp)); fclose (fp); } /* if fp */ } static void last_io_error () { cs_critical_error (ERR_LAST_FILE_IO_ERROR, ""); } static void write_one_message (MSG_NODE * msg_ptr, FILE * fp) { ATTACHMENT_NODE *attach_ptr; PERSON_NODE *person_ptr; if (fwrite (msg_ptr, sizeof (MSG_NODE), 1, fp) != 1) last_io_error (); for (attach_ptr = msg_ptr->attachment_head; attach_ptr; attach_ptr = attach_ptr->next) { if (fwrite (attach_ptr, sizeof (ATTACHMENT_NODE), 1, fp) != 1) last_io_error (); } for (person_ptr = msg_ptr->person_head; person_ptr; person_ptr = person_ptr->next) { if (fwrite (person_ptr, sizeof (PERSON_NODE), 1, fp) != 1) last_io_error (); } } static void write_last_list (GATHER_STRUCT * gather_criteria) { char last_path[MAX_PATH + 1]; FILE *fp; MSG_NODE *msg_ptr; snprintf (last_path, MAX_PATH + 1, "%s%s", discussion_path, GATHER_LAST_INBOX_FNAME); fp = fopen (last_path, "w"); if (!fp) last_io_error (); if (fwrite (gather_criteria, sizeof (GATHER_STRUCT), 1, fp) != 1) last_io_error (); if (gather_criteria->target == UNREAD) { for (msg_ptr = msg_head; msg_ptr; msg_ptr = msg_ptr->next) write_one_message (msg_ptr, fp); } fclose (fp); } static void read_attachment_data (int no_attachments, MSG_NODE * msg_ptr, FILE * fp) { ATTACHMENT_NODE *a_ptr = 0; ATTACHMENT_NODE attach; int i; if (no_attachments == -1) /* -1 flags website attached */ no_attachments = 1; for (i = 1; i <= no_attachments; i++) { if (fread (&attach, sizeof (ATTACHMENT_NODE), 1, fp) != 1) last_io_error (); if (!msg_ptr->attachment_head) { msg_ptr->attachment_head = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE)); if (!msg_ptr->attachment_head) memory_error (); a_ptr = msg_ptr->attachment_head; } else { a_ptr->next = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE)); if (!a_ptr->next) memory_error (); a_ptr = a_ptr->next; } *a_ptr = attach; a_ptr->next = 0; } } static void read_recipient_data (int number_recipients, MSG_NODE * msg_ptr, FILE * fp) { PERSON_NODE *p_ptr = 0; PERSON_NODE person; int i; for (i = 1; i <= number_recipients; i++) { if (fread (&person, sizeof (PERSON_NODE), 1, fp) != 1) last_io_error (); if (!msg_ptr->person_head) { msg_ptr->person_head = (PERSON_NODE *) malloc (sizeof (PERSON_NODE)); if (!msg_ptr->person_head) memory_error (); p_ptr = msg_ptr->person_head; } else { p_ptr->next = (PERSON_NODE *) malloc (sizeof (PERSON_NODE)); if (!p_ptr->next) memory_error (); p_ptr = p_ptr->next; } *p_ptr = person; p_ptr->next = 0; } } static void build_last_list (FILE * fp) { MSG_NODE msg; MSG_NODE *msg_ptr = 0; while (fread (&msg, sizeof (MSG_NODE), 1, fp) == 1) { if (!msg_head) { msg_head = (MSG_NODE *) malloc (sizeof (MSG_NODE)); if (!msg_head) memory_error (); msg_ptr = msg_head; } else { msg_ptr->next = (MSG_NODE *) malloc (sizeof (MSG_NODE)); if (!msg_ptr->next) memory_error (); msg_ptr = msg_ptr->next; } *msg_ptr = msg; msg_ptr->next = 0; msg_ptr->attachment_head = 0; msg_ptr->person_head = 0; if (msg_ptr->infofile_info.no_attachments) read_attachment_data (msg_ptr->infofile_info.no_attachments, msg_ptr, fp); if (msg_ptr->number_recipients) read_recipient_data (msg_ptr->number_recipients, msg_ptr, fp); } } static void read_last_criteria (GATHER_STRUCT * gather_criteria) { char last_path[MAX_PATH + 1]; FILE *fp; snprintf (last_path, MAX_PATH + 1, "%s%s", discussion_path, GATHER_LAST_INBOX_FNAME); fp = fopen (last_path, "r"); if (!fp) last_io_error (); if (fread (gather_criteria, sizeof (GATHER_STRUCT), 1, fp) != 1) last_io_error (); if (gather_criteria->target == UNREAD) build_last_list (fp); fclose (fp); } static void build_message_list (GATHER_STRUCT * gather_criteria, CONFIG_STRUCT *conf, SESSION *user) { if (gather_criteria->target == LAST) { read_last_criteria (gather_criteria); if (gather_criteria->target == UNREAD) return; } build_new_list (gather_criteria, conf, user); write_last_list (gather_criteria); } static void set_common_values (char *course, char *key, int can_write, GATHER_STRUCT * gather_criteria, char *topic_prog, CONFIG_STRUCT *conf) { char fromstring[MAX_PATH + 1]; /* how to get back to THIS page... */ char url[MAX_PATH + 1]; cs_set_course_info(conf); cs_set_current_time(); cs_set_value("back_url", topic_prog); cs_set_value("crs", course); cs_set_value("key", key); cs_set_int_value("can_write", can_write? 1: 0); cs_set_int_value("is_inbox", 1); switch(gather_criteria -> target) { case UNREAD: cs_set_value("gather_target", "UNREAD"); break; case ALL: cs_set_value("gather_target", "ALL"); break; case USERNAME: cs_set_value("gather_target", "USERNAME"); cs_set_value("gather_target_realname", gather_criteria->realname); break; case LAST: cs_set_value("gather_target", "LAST"); break; default: cs_set_value("gather_target", ""); break; /* should never happen? */ } snprintf (fromstring, MAX_PATH + 1, "from=%s%ccrs%c%s%cid%c%s%cgather%c_last_", "post_inbox_gather", QMARK_SUB, EQUAL_SUB, course, AMP_SUB, EQUAL_SUB, key, AMP_SUB, EQUAL_SUB); snprintf (url, MAX_PATH + 1, "%s?crs=%s&id=%s&%s", "post_inbox_info", course, key, fromstring); cs_set_value("info_partial_url", url); if(can_write) { snprintf (url, MAX_PATH + 1, "%s?crs=%s&id=%s&%s", "post_new_memo", course, key, fromstring); cs_set_value("new_memo_url", url); snprintf (url, MAX_PATH + 1, "%s?crs=%s&id=%s&src=1&%s", "post_forward_mail", course, key, fromstring); cs_set_value("forward_partial_url", url); } } static void set_one_message (MSG_NODE * msg_ptr, char *course, char *key, CONFIG_STRUCT *conf, SESSION *user, int can_write, int msg_no) { char msg_path[MAX_PATH + 1]; char name_prefix[30]; /* shared_post_inbox.c */ set_inbox_msg_header_data (&(msg_ptr->inbox), course, key, msg_ptr->website_attached, msg_ptr->offset, conf, user, msg_ptr->attachment_head, msg_ptr->person_head, msg_no); snprintf (msg_path, MAX_PATH + 1, "%s/%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, msg_ptr->inbox.newfile_info.sender, MAIL_DIR, msg_ptr->infofile_info.msg_fname); snprintf(name_prefix, 30, "msg.%d.", msg_no); set_msg_body_data (msg_path, name_prefix, ""); /* shared_msg_line.c */ } static void free_message_list () { MSG_NODE *msg_ptr; ATTACHMENT_NODE *attach_ptr; PERSON_NODE *person_ptr; while (msg_head) { msg_ptr = msg_head; msg_head = msg_head->next; while (msg_ptr->attachment_head) { attach_ptr = msg_ptr->attachment_head; msg_ptr->attachment_head = msg_ptr->attachment_head->next; free (attach_ptr); } while (msg_ptr->person_head) { person_ptr = msg_ptr->person_head; msg_ptr->person_head = msg_ptr->person_head->next; free (person_ptr); } free (msg_ptr); } } static void gather_msgs (char *course, char *key, char *gather, char *topic_prog, CONFIG_STRUCT *conf, SESSION *user, int can_write) { GATHER_STRUCT gather_criteria; MSG_NODE *msg_ptr; int msg_no; parse_gather_string (gather, &gather_criteria); build_message_list (&gather_criteria, conf, user); set_common_values (course, key, can_write, &gather_criteria, topic_prog, conf); for (msg_no = 0, msg_ptr = msg_head; msg_ptr; msg_ptr = msg_ptr->next, msg_no++) { set_one_message (msg_ptr, course, key, conf, user, can_write, msg_no); } cs_set_int_value("msg_count", msg_no); free_message_list (); } int main (void) { char course[MAX_PATH + 1]; /* from crs=? command line */ char key[MAX_KEY + 1]; /* from id=? command line */ char gather[MAX_PATH + 1]; /* from gather=? command line */ int del_link; /* optional command line argument */ int printer_friendly; /* from print=? command line provide "printer friendly" version? */ int fixed_font; /* from fixed=? command line print body as fixed font? */ char topic_prog[MAX_PATH + 1]; /* arguments to POST_INBOX program */ SESSION user; CONFIG_STRUCT conf; /* the configuration read from config file */ int can_write; /* does this user have write access? */ cs_cgi_init(); read_parameters (course, key, gather, &del_link, topic_prog, &printer_friendly, &fixed_font); read_configuration_file (course, &conf); /* shared_util.c */ validate_key (key, &user, &conf); /* shared_util.c */ can_write = has_write_permission(&user, &conf); /* shared_access.c */ set_discussion_names (conf.course_path, user.username, MAIL); /* shared_news_util.c */ /* see custom.h for next */ #ifndef SUPPORT_PRE24_POST_OFFICE_MSGS update_post_inbox (user.username, &conf); /* shared_post_inbox.c */ #else if(SUPPORT_PRE24_POST_OFFICE_MSGS) update_post_inbox (user.username, &conf); /* shared_post_inbox.c */ #endif cs_set_int_value("printer_friendly", printer_friendly); cs_set_int_value("fixed_font", fixed_font); gather_msgs (course, key, gather, topic_prog, &conf, &user, can_write); if (del_link) remove_stale_symlinks (user.username, course, conf.access); /* shared_news_util.c */ /* The 'post_read.lang' file is shared by several programs */ cs_load_lang("post_read"); /* The post_gather ClearSilver template is used by both this program and post_outbox_gather */ cs_cgi_display("post_gather", 0); cs_cgi_destroy(); return 0; }