nightmare3_fluffos_v2/
nightmare3_fluffos_v2/bin/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/ChangeLog.old/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/Win32/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/compat/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/compat/simuls/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/include/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/clone/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/command/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/data/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/etc/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/include/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/inherit/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/inherit/master/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/log/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/single/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/single/tests/compiler/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/single/tests/efuns/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/single/tests/operators/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/testsuite/u/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/tmp/
nightmare3_fluffos_v2/fluffos-2.9-ds2.08/windows/
nightmare3_fluffos_v2/lib/cmds/ambassador/
nightmare3_fluffos_v2/lib/cmds/database/
nightmare3_fluffos_v2/lib/cmds/hm/
nightmare3_fluffos_v2/lib/cmds/soul/
nightmare3_fluffos_v2/lib/daemon/cfg/
nightmare3_fluffos_v2/lib/daemon/cfg/mon_races/
nightmare3_fluffos_v2/lib/daemon/cfg/races/
nightmare3_fluffos_v2/lib/daemon/include/
nightmare3_fluffos_v2/lib/daemon/save/
nightmare3_fluffos_v2/lib/daemon/services/
nightmare3_fluffos_v2/lib/daemon/soul/
nightmare3_fluffos_v2/lib/doc/
nightmare3_fluffos_v2/lib/doc/TestPlans/
nightmare3_fluffos_v2/lib/doc/approval/
nightmare3_fluffos_v2/lib/doc/approval/QC/
nightmare3_fluffos_v2/lib/doc/approval/balance/
nightmare3_fluffos_v2/lib/doc/build/
nightmare3_fluffos_v2/lib/doc/build/armours/
nightmare3_fluffos_v2/lib/doc/build/economy/
nightmare3_fluffos_v2/lib/doc/build/etc/
nightmare3_fluffos_v2/lib/doc/build/monster/
nightmare3_fluffos_v2/lib/doc/build/room/
nightmare3_fluffos_v2/lib/doc/build/virtual/
nightmare3_fluffos_v2/lib/doc/build/weapon/
nightmare3_fluffos_v2/lib/doc/classes/
nightmare3_fluffos_v2/lib/doc/efun/
nightmare3_fluffos_v2/lib/doc/etc/
nightmare3_fluffos_v2/lib/doc/help/creator/
nightmare3_fluffos_v2/lib/doc/help/hm/
nightmare3_fluffos_v2/lib/doc/law/
nightmare3_fluffos_v2/lib/doc/lpc/basic/
nightmare3_fluffos_v2/lib/doc/lpc/data_types/
nightmare3_fluffos_v2/lib/doc/lpc/etc/
nightmare3_fluffos_v2/lib/doc/lpc/intermediate/
nightmare3_fluffos_v2/lib/doc/lpc/types/
nightmare3_fluffos_v2/lib/doc/mudlib/
nightmare3_fluffos_v2/lib/doc/mudlib/features/
nightmare3_fluffos_v2/lib/domains/Examples/etc/
nightmare3_fluffos_v2/lib/domains/Examples/room/
nightmare3_fluffos_v2/lib/domains/Examples/virtual/
nightmare3_fluffos_v2/lib/domains/Examples/virtual/exaA/
nightmare3_fluffos_v2/lib/domains/Examples/virtual/exaB/
nightmare3_fluffos_v2/lib/domains/Examples/weapon/
nightmare3_fluffos_v2/lib/domains/Praxis/
nightmare3_fluffos_v2/lib/domains/Praxis/adm/
nightmare3_fluffos_v2/lib/domains/Praxis/attic/
nightmare3_fluffos_v2/lib/domains/Praxis/cemetary/
nightmare3_fluffos_v2/lib/domains/Praxis/cemetary/mon/
nightmare3_fluffos_v2/lib/domains/Praxis/data/
nightmare3_fluffos_v2/lib/domains/Praxis/death/
nightmare3_fluffos_v2/lib/domains/Praxis/mountains/
nightmare3_fluffos_v2/lib/domains/Praxis/obj/armour/
nightmare3_fluffos_v2/lib/domains/Praxis/obj/magic/
nightmare3_fluffos_v2/lib/domains/Praxis/obj/weapon/
nightmare3_fluffos_v2/lib/domains/Praxis/orc_valley/
nightmare3_fluffos_v2/lib/domains/Praxis/quests/
nightmare3_fluffos_v2/lib/domains/Praxis/standardOld/
nightmare3_fluffos_v2/lib/include/
nightmare3_fluffos_v2/lib/log/
nightmare3_fluffos_v2/lib/log/errors/
nightmare3_fluffos_v2/lib/log/reports/
nightmare3_fluffos_v2/lib/log/watch/
nightmare3_fluffos_v2/lib/news/
nightmare3_fluffos_v2/lib/secure/cfg/
nightmare3_fluffos_v2/lib/secure/cmds/ambassador/
nightmare3_fluffos_v2/lib/secure/cmds/mortal/
nightmare3_fluffos_v2/lib/secure/save/users/d/
nightmare3_fluffos_v2/lib/secure/std/
nightmare3_fluffos_v2/lib/std/hm/
nightmare3_fluffos_v2/lib/std/living/
nightmare3_fluffos_v2/lib/std/room/
nightmare3_fluffos_v2/lib/std/user/
nightmare3_fluffos_v2/lib/std/virtual/
nightmare3_fluffos_v2/lib/www/
nightmare3_fluffos_v2/lib/www/errors/
nightmare3_fluffos_v2/lib/www/gateways/
nightmare3_fluffos_v2/win32/
/*    /daemon/http.c
 *    from Nightmare IV
 *    an http daemon that can talk to Mosaic and other WWW clients
 *    created by Descartes of Borg 940521
 *    callback fix by Robocoder 950117
 */

