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: /adm/daemons/aproposd.c
//   - apropos daemon - maintains dictionary
//
// History:
//   Created by Whiplash@TMI - 92/02/11
//   Minor rewrite by Truilkan@TMI - 92/02/11
//   Attic'd prior to TMI Release 1.0.1
//   Rewritten by Robocoder@TMI-2 (04-Jul-93)
//   Leto added some security checks (Dec-21 1994)
//
// See also: /cmds/xtra/_apropos.c, /cmds/adm/_aproposm.c

#include <config.h>
#include <logs.h>
#include <commands.h>
#include <man.h>
#include <uid.h>
#include <driver/origin.h>

#define APROPOS_DATA DATA_DIR "/adm/daemons/apropos"

// This mapping is indexed by phrase; the value is the name of the function
// subdirectory
mapping apropos_phrases;

static int already_updating;

// prototypes for local functions
void scan_file(string x, string y);
void hash(string x, string y);
void update_aplist(int x);
void process_dir(string x);

// initialization
void create() {
    string s;

    seteuid(ROOT_UID);
    already_updating = 0;
    if (!restore_object(APROPOS_DATA)) {
        apropos_phrases = allocate_mapping(400);
        save_object(APROPOS_DATA);
    }
}

void query_update() {
    write("Files left to process: " + already_updating + "\n");
}

// scan the doc subdirectories and [re]build apropos database
void update_aplist(int x) {
    string *docdirs;
    string tmp;
    int i, s;

#if 0
    tmp = base_name(previous_object());
    if (!adminp(geteuid(previous_object())) &&
	  tmp != CMD_APROPOSM && tmp != CMD_APROPOS &&
	  tmp != file_name(this_object())) {
	return;
    }
#else
    if (origin() != ORIGIN_CALL_OUT) {
        tmp = base_name(previous_object());
        if (!adminp(geteuid(previous_object())) &&
              tmp != CMD_APROPOSM && tmp != CMD_APROPOS)
            return;
    }
#endif

    if (already_updating) {
        return;
    }
    already_updating = 1;

    // process each subdirectory
//  docdirs = MAN_DIRLIST;
    docdirs = EXTENDED_MAN_DIR_LIST;
    s = sizeof(docdirs);
    for (i = 0; i < s; i++) {
//      call_out("process_dir", 1, docdirs[i]);
        process_dir(docdirs[i]);
    }
    already_updating--;
}

// apropos
//   called by /cmds/xtra/_apropos.c
//   returns an array of strings
//   each string is of the form:
//      doc file name: synopsis containing matching phrase
string *apropos(string str, int quiet) {
    string *r;
    mapping k;
    int i, j, s;

    if (base_name(previous_object()) != CMD_APROPOS)  return ({ });

    if (!str || str == "") {
#ifdef APROPOS_LOG
        log_file(APROPOS_LOG, wrap("apropos(): invalid string, from: " +
              "[" + file_name(previous_object()) + "] " +
              (this_player() ?
              capitalize(geteuid(this_player())) : "unknown") +
              " " + extract(ctime(time()), 4, 15)));
#endif
        return ({ });
    }

    if (!apropos_phrases || !sizeof(apropos_phrases)) {
        if (!already_updating) {
            call_out("update_aplist", 1, 0);
            return ({
"Updating apropos database. This may take a while.  Please try again, later."
	    });
        } else {
            return ({ "Update of apropos database in progress." });
        }
    }

    // find matching phrases
    r = regexp(keys(apropos_phrases), ".*" + str + ".*");

    // prepend phrases with dirname
    if (!quiet) {
        s = sizeof(r);
        for (i = 0; i < s; i++) {
            r[i] = apropos_phrases[r[i]] + ": " + r[i];
        }
    }

    return r;
}

// save_me
//   called via call_out
void save_me() {
    save_object(APROPOS_DATA);
    already_updating = 0;
}

// process_dir
//   called via call_out
void process_dir(string dirname) {
    string *docfiles;
    string *lines;
    int i, s;
    string tmp, tmp2;

//  if (origin() != ORIGIN_CALL_OUT)  return;
    if (origin() != ORIGIN_LOCAL)  return;
    // check this is a directory
//  tmp = man_root + "/" + dirname + "/";
     tmp = dirname + "/";
    if (file_size(tmp) != -2) {
        return;
    }

    docfiles = get_dir(tmp);
    s = sizeof(docfiles);
    already_updating += s;

    // process each file
    for (i = 0; i < s; i++) {
        tmp2 = tmp + docfiles[i];
        if (file_size(tmp2) <= 0 || docfiles[i] == "README") {
            // skip empty files, files I don't have read permission to,
            // ".", ".." and any directories (which I don't know about)
            already_updating--;
            continue;
        }

        // process file
        call_out("scan_file", 1, dirname, tmp2);
    }
}

int process_file(string filename) {
    string *p, tmp;
    int i, j, k, s;

    if (!filename || filename == "")
        return 0;

    if (already_updating) {
        return 0;
    }
    already_updating = 1;

    filename = resolv_path(this_player()->query("cwd"), filename);
    j = strlen(filename);

//  p = MAN_DIRLIST;
    p = EXTENDED_MAN_DIR_LIST;
    s = sizeof(p);
    for (i = 0; i < s; i++) {
//      tmp = man_root + "/" + p[i] + "/";
        tmp = p[i] + "/";
        k = strlen(tmp);
        if (j >= k && tmp == filename[0..k-1])
            break;
    }
    if (i == s) {
	already_updating = 0;
        return 0; // not found
    }

    scan_file( p[i], filename );
    return 1;
}

void scan_file(string dirname, string pathname) {
    string *lines;
    string tmp;
    int i, j, k, s;

    tmp = read_file(pathname);
    lines = (tmp) ? explode(tmp, "\n") : ({ });

    s = sizeof(lines);
    i = member_array("NAME", lines);
    if (i == -1) {
        i = member_array(".SH NAME", lines);
        k = 1;
    } else
        k = 0;

    if (i != -1) {
        // concat NAME lines
        tmp = "";
        if (k)
//          for (j = i+1; j < s && lines[j] != ""; j++) {
            for (j = i+1; j < s && lines[j] != "" && lines[j] != " "; j++) {
                if (lines[j] == ".nf")  continue;
                tmp += " " + lines[j];
            }
        else
            for (j = i+1; j < s && lines[j] != "" && lines[j] != " "; j++) {
                tmp += lines[j];
            }

	// this fix for words that get abbrev'd doesn't work if
	// there's a proper hyphenation at the end of a line
        tmp = replace_string(tmp, "-     ", "");

        call_out( "hash", 1, tmp, dirname );
    } else
	already_updating--; // else NAME not found or lines = ({ })
}

void hash(string tmp, string dirname) {
    string *lines;
    int i, k, s;

    // strip spaces
    lines = explode(tmp, " ");
    s = sizeof(lines);
    for (i = 0, k = 0; i < s; i++) {
        if (lines[i] == "") continue;
        lines[k++] = lines[i];
    }

    // compacting the array should to reduce iterations in the next loop
    lines = exclude_array(lines, k, s);
    s = sizeof(lines);
    tmp = implode(lines, " ");

    // add phrase to database
    apropos_phrases[tmp] = dirname;

    already_updating--;
    if (already_updating == 0)
	save_me();
}

string *query_phrases() {
    return keys(apropos_phrases);
}

string *query_files() {
    return values(apropos_phrases);
}

int compare(string x, string y) {
    return strcmp(x, y);
}