#include #include #include #include #include #include "global.h" #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_cs_util.h" #include "manhat-lib/shared_access.h" #include "manhat-lib/shared_lock.h" #include "manhat-lib/shared_file_util.h" static void read_parameters (char *course, char *key, long *offset, long *next, int *outbox) { char tmp[30 + 1]; cs_get_required_parameter ("crs", course, MAX_PATH); cs_get_required_parameter ("id", key, MAX_KEY); cs_get_required_parameter ("loc", tmp, 30); *offset = atol(tmp); cs_get_required_parameter ("next", tmp, 30); *next = atol(tmp); cs_get_optional_parameter ("outbox", tmp, 30); *outbox = strlen(tmp)? 1: 0; } static void clear_deleted_times(PERSON_NODE *person_head) { PERSON_NODE *ptr; for(ptr = person_head; ptr; ptr=ptr->next) ptr->data.time_deleted = 0; } static void mark_deleted(const char *deleter_username, PERSON_NODE *person_head) { PERSON_NODE *ptr; time_t now; now = time(NULL); for(ptr = person_head; ptr; ptr=ptr->next) if(!strcmp(ptr->data.username, deleter_username)) ptr->data.time_deleted = now; } /** Has everyone - all of the recipients plus the sender of *** the message deleted the message? *** *** Note if a person has been removed from the classroom, without *** deleting their Post Office messages, those messages can never *** be deleted. **/ static int everyone_deleted(PERSON_NODE *person_head, const char *sender_username, const char *info_fname, int is_outbox, const char *course_path) { PERSON_NODE *ptr; FILE *fp; char outbox_path[MAX_PATH + 1]; OUTBOX_RECORD outbox; int found; int outbox_deleted; /* Check the list of recipients to see ** if there's a recipient who did NOT ** delete the message */ for(ptr=person_head; ptr; ptr=ptr->next) if(!ptr->data.time_deleted) return 0; /* still here? then all recipients have deleted the msg ** Did the sender deleted the message? */ if(is_outbox) /* flag means person running this program from their outbox */ return 1; else /* don't know if sender deleted - need to check his outbox */ { snprintf(outbox_path, MAX_PATH + 1, "%s%s/%s/%s/%s", course_path, PEOPLE_DIR, sender_username, MAIL_DIR, OUTBOX_FNAME); fp = fopen(outbox_path, "r"); if(!fp) return 0; /* don't complain */ get_shared_lock(fileno(fp), 1); /* shared_lock.c */ found = 0; outbox_deleted = 0; while(!found && (fread(&outbox, sizeof(OUTBOX_RECORD), 1, fp) == 1) ) { if(!strcmp(outbox.info_fname, info_fname)) { found = 1; outbox_deleted = outbox.how_sent == DELETED? 1 : 0; } } release_lock(fileno(fp)); fclose(fp); return outbox_deleted; } } static void delete_msg_files(const char *course_path, const char *sender_username, const char *msg_fname, int no_attachments, ATTACHMENT_NODE *attachment_head) { char mail_dir[MAX_PATH + 1]; char filepath[MAX_PATH + 1]; ATTACHMENT_NODE *ptr; snprintf(mail_dir, MAX_PATH + 1, "%s%s/%s/%s", course_path, PEOPLE_DIR, sender_username, MAIL_DIR); /* delete the message file */ snprintf(filepath, MAX_PATH + 1, "%s/%s", mail_dir, msg_fname); unlink(filepath); /* now delete all attachments */ for(ptr=attachment_head; ptr; ptr=ptr->next) { snprintf(filepath, MAX_PATH + 1, "%s/%s", mail_dir, ptr->data.unique_fname); if( (no_attachments == -1) && (ptr == attachment_head) && isdirectory(mail_dir, ptr->data.unique_fname)) /* shared_file_util.c */ kill_directory(filepath); /* shared_file_util.c */ else unlink(filepath); } } static void complete_deletion(const char *sender_username, const char *info_fname, const char *deleter_username, CONFIG_STRUCT *conf, int is_outbox) { INFO infofile_info; char infopath[MAX_PATH + 1]; FILE *fp; ATTACHMENT_NODE *aptr = 0; PERSON_NODE *pptr = 0; int i; PERSON person_buffer; PERSON_NODE *person_head = 0; ATTACHMENT_NODE *attachment_head = 0; snprintf (infopath, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, sender_username, MAIL_DIR, info_fname); fp = fopen (infopath, "r+"); if (!fp) cs_critical_error (ERR_OPENING_INFO, infopath); get_exclusive_lock(fileno(fp),1); /* shared_lock.c */ if (fread (&infofile_info, sizeof (INFO), 1, fp) != 1) cs_critical_error (ERR_READING_INFO, infopath); /* process attachments */ for (i = 1; i <= abs(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_ERROR_READING_ATTACHMENT, 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; } /* now have all information from info file stored */ if(infofile_info.version != VERSION24) /* then this msg was sent with an earlier version of Manhattan */ { clear_deleted_times(person_head); infofile_info.version = VERSION24; } if(!is_outbox) mark_deleted(deleter_username, person_head); if(everyone_deleted(person_head,sender_username,info_fname,is_outbox, conf->course_path)) delete_msg_files(conf->course_path, sender_username, infofile_info.msg_fname, infofile_info.no_attachments, attachment_head); /** now rewrite the info file .... */ if (fseek (fp, 0, SEEK_SET)) cs_critical_error (ERR_FSEEK_FAILED, infopath); if(fwrite(&infofile_info, sizeof(INFO), 1, fp) != 1) cs_critical_error(ERR_FWRITE_FAILED, infopath); for(aptr= attachment_head; aptr; aptr=aptr->next) { if (fwrite (&aptr->data, sizeof (ATTACHMENT), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, infopath); } for(pptr= person_head; pptr; pptr=pptr->next) { if (fwrite (&pptr->data, sizeof (PERSON), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, infopath); } release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); } static void delete_outbox_msg(long offset, CONFIG_STRUCT *conf, const char *username) { FILE *fp; char outbox_path[MAX_PATH + 1]; OUTBOX_RECORD outbox; snprintf(outbox_path, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, username, MAIL_DIR, OUTBOX_FNAME); fp = fopen(outbox_path, "r+"); if(!fp) cs_critical_error(ERR_FOPEN_READ_FAILED, outbox_path); get_exclusive_lock(fileno(fp), 1); /* shared_lock.c */ if (fseek (fp, offset, SEEK_SET)) cs_critical_error (ERR_FSEEK_FAILED, outbox_path); if (fread (&outbox, sizeof (OUTBOX_RECORD), 1, fp) != 1) cs_critical_error (ERR_FREAD_FAILED, outbox_path); outbox.how_sent = DELETED; if(fseek (fp, offset, SEEK_SET)) cs_critical_error (ERR_FSEEK_FAILED, outbox_path); if (fwrite (&outbox, sizeof (OUTBOX_RECORD), 1, fp) != 1) cs_critical_error (ERR_FWRITE_FAILED, outbox_path); release_lock(fileno(fp)); /* shared_lock.c */ fclose(fp); complete_deletion(username, outbox.info_fname, username, conf, 1); } static void delete_inbox_msg(long offset, CONFIG_STRUCT *conf, const char *username) { FILE *fp; char inbox_path[MAX_PATH + 1]; INBOX_RECORD inbox; snprintf(inbox_path, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, username, MAIL_DIR, INBOX_FNAME); fp = fopen(inbox_path, "r+"); if(!fp) cs_critical_error(ERR_FOPEN_READ_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 allow deletions if this message has not been read. ** This can never happen unless someone is hacking around! */ if(!inbox.time_read) access_denied_error(); /* shared_access.c */ inbox.newfile_info.how_sent = DELETED; if(fseek (fp, offset, SEEK_SET)) cs_critical_error (ERR_FSEEK_FAILED, inbox_path); 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); complete_deletion(inbox.newfile_info.sender, inbox.newfile_info.info_fname, username, conf, 0); } 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 outbox; /* from optional outbox=? cmd line */ long next; /* from next=? command line */ SESSION user; CONFIG_STRUCT conf; cs_cgi_init(); read_parameters (course, key, &offset, &next, &outbox); 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 */ if(outbox) delete_outbox_msg(offset, &conf, user.username); else delete_inbox_msg(offset, &conf, user.username); if (next == -1) /* if there is no next item */ printf ("Location: %s?crs=%s&id=%s\n\n", outbox?"post_outbox":"post_inbox", course, key); else printf ("Location: %s?crs=%s&id=%s&loc=%ld\n\n", outbox?"post_read_outbox":"post_read_inbox", course, key, next); cs_cgi_destroy(); return 0; }