untermud/DOC/
untermud/DOC/U/
untermud/DOC/U/U-examples/
untermud/DOC/internals/
untermud/DOC/wizard/
untermud/MISC/
untermud/MISC/dbchk/
untermud/RWHO/
untermud/RWHO/rwhod/
/*
    Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/

/* configure all options BEFORE including system stuff. */
#include    "config.h"
/*
#define CRON_DEBUG
*/

/* define this prototype here to avoid extern/static conflict */
static int lowest_quant ();

#include    <sys/types.h>

#include    "mud.h"
#include    "vars.h"

/* flags for cron entries */
#define KRON_CMD    01          /* is macro */
#define KRON_U      02          /* is U-code */
#define KRON_BILL   04          /* bill owner for call */

typedef struct kron {
  int jobid;
  time_t interv;
  time_t last;
  int runcnt;
  int flgs;
  char *who;
  char *aswho;
  char *cmd;
  struct kron *nxt;
} Kron;

static Kron *crontab;
static int curjobid = 0;

static int cron_add(time_t interv, int runcnt, char *cmd, char *who, char *aswh, int flg);
static int lowest_quant(void);
static int cron_del(int jobid, char *who, int pf);
static void cron_list(char *who);

int cron_run (time_t now)
{
  Kron *k;
  Kron *p;
  long squant = -1;

  k = p = crontab;

#ifdef  CRON_DEBUG
  printf ("running cron - quantum is %d\n", cron_quantum);
#endif

  while (k != (Kron *) 0) {
    if (now - k->last >= k->interv) {
#ifdef  CRON_DEBUG
      printf ("trigger %s runs %s\n", k->who, k->cmd);
#endif
      if (cache_check (k->who)) {
        if (k->flgs & KRON_U) {
          parser_setinput (k->cmd);
          if (parser_compile (k->who)) {
            run_setactor (k->who);
            (void) parser_run (k->who, k->aswho, 0, (char **) 0);
          }
        } else if (k->flgs & KRON_CMD) {
          (void) run (k->who, k->aswho, k->cmd, 0, 0, 1);
        }
      }
      k->last = now;

      if (k->runcnt != -1)
        k->runcnt--;

#ifdef  COMBAT
      /* debit the guy some action points */
      if (k->flgs & KRON_BILL) {
        int vat;

        if (ut_getnum (k->who, var_action, &vat) < 0 ||
          (vat - (2000 / k->interv) <= 0)) {
          k->runcnt = 0;
#ifdef  CRON_DEBUG
          printf ("expire %s action %s\n", k->who, k->cmd);
#endif
        } else {
          vat -= (2000 / k->interv);
          ut_setnum (k->who, k->who, var_action, vat);
        }
      }
#endif
    }

    if (k->runcnt == 0) {
      if (k == crontab)
        crontab = k->nxt;
      else
        p->nxt = k->nxt;
      if (squant == -1)
        squant = k->interv;
      else {
        if (k->interv < squant)
          squant = k->interv;
      }

      if (k->cmd != (char *) 0)
        free ((mall_t) k->cmd);
      if (k->aswho != (char *) 0)
        free ((mall_t) k->aswho);
      if (k->who != (char *) 0)
        free ((mall_t) k->who);
      p = k;
      free ((mall_t) k);
      k = p->nxt;
      continue;
    }

    p = k;
    k = k->nxt;
  }
  if (squant != -1 && squant <= cron_quantum) {
    cron_quantum = lowest_quant ();
#ifdef  CRON_DEBUG
    printf ("new cron quantum %d\n", cron_quantum);
#endif
  }
  return (0);
}





