/* Mail.c */
/* Dec 1991, Justin McKinnerney <Joarm> */

#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>
#include "config.h"
#include "db.h"
#include "interface.h"
#include "externs.h"

struct mail *mdb;
mdbref mdb_top;

static const char *dash_line = 
  "-------------------------------------------------------------------------";

void read_mail();		/* make compiler happy */

void do_mail(player, list, obj)
     dbref player;
     char *list;
     char *obj;
{
  dbref to;
  mdbref temp;

  if(!Wizard(player) && Typeof(player) != TYPE_PLAYER) {
    notify(player, "Sorry, only players can do that.");
    return;
  }

  if(!*list) {
    check_mail(player, 1);
    return;
  }
  if(Wizard(player) && !string_compare(list, "mdb-stats")) {
    notify(player, tprintf("There are %d messages total.", mdb_top));
    return;
  }
  if(Wizard(player) && !string_compare(list, "mdb-purge")) {
    mail_init();
    fprintf(stderr, "MAIL ERASE BY: %s", db[player].name);
    notify(player, "You have cleared ALL mail!");
    return;
  }
  if(*list > '0' && *list <= '9' && (!*obj || obj == NULL)) {
    read_mail(player, atol(list));
    return;
  }
  if(!string_compare(list, "clear")) {
    clear_mail(player, obj);
    return;
  }
  if(*list > '0' && *list <= '9') {
    temp = search_mail(player, atol(list));
    if(temp > 0 && temp <= mdb_top)
      to = mdb[temp].from;
    else {
      notify(player, "Invalid message number.");
      return;
    }
  } else
    if((to = lookup_player(list)) == NOTHING) {
      notify(player, "No such player.");
      return;
    }
  send_mail(player, to, obj);
}

void send_mail(player, to, msg)
     dbref player;
     dbref to;
     char *msg;
{
  time_t tt;
  struct mail *newdb;
  char *p;
  char temp[BUFFER_LEN];

  if(player == to) {
    notify(player, "Why would you want to send mail to yourself?");
    return;
  }

  mdb_top++;
  if((newdb = (struct mail *) realloc(mdb, (mdb_top+1)*sizeof(struct mail)+1))
     == NULL) {
    notify(player, "Out of memory error, please notify God.");
    return;
  }
  memcpy(newdb, mdb, (mdb_top+1) * sizeof(struct mail)+1);
  mdb = (struct mail *)newdb;
  mdb[mdb_top].number = 0;
  mdb[mdb_top].number = mail_top(to) + 1;
  mdb[mdb_top].message = NULL;
  for(p = temp; *msg; msg++) {
    if(*msg == '%' && tolower(*(msg+1) == 'r'))
      msg++;
    else
      *p++ = *msg;
  }
  *p = 0;
  SET(mdb[mdb_top].message, pronoun_substitute(player, temp, player));
  mdb[mdb_top].from = player;
  mdb[mdb_top].to = to;
  mdb[mdb_top].read = 0;
  tt = time((time_t *) 0);
  mdb[mdb_top].time = NULL;
  strcpy(temp, ctime(&tt));
  SET(mdb[mdb_top].time, temp);
  mdb[mdb_top].time[strlen(mdb[mdb_top].time) -1] = 0;
  if(db[to].flags & PLAYER_CONNECT)
    notify(to, tprintf("You sense that you have new mail from %s.",
		       db[player].name));
  notify(player, tprintf("Your mail has been sent to %s.", db[to].name));
}

mdbref mail_top(player)
     dbref player;
{
  mdbref loop;
  mdbref check = 0;
  for(loop = 1; loop <= mdb_top; loop++)
    if(mdb[loop].to == player && mdb[loop].number > check)
      check = mdb[loop].number;
  return(check);
}

mdbref search_mail(player, number)
     dbref player;
     mdbref number;
{
  mdbref loop;
  for(loop = 1; loop <= mdb_top; loop++)
    if(mdb[loop].to == player && mdb[loop].number == number)
	return(loop);
  return(0);
}

void read_mail(player, number)
     dbref player;
     mdbref number;
{
  mdbref msg;
  char tbuf1[BUFFER_LEN];
  if((msg = search_mail(player, number)) > 0 && msg <= mdb_top) {
    sprintf(tbuf1, "From: %-16s Time: %s", db[(mdb[msg].from)].name,
	    mdb[msg].time);
    if(mdb[msg].read)
      sprintf(tbuf1+strlen(tbuf1),"   Status: Read");
    else
      sprintf(tbuf1+strlen(tbuf1),"   Status: Unread");
    notify(player, dash_line);
    notify(player, tbuf1);
    notify(player, dash_line);
    notify(player, mdb[msg].message);
    notify(player, dash_line);
    mdb[msg].read = 1;
  }
  else
    notify(player, "Invalid message number.");
}

void check_mail(player, mode)
     dbref player;
     char mode;
{
  mdbref loop;
  mdbref num = 0;
  char tbuf1[BUFFER_LEN];
  switch(mode) {
  case 0:
    for(loop = 1; loop <= mdb_top && num != 2; loop++)
      if(mdb[loop].to == player)
	if(mdb[loop].read)
	  num = 1;
         else
	   num = 2;
    switch(num) {
    case 0:
      notify(player, "\n*** You have no mail ***\n");
      break;
    case 1:
      notify(player, "\n*** You have mail ***\n");
      break;
    case 2:
      notify(player, "\n*** You have NEW mail ***\n");
      break;
    }
    break;
  case 1:
    notify(player, 
"--------------------------------   MAIL   -------------------------------");
    for(loop = 1; num = search_mail(player, loop); loop++) {
	tbuf1[0] = 0;
	if(mdb[num].read)
	  sprintf(tbuf1, "[ ] ");
	else
	  sprintf(tbuf1, "[*] ");
	sprintf(tbuf1+strlen(tbuf1),"%d ", loop);
	sprintf(tbuf1+strlen(tbuf1),"From: %-16s Time: %s",
		db[(mdb[num].from)].name, mdb[num].time);
	notify(player, tbuf1);
      }
    notify(player, dash_line);
    break;
  }
}

