#include #include #include #include #include #include "../global.h" #include "shared_news_util.h" /* for read_red_file() */ #include "shared_lock.h" #include "shared_cs_util.h" /* for cs_critical_error(), etc */ static void read_update_post_infofile (READ_STRUCT * read_info, int *allread, const char *course_path, const char *username) { FILE *fp; INFO info; ATTACHMENT attachment; int i; char info_fname[MAX_PATH + 1]; long offset; PERSON person; int found = 0; int finished = 0; snprintf (info_fname, MAX_PATH + 1, "%s%s/%s/%s/%s", course_path, PEOPLE_DIR, username, MAIL_DIR, read_info->info_fname); fp = fopen (info_fname, "r+"); if (!fp) cs_critical_error (ERR_ERROR_OPENING_INFO, ""); get_exclusive_lock(fileno(fp),1); /* shared_lock.c */ if (fread (&info, sizeof (INFO), 1, fp) != 1) cs_critical_error (ERR_ERROR_READING_INFO, ""); /** adjust for attached web page **/ if (info.no_attachments == -1) info.no_attachments = 1; for (i = 1; i <= info.no_attachments; i++) fread (&attachment, sizeof (ATTACHMENT), 1, fp); *allread = 1; offset = ftell (fp); while ((fread (&person, sizeof (PERSON), 1, fp) == 1) && !finished) { if (!strcmp (person.username, read_info->reader_username)) { person.time_read = read_info->time_read; fseek (fp, offset, SEEK_SET); fwrite (&person, sizeof (PERSON), 1, fp); found = 1; finished = !*allread; } else if (!person.time_read) { *allread = 0; finished = found; } offset = ftell (fp); } release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); } static void mark_outbox_allread (const char *outbox_fname, READ_STRUCT * read_info) { FILE *fp; long offset; int done = 0; OUTBOX_RECORD outbox; fp = fopen (outbox_fname, "r+"); if (!fp) cs_critical_error (ERR_ERROR_OPENING_OUTBOX, ""); get_exclusive_lock(fileno(fp), 1); /* shared_lock.c */ offset = ftell (fp); while (!done && (fread (&outbox, sizeof (OUTBOX_RECORD), 1, fp) == 1)) { if (!strcmp (outbox.info_fname, read_info->info_fname)) { done = 1; outbox.unread = 0; fseek (fp, offset, SEEK_SET); fwrite (&outbox, sizeof (OUTBOX_RECORD), 1, fp); } offset = ftell (fp); } release_lock(fileno(fp)); /* shared_lock.h */ fclose (fp); } static void process_red_file (const char *red_fname, const char *outbox_fname, CONFIG_STRUCT *conf, SESSION *user) { READ_STRUCT read_info; int allread; read_red_file (red_fname, &read_info); /* shared_news_util.c */ read_update_post_infofile (&read_info, &allread, conf->course_path, user->username); if (allread) mark_outbox_allread (outbox_fname, &read_info); } void update_post_outbox (CONFIG_STRUCT *conf, SESSION *user) { DIR *dir_p; struct dirent *dir_entry_p; char *ptr; char mail_dir[MAX_PATH + 1]; char red_fname[MAX_PATH + 1], del_fname[MAX_PATH + 1]; char outbox_fname[MAX_PATH + 1]; snprintf (mail_dir, MAX_PATH + 1, "%s%s/%s/%s", conf->course_path, PEOPLE_DIR, user->username, MAIL_DIR); snprintf (outbox_fname, MAX_PATH + 1, "%s/%s", mail_dir, OUTBOX_FNAME); dir_p = opendir (mail_dir); if (!dir_p) cs_critical_error (ERR_CANT_OPEN_NEWS_DIR, ""); /**** do *.red files ***/ while (NULL != (dir_entry_p = readdir (dir_p))) { ptr = strstr (dir_entry_p->d_name, ".red"); if (ptr && *(ptr + 4) == '\0') /* i.e. if file ends in .red */ { snprintf (red_fname, MAX_PATH + 1, "%s/%s", mail_dir, dir_entry_p->d_name); process_red_file (red_fname, outbox_fname, conf, user); unlink (red_fname); } else { ptr = strstr (dir_entry_p->d_name, ".del"); if (ptr && *(ptr + 4) == '\0') /* i.e. if file ends in .del */ { snprintf (del_fname, MAX_PATH + 1, "%s/%s", mail_dir, dir_entry_p->d_name); /* don't process the del file, just delete it - transition to version that doesn't use *.del files commented out --> process_del_file (del_fname, outbox_fname, conf, user); */ unlink (del_fname); } } } closedir (dir_p); } /* A Post Office message is marked as read in two places: ** 1 the reader's inbox ** 2 the *.inf file located in the sender's directory ** Additionally, if while doing #2, we find that the message has ** been read by all of the recipients, we need to do: ** 3 Mark the sender's outbox record as completely read. ** ** This function does #2 and #3 above. This used to be accomplished ** by a *.red file to the sender. When the sender entered their outbox, ** they would perform the same task on their own files. */ void mark_sender_files_read (INBOX_RECORD * inbox, CONFIG_STRUCT *conf, SESSION *user) { READ_STRUCT red; int allread; char outbox_fname[MAX_PATH + 1]; /* path to the outbox.dat file of the person who sent the msg */ strncpy (red.info_fname, inbox->newfile_info.info_fname, MAX_FILENAME + 1); strncpy (red.reader_username, user->username, MAX_USERNAME + 1); red.time_read = inbox->time_read; read_update_post_infofile(&red, &allread, conf->course_path, inbox->newfile_info.sender); /* shared_post_outbox.c */ if (allread) { snprintf (outbox_fname, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR, inbox->newfile_info.sender, MAIL_DIR, OUTBOX_FNAME); mark_outbox_allread (outbox_fname, &red); /* shared_post_outbox.c */ } } static int multiple_recipients (SESSION *user, PERSON_NODE *pers_head) { PERSON_NODE *pptr; for (pptr = pers_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 set_msg_value(int index, char *name, char *value) { #define MAX_TMP_NAME 50 char the_name[MAX_TMP_NAME + 1]; if(index < 0) snprintf(the_name, MAX_TMP_NAME + 1, "msg.%s", name); else snprintf(the_name, MAX_TMP_NAME + 1, "msg.%d.%s", index, name); cs_set_value(the_name, value); #undef MAX_TMP_NAME } void set_outbox_msg_header_data (OUTBOX_RECORD * outbox, char *course, char *key, int website_attached, long offset, CONFIG_STRUCT *conf, SESSION *user, ATTACHMENT_NODE *attach_head, PERSON_NODE *pers_head, int index) { #define MAX_TMP_NAME 40 ATTACHMENT_NODE *aptr; PERSON_NODE *pptr; char timestring[MAX_TIMESTRING + 1]; int i; char extension[MAX_FILENAME + 1]; char name[MAX_TMP_NAME]; char url[MAX_PATH * 2]; char *escaped_subject = (char *) 0; /* time the user running this program first opened this message ** Since this is the outbox, that's the same as the time this user ** sent the message */ strftime (timestring, MAX_TIMESTRING, DOW_DATE_TIME_FORMAT, localtime (&outbox->time_sent)); set_msg_value(index, "time_read", timestring); /* did the user mark this message as 'sleepy' or 'hidden' ? */ set_msg_value(index,"is_user_hidden", outbox->is_sleepy? "1": "0"); /* username of person who wrote the message */ set_msg_value(index, "sender", user->username); /* real name of person who wrote the message */ set_msg_value(index, "sender_realname", user->realname); /* set a 'has_multiple_recipients' value ** For inbox msgs, this is used to decide whether ** or not to include a 'group reply' button. ** But this is the outbox... hmm. maybe it'll be of ** some use to someone someday. **/ if(multiple_recipients(user, pers_head)) set_msg_value(index, "has_multiple_recipients", "1"); /* The 'how_sent' value shouldn't be needed, but we'll set values ** for this enumerated type anyway **/ switch(outbox->how_sent) { case NEWMSG: set_msg_value(index, "how_sent", "NEWMSG"); break; case FORWARD: set_msg_value(index, "how_sent", "FORWARD"); break; case REPLY: set_msg_value(index, "how_sent", "REPLY"); break; case GROUP_REPLY: set_msg_value(index, "how_sent", "GROUP_REPLY"); break; case 4: set_msg_value(index, "how_sent", "DELETED"); break; /* because DELETED exists *twice* in global.h */ default: set_msg_value(index, "how_sent", "unknown"); break; } /********* Subject provided in both 'raw' and html escaped versions */ set_msg_value(index, "subject", outbox->subject); escaped_subject = (char *)0; cs_html_escape_string(outbox->subject, &escaped_subject); /* shared_cs_util.c */ if(escaped_subject) { set_msg_value(index, "escaped_subject", (char *)escaped_subject); free(escaped_subject); escaped_subject = (char *) 0; } else /* should never happen */ set_msg_value(index, "escaped_subject", outbox->subject); /* time the message was sent */ strftime (timestring, MAX_TIMESTRING, DOW_DATE_TIME_FORMAT, localtime (&outbox->time_sent)); set_msg_value(index, "time_sent", timestring); /* how many attachments are there? */ snprintf(url, MAX_PATH * 2, "%d", outbox->attachments); set_msg_value(index, "attachments", url); /* name of the 'info' file */ set_msg_value(index, "info_fname", outbox->info_fname); /* offset value */ snprintf(timestring, MAX_TIMESTRING, "%ld", offset); set_msg_value(index, "offset", timestring); /******** To: list ********/ for (i = 0, pptr = pers_head; pptr; pptr = pptr->next) if (pptr->data.how_received == TO) { snprintf(name, MAX_TMP_NAME, "to.%d", i); set_msg_value(index, name, pptr->data.realname); i++; } snprintf(url, MAX_PATH * 2, "%d", i); set_msg_value(index, "to_count", url); /* provide a count of 'to' recipients */ /******** CC list *********/ for ( i = 0, pptr = pers_head; pptr; pptr = pptr->next) if (pptr->data.how_received == CC) { snprintf(name, MAX_TMP_NAME, "cc.%d", i); set_msg_value(index, name, pptr->data.realname); i++; } snprintf(url, MAX_PATH * 2, "%d", i); set_msg_value(index, "cc_count", url); /* provide a count of 'cc' recipients */ if (website_attached) { set_msg_value(index, "website_attached", "1"); snprintf(url, MAX_PATH *2, "%s?crs=%s&id=%s&sender=%s&inf=%s&grp=%d&read=1&loc=%ld&inbox=yes&from=post_read_outbox", "web_page_start", course, key, user->username, outbox->info_fname, MAIL, offset); set_msg_value(index, "website_url", url); } else /***** attachments ***/ if (attach_head) { /* note the ext= parameter isn't used by the "send_file" program ** it's there to help offline browser programs to determine the type of file ** being sent */ i =0; for (aptr = attach_head; aptr; aptr = aptr->next) { get_extension(aptr->data.orig_fname, extension); /* shared_news_util.c */ snprintf(name, MAX_TMP_NAME, "file.%d.url", i); snprintf (url, MAX_PATH*2, "%s?crs=%s&id=%s&user=%s&fname=%s&info=%s&attach=%d&ext=.%s", "send_file", course, key, user->username, aptr->data.unique_fname, outbox->info_fname, outbox->attachments, extension); set_msg_value(index,name, url); snprintf(name, MAX_TMP_NAME, "file.%d.orig_fname", i); set_msg_value(index, name, aptr->data.orig_fname); /* if this is an mp3 file, and the feature is enabled, ** provide url for wimpy_button mp3 player */ if(!strcmp(extension,"mp3")) /* custom.h */ { cs_set_server_name(); snprintf(url, MAX_PATH +1, "podcast_launch_framaplayer?crs=%s&id=%s&title=%s&sender=%s&fname=%s&inf=%s&grp=%d&realname=%s", course, key, outbox->subject, user->username, aptr->data.unique_fname, outbox->info_fname, MAIL, user->realname); snprintf(name, MAX_TMP_NAME, "file.%d.wimpy_button_url", i); set_msg_value(index, name, url); } i++; } } #undef MAX_TMP_NAME }