#include #include #include /* for mktemp() */ #include "global.h" #include "custom.h" /* for date FORMAT strings */ #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_read_infofile.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_post_inbox.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_cs_util.h" #include "manhat-lib/shared_news_util.h" #include "manhat-lib/shared_fold_file.h" RECEIVER_NODE *to_head = 0; RECEIVER_NODE *cc_head = 0; RECEIVER_NODE *bcc_head = 0; FILE_NODE *file_head = 0; /*list of attached files */ int attachments = 0; /* how many files are attached? */ static void read_parameters (char *course, char *key, char *fromprog, int *fwd_files, char *fwd_sender, char *fwd_inf_fname, int *width) { char temp[25]; cs_get_required_parameter ("crs", course, MAX_PATH); cs_get_required_parameter ("id", key, MAX_KEY); cs_get_required_parameter ("from", fromprog, MAX_PATH); cs_get_required_parameter ("width", temp, 20); *width = atoi(temp); /* check if there MAY BE some files forwarded */ cs_get_optional_parameter ("files", temp, 24); if(strlen(temp)) *fwd_files = atoi (temp); else *fwd_files = 0; if (*fwd_files) /* if files are to be forwarded, these parameters are cs_get_required_parameterd */ { cs_get_required_parameter ("sender", fwd_sender, MAX_USERNAME); cs_get_required_parameter ("inf", fwd_inf_fname, MAX_FILENAME); } } static void verify_non_empty (CONFIG_STRUCT *conf) { char to[MAX_PATH +1]; FILE *fp; int i; char name[MAX_PATH +1]; char filename[MAX_PATH +1]; struct stat buf; int has_attachments = 0; cs_get_required_parameter("to",to, MAX_PATH); cs_get_required_parameter("subject",to, MAX_PATH); for(i =1; i <= conf->mail_attachments; i++) { snprintf(name, MAX_PATH, "file%d", i); cs_get_optional_parameter(name, filename, MAX_PATH); if(strlen(filename)) { fp = cgi_filehandle(global_cgi, name); if(fstat(fileno(fp), &buf)) cs_critical_error (ERR_STAT_FAILED, filename); if(buf.st_size ==0) cs_critical_error (ERR_EMPTY_FILE, filename); has_attachments = 1; } } if(has_attachments) check_incomplete_upload(); /* shared_news_util.c */ } static int in_to_list (char *username) { RECEIVER_NODE *ptr; for (ptr = to_head; ptr; ptr = ptr->next) if (!strcmp (ptr->username, username)) return 1; return 0; } static int in_cc_list (char *username) { RECEIVER_NODE *ptr; for (ptr = cc_head; ptr; ptr = ptr->next) if (!strcmp (ptr->username, username)) return 1; return 0; } /*** SHOULD THIS FUNCTION BE SCRAPPED? *** BCC's haven't been used in years ***/ void clean_bcc_list () { RECEIVER_NODE *ptr, *ptr2; ptr = bcc_head; while (ptr) if (in_to_list (ptr->username) || in_cc_list (ptr->username)) { if (ptr == bcc_head) { ptr2 = ptr; bcc_head = bcc_head->next; free (ptr2); ptr = bcc_head; } else { for (ptr2 = bcc_head; ptr2->next != ptr; ptr2 = ptr2->next); ptr2->next = ptr->next; free (ptr); ptr = ptr2->next; } } else ptr = ptr->next; } static void clean_cc_list () { RECEIVER_NODE *ptr, *ptr2; ptr = cc_head; while (ptr) if (in_to_list (ptr->username)) { if (ptr == cc_head) { ptr2 = ptr; cc_head = cc_head->next; free (ptr2); ptr = cc_head; } else { for (ptr2 = cc_head; ptr2->next != ptr; ptr2 = ptr2->next); ptr2->next = ptr->next; free (ptr); ptr = ptr2->next; } } else ptr = ptr->next; } static void build_receiver_lists () { create_rec_list ("to", &to_head); create_rec_list ("cc", &cc_head); clean_cc_list (); } static void free_receiver_lists () { RECEIVER_NODE *ptr; while (to_head) { ptr = to_head; to_head = to_head->next; free (ptr); } while (cc_head) { ptr = cc_head; cc_head = cc_head->next; free (ptr); } while (bcc_head) { ptr = bcc_head; bcc_head = bcc_head->next; free (ptr); } } static void free_file_list (void) { FILE_NODE *ptr; while (file_head) { ptr = file_head; file_head = file_head->next; free (ptr); } } static void get_unique_fname (char *unique_fname, const char *ext, time_t * time_sent, CONFIG_STRUCT *conf, SESSION *user) { static int n = 0; char timestring[MAX_TIMESTRING + 1]; char filedir[MAX_PATH + 1]; char filepath[MAX_PATH + 1]; snprintf (filedir, MAX_PATH + 1, "%s%s/%s/%s/", conf->course_path, PEOPLE_DIR, user->username, MAIL_DIR); strftime (timestring, MAX_TIMESTRING, "%m%d%Y%H%M%S", localtime (time_sent)); do { n++; snprintf (unique_fname, MAX_FILENAME + 1, "%s%d%d.%s", timestring, n, getpid(),ext); snprintf (filepath, MAX_PATH + 1, "%s%s", filedir, unique_fname); } while (file_exists(filepath)); /* shared_file_util.c */ } /*static void get_orig_fname (const char *full_orig_name, char *orig_fname) { char *ptr; ptr = strrchr (full_orig_name, '\\'); if (ptr) strncpy (orig_fname, ptr + 1, MAX_PATH + 1); else { ptr = strrchr (full_orig_name, '/'); if (ptr) strncpy (orig_fname, ptr + 1, MAX_PATH + 1); else strncpy (orig_fname, full_orig_name, MAX_PATH + 1); } } */ static void get_system_filenames (const char *full_orig_name, char *unique_fname, char *orig_fname, time_t * time_sent, CONFIG_STRUCT *conf, SESSION *user) { get_unique_fname (unique_fname, "fil", time_sent, conf, user); get_orig_fname (full_orig_name, orig_fname); } static void add_to_file_list (const char *unique_fname, const char *orig_fname) { FILE_NODE *ptr; if (!file_head) { file_head = (FILE_NODE *) malloc (sizeof (FILE_NODE)); if (!file_head) cs_critical_error (ERR_MALLOC_FAILED, ""); ptr = file_head; } else { for (ptr = file_head; ptr->next; ptr = ptr->next); ptr->next = (FILE_NODE *) malloc (sizeof (FILE_NODE)); if (!ptr->next) cs_critical_error (ERR_MALLOC_FAILED, ""); ptr = ptr->next; } strncpy (ptr->unique_fname, unique_fname, MAX_PATH + 1); strncpy (ptr->orig_fname, orig_fname, MAX_PATH + 1); ptr->next = (FILE_NODE *) 0; } static void write_cgi_post_file (FILE *infp, off_t size, const char *unique_fname, CONFIG_STRUCT *conf, SESSION *user) { #define CHUNKSIZE 2048 FILE *outfp; char filepath[MAX_PATH + 1]; int bytes_read; int bytes_left; char buffer[CHUNKSIZE]; snprintf (filepath, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, user->username, MAIL_DIR, unique_fname); outfp = fopen (filepath, "w"); if (!outfp) cs_critical_error (ERR_FOPEN_WRITE_FAILED, filepath); bytes_left = size; bytes_read = CHUNKSIZE; while (bytes_left) { if (bytes_left < CHUNKSIZE) bytes_read = bytes_left; if (fread (buffer, bytes_read, 1, infp) != 1) cs_critical_error (ERR_FREAD_FAILED, "in write_cgi_file()"); bytes_left -= bytes_read; if (fwrite (buffer, bytes_read, 1, outfp) != 1) cs_critical_error (ERR_FWRITE_FAILED, filepath); } fclose (outfp); #undef CHUNKSIZE } static void create_link (const char *sender, const char *fwd_unique_fname, const char *unique_fname, CONFIG_STRUCT *conf, SESSION *user) { char linkdir[MAX_PATH + 1]; char current_dir[MAX_PATH + 1]; char oldpath[MAX_PATH + 1]; if(!getcwd(current_dir, MAX_PATH + 1)) cs_critical_error(ERR_GETCWD_FAILED, "in create_link()"); *(current_dir + MAX_PATH) = '\0'; snprintf (linkdir, MAX_PATH + 1, "%s%s/%s/%s", conf->course_path,PEOPLE_DIR, user->username, MAIL_DIR); if (chdir (linkdir) == -1) cs_critical_error (ERR_CHDIR_FAILED, linkdir); snprintf (oldpath, MAX_PATH + 1, "../../%s/%s/%s", sender, MAIL_DIR, fwd_unique_fname); if (link (oldpath, unique_fname) == -1) cs_critical_error (ERR_SYMLINK_FAILED, oldpath); /** PROBLEM ... the next line assumes too much! */ if (chdir (current_dir) == -1) cs_critical_error (ERR_ERROR_CHDIR_TO_BIN, current_dir); } void process_forwarded_files (time_t * time_sent, int fwd_files, char *fwd_sender, char *fwd_inf_fname, CONFIG_STRUCT *conf, SESSION *user) { #define MAX_MSG 80 INFO infofile_info; char varname[20]; int i, found=0; ATTACHMENT_NODE *aptr =0; char fwd_unique_fname[MAX_FILENAME + 1]; char unique_fname[MAX_FILENAME + 1]; read_post_infofile (fwd_sender, fwd_inf_fname, &infofile_info, conf); /* shared_read_infofile.c */ free_person_list (); /* shared_read_infofile.c */ for (i = 1; i <= fwd_files; i++) { snprintf (varname, 20, "f%d", i); cs_get_optional_parameter(varname, fwd_unique_fname, MAX_FILENAME); if(strlen(fwd_unique_fname)) { for (found = 0, aptr = attachment_head; aptr && !found; aptr = aptr->next) { found = !strcmp (aptr->data.unique_fname, fwd_unique_fname); if (found) { get_unique_fname (unique_fname, "fil", time_sent, conf, user); add_to_file_list (unique_fname, aptr->data.orig_fname); create_link(fwd_sender, fwd_unique_fname, unique_fname, conf, user); attachments++; } } if (!found) cs_critical_error (ERR_UNIQUE_FNAME_NOT_FOUND, "in process_forwared_files()"); } } free_attachment_list (); /* shared_read_infofile.c */ #undef MAX_MSG } static void process_attached_files (time_t * time_sent, CONFIG_STRUCT *conf, SESSION *user) { char unique_fname[MAX_PATH + 1]; char orig_fname[MAX_PATH + 1]; char name[MAX_PATH + 1]; char filename[MAX_PATH + 1]; int i; struct stat buf; FILE *fp; for(i =1; i<= conf->mail_attachments; i++) { snprintf(name, MAX_PATH, "file%d", i); cs_get_optional_parameter(name, filename, MAX_PATH); if(strlen(filename)) { fp = cgi_filehandle(global_cgi, name); if(fstat(fileno(fp), &buf)) cs_critical_error (ERR_STAT_FAILED, filename); get_system_filenames (filename, unique_fname, orig_fname,time_sent, conf, user); add_to_file_list (unique_fname, orig_fname); write_cgi_post_file (fp, buf.st_size, unique_fname, conf, user); attachments++; } } } static void process_message_file (char *msg_fname, time_t * time_sent, CONFIG_STRUCT *conf, SESSION *user, int width) { char filepath[MAX_PATH+1]; char *msg; FILE *fp; int len; msg = hdf_get_value(global_cgi->hdf, "Query.msg", 0); get_unique_fname (msg_fname, "msg", time_sent, conf, user); snprintf (filepath, MAX_PATH + 1, "%s%s/%s/mail/%s", conf->course_path, PEOPLE_DIR, user->username, msg_fname); fp = fopen(filepath, "w"); if(!fp) cs_critical_error(ERR_FOPEN_WRITE_FAILED, filepath); if(msg && strlen(msg)) { len = strlen(msg); if(len < width || USE_TEXTAREA_HARD_WRAP) { if(fwrite(msg, strlen(msg), 1, fp) != 1) cs_critical_error(ERR_FWRITE_FAILED, filepath); } else write_folded(fp, msg, width); /* shared_fold_file.c */ } fclose(fp); } static void write_info_file (char *msg_fname, char *info_fname, char *subject, time_t time_sent, CONFIG_STRUCT *conf, SESSION *user) { FILE *fp; INFO info; ATTACHMENT attach; PERSON person; FILE_NODE *fptr; RECEIVER_NODE *rptr; char info_path[MAX_PATH + 1]; get_unique_fname (info_fname, "inf", &time_sent, conf, user); cs_get_required_parameter("subject", subject, MAX_SUBJECT); strncpy (info.msg_fname, msg_fname, MAX_FILENAME + 1); strncpy (info.subject, subject, MAX_SUBJECT + 1); info.version = VERSION24; /* flags this as a message sent with the 'new' post office module ** introduced with version 24 */ info.time_sent = time_sent; info.no_attachments = attachments; snprintf (info_path, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR,user->username, MAIL_DIR, info_fname); fp = fopen (info_path, "w"); if (!fp) cs_critical_error (ERR_FOPEN_WRITE_FAILED, info_path); if (fwrite (&info, sizeof (INFO), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, info_path); for (fptr = file_head; fptr; fptr = fptr->next) { strncpy (attach.unique_fname, fptr->unique_fname, MAX_FILENAME + 1); strncpy (attach.orig_fname, fptr->orig_fname, MAX_FILENAME + 1); if (fwrite (&attach, sizeof (ATTACHMENT), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, info_path); } for (rptr = to_head; rptr; rptr = rptr->next) { strncpy (person.username, rptr->username, MAX_USERNAME + 1); strncpy (person.realname, rptr->realname, MAX_NAME + 1); person.how_received = TO; person.time_read = 0; person.time_deleted = 0; if (fwrite (&person, sizeof (PERSON), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, info_path); } for (rptr = cc_head; rptr; rptr = rptr->next) { strncpy (person.username, rptr->username, MAX_USERNAME + 1); strncpy (person.realname, rptr->realname, MAX_NAME + 1); person.how_received = CC; person.time_read = 0; person.time_deleted = 0; if (fwrite (&person, sizeof (PERSON), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, info_path); } for (rptr = bcc_head; rptr; rptr = rptr->next) { strncpy (person.username, rptr->username, MAX_USERNAME + 1); strncpy (person.realname, rptr->realname, MAX_NAME + 1); person.how_received = BCC; person.time_read = 0; person.time_deleted = 0; if (fwrite (&person, sizeof (PERSON), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, info_path); } fclose (fp); } static void update_inboxes (NEWFILE_RECORD * newinfo, RECEIVE_TYPE t, const char *course_path) { RECEIVER_NODE *rptr; char inbox_path[MAX_PATH + 1]; rptr = (t == TO ? to_head : t == CC ? cc_head : bcc_head); newinfo->how_received = t; for (; rptr; rptr = rptr->next) { snprintf (inbox_path, MAX_PATH + 1, "%s%s/%s/%s/%s", course_path,PEOPLE_DIR, rptr->username, MAIL_DIR, INBOX_FNAME); add_new_post_msg(newinfo, inbox_path); /* shared_post_inbox.c */ } } void update_all_inboxes (char *inf_fname, char *subject, time_t time_sent, CONFIG_STRUCT *conf, SESSION *user) { NEWFILE_RECORD newinfo; strncpy (newinfo.sender, user->username, MAX_USERNAME + 1); strncpy (newinfo.sender_realname, user->realname, MAX_NAME + 1); newinfo.how_sent = NEWMSG; strncpy (newinfo.subject, subject, MAX_SUBJECT + 1); newinfo.time_sent = time_sent; newinfo.attachments = attachments; strncpy (newinfo.info_fname, inf_fname, MAX_FILENAME + 1); update_inboxes (&newinfo, TO, conf->course_path); update_inboxes (&newinfo, CC, conf->course_path); update_inboxes (&newinfo, BCC, conf->course_path); } static void back_up (char *program) { char temp[MAX_PATH + 1]; translate_url_substitutes (temp, program, MAX_PATH + 1, 0); /* shared_cgi_util.c */ printf ("Location: %s\n\n", temp); } static void record_in_outbox (const char *inf_fname, const char *subject, time_t time_sent, CONFIG_STRUCT *conf, SESSION *user) { OUTBOX_RECORD outbox; FILE *fp; RECEIVER_NODE *rptr; int i; char outbox_fname[MAX_PATH + 1]; strncpy (outbox.info_fname, inf_fname, MAX_FILENAME + 1); strncpy (outbox.subject, subject, MAX_SUBJECT + 1); outbox.time_sent = time_sent; /* build list of up to MAX_TO recipients, each recipient name separated by ** vertical bar character */ *outbox.to = '\0'; for (rptr = to_head, i = 1; rptr && i <= MAX_TO; rptr = rptr->next, i++) { if (i > 1) strcat (outbox.to, "|"); strcat (outbox.to, rptr->realname); } if (rptr) /* if we did not finish list */ strcat (outbox.to, "|"); /* then end list with a vertical bar */ outbox.how_sent = NEWMSG; outbox.is_sleepy = 0; outbox.unread = 1; outbox.attachments = attachments; /* defined globally in this file */ snprintf (outbox_fname, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, user->username, MAIL_DIR, OUTBOX_FNAME); fp = fopen (outbox_fname, "a"); if (!fp) cs_critical_error (ERR_FOPEN_APPEND_FAILED, outbox_fname); get_exclusive_lock(fileno(fp), 1); /* shared_lock.c */ if (fwrite (&outbox, sizeof (OUTBOX_RECORD), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, outbox_fname); release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); } int main (void) { char course[MAX_PATH + 1]; /* from crs=? command line */ char key[MAX_KEY + 1]; /* from id=? command line */ char from[MAX_PATH + 1]; /* from from=? command line */ char msg_fname[MAX_FILENAME + 1]; /* name given to the message */ char inf_fname[MAX_FILENAME + 1]; /* the info file name */ time_t time_sent; char subject[MAX_SUBJECT + 1]; int width; int fwd_files; /* derived from files=? cmd line */ char fwd_sender[MAX_USERNAME + 1]; /* from sender = ? cmd line */ char fwd_inf_fname[MAX_FILENAME + 1]; /* from inf=? cmd line */ SESSION user; CONFIG_STRUCT conf; cs_cgi_init(); read_parameters (course, key, from, &fwd_files, fwd_sender, fwd_inf_fname, &width); 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(); /* shared_access.c */ verify_non_empty (&conf); /* make sure message is not empty */ build_receiver_lists (); /* who to send to */ time_sent = time (NULL); process_message_file (msg_fname, &time_sent, &conf, &user, width); if (fwd_files) process_forwarded_files (&time_sent, fwd_files, fwd_sender, fwd_inf_fname, &conf, &user); process_attached_files (&time_sent, &conf, &user); write_info_file (msg_fname, inf_fname, subject, time_sent, &conf, &user); update_all_inboxes (inf_fname, subject, time_sent, &conf, &user); record_in_outbox (inf_fname, subject, time_sent, &conf, &user); free_receiver_lists (); free_file_list (); back_up (from); cs_cgi_destroy(); return 0; }