tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
//  File    : /cmds/xtra/_event.c
//  Creator : Watcher@TMI  (12/14/92)
//
//  Command which allows users to input scheduled events to the
//  central event daemon for future initiation.

#include <mudlib.h>
#include <daemons.h>
#include <uid.h>
#include <driver/localtime.h>

inherit DAEMON;
inherit TIME_D;

#define SECS_IN_DAY     (60*60*24)
#define YEARS_IN_GOOGLE 4   /* google is a 4 year period including leap year */
#define DAYS_IN_GOOGLE  (4*365+1)
#define SECS_IN_MIN     60
#define MIN_IN_HOUR     60
#define HOURS_IN_DAY    24
#define SECS_IN_HOUR    (60*60)

// maximum earliness (seconds in advance) by which to schedule new events
// In this example, we choose a month
#define MAX_EARLY_SCHED   ( 31 * SECS_IN_DAY )

#define TYPES   ({ "once", "hourly", "daily", "weekly" })

#define MONTHS  ({ "Jan", "Feb", "Mar", "Apr", "May", "Jun", \
                   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" })

#define DAYS    ({ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 })

#define SYNTAX \
        "Syntax: event [command] [stack]\n\n" + \
        "        event add       [once/hourly/daily/weekly]\n" + \
        "        event add root  [once/hourly/daily/weekly] (admin only)\n" + \
        "        event remove    [once/hourly/daily/weekly]\n" + \
        "        event list      [once/hourly/daily/weekly]\n"

static int list_stack(string type);
static int add_event(string type, int root);
static int rem_event(string type);
static int root_check(string perm);

int busy;

int cmd_event(string str) {
    string type, form;
    int root;

    notify_fail( SYNTAX );
    if (!str || str == "")
        return 0;

    // Check busy flag to see if the daemon is presently in use
    if (busy) {
        write("Sorry, the event daemon is busy right now.\n" +
              "Please try again in a few minutes.\n");
        return 1;
    }

    if (sscanf(str, "add %s", type) == 1) {
        form = "add";

        // Check to see if root permission settings are requested
        if (sscanf(type, "root %s", type) == 1) {
            if (!root_check(geteuid(this_player()))) {
                write("Only admin may set root permission events.\n");
                return 1;
            }
            root = 1;
        }

        if (member_array(type, TYPES) == -1)
            return 0;
    } else if (sscanf(str, "remove %s", type) == 1) {
        form = "remove";
        if (member_array(type, TYPES) == -1)
            return 0;
    } else if (str == "list") {
        form = "list";
    } else if (sscanf(str, "list %s", type) == 1) {
        form = "list";
        if (member_array(type, TYPES) == -1)
            return 0;
    } else
        return 0;

    if (form == "list")
        return list_stack(type);
    else if (form == "add")
        return add_event(type, root);
    else if (form == "remove")
        return rem_event(type);

    return 0;
}


static int root_check(string perm) {
    if (perm == ROOT_UID || adminp(perm))
        return 1;

    return 0;
}


static int list_stack(string type) {
    mixed *stack;
    int loop, s;

    if (!type || type == "") {            // Check all stacks
        write("Event Stack status:\n");

        s = sizeof(TYPES);
        for (loop = 0; loop < s; loop++) {
            stack = EVENT->query_stack(TYPES[loop]);
            if (!stack || stack == ({ }))
                write(sprintf(" The \"%s\" stack is presently empty.\n",
                      TYPES[loop]));
            else
                write(sprintf(" The \"%s\" stack has %d events queued.\n",
                      TYPES[loop], sizeof(stack)));
        }

        return 1;
    }

    // Read in particular event stack for element check and display
    stack = EVENT->query_stack(type);

    if (!stack || stack == ({ })) {
        write(sprintf(" The \"%s\" stack is presently empty.\n", type));
        return 1;
    }

    // Display queued contents of selected event stack
    write(sprintf(" The \"%s\" stack presently contains:\n", type));

    s = sizeof(stack);
    for (loop = 0; loop < s; loop++)
        if (atoi(stack[loop][3]))
            write(wrap(" " + (loop + 1) + "] " + stack[loop][2] + "(" +
                  stack[loop][3]+ ") on " + stack[loop][1] + " by " +
                  capitalize(stack[loop][4]) + " [" +
                  extract(ctime(stack[loop][0]), 4, 15) + "]\n"));
        else
            write(wrap(" " + (loop + 1) + "] " + stack[loop][2] + "(\"" +
                  stack[loop][3] + "\") on " + stack[loop][1] + " by " +
                  capitalize(stack[loop][4]) + " [" +
                  extract(ctime(stack[loop][0]), 4, 15) + "]\n"));
    return 1;
}


static int rem_event(string type) {
    mixed *stack;

    // Read in particular event stack for element check

    stack = EVENT->query_stack(type);

    if (!stack || stack == ({ })) {
        write(sprintf(" The \"%s\" stack is presently empty.\n", type));
        return 1;
    }

    busy = 1;                    // Set busy flag

    // Display selected stack and request deletion event number
    list_stack(type);
    write("\nDelete which event? [num]  ");
    input_to("del_number", 0, type);

    return 1;
}


