#include #include /* for stat() */ #include #include #include /* for tolower() */ #include /* for mktemp() */ #include /* for opendir() */ #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_translate_url.h" #include "manhat-lib/shared_file_util.h" #include "manhat-lib/shared_access.h" #include "manhat-lib/shared_bio.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_post_outbox.h" #include "manhat-lib/shared_post_inbox.h" #include "manhat-lib/shared_msg_line.h" static char inbox_path[MAX_PATH + 1]; /* full path to inbox.dat */ PERSON_NODE *person_head = 0; ATTACHMENT_NODE *attachment_head = 0; static void read_parameters (char *course, char *key, long *offset,int *del_link, int *printer_friendly, int *fixed_font) { char off_set[MAX_FILENAME + 1]; /* for holding the long value */ cs_get_required_parameter ("crs", course, MAX_PATH); /* shared_cgi_util.c */ cs_get_required_parameter ("id", key, MAX_KEY); /* just check if the "del_link" parameter is there */ cs_get_optional_parameter ("del_link", off_set, 5); *del_link = strlen(off_set); cs_get_required_parameter ("loc", off_set, 10); *offset = atol (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? 1: 0; } static int multiple_recipients (SESSION *user) { PERSON_NODE *pptr; for (pptr = person_head; pptr; pptr = pptr->next) if (((pptr->data.how_received == CC) || (pptr->data.how_received == TO)) && strcmp (user->username, pptr->data.username)) return 1; return 0; } static void get_previous_offset (long offset, long *prev_offset, int *found, int show_user_hidden) { FILE *fp; INBOX_RECORD data; fp = fopen (inbox_path, "r"); /* inbox_path is global top of this file */ if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, inbox_path); get_shared_lock(fileno(fp), 1); /* shared_lock.c */ *prev_offset = offset; *found = 0; do { *prev_offset = (*prev_offset - sizeof (INBOX_RECORD)); if (*prev_offset < 0) { *found = 0; release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); return; } fseek (fp, *prev_offset, SEEK_SET); fread (&data, sizeof (INBOX_RECORD), 1, fp); if(data.newfile_info.how_sent != DELETED) *found = show_user_hidden || !data.is_sleepy; if (*found) { release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); } } while (!*found); } static void get_next_offset (long offset, long *next_offset, int *found, int show_user_hidden) { FILE *fp; INBOX_RECORD data; fp = fopen (inbox_path, "r"); /* inbox_path is global top of this file */ if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, ""); get_shared_lock(fileno(fp), 1); /* shared_lock.c */ fseek (fp, offset, SEEK_SET); fread (&data, sizeof (INBOX_RECORD), 1, fp); /* read THIS record */ *found = 0; while (!*found && fread (&data, sizeof (INBOX_RECORD), 1, fp) == 1) if(data.newfile_info.how_sent != DELETED) *found = show_user_hidden || !data.is_sleepy; if (*found) *next_offset = ftell (fp) - sizeof (INBOX_RECORD); release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); } static void set_command_button_urls (char *course, char *key, long offset, NEWS_FILTER * filter, SESSION *user, int can_write) { long next_offset, prev_offset; int found; char fromstring[MAX_FROM + 1]; char url[MAX_PATH + 1]; snprintf(url, MAX_PATH, "%s?crs=%s&id=%s","post_inbox", course, key); cs_set_value("post_inbox_url", url); cs_set_value("back_url", url); snprintf (url, MAX_PATH, "%s?crs=%s&id=%s", "post_outbox",course, key); cs_set_value("post_outbox_url", url); snprintf (url, MAX_PATH, "%s?crs=%s&id=%s", "main_menu", course, key); cs_set_value("main_menu_url", url); snprintf (fromstring, MAX_FROM + 1, "%s%ccrs%c%s%cid%c%s%cloc%c%ld", "post_read_inbox", QMARK_SUB, EQUAL_SUB, course, AMP_SUB, EQUAL_SUB, key, AMP_SUB, EQUAL_SUB, offset); /* new memo button is activated only if can_write is true */ if(can_write) { snprintf (url,MAX_PATH, "%s?crs=%s&id=%s&from=%s", "post_new_memo", course, key, fromstring); cs_set_value("new_memo_url", url); } /* reply button is active only if can_write is true */ if(can_write) { snprintf (url, MAX_PATH, "%s?crs=%s&id=%s&from=%s&loc=%ld&grp=0", "post_new_memo", course, key, fromstring, offset); cs_set_value("reply_url", url); } /* group reply button */ if (multiple_recipients (user)) { if(can_write) { snprintf (url, MAX_PATH, "%s?crs=%s&id=%s&from=%s&loc=%ld&grp=1", "post_new_memo", course, key, fromstring, offset); cs_set_value("group_reply_url", url); } } /* forward button, only if can_write */ if(can_write) { snprintf (url, MAX_PATH, "%s?crs=%s&id=%s&src=1&from=%s&loc=%ld", "post_forward_mail", course, key, fromstring, offset); cs_set_value("forward_url", url); } if (filter->oldest_first) get_next_offset (offset, &next_offset, &found, filter->show_user_hidden); else get_previous_offset (offset, &next_offset, &found, filter->show_user_hidden); if(can_write) { snprintf (url, MAX_PATH, "%s?crs=%s&id=%s&loc=%ld&next=%ld", "post_delete", course, key, offset, found ? next_offset : -1); cs_set_value("delete_url", url); } if (found) { snprintf (url, MAX_PATH, "%s?crs=%s&id=%s&loc=%ld", "post_read_inbox", course, key, next_offset); cs_set_value("next_msg_url", url); } if (filter->oldest_first) get_previous_offset (offset, &prev_offset, &found, filter->show_user_hidden); else get_next_offset (offset, &prev_offset, &found, filter->show_user_hidden); if (found) { snprintf (url, MAX_PATH, "%s?crs=%s&id=%s&loc=%ld", "post_read_inbox", course, key, prev_offset); cs_set_value("prev_msg_url", url); } snprintf (url, MAX_PATH, "%s?crs=%s&id=%s&loc=%ld&from=%s", "post_inbox_info", course, key, offset, fromstring); cs_set_value("info_url", url); } /* reads the inbox file and then the corresponding *.inf file, to get everything ** ready to be displayed **/ static void process_inbox_record (long offset, INBOX_RECORD * inbox, INFO * infofile_info, int *website_attached, CONFIG_STRUCT *conf, SESSION *user) { char infopath[MAX_PATH + 1]; FILE *fp; ATTACHMENT_NODE *aptr = 0; PERSON_NODE *pptr = 0; int i; PERSON person_buffer; snprintf (inbox_path, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR,user->username, MAIL_DIR, INBOX_FNAME); fp = fopen (inbox_path, "r+"); if (!fp) cs_critical_error (ERR_FOPEN_APPEND_FAILED, inbox_path); get_exclusive_lock(fileno(fp), 1); /* shared_lock.c */ if (fseek (fp, offset, SEEK_SET)) cs_critical_error (ERR_FSEEK_FAILED, inbox_path); if (fread (inbox, sizeof (INBOX_RECORD), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, inbox_path); /* don't mark messages as read if we are in capture mode */ if (!inbox->time_read && conf->access != ACCESS_CAPTURE) { inbox->time_read = time (NULL); mark_sender_files_read (inbox, conf, user); /* shared_post_outbox.c */ fseek (fp, offset, SEEK_SET); if (fwrite (inbox, sizeof (INBOX_RECORD), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, inbox_path); } release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); snprintf (infopath, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, inbox->newfile_info.sender, MAIL_DIR,inbox->newfile_info.info_fname); fp = fopen (infopath, "r"); if (!fp) cs_critical_error (ERR_FOPEN_READ_FAILED, infopath); get_shared_lock(fileno(fp), 1); /* shared_lock.c */ if (fread (infofile_info, sizeof (INFO), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, infopath); /* process attachments */ *website_attached = (infofile_info->no_attachments == -1); if (*website_attached) infofile_info->no_attachments = 1; /* since we have to pick up the dirname */ for (i = 1; i <= infofile_info->no_attachments; i++) { if (!attachment_head) { attachment_head = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE)); if (!attachment_head) cs_critical_error (ERR_MALLOC_FAILED, ""); aptr = attachment_head; } else { aptr->next = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE)); if (!aptr->next) cs_critical_error (ERR_MALLOC_FAILED, ""); aptr = aptr->next; } if (fread (&aptr->data, sizeof (ATTACHMENT), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, infopath); aptr->next = 0; } /* process list of people msg was sent to */ while (fread (&person_buffer, sizeof (PERSON), 1, fp) == 1) { if (!person_head) { person_head = (PERSON_NODE *) malloc (sizeof (PERSON_NODE)); if (!person_head) cs_critical_error (ERR_MALLOC_FAILED, ""); pptr = person_head; } else { pptr->next = (PERSON_NODE *) malloc (sizeof (PERSON_NODE)); if (!pptr->next) cs_critical_error (ERR_MALLOC_FAILED, ""); pptr = pptr->next; } pptr->data = person_buffer; pptr->next = 0; } release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); } static void read_filter (NEWS_FILTER * filter, CONFIG_STRUCT *conf, SESSION *user) { FILE *fp; char filter_path[MAX_PATH + 1]; snprintf (filter_path, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, user->username, MAIL_DIR, NEWS_FILTER_FNAME); fp = fopen (filter_path, "r"); if (fp) { fread (filter, sizeof (NEWS_FILTER), 1, fp); fclose (fp); } else { filter->oldest_first = 1; filter->show_user_hidden = 1; } } static void set_inbox_msg_data (char *course, char *key, long offset, CONFIG_STRUCT *conf, SESSION *user, int can_write) { INBOX_RECORD inbox; INFO infofile_info; NEWS_FILTER filter; int website_attached; char url[MAX_PATH*2]; char msg_path[MAX_PATH + 1]; read_filter (&filter, conf, user); process_inbox_record (offset, &inbox, &infofile_info, &website_attached, conf, user); cs_set_course_info(conf); cs_set_value("crs", course); cs_set_value("key", key); cs_set_bio_link(inbox.newfile_info.sender,course, conf, key, MAIL, 0, "user", 30); /* shared_bio.c */ set_command_button_urls (course, key, offset, &filter, user, can_write); /* shared_post_inbox.c */ set_inbox_msg_header_data (&inbox, course, key, website_attached, offset,conf, user, attachment_head, person_head, -1); snprintf (msg_path, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, inbox.newfile_info.sender, MAIL_DIR, infofile_info.msg_fname); set_msg_body_data (msg_path, "", ""); /* shared_msg_line.c */ if(user->group == FACULTY) { cs_set_value("is_faculty", "1"); if (conf->access != ACCESS_CAPTURE) { snprintf (url, MAX_PATH * 2, "%s?crs=%s&id=%s&loc=%ld&grp=%d&inbox=yes", "clipboard_copy", course, key, offset, MAIL); cs_set_value("clipboard_url", url); } } cs_set_int_value("can_write", can_write? 1 : 0); if(conf->access == ACCESS_CAPTURE) cs_set_value("capture_mode", "1"); } void free_person_list (void) { PERSON_NODE *ptr; while (person_head) { ptr = person_head; person_head = person_head->next; free (ptr); } } void free_attachment_list (void) { ATTACHMENT_NODE *ptr; while (attachment_head) { ptr = attachment_head; attachment_head = attachment_head->next; free (ptr); } } 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 */ 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? */ SESSION user; CONFIG_STRUCT conf; /* the configuration read from config file */ int can_write; /* does this user have write permission? */ cs_cgi_init(); read_parameters (course, key, &offset, &del_link, &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 */ cs_set_int_value("printer_friendly", printer_friendly); cs_set_int_value("fixed_font", fixed_font); set_inbox_msg_data (course, key, offset, &conf, &user, can_write); free_person_list (); if (del_link) remove_stale_symlinks (user.username, course, conf.access); /* shared_news_util.c */ free_attachment_list (); cs_set_int_value("is_inbox", 1); /* NOTE: the post_read.cs ClearSilver template is used to process both ** post_read_inbox.c and post_read_outbox.c */ cs_cgi_display("post_read", 1); cs_cgi_destroy(); return 0; }