617 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			617 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* ************************************************************************
 | |
| *   File: mail.c                                        Part of CircleMUD *
 | |
| *  Usage: Internal funcs and player spec-procs of mud-mail system         *
 | |
| *                                                                         *
 | |
| *  All rights reserved.  See license.doc for complete information.        *
 | |
| *                                                                         *
 | |
| *  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
 | |
| *  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
 | |
| ************************************************************************ */
 | |
| 
 | |
| /******* MUD MAIL SYSTEM MAIN FILE ***************************************
 | |
| 
 | |
| Written by Jeremy Elson (jelson@circlemud.org)
 | |
| 
 | |
| *************************************************************************/
 | |
| 
 | |
| #include "conf.h"
 | |
| #include "sysdep.h"
 | |
| 
 | |
| #include "structs.h"
 | |
| #include "utils.h"
 | |
| #include "comm.h"
 | |
| #include "db.h"
 | |
| #include "interpreter.h"
 | |
| #include "handler.h"
 | |
| #include "mail.h"
 | |
| 
 | |
| 
 | |
| /* external variables */
 | |
| extern int no_mail;
 | |
| 
 | |
| /* external functions */
 | |
| SPECIAL(postmaster);
 | |
| 
 | |
| /* local globals */
 | |
| mail_index_type *mail_index = NULL;	/* list of recs in the mail file  */
 | |
| position_list_type *free_list = NULL;	/* list of free positions in file */
 | |
| long file_end_pos = 0;			/* length of file */
 | |
| 
 | |
| /* local functions */
 | |
| void postmaster_send_mail(struct char_data *ch, struct char_data *mailman, int cmd, char *arg);
 | |
| void postmaster_check_mail(struct char_data *ch, struct char_data *mailman, int cmd, char *arg);
 | |
| void postmaster_receive_mail(struct char_data *ch, struct char_data *mailman, int cmd, char *arg);
 | |
| void push_free_list(long pos);
 | |
| long pop_free_list(void);
 | |
| void clear_free_list(void);
 | |
| mail_index_type *find_char_in_index(long searchee);
 | |
| void write_to_file(void *buf, int size, long filepos);
 | |
| void read_from_file(void *buf, int size, long filepos);
 | |
| void index_mail(long id_to_index, long pos);
 | |
| int mail_recip_ok(const char *name);
 | |
| 
 | |
| /* -------------------------------------------------------------------------- */
 | |
| 
 | |
| int mail_recip_ok(const char *name)
 | |