static int del_number(string str, string type) {
    mixed *stack;
    int num;

    // Read in selected stack for removal processing
    stack = EVENT->query_stack(type);
    num = atoi(str);

    // Check to see if requested deletion is within event bounds
    if (num < 1 || num > sizeof(stack)) {
        write("There is no such event available for removal.\n");
        busy = 0;
        return 1;
    }

    // Check to see if permissions match or are ROOT to allow deletion
    if (!root_check(geteuid(this_player())) &&
          geteuid(this_player()) != stack[num - 1][4]) {
        write("You do not have the proper permissions to remove that event.\n");
        busy = 0;
        return 1;
    }

    // Tell event daemon to remove selected event
    if (!EVENT->remove_event( type, stack[num - 1] )) {
        write("Error:  Unable to remove requested event.\n");
    } else {
        write(sprintf("Event %d removed from \"%s\" event stack.\n", num, type));
    }

    busy = 0;
    return 1;
}


static int add_event(string type, int root) {
    // Set busy flag on
    busy = 1;

    write("\nInput [target filename],[function],[optional argument]\n: ");
    input_to("receive_event", 0, type, root);

    return 1;
}


static int receive_event(string str, string type, int root) {
    object target;
    string obj, func, arg;

    if (sscanf(str,"%s, %s, %s", obj, func, arg) != 3 &&
          sscanf(str,"%s,%s,%s", obj, func, arg) != 3 &&
          sscanf(str,"%s,%s", obj, func) != 2) {
        write("\nIllegal event addition format.\n");
        busy = 0;
        return 1;
    }

    if (catch( call_other(obj, "???") )) {
        write(sprintf("Error: Could not access %s\n", obj));
        busy = 0;
        return 1;
    }

    target = find_object(obj);

    if (!target) {
        write(sprintf("Error: Could not access %s\n", obj));
        busy = 0;
        return 1;
    }

    if (geteuid(target) == ROOT_UID && !root_check(geteuid(this_player()))) {
        write("You have insufficient permissions to access that object.\n");
        busy = 0;
        return 1;
    }

    write(sprintf("\nCurrent time is: %s GMT\n\n" 
                  "Input activation time [Format: mm/dd/yyyy 24:00]\n: ",
                  ctime(time())));
    input_to("process_time", 0, type, root, obj, func, arg);

    return 1;
}


static int process_time(string str, string type, int root, string obj,
            string func, string arg) {
    string when, permit, target;
    int date, month, day, year, hour, minute;
    int i, yd, googles, ry;
    mixed *ltime;

    if (!str || sscanf(str,"%d/%d/%d %d:%d",month,day,year,hour,minute) != 5) {
        write("Illegal activation time format.\n");
        busy = 0;
        return 1;
    }

    // a 20th century hack
    if (year < 100)
        year += 1900;

    // Discard requests outside standard time/date bounds
    if (month < 1 || month > 12 || day < 1 || day > DAYS[month-1] ||
          minute < 0 || minute > 59 ||
          hour < 0 || hour > 24 || year < 1992 ||
          (month == 2 && day == 28 &&
                !(year % 4 == 0 && (year % 100 > 0 || year % 400 == 0)))) {
        write("Illegal activation time format.\n");
        busy = 0;
        return 1;
    }

    // Set user's permission string...
    // ...but if root is requested, set it
    permit = root ? ROOT_UID : geteuid(this_player());

    // Convert user's date/time input specification to time_t (int)
    // BTW I don't think this code will work in/after the year 2100 AD
    // Code for mktime() follows:

    // First, make some adjustments
    month--;
    year -= 1900;

    // Then, take care of time-of-day
    date = (SECS_IN_MIN * minute) +
           (SECS_IN_HOUR * hour) +
           (SECS_IN_DAY * (day - 1));

    // Next, calculate the number of days already past in the current year
    for (i = 0, yd = 0; i < month; i++) {
        yd += DAYS[i];
        if (i == 1 && (year & 3) == 0)
            yd++; // add an extra day for leap year
    }
    date += yd * SECS_IN_DAY;

    googles = (year - 70) / YEARS_IN_GOOGLE;
    date += googles * DAYS_IN_GOOGLE * SECS_IN_DAY;

    // Calculate the number of days since the last google
    ry = 70 + YEARS_IN_GOOGLE * googles;
    for (i = ry, yd = 0; i < year; i++) {
        yd += 365;
        if ((i & 3) == 0)
            yd++;
    }
    date += yd * SECS_IN_DAY;

    // Lastly, make adjustment for local timezone from GMT
    ltime = localtime(time());
    date -= ltime[LT_GMTOFF];

    if (date > (time() + MAX_EARLY_SCHED)) {
        write("That date is too far in advance of present date.\n");
        busy = 0;
        return 1;
    }

    if (date <= time()) {
        write("That time has already gone past. Pick a time in the future.\n");
        busy = 0;
        return 1;
    }

    if (!EVENT->add_event(type, ({ date, obj, func, arg, permit }))) {
        write("Error: Could not add requested event.\n");
    } else {
        write(sprintf("\nEvent added to the \"%s\" event stack.\n", type));
    }

    busy = 0;
    return 1;
}


int help() {
  write(SYNTAX "\n" @ENDTEXT
This command allows a user to add or remove an event into one of four
event stacks (once, hourly, daily, weekly).  If an event is scheduled
in the "once" stack, then it will occur once at its preset time,
then is removed from the stack.  The other three stacks involve the
event being called at its scheduled time, then rescheduled to the next
time slot corresponding to that particular stack.  Individual stacks
or the entire stack set can be listed using the "list" parameter.

Only the scheduler, or an admin, can remove an event from a stack,
and only an admin may set an event to root permissions.
ENDTEXT
    );
  return 1;
}