#include <std.h>
#include <daemons.h>
#include <security.h>
#include <network.h>
#include "http.h"

inherit DAEMON;

static private int __SocketHTTP;
static private mapping __Sockets, __Activity;

void create() { 
    daemon::create();
    set_no_clean(1);
    __Sockets = ([]);
    __Activity = ([]);
    call_out("setup", 2);
    call_out("clean_sockets", 180);
}

static void setup() {
    if((__SocketHTTP=socket_create(STREAM,"read_callback","close_callback"))<0){
        log_file("httpd", "Failed to create socket.\n");
        return;
    }
    if(socket_bind(__SocketHTTP, PORT_HTTP) < 0) {
        socket_close(__SocketHTTP);
        log_file("httpd", "Failed to listen to socket.\n");
        return;
    }
    if(socket_listen(__SocketHTTP, "listen_callback") < 0) {
        socket_close(__SocketHTTP);
        log_file("httpd", "Failed to listen to socket.\n");
    }
}

void listen_callback(int fd) {
    int neu;

    if((neu = socket_accept(fd, "read_callback", "write_callback")) < 0)
      return;
    write_callback(neu);
}

void write_callback(int fd) {
    string tmp;
    int x;

    if(!__Sockets[fd]) {
        sscanf(socket_address(fd), "%s %*s", tmp);
        x = resolve(tmp, "resolve_incoming");
        __Sockets[fd] = ([ "address": tmp, "key": x, "time": time() ]);
        add_activity(fd, sprintf("CONNECTED (%s)\n", ctime(time())));
      }
    else close_connection(fd);
}

void read_callback(int fd, string str) {
    string cmd, args;

    if(!str || str == "") {
        http_error(fd, BAD_CMD);
        return;
      }
    str = explode(replace_string(str, "\r", ""), "\n")[0];
    sscanf(str, "%s %s", cmd, args);
    switch(lower_case(cmd)) {
        case "get": get_file(fd, args); return;
        default: http_error(fd, BAD_CMD); return;
	}
  }

void close_callback(int fd) {
    log_file("httpd", "Socket closed.\n");
    socket_close(fd);
    if(fd == __SocketHTTP) this_object()->remove();
}