static int cron_add (interv, runcnt, cmd, who, aswho, flg)
time_t interv;
int runcnt;
char *cmd;
char *who;
char *aswho;
int flg;
{
  static char *allerr = "cannot allocate cron structure\n";
  Kron *k;

  if (cmd == (char *) 0 || who == (char *) 0 || aswho == (char *) 0 ||
    *cmd == '\0' || *who == '\0' || *aswho == '\0')
    return (1);

  if ((k = (Kron *) malloc (sizeof (Kron))) == (Kron *) 0) {
    log_printf (allerr, (char *) 0);
    return (-1);
  }

  k->interv = interv;
  (void) time (&k->last);
  k->runcnt = runcnt;

  k->who = (char *) malloc ((unsigned) (strlen (who) + 1));
  if (k->who == (char *) 0) {
    log_printf (allerr, (char *) 0);
    return (-1);
  }
  strcpy (k->who, who);

  k->aswho = (char *) malloc ((unsigned) (strlen (aswho) + 1));
  if (k->aswho == (char *) 0) {
    log_printf (allerr, (char *) 0);
    return (-1);
  }
  strcpy (k->aswho, aswho);

  k->cmd = (char *) malloc ((unsigned) (strlen (cmd) + 1));
  if (k->cmd == (char *) 0) {
    log_printf (allerr, (char *) 0);
    return (-1);
  }
  strcpy (k->cmd, cmd);
  k->flgs = flg;
  k->nxt = crontab;
  crontab = k;
  k->jobid = curjobid++;
  return (k->jobid);
}





static int lowest_quant (void)
{
  Kron *k;
  int lowest = 3600;

  for (k = crontab; k != (Kron *) 0; k = k->nxt)
    if (k->interv < lowest)
      lowest = k->interv < CRONQUANT ? CRONQUANT : k->interv;
  return (lowest);
}





static int cron_del (jobid, who, pf)
int jobid;
char *who;
int pf;
{
  Kron *k;
  Kron *p;

  k = p = crontab;

  while (k != (Kron *) 0) {
    if (k->jobid == jobid) {
      int squant;

      if (!pf && strcmp (who, k->who)) {
        say (who, "Permission denied.\n", (char *) 0);
        return (UERR_PERM);
      }

      squant = k->interv;
      if (k == crontab)
        crontab = k->nxt;
      else
        p->nxt = k->nxt;

      if (k->cmd != (char *) 0)
        free ((mall_t) k->cmd);
      if (k->aswho != (char *) 0)
        free ((mall_t) k->aswho);
      if (k->who != (char *) 0)
        free ((mall_t) k->who);
      free ((mall_t) k);
      if (squant <= cron_quantum) {
        cron_quantum = lowest_quant ();
#ifdef  CRON_DEBUG
        printf ("new cron quantum %d\n", cron_quantum);
#endif
      }
      say (who, "Event deleted.\n", (char *) 0);
      return (UERR_NONE);
    }
    p = k;
    k = k->nxt;
  }
  say (who, "Unknown event.\n", (char *) 0);
  return (UERR_NOMATCH);
}





static void cron_list (char *who)
{
  Kron *k;
  char pbuf[80];

  k = crontab;

  while (k != (Kron *) 0) {
    snprintf (pbuf, sizeof (pbuf), "id# %d, every %d sec., ", k->jobid,
      (int) k->interv);
    say (who, pbuf, (char *) 0);

    if (k->runcnt != -1) {
      snprintf (pbuf, sizeof (pbuf), "%d runs, ", k->runcnt);
      say (who, pbuf, (char *) 0);
    }

    snprintf (pbuf, sizeof (pbuf), "(%s/%s): %-30s\n", k->who, k->aswho,
      k->cmd);
    say (who, pbuf, (char *) 0);
    k = k->nxt;
  }
}