void clear_mail(player, list)
     dbref player;
     char *list;
{
  mdbref num, loop;
  int flag = 0;
  struct mail *newdb;
  if(!list || !*list) {
    for(loop = 1; num = search_mail(player, loop); loop++) {
	flag = 1;
	mdb[num].to = mdb[mdb_top].to;
	mdb[num].from = mdb[mdb_top].from;
	mdb[num].number = mdb[mdb_top].number;
	mdb[mdb_top].number = 0;
	mdb[num].read = mdb[mdb_top].read;
	mdb[num].message = mdb[mdb_top].message;
	mdb[num].time = mdb[mdb_top].time;
	--mdb_top;
      }
    if(flag) {
      if((newdb=(struct mail *)realloc(mdb,(mdb_top+1)*sizeof(struct mail)+1))
	 == NULL) {
	notify(player, "ERROR: Out of memory <Please notify God>");
	fprintf(stderr, "ERROR: Out of memory in clear_mail\n");
	return;
      }
      memcpy(newdb, mdb, (mdb_top+1)*sizeof(struct mail)+1);
      mdb = (struct mail *)newdb;
      notify(player, "Mailbox cleared!");
    }
    else
      notify(player, "No mail to clear!");
  } else {
    if(flag = atol(list))
      if(num = search_mail(player, flag)) {
	mdb[num].to = mdb[mdb_top].to;
	mdb[num].from = mdb[mdb_top].from;
	mdb[num].number = mdb[mdb_top].number;
	mdb[num].read = mdb[mdb_top].read;
	mdb[num].message = mdb[mdb_top].message;
	mdb[num].time = mdb[mdb_top].time;
	--mdb_top;
       if((newdb=(struct mail *)realloc(mdb,(mdb_top+1)*sizeof(struct mail)+1))
	   == NULL) {
	  notify(player, "ERROR: Out of memory <please notify God>");
	  fprintf(stderr, "ERROR: Out of memory in clear_mail\n");
	  return;
	}
	memcpy(newdb, mdb, (mdb_top+1)*sizeof(struct mail)+1);
	mdb = (struct mail *)newdb;
	if(flag < mail_top(player))
	  for(loop = flag+1; num = search_mail(player, loop); loop++)
	    mdb[num].number--;
	notify(player, tprintf("Message #%d cleared!", flag));
      }
    else 
      notify(player, "Invalid message number.");
  }
}

void putmref(f, ref)
     FILE *f;
     mdbref ref;
{
  fprintf(f, "%d\n", ref);
}

void putstring(f, s)
     FILE *f;
     char *s;
{
  if(s)
    fputs(s, f);
  putc('\n', f);
}

mdbref getmref(f)
     FILE *f;
{
  static char buff[BUFFER_LEN];
  fgets(buff, sizeof(buff), f);
  return(atol(buff));
}

static const char *getstring(f)
     FILE *f;
{
  static char buff[BUFFER_LEN];
  char *p;
  fgets(buff, sizeof(buff), f);
  for(p = buff; *p; p++)
    if(*p == '\n') {
      *p = '\0';
      break;
    }
  return buff;
}

void dump_mail(f)
     FILE *f;
{
  mdbref loop;
  if(mdb_top <=0) return;
  putmref(f, mdb_top);
  for(loop = 1; loop <= mdb_top; loop++) {
    putmref(f, mdb[loop].from);
    putmref(f, mdb[loop].to);
    putmref(f, mdb[loop].number);
    putmref(f, mdb[loop].read);
    putstring(f, mdb[loop].time);
    putstring(f, mdb[loop].message);
  }
}

void load_mail(f)
     FILE *f;
{
  mdbref loop;
  char temp[BUFFER_LEN];
  struct mail *newdb;
  mdb_top = 0;
  mdb = (struct mail *) malloc(sizeof(struct mail)+1);
  mdb[0].message = 0;  mdb[0].time = 0;
  mdb[0].to = 0; mdb[0].from = 0; mdb[0].read = 0;
  mdb_top = getmref(f);
  if((newdb=(struct mail *)realloc(mdb,(mdb_top+1)*sizeof(struct mail)+1))
     == NULL) {
    fprintf(stderr, "ERROR: Out of memory in load_mail\n");
    return;
  }
  memcpy(newdb, mdb, (mdb_top+1) * sizeof(struct mail)+1);
  mdb = (struct mail *)newdb;
  for(loop = 1; loop <= mdb_top; loop++) {
    mdb[loop].from = getmref(f);
    mdb[loop].to = getmref(f);
    mdb[loop].number = getmref(f);
    mdb[loop].read = getmref(f);
    strcpy(temp, getstring(f));
    mdb[loop].time = NULL;
    SET(mdb[loop].time, temp);
    strcpy(temp, getstring(f));
    mdb[loop].message = NULL;
    SET(mdb[loop].message, temp);
  }
}

void mail_init()
{
  fprintf(stderr, "MAIL INIT\n");
  mdb_top = 0;
  mdb = (struct mail *) malloc(sizeof(struct mail)+1);
  mdb[0].message = 0;  mdb[0].time = 0; mdb[0].number = 0;
  mdb[0].to = 0; mdb[0].from = 0; mdb[0].read = 0;
  fprintf(stderr, "INITALIZED\n");
}