#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_post_outbox.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_msg_line.h" #define GATHER_ALL "_all_" #define GATHER_UNREAD "_unread_" #define GATHER_LAST "_last_" typedef struct msg_node { OUTBOX_RECORD outbox; 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; char outbox_path[MAX_PATH + 1]; /* full path to outbox.dat */ 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) ==0) strncpy (gather, GATHER_LAST, MAX_PATH + 1); snprintf (topic_prog, MAX_PATH + 1, "%s?crs=%s&id=%s", "post_outbox", 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, ""); } } static int meets_gather_criteria (GATHER_STRUCT * criteria, MSG_NODE * msg) { PERSON_NODE *pptr; switch (criteria->target) { case UNREAD: return (msg->outbox.unread); break; /* show messages that have not been read by one or more people */ case ALL: return 1; break; case USERNAME: for (pptr = msg->person_head; pptr; pptr = pptr->next) { if (!strcmp (pptr->data.username, criteria->username)) return 1; } return 0; 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, SESSION *user) { FILE *fp; char infopath[MAX_PATH + 1]; int i; ATTACHMENT_NODE *aptr = 0; PERSON_NODE *pptr = 0; PERSON person_buffer; msg->attachment_head = 0; msg->person_head = 0; snprintf (infopath, MAX_PATH + 1, "%speople/%s/%s/%s", conf->course_path, user->username, discussion_fname, msg->outbox.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 outbox_path[MAX_PATH + 1]; MSG_NODE *msg_ptr = 0, msg_node; long offset = 0; snprintf (outbox_path, MAX_PATH + 1, "%s/%s", discussion_path, OUTBOX_FNAME); fp = fopen (outbox_path, "r+"); if (fp) { get_exclusive_lock(fileno(fp), 1); /* shared_lock.c */ while (fread (&msg_node.outbox, sizeof (OUTBOX_RECORD), 1, fp) == 1) { if(msg_node.outbox.how_sent != DELETED) { read_inf_file (&msg_node, conf, user); if (meets_gather_criteria (gather_criteria, &msg_node)) { 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_node; msg_ptr->offset = offset; msg_ptr->next = 0; } /* if meets_gather_criteria ... */ } /* if not deleted */ offset = ftell (fp); } /* while fread(... */ release_lock(fileno(fp)); /* shared_lock.c */ 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_OUTBOX_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_OUTBOX_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_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_outbox.c */ set_outbox_msg_header_data (&(msg_ptr->outbox), 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, user->username, 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 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); /* shared_cs_util.c */ cs_set_current_time(); /* shared_cs_util.c */ 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", 0); 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_outbox_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_outbox_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=0&%s", "post_forward_mail", course, key, fromstring); cs_set_value("forward_partial_url", url); } } 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 = 0; 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_OUTBOX program */ SESSION user; CONFIG_STRUCT conf; /* the configuration read from config file */ int can_write; /* does user have write access to this course? */ 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_outbox (&conf, &user); /* shared_post_outbox.c */ #else if(SUPPORT_PRE24_POST_OFFICE_MSGS) update_post_outbox (&conf, &user); /* shared_post_outbox.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_inbox_gather */ cs_cgi_display("post_gather", 0); cs_cgi_destroy(); return 0; }