/* ARGSUSED */
int cmd__cronconfig (int ac, char *av[], char *who, char *aswho)
{
  /* define an event */
  if (!strcmp (av[1], "defevent") || !strcmp (av[1], "defUevent")) {
    int eid;
    int iv;
    int rc = -1;                /* repeat forever */

    char *twho;
    char *taswho;
    int flg = 0;

    if (!strcmp (av[1], "defUevent"))
      flg |= KRON_U;
    else
      flg |= KRON_CMD;

    if (ac < 4) {
      log_printf ("usage: defevent interval macro [who] [aswho] [count]\n",
        (char *) 0);
      return (UERR_ARGCNT);
    }


    if ((iv = atoi (av[2])) < CRONQUANT) {
      log_printf ("event interval is too short\n", (char *) 0);
      iv = CRONQUANT;
    }

    if (iv < cron_quantum) {
      cron_quantum = iv;
#ifdef  CRON_DEBUG
      printf ("new cron quantum %d\n", cron_quantum);
#endif
    }

    twho = who;
    if (ac > 4)
      twho = av[4];

    taswho = who;
    if (ac > 5)
      taswho = av[5];

    if (ac > 6)
      rc = atoi (av[6]);

    eid = cron_add (iv, rc, av[3], twho, taswho, flg);

    if (eid < 0) {
      log_printf ("event not added\n", (char *) 0);
      return (UERR_FATAL);
    }
    log_printf ("added event: ", av[3], "\n", (char *) 0);
    return (UERR_NONE);
  }


  /* UNdefine an event */
  if (!strcmp (av[1], "undefevent")) {
    if (ac != 3) {
      log_printf ("usage: undefevent event-id\n", (char *) 0);
      return (UERR_ARGCNT);
    }

    return (cron_del (atoi (av[2]), who, 1));
  }

  if (!strcmp (av[1], "list")) {
    cron_list (who);
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "help")) {
    say (who, av[0], " undefevent event-id\n", (char *) 0);
    say (who, av[0], " defevent interval macro [who] [aswho] [count]\n",
      (char *) 0);
    say (who, av[0], " list\n", (char *) 0);
    return (UERR_NONE);
  }

  log_printf ("_cronconfig: I don't understand ", av[1], "\n", (char *) 0);
  return (UERR_BADPARM);
}


#ifdef  COMBAT
/* ARGSUSED */
int cmd__crondel (int ac, char *av[], char *who, char *aswho)
{
  return (cron_del (atoi (av[1]), who, 0));
}




/* ARGSUSED */
int cmd__cronlist (int ac, char *av[], char *who, char *aswho)
{
  Kron *k;
  char pbuf[80];
  int got = 0;

  for (k = crontab; k != (Kron *) 0; k = k->nxt) {
    if (strcmp (who, k->who))
      continue;
    snprintf (pbuf, sizeof (pbuf), "id# %d, every %d sec., ", k->jobid,
      (int) k->interv);
    say (who, pbuf, (char *) 0);

    if (k->runcnt != -1) {
      snprintf (pbuf, sizeof (pbuf), "%d runs, ", k->runcnt);
      say (who, pbuf, (char *) 0);
    }
    snprintf (pbuf, sizeof (pbuf), ": %-30s\n", k->cmd);
    say (who, pbuf, (char *) 0);
    got++;
  }
  if (!got)
    say (who, "No cron entries.\n", (char *) 0);
  return (UERR_NONE);
}




/* ARGSUSED */
int cmd__cron (int ac, char *av[], char *who, char *aswho)
{
  int eid;
  int iv;
  int rc = -1;                  /* repeat forever */
  char *twho;
  int flg = 0;

  if (!strcmp (av[0], "_Ucron"))
    flg |= KRON_U | KRON_BILL;
  else
    flg |= KRON_CMD | KRON_BILL;


  if (ac < 3) {
    say (who, "usage: ", av[0],
      " second-count command [repeats] [object-actor]\n", (char *) 0);
    return (UERR_ARGCNT);
  }

  if ((iv = atoi (av[1])) < CRONQUANT) {
    log_printf ("event interval is too short\n", (char *) 0);
    iv = CRONQUANT;
  }

  twho = who;
  if (ac > 4)
    twho = av[4];
  if (!ut_isobjown (aswho, twho) && !ut_flagged (aswho, var_wiz)) {
    say (who, "You do not own ", ut_name (twho), ".\n", (char *) 0);
    return (UERR_PERM);
  }

  if (ac > 3)
    rc = atoi (av[3]);


  if (iv < cron_quantum) {
    cron_quantum = iv;
#ifdef  CRON_DEBUG
    printf ("new cron quantum %d\n", cron_quantum);
#endif
  }
  eid = cron_add (iv, rc, av[2], twho, twho, flg);

  if (eid < 0) {
    say (who, "Event not added.\n", (char *) 0);
    return (UERR_FATAL);
  } else {
    char fubb[MAXOID];
    say (who, "Added event ", itoa (eid, fubb, 10), ".\n", (char *) 0);
    eval_cmd_returnint (eid);
    return (UERR_NONE);
  }
}
#endif