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

#include "os.h"
#include "config.h"
#include "db.h"
#include "interface.h"
#include "externs.h"

struct mail *mdb;
mdbref mdb_top;

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

static void read_mail (dbref player, mdbref number);
static mdbref mail_top (dbref player);

void do_mail (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 (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 ((int)*(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));
}

static mdbref mail_top (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 (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);
}

static void read_mail (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 (dbref player, int 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 (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.");
  }
}

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

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

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

static const char *getstring (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 (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, (char*)mdb[loop].message);
  }
}

void load_mail (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 (void)
{
  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");
}