/* ************************************************************************
* 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);
}