foundation2_fluffos_v1/
foundation2_fluffos_v1/bin/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/ChangeLog.old/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/Win32/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/compat/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/compat/simuls/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/include/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/clone/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/command/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/data/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/etc/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/include/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/inherit/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/inherit/master/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/log/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/single/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/single/tests/compiler/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/single/tests/efuns/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/single/tests/operators/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/u/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/tmp/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/windows/
foundation2_fluffos_v1/lib/cfg/
foundation2_fluffos_v1/lib/cmds/adm/
foundation2_fluffos_v1/lib/daemon/save/
foundation2_fluffos_v1/lib/daemon/services/
foundation2_fluffos_v1/lib/daemon/soul/
foundation2_fluffos_v1/lib/doc/build/
foundation2_fluffos_v1/lib/doc/classes/
foundation2_fluffos_v1/lib/doc/driver/
foundation2_fluffos_v1/lib/doc/driver/applies/
foundation2_fluffos_v1/lib/doc/driver/applies/interactive/
foundation2_fluffos_v1/lib/doc/driver/concepts/
foundation2_fluffos_v1/lib/doc/driver/driver/
foundation2_fluffos_v1/lib/doc/driver/efuns/arrays/
foundation2_fluffos_v1/lib/doc/driver/efuns/buffers/
foundation2_fluffos_v1/lib/doc/driver/efuns/calls/
foundation2_fluffos_v1/lib/doc/driver/efuns/compile/
foundation2_fluffos_v1/lib/doc/driver/efuns/filesystem/
foundation2_fluffos_v1/lib/doc/driver/efuns/floats/
foundation2_fluffos_v1/lib/doc/driver/efuns/functions/
foundation2_fluffos_v1/lib/doc/driver/efuns/general/
foundation2_fluffos_v1/lib/doc/driver/efuns/mappings/
foundation2_fluffos_v1/lib/doc/driver/efuns/numbers/
foundation2_fluffos_v1/lib/doc/driver/efuns/parsing/
foundation2_fluffos_v1/lib/doc/driver/lpc/constructs/
foundation2_fluffos_v1/lib/doc/driver/lpc/types/
foundation2_fluffos_v1/lib/doc/driver/platforms/
foundation2_fluffos_v1/lib/doc/efun/
foundation2_fluffos_v1/lib/doc/etc/
foundation2_fluffos_v1/lib/doc/faq/
foundation2_fluffos_v1/lib/doc/help/creator/
foundation2_fluffos_v1/lib/doc/help/player/
foundation2_fluffos_v1/lib/doc/lpc/basic/
foundation2_fluffos_v1/lib/doc/lpc/data_types/
foundation2_fluffos_v1/lib/doc/lpc/etc/
foundation2_fluffos_v1/lib/doc/lpc/intermediate/
foundation2_fluffos_v1/lib/doc/lpc/types/
foundation2_fluffos_v1/lib/doc/mudlib/
foundation2_fluffos_v1/lib/doc/mudlib/Features/
foundation2_fluffos_v1/lib/domains/Examples/armour/
foundation2_fluffos_v1/lib/domains/Examples/etc/
foundation2_fluffos_v1/lib/domains/Examples/npc/
foundation2_fluffos_v1/lib/domains/Examples/room/
foundation2_fluffos_v1/lib/domains/Examples/virtual/
foundation2_fluffos_v1/lib/domains/Examples/virtual/exaA/
foundation2_fluffos_v1/lib/domains/Examples/virtual/exaB/
foundation2_fluffos_v1/lib/domains/Examples/weapon/
foundation2_fluffos_v1/lib/domains/School/doc/
foundation2_fluffos_v1/lib/domains/School/room/
foundation2_fluffos_v1/lib/domains/School/room/Classes/
foundation2_fluffos_v1/lib/domains/School/room/Offices/
foundation2_fluffos_v1/lib/domains/Standard/
foundation2_fluffos_v1/lib/domains/Standard/pools/
foundation2_fluffos_v1/lib/domains/Standard/std/
foundation2_fluffos_v1/lib/domains/Standard/xtra/
foundation2_fluffos_v1/lib/include/
foundation2_fluffos_v1/lib/lib/obj/
foundation2_fluffos_v1/lib/news/
foundation2_fluffos_v1/lib/save/
foundation2_fluffos_v1/lib/secure/cfg/
foundation2_fluffos_v1/lib/secure/cmds/player/
foundation2_fluffos_v1/lib/secure/lib/
foundation2_fluffos_v1/old/
foundation2_fluffos_v1/win32/
/* Copyright 1994 - Tim Hollebeek
 *
 * Permission is granted to copy and use this code elsewhere, provided
 * that all code derived from this code retain this header and credit
 * the author (Tim Hollebeek) for the source, that all improvements
 * to this code be communicated to the above mentioned author for possible
 * inclusion in this code, that all derived works are made publicly
 * available to whoever wants them, and no profit is made off of this
 * code or any other derived works or any other package or system this
 * is used in without express written permission of the author.
 */
