/* ************************************************************************ * file: readmail.c Part of CircleMud * * Usage: read mail in a player mail file without removing it from file * * Written by Jeremy Elson * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * * All Rights Reserved * * Copyright (C) 1993 The Trustees of The Johns Hopkins University * **************************************************************************/ #include <stdio.h> #include <assert.h> #include <ctype.h> #include <string.h> #include <time.h> #include "../mail.h" #define log(x) puts(x) /* defines for fseek */ #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif char MAIL_FILE[100]; mail_index_type *mail_index = 0; /* list of recs in the mail file */ position_list_type *free_list = 0; /* list of free positions in file */ long file_end_pos = 0; /* length of file */ void push_free_list(long pos) { position_list_type * new_pos; new_pos = (position_list_type * )malloc(sizeof(position_list_type)); new_pos->position = pos; new_pos->next = free_list; free_list = new_pos; } long pop_free_list(void) { position_list_type * old_pos; long return_value; if ((old_pos = free_list) != 0) { return_value = free_list->position; free_list = old_pos->next; free(old_pos); return return_value; } else return file_end_pos; } mail_index_type *find_char_in_index(char *searchee) { mail_index_type * temp_rec; if (!*searchee) { log("Mail system -- non fatal error 1"); return 0; } for (temp_rec = mail_index; (temp_rec && strcmp(temp_rec->recipient, searchee)); temp_rec = temp_rec->next) ; return temp_rec; } void read_from_file(void *buf, int size, long filepos) { FILE * mail_file; if (!(mail_file = fopen(MAIL_FILE, "r"))) { perror("Error opening mail file for read"); exit(1); } if (filepos % BLOCK_SIZE) { log("Mail system -- fatal error #2!!!"); return; } fseek(mail_file, filepos, SEEK_SET); fread(buf, size, 1, mail_file); fclose(mail_file); return; } void index_mail(char *name_to_index, long pos) { mail_index_type * new_index; position_list_type * new_position; if (!*name_to_index) { log("Mail system -- non-fatal error 2"); return; } if (!(new_index = find_char_in_index(name_to_index))) { /* name not already in index.. add it */ new_index = (mail_index_type * )malloc(sizeof(mail_index_type)); strncpy(new_index->recipient, name_to_index, NAME_SIZE); new_index->recipient[strlen(name_to_index)] = '\0'; new_index->list_start = 0; /* add to front of list */ new_index->next = mail_index; mail_index = new_index; } /* now, add this position to front of position list */ new_position = (position_list_type * )malloc(sizeof(position_list_type)); new_position->position = pos; new_position->next = new_index->list_start; new_index->list_start = new_position; } /* SCAN_FILE */ /* scan_file is called once during boot-up. It scans through the mail file and indexes all entries currently in the mail file. */ int scan_file(void) { FILE * mail_file; header_block_type next_block; int total_messages = 0, block_num = 0; char buf[100]; if (!(mail_file = fopen(MAIL_FILE, "r"))) { perror("Error opening mail file for read"); exit(0); } while (fread(&next_block, sizeof(header_block_type), 1, mail_file)) { if (next_block.block_type == HEADER_BLOCK) { index_mail(next_block.to, block_num * BLOCK_SIZE); total_messages++; } else if (next_block.block_type == DELETED_BLOCK) push_free_list(block_num * BLOCK_SIZE); block_num++; } file_end_pos = ftell(mail_file); sprintf(buf, " %ld bytes read.", file_end_pos); log(buf); if (file_end_pos % BLOCK_SIZE) { log("Error booting mail system -- Mail file corrupt!"); log("Mail disabled!"); return 0; } sprintf(buf, " Mail file read -- %d messages.", total_messages); log(buf); return 1; } /* end of scan_file */ /* HAS_MAIL */ /* a simple little function which tells you if the guy has mail or not */ int has_mail(char *recipient) { if (find_char_in_index(recipient)) return 1; return 0; } /* READ_DELETE */ /* read_delete takes 1 char pointer to the name of the person whose mail you're retrieving. It returns to you a char pointer to the message text. The mail is then discarded from the file and the mail index. */ char *read_delete(char *recipient, char *recipient_formatted) /* recipient is the name as it appears in the index. recipient_formatted is the name as it should appear on the mail header (i.e. the text handed to the player) */ { header_block_type header; data_block_type data; mail_index_type * mail_pointer, *prev_mail; position_list_type * position_pointer; long mail_address, following_block; char *message, *tmstr, buf[200]; size_t string_size; if (!*recipient || !*recipient_formatted) { log("Mail system -- non fatal error 5"); return 0; } if (!(mail_pointer = find_char_in_index(recipient))) { log("Stupid post-office-spec_proc-error"); return 0; } if (!(position_pointer = mail_pointer->list_start)) { log("Stupid Rasmussen error!"); return 0; } if (!(position_pointer->next)) /* just 1 entry in list. */ { mail_address = position_pointer->position; free(position_pointer); /* now free up the actual name entry */ if (mail_index == mail_pointer) /* name is 1st in list */ { mail_index = mail_pointer->next; free(mail_pointer); } else { /* find entry before the one we're going to del */ for (prev_mail = mail_index; prev_mail->next != mail_pointer; prev_mail = prev_mail->next) ; prev_mail->next = mail_pointer->next; free(mail_pointer); } } else { /* move to next-to-last record */ while (position_pointer->next->next) position_pointer = position_pointer->next; mail_address = position_pointer->next->position; free(position_pointer->next); position_pointer->next = 0; } /* ok, now lets do some readin'! */ read_from_file(&header, BLOCK_SIZE, mail_address); if (header.block_type != HEADER_BLOCK) { log("Oh dear."); log("Mail system disabled!"); return 0; } tmstr = asctime(localtime(&header.mail_time)); *(tmstr + strlen(tmstr) - 1) = '\0'; sprintf(buf, " * * * * Midgaard Mail System * * * *\n\r" "Date: %s\n\r" " To: %s\n\r" "From: %s\n\r\n\r", tmstr, recipient_formatted, header.from); string_size = (CHAR_SIZE * (strlen(buf) + strlen(header.txt) + 1)); message = (char *)malloc(string_size); strcpy(message, buf); message[strlen(buf)] = '\0'; strcat(message, header.txt); message[string_size - 1] = '\0'; following_block = header.next_block; while (following_block != LAST_BLOCK) { read_from_file(&data, BLOCK_SIZE, following_block); string_size = (CHAR_SIZE * (strlen(message) + strlen(data.txt) + 1)); message = (char *)realloc(message, string_size); strcat(message, data.txt); message[string_size - 1] = '\0'; mail_address = following_block; following_block = data.block_type; } return message; } int main(int argc, char *argv[]) { char searchee[NAME_SIZE+1], *ptr; if (argc != 3) { log("Usage: readmail <filename> <plrname>"); exit(1); } strcpy(MAIL_FILE, argv[1]); scan_file(); strcpy(searchee, argv[2]); if (!has_mail(searchee)) { printf("%s does not have any mail in %s.\n", argv[2], argv[1]); exit(1); } while (has_mail(searchee)) { ptr = read_delete(searchee, argv[2]); printf("%s\n\n-----------------\n\n", ptr); free(ptr); } exit(0); }