#include #include #include #include #include #include #include #include "../global.h" #include "shared_lock.h" #include "shared_news_util.h" #include "shared_lock.h" #include "shared_cs_util.h" typedef struct disabled_topic_node { int topic_id; struct disabled_topic_node *next; } DISABLED_TOPIC_NODE; int new_files_exist (char *mail_dir) { DIR *dir_p; struct dirent *dir_entry_p; char *ptr; dir_p = opendir (mail_dir); if (!dir_p) cs_critical_error (ERR_OPENDIR_FAILED, mail_dir); while (NULL != (dir_entry_p = readdir (dir_p))) { ptr = strstr (dir_entry_p->d_name, ".new"); if (ptr && *(ptr + 4) == '\0') /* i.e. if file ends in .new */ { closedir (dir_p); return 1; } } closedir (dir_p); return 0; } /* returns 1 if inbox.dat file contains a msg that was not read and ** was not deleted, else returns 0 */ int old_unread_mail (const char *maildir) { char inbox_path[MAX_PATH + 1]; FILE *fp; INBOX_RECORD msg; snprintf (inbox_path, MAX_PATH + 1, "%s/%s", maildir, INBOX_FNAME); fp = fopen (inbox_path, "r"); if (!fp) /* no inbox, no friends */ return 0; get_shared_lock(fileno(fp), 1); /* shared_lock.c */ while (fread (&msg, sizeof (INBOX_RECORD), 1, fp) == 1) if (!msg.time_read && (msg.newfile_info.how_sent != DELETED)) { release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); return 1; } release_lock(fileno(fp)); /* shared_lock.c */ fclose (fp); return 0; } /* returns 0 if there is no unread mail/ else returns 1 */ int unread_mail (const char *username, const CONFIG_STRUCT *conf) { char mail_dir[MAX_PATH + 1]; int has_new_files = 0; snprintf (mail_dir, MAX_PATH + 1, "%s%s/%s/%s", conf->course_path, PEOPLE_DIR, username, MAIL_DIR); /* custom.h - versions prior to 2.4 used *.new files to flag ** the delivery of Post Office messages. ** The custom.h entry controls whether or not we should check ** for these files */ #ifndef SUPPORT_PRE24_POST_OFFICE_MSGS has_new_files = new_files_exist (mail_dir); #else if(SUPPORT_PRE24_POST_OFFICE_MSGS) has_new_files = new_files_exist (mail_dir); #endif return (has_new_files || old_unread_mail (mail_dir)); } int is_unread(CENTRAL_INBOX_RECORD *msg, USER_INBOX_NODE *user_head) { USER_INBOX_NODE *ptr; for(ptr=user_head; ptr; ptr=ptr->next) if (ptr->data.msg_id == msg->info.msg_id) return (ptr->data.time_read == 0); return 1; /* msg is not listed, so it is unread */ } static DISABLED_TOPIC_NODE * add_to_disabled_topic_list(DISABLED_TOPIC_NODE *head, int topic_id) { DISABLED_TOPIC_NODE *new_node, *ptr; new_node = (DISABLED_TOPIC_NODE *) malloc(sizeof(DISABLED_TOPIC_NODE)); if(!new_node) cs_critical_error(ERR_MALLOC_FAILED, ""); new_node -> topic_id = topic_id; new_node ->next = 0; if(!head) head = new_node; else { for(ptr = head; ptr->next; ptr=ptr->next); ptr->next = new_node; } return head; } static int on_disabled_topic_list(DISABLED_TOPIC_NODE *head, int topic_id) { DISABLED_TOPIC_NODE *ptr; for(ptr = head; ptr; ptr = ptr->next) if (ptr->topic_id == topic_id) return 1; return 0; } static DISABLED_TOPIC_NODE *free_disabled_topic_list(DISABLED_TOPIC_NODE *head) { DISABLED_TOPIC_NODE *ptr; while(head) { ptr = head; head = head->next; free(ptr); } return head; } int unread_news (SESSION *user, int grp, const CONFIG_STRUCT *conf, time_t current_time) { int show_all_teamteach; int show_teacher_hidden; USER_INBOX_NODE *user_head = 0; FILE *fp; int fd; char inbox_fname[MAX_PATH + 1]; /* full path to central inbox */ CENTRAL_INBOX_RECORD data; int unread_found = 0; int check_for_hidden_topics; int should_display; DISABLED_TOPIC_NODE *head = 0; /* When a topic is marked as hidden by the teacher, each message that belongs to that topic is NOT ** also marked as hidden. The tree structure used within the programs that list the indexes of messages ** handle the display correctly. However here we might have to check each msg to make sure the topic ** that msg belongs to has not been hidden by the teacher ** Do we need to check each message to make sure its topic has not been hidden by the teaher? */ /* Another thing... the next used to do the check only for students, but on rare occasions it turns out ** that teachers became the victim of red stars on the main menu that won't go away. **/ check_for_hidden_topics = group_uses_topic(grp); /* shared_news_util.c */ show_all_teamteach = (user->group == FACULTY) && (grp == TEAM_TEACH); show_teacher_hidden = (user->group == FACULTY)? 1 : 0; set_discussion_names (conf->course_path, user->username, grp); /* shared_news_util.c */ user_head = build_user_inbox_list(); /* shared_news_util.c */ snprintf(inbox_fname,MAX_PATH + 1,"%s%s",central_discussion_path,INBOX_FNAME); fp = fopen(inbox_fname,"r"); if(!fp) /* inbox.dat doesn't exist */ { free_user_inbox_list(); return 0; /* so there are no unread msgs */ } fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ /*Just a guess. An unread msg often will be often the last record in the inbox file **Let's test that first and see if we get lucky. We can only try this if we don't need to ** check for hidden topics. */ if(!check_for_hidden_topics) { if(!fseek(fp,-sizeof(CENTRAL_INBOX_RECORD), SEEK_END)) /* if we can move back one record from the end */ { if(fread(&data,sizeof(CENTRAL_INBOX_RECORD),1,fp) == 1) /* if the read is successful */ unread_found = (msg_should_display(&data, user, grp, current_time, show_all_teamteach, show_teacher_hidden) && is_unread(&data, user_head) ); } } if(!unread_found) /* our trick didn't work, so we need to deal with the whole file */ { if(fseek(fp, 0, SEEK_SET)) /* move to the start of the file */ { release_lock(fd); fclose(fp); cs_critical_error(ERR_FSEEK_FAILED, inbox_fname); } do { if(fread(&data,sizeof(CENTRAL_INBOX_RECORD),1,fp) != 1) break; /* msg_should_display() is in shared_news_util.c */ should_display = msg_should_display(&data, user, grp, current_time, show_all_teamteach, show_teacher_hidden); /** If we need to check each message to see if it belongs to a hidden topic, *** and if this message is a topic, and if it should NOT be shown to this user, *** we add it to a linked list of 'bad' topics */ if(check_for_hidden_topics && (data.info.reply_to == -1) && !should_display) head = add_to_disabled_topic_list(head, data.info.msg_id); unread_found = (should_display && is_unread(&data, user_head) ); /** if the message seems to be unread, and if we need to check the msg to see *** if it belongs to a hidden topic, and if this message is not a topic, *** the message is only really unread if *** the topic it belongs to is not on the bad topic list **/ if(check_for_hidden_topics && unread_found && (data.info.reply_to != -1)) unread_found = !on_disabled_topic_list(head, data.info.topic_id); } while (!unread_found); } /* our trick didn't work */ release_lock(fd); fclose(fp); free_user_inbox_list(); head = free_disabled_topic_list(head); return unread_found; } int unread_grades (const char *username, const CONFIG_STRUCT *conf) { FILE *fp; char fname[MAX_PATH + 1]; snprintf (fname, MAX_PATH + 1, "%speople/%s/grades/%s", conf->course_path, username, GRADES_NEW_FNAME); fp = fopen (fname, "r"); if (fp) { fclose (fp); return 1; } return 0; } int non_empty_chatroom () { struct stat buf; return (!stat (CHAT_ACTIVE_FILE, &buf)); }