void resolve_incoming(string nom, string addr, int cle) {
    int *fds;
    int i;

    i = sizeof(fds = keys(__Sockets));
    while(i--)
      if(__Sockets[fds[i]]["key"]==cle && __Sockets[fds[i]]["address"]==addr) {
          __Sockets[fds[i]]["name"] = (nom ? nom : addr);
          return;
      }
    log_file("httpd",sprintf("Ip %s resloved to %s after connection closed.\n",
      addr, (nom ? nom : "NOT RESOLVED")));
  }

static private void http_error(int fd, mapping err) {
    string str;

    add_activity(fd, sprintf("ERROR: %s (%s)\n", err["error"], ctime(time())));
    retry(fd, str = read_file(err["file"]) ? str : "");
}

static private void add_activity(int fd, string act) {
    if(!__Activity[fd]) __Activity[fd] = ({ act });
    else __Activity[fd] += ({ act });
}

void close_connection(int fd) {
    int i, maxi;

    maxi = sizeof(__Activity[fd]);
    if(!__Sockets[fd]["name"]) __Sockets[fd]["name"]=__Sockets[fd]["address"];
    for(i =0; i<maxi; i++)
      log_file("httpd", sprintf("%s: %s", 
        __Sockets[fd]["name"], __Activity[fd][i]));
    map_delete(__Sockets, fd);
    map_delete(__Activity, fd);
    socket_close(fd);
  }
    
static void clean_sockets() {
    int *cles;
    int i;

    i = sizeof(cles = keys(__Sockets));
    while(i--)
      if(time() - __Sockets[cles[i]]["time"] > 180) close_connection(cles[i]);
    call_out("clean_sockets", 180);
}

static private void get_file(int fd, string file) {
    string *parts, *tmp;
    mixed str;
    string id, args;
    int x;

    add_activity(fd, sprintf("GET %s (%s)\n", file, ctime(time())));
    file = (tmp = explode(file, " "))[0];
    id = sizeof(parts) > 1 ? parts[1] : "";
    if(file[0] != '/') file = sprintf("/%s", file);
    parts = explode(file = absolute_path("/", file), "/");
    if(!sizeof(parts)) file = sprintf("%s/index.html", DIR_WWW);
    else if(parts[0][0] == '~') {
        parts[0] = sprintf("%spublic_html", 
          user_path(parts[0][1..strlen(parts[0])-1]));
        file = implode(parts, "/");
      }
    if(strsrch(file, DIR_WWW) && strsrch(file, REALMS_DIRS))
      file = sprintf("%s%s", DIR_WWW, file);
    if(file_size(file) == -2) file = sprintf("%s/index.html", file);
    if(!strsrch(file, DIR_WWW_GATEWAYS)) {
        if(sscanf(file, DIR_WWW_GATEWAYS+"/%s/%s", id, args) != 2) {
            args = 0;
            sscanf(file, DIR_WWW_GATEWAYS+"/%s", id);
        }
        if(catch(str=(string)call_other(DIR_WWW_GATEWAYS+"/"+id,"gateway",args))) {
            http_error(fd, BAD_GATEWAY);
            return;
        }
        str = strip_colours(str);
    }
    else if(!file_exists(file)) {
        http_error(fd, NOT_FOUND);
        return;
      }
    else str = read_buffer(file);
    retry(fd, str);
}

void retry(int fd, string str) {
    int res;

    if((res = socket_write(fd, str)) != EECALLBACK) {
        if(res == EEWOULDBLOCK) call_out("retry", 10, fd, str); 
        else close_connection(fd);
    }
}
    

int remove() {
    socket_close(__SocketHTTP);
    return daemon::remove();
}

 string format_date(int x) {
    string *parts;
    string str;

    parts = explode(replace_string(ctime((int)TIME_D->query_tzone("GMT")),
      "  ", " "), " ");
    switch(parts[0]) {
        case "Mon": str = "Monday, "; break;
        case "Tue": str = "Tuesday, "; break;
        case "Wed": str = "Wednesday, "; break;
        case "Thu": str = "Thursday, "; break;
        case "Fri": str = "Friday, "; break;
        case "Sat": str = "Saturday, "; break;
        case "Sun": str = "Sunday, "; break;
    }
    str = sprintf("%s%s-%s-%s %s GMT", str, parts[2], parts[1], 
      parts[4][2..3], parts[3]);
    return str;
}