| {
 | |
|   struct char_file_u tmp_store;
 | |
|   struct char_data *victim;
 | |
|   int ret = FALSE;
 | |
| 
 | |
|   CREATE(victim, struct char_data, 1);
 | |
|   clear_char(victim);
 | |
|   if (load_char(name, &tmp_store) >= 0) {
 | |
|     store_to_char(&tmp_store, victim);
 | |
|     char_to_room(victim, 0);
 | |
|     if (!PLR_FLAGGED(victim, PLR_DELETED))
 | |
|       ret = TRUE;
 | |
|     extract_char_final(victim);
 | |
|   } else 
 | |
|     free(victim);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * void push_free_list(long #1)
 | |
|  * #1 - What byte offset into the file the block resides.
 | |
|  *
 | |
|  * Net effect is to store a list of free blocks in the mail file in a linked
 | |
|  * list.  This is called when people receive their messages and at startup
 | |
|  * when the list is created.
 | |
|  */
 | |
| void push_free_list(long pos)
 | |
| {
 | |
|   position_list_type *new_pos;
 | |
| 
 | |
|   CREATE(new_pos, position_list_type, 1);
 | |
|   new_pos->position = pos;
 | |
|   new_pos->next = free_list;
 | |
|   free_list = new_pos;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * long pop_free_list(none)
 | |
|  * Returns the offset of a free block in the mail file.
 | |
|  *
 | |
|  * Typically used whenever a person mails a message.  The blocks are not
 | |
|  * guaranteed to be sequential or in any order at all.
 | |
|  */
 | |
| long pop_free_list(void)
 | |
| {
 | |
|   position_list_type *old_pos;
 | |
|   long return_value;
 | |
| 
 | |
|   /*
 | |
|    * If we don't have any free blocks, we append to the file.
 | |
|    */
 | |
|   if ((old_pos = free_list) == NULL)
 | |
|     return (file_end_pos);
 | |
| 
 | |
|   /* Save the offset of the free block. */
 | |
|   return_value = free_list->position;
 | |
|   /* Remove this block from the free list. */
 | |
|   free_list = old_pos->next;
 | |
|   /* Get rid of the memory the node took. */
 | |
|   free(old_pos);
 | |
|   /* Give back the free offset. */
 | |
|   return (return_value);
 | |
| }
 | |
| 
 | |
| 
 | |
| void clear_free_list(void)
 | |
| {
 | |
|   while (free_list)
 | |
|     pop_free_list();
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * main_index_type *find_char_in_index(long #1)
 | |
|  * #1 - The idnum of the person to look for.
 | |
|  * Returns a pointer to the mail block found.
 | |
|  *
 | |
|  * Finds the first mail block for a specific person based on id number.
 | |
|  */
 | |
| mail_index_type *find_char_in_index(long searchee)
 | |
| {
 | |
|   mail_index_type *tmp;
 | |
| 
 | |
|   if (searchee < 0) {
 | |
|     log("SYSERR: Mail system -- non fatal error #1 (searchee == %ld).", searchee);
 | |
|     return (NULL);
 | |
|   }
 | |
|   for (tmp = mail_index; (tmp && tmp->recipient != searchee); tmp = tmp->next);
 | |
| 
 | |
|   return (tmp);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * void write_to_file(void * #1, int #2, long #3)
 | |
|  * #1 - A pointer to the data to write, usually the 'block' record.
 | |
|  * #2 - How much to write (because we'll write NUL terminated strings.)
 | |
|  * #3 - What offset (block position) in the file to write to.
 | |
|  *
 | |
|  * Writes a mail block back into the database at the given location.
 | |
|  */
 | |
| void write_to_file(void *buf, int size, long filepos)
 | |
| {
 | |
|   FILE *mail_file;
 | |
| 
 | |
|   if (filepos % BLOCK_SIZE) {
 | |
|     log("SYSERR: Mail system -- fatal error #2!!! (invalid file position %ld)", filepos);
 | |
|     no_mail = TRUE;
 | |
|     return;
 | |
|   }
 | |
|   if (!(mail_file = fopen(MAIL_FILE, "r+b"))) {
 | |
|     log("SYSERR: Unable to open mail file '%s'.", MAIL_FILE);
 | |
|     no_mail = TRUE;
 | |
|     return;
 | |
|   }
 | |
|   fseek(mail_file, filepos, SEEK_SET);
 | |
|   fwrite(buf, size, 1, mail_file);
 | |
| 
 | |
|   /* find end of file */
 | |
|   fseek(mail_file, 0L, SEEK_END);
 | |
|   file_end_pos = ftell(mail_file);
 | |
|   fclose(mail_file);
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * void read_from_file(void * #1, int #2, long #3)
 | |
|  * #1 - A pointer to where we should store the data read.
 | |
|  * #2 - How large the block we're reading is.
 | |
|  * #3 - What position in the file to read.
 | |
|  *
 | |
|  * This reads a block from the mail database file.
 | |
|  */
 | |
| void read_from_file(void *buf, int size, long filepos)
 | |
| {
 | |
|   FILE *mail_file;
 | |
| 
 | |
|   if (filepos % BLOCK_SIZE) {
 | |
|     log("SYSERR: Mail system -- fatal error #3!!! (invalid filepos read %ld)", filepos);
 | |
|     no_mail = TRUE;
 | |
|     return;
 | |
|   }
 | |
|   if (!(mail_file = fopen(MAIL_FILE, "r+b"))) {
 | |
|     log("SYSERR: Unable to open mail file '%s'.", MAIL_FILE);
 | |
|     no_mail = TRUE;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   fseek(mail_file, filepos, SEEK_SET);
 | |
|   fread(buf, size, 1, mail_file);
 | |
|   fclose(mail_file);
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 
 | |
| void index_mail(long id_to_index, long pos)
 | |
| {
 | |
|   mail_index_type *new_index;
 | |
|   position_list_type *new_position;
 | |
| 
 | |
|   if (id_to_index < 0) {
 | |
|     log("SYSERR: Mail system -- non-fatal error #4. (id_to_index == %ld)", id_to_index);
 | |
|     return;
 | |
|   }
 | |
|   if (!(new_index = find_char_in_index(id_to_index))) {
 | |
|     /* name not already in index.. add it */
 | |
|     CREATE(new_index, mail_index_type, 1);
 | |
|     new_index->recipient = id_to_index;
 | |
|     new_index->list_start = NULL;
 | |
| 
 | |
|     /* add to front of list */
 | |
|     new_index->next = mail_index;
 | |
|     mail_index = new_index;
 | |
|   }
 | |
|   /* now, add this position to front of position list */
 | |
|   CREATE(new_position, position_list_type, 1);
 | |
|   new_position->position = pos;
 | |
|   new_position->next = new_index->list_start;
 | |
|   new_index->list_start = new_position;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * int scan_file(none)
 | |
|  * Returns false if mail file is corrupted or true if everything correct.
 | |
|  *
 | |
|  * This 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;
 | |
| 
 | |
|   if (!(mail_file = fopen(MAIL_FILE, "rb"))) {
 | |
|     log("   Mail file non-existant... creating new file.");
 | |
|     touch(MAIL_FILE);
 | |
|     return (1);
 | |
|   }
 | |
|   while (fread(&next_block, sizeof(header_block_type), 1, mail_file)) {
 | |
|     if (next_block.block_type == HEADER_BLOCK) {
 | |
|       index_mail(next_block.header_data.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);
 | |
|   fclose(mail_file);
 | |
|   log("   %ld bytes read.", file_end_pos);
 | |
|   if (file_end_pos % BLOCK_SIZE) {
 | |
|     log("SYSERR: Error booting mail system -- Mail file corrupt!");
 | |
|     log("SYSERR: Mail disabled!");
 | |
|     return (0);
 | |
|   }
 | |
|   log("   Mail file read -- %d messages.", total_messages);
 | |
|   return (1);
 | |
| }				/* end of scan_file */
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * int has_mail(long #1)
 | |
|  * #1 - id number of the person to check for mail.
 | |
|  * Returns true or false.
 | |
|  *
 | |
|  * A simple little function which tells you if the guy has mail or not.
 | |
|  */
 | |
| int has_mail(long recipient)
 | |
| {
 | |
|   return (find_char_in_index(recipient) != NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * void store_mail(long #1, long #2, char * #3)
 | |
|  * #1 - id number of the person to mail to.
 | |
|  * #2 - id number of the person the mail is from.
 | |
|  * #3 - The actual message to send.
 | |
|  *
 | |
|  * call store_mail to store mail.  (hard, huh? :-) )  Pass 3 arguments:
 | |
|  * who the mail is to (long), who it's from (long), and a pointer to the
 | |
|  * actual message text (char *).
 | |
|  */
 | |
| void store_mail(long to, long from, char *message_pointer)
 | |
| {
 | |
|   header_block_type header;
 | |
|   data_block_type data;
 | |
|   long last_address, target_address;
 | |
|   char *msg_txt = message_pointer;
 | |
|   int bytes_written, total_length = strlen(message_pointer);
 | |
| 
 | |
|   if ((sizeof(header_block_type) != sizeof(data_block_type)) ||
 | |
|       (sizeof(header_block_type) != BLOCK_SIZE)) {
 | |
|     core_dump();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (from < 0 || to < 0 || !*message_pointer) {
 | |
|     log("SYSERR: Mail system -- non-fatal error #5. (from == %ld, to == %ld)", from, to);
 | |
|     return;
 | |
|   }
 | |
|   memset((char *) &header, 0, sizeof(header));	/* clear the record */
 | |
|   header.block_type = HEADER_BLOCK;
 | |
|   header.header_data.next_block = LAST_BLOCK;
 | |
|   header.header_data.from = from;
 | |
|   header.header_data.to = to;
 | |
|   header.header_data.mail_time = time(0);
 | |
|   strncpy(header.txt, msg_txt, HEADER_BLOCK_DATASIZE);	/* strncpy: OK (h.txt:HEADER_BLOCK_DATASIZE+1) */
 | |
|   header.txt[HEADER_BLOCK_DATASIZE] = '\0';
 | |
| 
 | |
|   target_address = pop_free_list();	/* find next free block */
 | |
|   index_mail(to, target_address);	/* add it to mail index in memory */
 | |
|   write_to_file(&header, BLOCK_SIZE, target_address);
 | |
| 
 | |
|   if (strlen(msg_txt) <= HEADER_BLOCK_DATASIZE)
 | |
|     return;			/* that was the whole message */
 | |
| 
 | |
|   bytes_written = HEADER_BLOCK_DATASIZE;
 | |
|   msg_txt += HEADER_BLOCK_DATASIZE;	/* move pointer to next bit of text */
 | |
| 
 | |
|   /*
 | |
|    * find the next block address, then rewrite the header to reflect where
 | |
|    * the next block is.
 | |
|    */
 | |
|   last_address = target_address;
 | |
|   target_address = pop_free_list();
 | |
|   header.header_data.next_block = target_address;
 | |
|   write_to_file(&header, BLOCK_SIZE, last_address);
 | |
| 
 | |
|   /* now write the current data block */
 | |
|   memset((char *) &data, 0, sizeof(data));	/* clear the record */
 | |
|   data.block_type = LAST_BLOCK;
 | |
|   strncpy(data.txt, msg_txt, DATA_BLOCK_DATASIZE);	/* strncpy: OK (d.txt:DATA_BLOCK_DATASIZE+1) */
 | |
|   data.txt[DATA_BLOCK_DATASIZE] = '\0';
 | |
|   write_to_file(&data, BLOCK_SIZE, target_address);
 | |
|   bytes_written += strlen(data.txt);
 | |
|   msg_txt += strlen(data.txt);
 | |
| 
 | |
|   /*
 | |
|    * if, after 1 header block and 1 data block there is STILL part of the
 | |
|    * message left to write to the file, keep writing the new data blocks and
 | |
|    * rewriting the old data blocks to reflect where the next block is.  Yes,
 | |
|    * this is kind of a hack, but if the block size is big enough it won't
 | |
|    * matter anyway.  Hopefully, MUD players won't pour their life stories out
 | |
|    * into the Mud Mail System anyway.
 | |
|    * 
 | |
|    * Note that the block_type data field in data blocks is either a number >=0,
 | |
|    * meaning a link to the next block, or LAST_BLOCK flag (-2) meaning the
 | |
|    * last block in the current message.  This works much like DOS' FAT.
 | |
|    */
 | |
|   while (bytes_written < total_length) {
 | |
|     last_address = target_address;
 | |
|     target_address = pop_free_list();
 | |
| 
 | |
|     /* rewrite the previous block to link it to the next */
 | |
|     data.block_type = target_address;
 | |
|     write_to_file(&data, BLOCK_SIZE, last_address);
 | |
| 
 | |
|     /* now write the next block, assuming it's the last.  */
 | |
|     data.block_type = LAST_BLOCK;
 | |
|     strncpy(data.txt, msg_txt, DATA_BLOCK_DATASIZE);	/* strncpy: OK (d.txt:DATA_BLOCK_DATASIZE+1) */
 | |
|     data.txt[DATA_BLOCK_DATASIZE] = '\0';
 | |
|     write_to_file(&data, BLOCK_SIZE, target_address);
 | |
| 
 | |
|     bytes_written += strlen(data.txt);
 | |
|     msg_txt += strlen(data.txt);
 | |
|   }
 | |
| }				/* store mail */
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * char *read_delete(long #1)
 | |
|  * #1 - The id number of the person we're checking mail for.
 | |
|  * Returns the message text of the mail received.
 | |
|  *
 | |
|  * Retrieves one messsage for a player. The mail is then discarded from
 | |
|  * the file and the mail index.
 | |
|  */
 | |
| char *read_delete(long recipient)
 | |
| {
 | |
|   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 *tmstr, buf[MAX_MAIL_SIZE + 256];	/* + header */
 | |
|   char *from, *to;
 | |
| 
 | |
|   if (recipient < 0) {
 | |
|     log("SYSERR: Mail system -- non-fatal error #6. (recipient: %ld)", recipient);
 | |
|     return (NULL);
 | |
|   }
 | |
|   if (!(mail_pointer = find_char_in_index(recipient))) {
 | |
|     log("SYSERR: Mail system -- post office spec_proc error?  Error #7. (invalid character in index)");
 | |
|     return (NULL);
 | |
|   }
 | |
|   if (!(position_pointer = mail_pointer->list_start)) {
 | |
|     log("SYSERR: Mail system -- non-fatal error #8. (invalid position pointer %p)", position_pointer);
 | |
|     return (NULL);
 | |
|   }
 | |
|   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 = NULL;
 | |
|   }
 | |
| 
 | |
|   /* ok, now lets do some readin'! */
 | |
|   read_from_file(&header, BLOCK_SIZE, mail_address);
 | |
| 
 | |
|   if (header.block_type != HEADER_BLOCK) {
 | |
|     log("SYSERR: Oh dear. (Header block %ld != %d)", header.block_type, HEADER_BLOCK);
 | |
|     no_mail = TRUE;
 | |
|     log("SYSERR: Mail system disabled!  -- Error #9. (Invalid header block.)");
 | |
|     return (NULL);
 | |
|   }
 | |
|   tmstr = asctime(localtime(&header.header_data.mail_time));
 | |
|   *(tmstr + strlen(tmstr) - 1) = '\0';
 | |
| 
 | |
|   from = get_name_by_id(header.header_data.from);
 | |
|   to = get_name_by_id(recipient);
 | |
| 
 | |
|   snprintf(buf, sizeof(buf),
 | |
| 	" * * * * Midgaard Mail System * * * *\r\n"
 | |
| 	"Date: %s\r\n"
 | |
| 	"  To: %s\r\n"
 | |
| 	"From: %s\r\n"
 | |
| 	"\r\n"
 | |
| 	"%s",
 | |
| 
 | |
| 	tmstr,
 | |
| 	to ? to : "Unknown",
 | |
| 	from ? from : "Unknown",
 | |
| 	header.txt
 | |
| 	);
 | |
|   following_block = header.header_data.next_block;
 | |
| 
 | |
|   /* mark the block as deleted */
 | |
|   header.block_type = DELETED_BLOCK;
 | |
|   write_to_file(&header, BLOCK_SIZE, mail_address);
 | |
|   push_free_list(mail_address);
 | |
| 
 | |
|   while (following_block != LAST_BLOCK) {
 | |
|     read_from_file(&data, BLOCK_SIZE, following_block);
 | |
| 
 | |
|     strcat(buf, data.txt);	/* strcat: OK (data.txt:DATA_BLOCK_DATASIZE < buf:MAX_MAIL_SIZE) */
 | |
|     mail_address = following_block;
 | |
|     following_block = data.block_type;
 | |
|     data.block_type = DELETED_BLOCK;
 | |
|     write_to_file(&data, BLOCK_SIZE, mail_address);
 | |
|     push_free_list(mail_address);
 | |
|   }
 | |
| 
 | |
|   return strdup(buf);
 | |
| }
 | |
| 
 | |
| 
 | |
| /****************************************************************
 | |
| * Below is the spec_proc for a postmaster using the above       *
 | |
| * routines.  Written by Jeremy Elson (jelson@circlemud.org) *
 | |
| ****************************************************************/
 | |
| 
 | |
| SPECIAL(postmaster)
 | |
| {
 | |
|   if (!ch->desc || IS_NPC(ch))
 | |
|     return (0);			/* so mobs don't get caught here */
 | |
| 
 | |
|   if (!(CMD_IS("mail") || CMD_IS("check") || CMD_IS("receive")))
 | |
|     return (0);
 | |
| 
 | |
|   if (no_mail) {
 | |
|     send_to_char(ch, "Sorry, the mail system is having technical difficulties.\r\n");
 | |
|     return (0);
 | |
|   }
 | |
| 
 | |
|   if (CMD_IS("mail")) {
 | |
|     postmaster_send_mail(ch, (struct char_data *)me, cmd, argument);
 | |
|     return (1);
 | |
|   } else if (CMD_IS("check")) {
 | |
|     postmaster_check_mail(ch, (struct char_data *)me, cmd, argument);
 | |
|     return (1);
 | |
|   } else if (CMD_IS("receive")) {
 | |
|     postmaster_receive_mail(ch, (struct char_data *)me, cmd, argument);
 | |
|     return (1);
 | |
|   } else
 | |
|     return (0);
 | |
| }
 | |
| 
 | |
| 
 | |
| void postmaster_send_mail(struct char_data *ch, struct char_data *mailman,
 | |
| 			  int cmd, char *arg)
 | |
| {
 | |
|   long recipient;
 | |
|   char buf[MAX_INPUT_LENGTH], **mailwrite;
 | |
| 
 | |
|   if (GET_LEVEL(ch) < MIN_MAIL_LEVEL) {
 | |
|     snprintf(buf, sizeof(buf), "$n tells you, 'Sorry, you have to be level %d to send mail!'", MIN_MAIL_LEVEL);
 | |
|     act(buf, FALSE, mailman, 0, ch, TO_VICT);
 | |
|     return;
 | |
|   }
 | |
|   one_argument(arg, buf);
 | |
| 
 | |
|   if (!*buf) {			/* you'll get no argument from me! */
 | |
|     act("$n tells you, 'You need to specify an addressee!'",
 | |
| 	FALSE, mailman, 0, ch, TO_VICT);
 | |
|     return;
 | |
|   }
 | |
|   if (GET_GOLD(ch) < STAMP_PRICE) {
 | |
|     snprintf(buf, sizeof(buf), "$n tells you, 'A stamp costs %d coin%s.'\r\n"
 | |
| 	    "$n tells you, '...which I see you can't afford.'", STAMP_PRICE,
 | |
|             STAMP_PRICE == 1 ? "" : "s");
 | |
|     act(buf, FALSE, mailman, 0, ch, TO_VICT);
 | |
|     return;
 | |
|   }
 | |
|   if ((recipient = get_id_by_name(buf)) < 0 || !mail_recip_ok(buf)) {
 | |
|     act("$n tells you, 'No one by that name is registered here!'",
 | |
| 	FALSE, mailman, 0, ch, TO_VICT);
 | |
|     return;
 | |
|   }
 | |
|   act("$n starts to write some mail.", TRUE, ch, 0, 0, TO_ROOM);
 | |
|   snprintf(buf, sizeof(buf), "$n tells you, 'I'll take %d coins for the stamp.'\r\n"
 | |
|        "$n tells you, 'Write your message, use @ on a new line when done.'",
 | |
| 	  STAMP_PRICE);
 | |
| 
 | |
|   act(buf, FALSE, mailman, 0, ch, TO_VICT);
 | |
|   GET_GOLD(ch) -= STAMP_PRICE;
 | |
|   SET_BIT(PLR_FLAGS(ch), PLR_MAILING);	/* string_write() sets writing. */
 | |
| 
 | |
|   /* Start writing! */
 | |
|   CREATE(mailwrite, char *, 1);
 | |
|   string_write(ch->desc, mailwrite, MAX_MAIL_SIZE, recipient, NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| void postmaster_check_mail(struct char_data *ch, struct char_data *mailman,
 | |
| 			  int cmd, char *arg)
 | |
| {
 | |
|   if (has_mail(GET_IDNUM(ch)))
 | |
|     act("$n tells you, 'You have mail waiting.'", FALSE, mailman, 0, ch, TO_VICT);
 | |
|   else
 | |
|     act("$n tells you, 'Sorry, you don't have any mail waiting.'", FALSE, mailman, 0, ch, TO_VICT);
 | |
| }
 | |
| 
 | |
| 
 | |
| void postmaster_receive_mail(struct char_data *ch, struct char_data *mailman,
 | |
| 			  int cmd, char *arg)
 | |
| {
 | |
|   char buf[256];
 | |
|   struct obj_data *obj;
 | |
| 
 | |
|   if (!has_mail(GET_IDNUM(ch))) {
 | |
|     snprintf(buf, sizeof(buf), "$n tells you, 'Sorry, you don't have any mail waiting.'");
 | |
|     act(buf, FALSE, mailman, 0, ch, TO_VICT);
 | |
|     return;
 | |
|   }
 | |
|   while (has_mail(GET_IDNUM(ch))) {
 | |
|     obj = create_obj();
 | |
|     obj->item_number = NOTHING;
 | |
|     obj->name = strdup("mail paper letter");
 | |
|     obj->short_description = strdup("a piece of mail");
 | |
|     obj->description = strdup("Someone has left a piece of mail here.");
 | |
| 
 | |
|     GET_OBJ_TYPE(obj) = ITEM_NOTE;
 | |
|     GET_OBJ_WEAR(obj) = ITEM_WEAR_TAKE | ITEM_WEAR_HOLD;
 | |
|     GET_OBJ_WEIGHT(obj) = 1;
 | |
|     GET_OBJ_COST(obj) = 30;
 | |
|     GET_OBJ_RENT(obj) = 10;
 | |
|     obj->action_description = read_delete(GET_IDNUM(ch));
 | |
| 
 | |
|     if (obj->action_description == NULL)
 | |
|       obj->action_description =
 | |
| 	strdup("Mail system error - please report.  Error #11.\r\n");
 | |
| 
 | |
|     obj_to_char(obj, ch);
 | |
| 
 | |
|     act("$n gives you a piece of mail.", FALSE, mailman, 0, ch, TO_VICT);
 | |
|     act("$N gives $n a piece of mail.", FALSE, ch, 0, mailman, TO_ROOM);
 | |
|   }
 | |
| }
 |