/*
 *  General news daemon, by Beek
 *  Oct 10, 1994
 *
 * Interface:
 *
 * id NEWS_D->post(group, subject, message)
 * id NEWS_D->followup(group, id, message)
 * NEWS_D->remove_post(group, id)
 * message NEWS_D->get_message(group, id)
 * id array NEWS_D->get_messages(group, filter)
 * id array NEWS_D->get_thread(group, thread)
 * NEWS_D->get_groups()
 * id array NEWS_D->query_removed(group, id array)
 *
 * Internews interface stuff:
 * NEWS_D->remote_post(group, poster, subject, message)
 * NEWS_D->query_export_list(xxx)
 */
#include "/secure/include/daemons.h"

#define SAVE_FILE "/save/news/news"
#define ARCHIVE_DAYS 14
#define ARCHIVE_DIR "/save/news/archive"

void archive_posts();

private mapping data = ([]);

create() {
    string tmp;

    if (clonep()) destruct(this_object());

    restore_object(SAVE_FILE);
    archive_posts();
}

void
save_me() {
    unguarded( (: save_object, SAVE_FILE :) );
}

private int get_new_id(string group) {
    return data[group]["next_id"]++;
}

int
post(string group, string subject, string message) {
    int post_id;
    mapping map = allocate_mapping(5);

    if (!data[group]) return 0;
    post_id = get_new_id(group);
    map["TIME"] = time();
    map["THREAD"] = post_id;
    map["SUBJECT"] = subject;
    map["MESSAGE"] = message;
    map["POSTER"] = this_player()->GetCapName();
    data[group][post_id] = map;
    save_me();
    return post_id;
}

int
remote_post(string group, string poster, string subject, string message) {
    mapping map = allocate_mapping(5);
    int post_id;

    return -1;
    if (!data[group]) return 0;
    post_id = get_new_id(group);
    map["TIME"] = time();
    map["THREAD"] = post_id;
    map["SUBJECT"] = subject;
    map["MESSAGE"] = message;
    map["POSTER"] = poster;
    map["REMOTE"] = 1;
    data[group][post_id] = map;
    save_me();
    return post_id;
}

void

add_group(string group) {
    string fn = file_name(previous_object());

    if (fn != "/secure/cmds/adm/newsadm") return;

    data[group] = (["next_id":1]);
    save_me();
}

void
remove_group(string group) {
    string fn = file_name(previous_object());

    if (fn != "/secure/cmds/adm/_newsadm") return;
    map_delete(data, group);
    save_me();
}

int
followup(string group, int id, string message) {
    int post_id;
    int tmp;
    mapping map = allocate_mapping(6);
    string subject;

    if (!data[group]) return 0;
    if (!data[group][id]) return 0;
    post_id = get_new_id(group);
    subject = ">" + data[group][id]["SUBJECT"];

    /* the original article is the thread id */
    while (tmp = data[group][id]["FOLLOW"])
	id = tmp;
    map["TIME"] = time();
    map["THREAD"] = id;
    map["SUBJECT"] = subject;
    map["MESSAGE"] = message;
    map["POSTER"] = this_player()->GetCapName();
    data[group][post_id] = map;
    save_me();
    return post_id;
}

mapping
get_message(string group, int id) {
    /* sigh */
    return copy(data[group][id]);
}

int
remove_post(string group, int id) {
    if (this_player()->GetCapName() != data[group][id]["POSTER"] && !archp(this_player())) return 0;
    data[group][id]["MESSAGE"] = "***REMOVED***\n";
    data[group][id]["REMOVED"] = 1;
    return 1;
}

int *
get_messages(string group, function filter) {
    int *ret;

    ret = keys(data[group]) - ({ "next_id" });
    if (!filter) filter = (: 1 :);
    ret = filter_array(ret, (: evaluate($(filter), $1, $(data[group])[$1]) :) );
    return sort_array(ret, 1);
}

int *
query_removed(string group, int *ids) {
    return filter_array(ids, (: $(data[group])[$1]["REMOVED"] :) );
}

int *
get_thread(string group, int thread) {
    return filter_array(keys(data[group]), (: $1 != "next_id" 
		       && $(data[group])[$1]["THREAD"] == $(thread) :));
}

string *
get_groups() {
    return sort_array(keys(data), 1);
}

private void
archive_post(string group, int id) {
    string file = sprintf("%s/%s", ARCHIVE_DIR, group);
    string msg = sprintf("---\nposter: %s\nsubject: %s\ndate: %s\n%s\n\n", data[group][id]["POSTER"], data[group][id]["SUBJECT"], ctime(data[group][id]["TIME"]), data[group][id]["MESSAGE"]);
    unguarded( (: write_file, file, msg :) );
    map_delete(data[group], id);
}


void
archive_posts() {
    string *groups;
    int *ids;
    int i,j,ni,nj;
    mapping group;
    int archive_time = time() - ARCHIVE_DAYS * 24 * 60 * 60;

    groups = keys(data);
    ni = sizeof(groups);

    for (i=0; i<ni; i++) {
	group = data[groups[i]];
	ids = keys(group) - ({ "next_id" });
	nj = sizeof(ids);

	for (j=0; j<nj; j++) {
	    if (group[ids[j]]["TIME"] < archive_time)
		archive_post(groups[i], ids[j]);
	}
    }
}