dsI/bin/
dsI/extra/creremote/
dsI/extra/mingw/
dsI/extra/wolfpaw/
dsI/fluffos-2.7-ds2.018/
dsI/fluffos-2.7-ds2.018/ChangeLog.old/
dsI/fluffos-2.7-ds2.018/Win32/
dsI/fluffos-2.7-ds2.018/compat/
dsI/fluffos-2.7-ds2.018/compat/simuls/
dsI/fluffos-2.7-ds2.018/testsuite/
dsI/fluffos-2.7-ds2.018/testsuite/clone/
dsI/fluffos-2.7-ds2.018/testsuite/command/
dsI/fluffos-2.7-ds2.018/testsuite/data/
dsI/fluffos-2.7-ds2.018/testsuite/etc/
dsI/fluffos-2.7-ds2.018/testsuite/include/
dsI/fluffos-2.7-ds2.018/testsuite/inherit/
dsI/fluffos-2.7-ds2.018/testsuite/inherit/master/
dsI/fluffos-2.7-ds2.018/testsuite/log/
dsI/fluffos-2.7-ds2.018/testsuite/single/
dsI/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
dsI/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
dsI/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
dsI/fluffos-2.7-ds2.018/testsuite/u/
dsI/fluffos-2.7-ds2.018/tmp/
dsI/lib/cfg/
dsI/lib/cmds/common/
dsI/lib/cmds/creators/include/
dsI/lib/cmds/creators/include/SCCS/
dsI/lib/daemon/services/
dsI/lib/doc/
dsI/lib/domains/Ylsrim/
dsI/lib/domains/Ylsrim/adm/
dsI/lib/domains/Ylsrim/armour/
dsI/lib/domains/Ylsrim/broken/
dsI/lib/domains/Ylsrim/fish/
dsI/lib/domains/Ylsrim/meal/
dsI/lib/domains/Ylsrim/npc/
dsI/lib/domains/Ylsrim/virtual/
dsI/lib/domains/Ylsrim/weapon/
dsI/lib/domains/default/creator/
dsI/lib/domains/default/etc/
dsI/lib/domains/default/room/
dsI/lib/lib/comp/
dsI/lib/lib/lvs/
dsI/lib/lib/user/
dsI/lib/lib/virtual/
dsI/lib/obj/
dsI/lib/obj/include/
dsI/lib/realms/
dsI/lib/save/kills/a/
dsI/lib/save/kills/b/
dsI/lib/save/kills/f/
dsI/lib/save/kills/m/
dsI/lib/save/kills/q/
dsI/lib/save/kills/r/
dsI/lib/secure/cfg/
dsI/lib/secure/cfg/classes/
dsI/lib/secure/cfg/races/SCCS/
dsI/lib/secure/cmds/creators/include/
dsI/lib/secure/cmds/players/
dsI/lib/secure/cmds/players/include/
dsI/lib/secure/daemon/include/
dsI/lib/secure/lib/
dsI/lib/secure/lib/include/
dsI/lib/secure/lib/net/
dsI/lib/secure/lib/net/include/
dsI/lib/secure/lib/std/
dsI/lib/secure/obj/
dsI/lib/secure/obj/include/
dsI/lib/secure/save/
dsI/lib/spells/
dsI/lib/verbs/admins/include/
dsI/lib/verbs/common/
dsI/lib/verbs/common/include/
dsI/lib/verbs/creators/
dsI/lib/verbs/creators/include/
dsI/lib/verbs/players/include/SCCS/
dsI/lib/verbs/rooms/
dsI/lib/verbs/rooms/include/
dsI/lib/www/
dsI/v22.2b14/
dsI/win32/
/*    /secure/lib/connect.c
 *    from the Nightmare IVr2 Object Library
 *    the object a user connects to before determining their real body
 *    created by Descartes of Borg 951103
 *    Version: @(#) connect.c 1.2@(#)
 *    Last Modified: 96/05/28
 */

#include <lib.h>
#include <news.h>
#include <flags.h>
#include <config.h>
#include <daemons.h>
#include <message_class.h>
#include "include/connect.h"

inherit LIB_PAGER;

static private int CrackCount, NetDead; 
static private string Name, Terminal; 
static private object Player; 
static private mapping LastError;
static private int *Screen;
 
static void create(int binary) {
    CrackCount = 0;
    Name = "";
    Player = 0;
    NetDead = 0;
}

static void logon() {
    string welcome;
    
    call_out((: eventTimeout :), LOGON_TIMEOUT);
    welcome = read_file(NEWS_WELCOME) || "Welcome to " + mud_name() + "!";
    receive(welcome);
    receive("\n" + center("Driver: " + version() + "               Mudlib: "+
			  mudlib() + " " + mudlib_version()) + "\n");
    receive("\nWhat name do you wish? ");
    input_to((: InputName :), I_NOESC); 
} 

static void InputName(string name, string kill_me) {
    string news;
    mixed tmp;
    
    if( !name || name == "" ) {
	if( kill_me ) {
	    receive("\nPerhaps try another time then?\n");
	    Destruct();
	    return;
	}
	else {
	    receive("\nYou must enter a name in order to join!\n");
	    receive("\nWhat name do you wish? ");
	    input_to((: InputName :), I_NOESC, "kill me");
	    return;
	}
    }
    Name = convert_name(name);
    name = capitalize(name);
    if( (int)master()->is_locked() ) {
	news = read_file(NEWS_LOCKED) || "No reason logged.";
	receive("\n" + mud_name() + " is locked.  Reason:\n" + news + "\n");
	if( CanLogin() ) receive("\n        >>> Access allowed <<<\n");
	else {
	    receive("\n        >>> Access denied <<<\n");
	    Destruct();
	    return;
	}
    }
    if( !user_exists(Name) ) {
	eventCreatePlayer(name);
	return;
    }
    if( !((int)BANISH_D->eventConnect(Name, query_ip_number())) ) {
	news = read_file(NEWS_BANISHED) || "You are not allowed here.";
	receive("\n" + news + "\n");
	Destruct();
        return; 
    }
    if( (tmp = (mixed)CHARACTER_D->eventConnect(Name)) != 1 ) {
	if( tmp ) receive(tmp + "\n");
	else receive("One of your characters was recently logged in.\n"
		     "You must wait a little longer before logging in.\n");
	Destruct();
	return;
    }
    if( find_player(Name) ) NetDead = 1;
    Player = (object)master()->player_object(Name);
    if( !Player ) {
	receive("\nIt seems some work is being done right now, try later.\n");
	Destruct();
	return;
    }
    if( (string)Player->GetRace() == "blob" ) {
	string sf;

	NetDead = 0;
	sf = save_file(Name);
	unguarded( (: rm, sf + __SAVE_EXTENSION__ :) );
	Player->eventDestruct();
	eventCreatePlayer(name);
	return;
    }
    receive("Password: ");
    input_to((: InputPassword :), I_NOECHO | I_NOESC, name);
} 

static void InputPassword(string pass, string cap) {
    string control;
    
    if( !pass || pass == "" ) {
	receive("\nYou must enter a password.  Please try again later.\n");
	Destruct();
	return;
    }
    control = (string)Player->GetPassword();
    if( control != crypt(pass, control) ) {
	receive("\nInvalid password.\n");
	if( ++CrackCount > MAX_PASSWORD_TRIES ) {
	    receive("\nNo more attempts allowed\n");
	    log_file("security", "Maximum password tries exceeded by " +
		     Name + " from " + query_ip_number() + "\n");
	    filter(users(), (: archp :))->eventPrint("System %^MAGENTA%^"
					 "<error>%^RESET%^ Maximum password "
					 "attempts exceeded by " + cap +
					 " from " + query_ip_number() + ".",
						     MSG_ERROR);
	    Destruct();
	    return;
	}
	receive("Password: ");
	input_to( (: InputPassword :), I_NOECHO | I_NOESC, cap);
	return;
    }
    if( !NetDead ) eventEnterGame();
    else eventReEnterGame(cap);
}

static void eventCreatePlayer(string cap) {
    if( !((int)BANISH_D->valid_name(Name)) ) {
	receive(capitalize(cap) + " is not a valid name.\n");
	receive(mud_name() + " requires that all names meet the following "
		"requirements:\n");
	receive("\tAll characters must be:\n");
	receive("\t\tA-Z\n\t\ta-z\n\t\t'\n\t\t-\n");
	receive("\tMinimum length: " + MIN_USER_NAME_LENGTH + "\n");
	receive("\tMaximum length: " + MAX_USER_NAME_LENGTH + "\n");
	receive("\nPlease enter a new name: ");
	input_to( (: InputName :), I_NOESC );
	return;
    }
    if( !((int)BANISH_D->eventConnect(Name, query_ip_number())) ) {
	string news;

	news = read_file(NEWS_REGISTER) || "No registration info.";
	receive(news);
	Destruct();
	return;
    }
    receive("Do you really wish to be known as " + cap + "? (y/n) ");
    input_to((: ConfirmName :), I_NOESC, cap);
}

static void ConfirmName(string ans, string cap) {
    if( !ans || ans == "" || lower_case(ans)[0..0] != "y" ) {
	receive("\nOk, then enter the name you really want: ");
	input_to( (: InputName :), I_NOESC );
	return;
    }
    log_file("new_players", Name + " from " + query_ip_number() + " (" +
	     ctime(time()) + ")\n");
    receive("\nCreate a password of at least 5 letters: ");
    input_to((: CreatePassword :), I_NOECHO | I_NOESC, cap);
} 
    
static void eventReEnterGame(string cap) {
    if( interactive(Player) ) {
	receive("\nAn interactive copy of you currently exists.\n");
	receive("Do you wish to take over this copy? (y/n) ");
        input_to((: ConfirmReconnect :), I_NOESC, cap);
	return;
    }
    if( exec(Player, this_object()) ) {
	log_file("enter", cap + " (exec): " + ctime(time()) + "\n"); 
	Player->eventReconnect();
    }
    receive("\nProblem reconnecting.\n");
    Destruct();
}

static void ConfirmReconnect(string ans, string cap) {
    object tmp; 

    if( !stringp(ans) || ans == "" || lower_case(ans)[0..0] != "y" ) {
	receive("\nThen please try again later!\n");
	Destruct();
	return;
    }
    exec(tmp = new(LIB_PLAYER), Player); 
    exec(Player, this_object()); 
    destruct(tmp);
    Player->eventPrint("\nAllowing login.\n", MSG_SYSTEM);
    Destruct();
}

static int CanLogin() {
    string group;
    
    if( (int)BANISH_D->GetGuest(Name) ) return 1;
    foreach(group in LOCKED_ACCESS_ALLOWED)
      if( member_group(Name, group) ) return 1;
    return 0;
}
 
static private void eventEnterGame() { 
    if(!exec(Player, this_object())) { 
	receive("\nProblem connecting.\n"); 
        Player->eventDestruct();
        destruct(this_object());
        return; 
    } 
    if( Terminal ) Player->SetTerminal(Terminal);
    if( Screen ) Player->SetScreen(Screen[0], Screen[1]);
    Player->Setup();
    destruct(this_object()); 
} 
 
static void CreatePassword(string pass, string cap) {
    if( strlen(pass) < 5) {
	receive("\nYour password must be at least 5 letters in length.\n");
	receive("Please choose another password: ");
	input_to( (: CreatePassword :), I_NOECHO | I_NOESC, cap);
	return;
    }
    receive("\nPlease confirm your password: ");
    input_to( (: ConfirmPassword :), I_NOECHO | I_NOESC, cap, pass);
}
 
static void ConfirmPassword(string control, string cap, string pass) {
    if( control == pass ) {
	Player = (object)master()->player_object(Name);
        Player->SetPassword(pass = crypt(pass, 0));
	receive("\n\nPlease choose an interesting gender (male or female): ");
	input_to((: InputGender :), I_NOESC, cap);
        return; 
    } 
    receive("\nPassword entries do not match, re-choose password: ");
    input_to((: CreatePassword :), I_NOECHO | I_NOESC, cap);
    return; 
} 
 
static void InputGender(string str, string cap) {
    if( str != "male" && str != "female" ) { 
       receive("\nCute, but pretend to be either male or female instead.\n");
       receive("Gender: ");
       input_to((: InputGender :), I_NOESC, cap);
       return;
    }
    Player->SetGender(str);
    receive("\nYou may format " + cap + " to appear however you wish using "
	    "spaces, ', or -.\nEnter a display name (default: " + cap +"): ");
    input_to((: InputCapName :), I_NOESC, cap);
}

static void InputCapName(string name, string cap) {
    if( !name || name == "" ) name = cap;
    if( !((int)BANISH_D->valid_cap_name(name, Name)) ) {
	receive("\nThat was not a valid name format, choose again: ");
	input_to((: InputCapName :), I_NOESC, cap);
        return;
    }
    Player->SetCapName(cap = capitalize(name));
    receive("\nFor security reasons, " + mud_name() + " requires a valid "
	    "email.\nYou can restrict this information as being admin only "
	    "by preceeding it\nwith a '#' character (e.g. #user@host).\n"
	    "Email: ");
    input_to((: InputEmail :), I_NOESC);
} 
 
static void InputEmail(string email) {
    string user, host; 

    if( !email || sscanf(email, "%s@%s", user, host) != 2 ) {
	receive("\nThat is not a valid email address.\n");
	receive("Please enter a valid email address: ");
	input_to( (: InputEmail :), I_NOESC );
        return; 
    } 
    Player->SetEmail(email);
    receive("\nIf you do not mind, please enter your real name (optional): ");
    input_to( (: InputRealName :), I_NOESC );
}
 
static void InputRealName(string rname) {
    if( !rname || rname == "" ) rname = "Unknown";
    Player->SetRealName(rname);
    receive("\n\nYou must now pick a race.\n");
    receive("Picking a race influences what physical traits your character "
	    "will have.\n");
    receive("\nYou may issue the following commands:\n");
    receive("\tlist - lists all races from which you can choose\n");
    receive("\thelp - get help on what races mean\n");
    receive("\thelp RACE - (e.g. \"help human\") gives you information on "
	    "a race\n");
    receive("\tpick RACE - pick a particular race for yourself\n");
    receive("\nRace: ");
    input_to((: InputRace :), I_NOESC);
}

static void InputRace(string str) {
    string cmd, args;

    if( str == "" || !str ) {
	receive("\nRace: ");
	input_to((: InputRace :), I_NOESC);
	return;
    }
    if( sscanf(str, "%s %s", cmd, args) != 2 ) {
	cmd = str;
	args = 0;
    }
    switch(cmd) {
	case "list":
	cmdList();
	return;

	case "help":
	cmdHelp(args);
	return;

	case "pick":
	cmdPick(args);
	return;

	default:
	receive("\nInvalid command.\nRace: ");
	input_to((: InputRace :), I_NOESC);
	return;
    }
}

static void cmdHelp(string args) {
    function f;
    string array races = (string array)RACES_D->GetRaces(1);
    string help;

    f = function(string str) {
	receive("\nRace: ");
	input_to((: InputRace :), I_NOESC);
    };
    if( !args ) {
	help = read_file(DIR_PLAYER_HELP + "/races") ||
	  "Error reading help file.\n";
	eventPage(explode(help, "\n"), MSG_HELP, f);
	return;
    }
    if( member_array(args = lower_case(args), races) == -1 ) {
	receive("No such race exists.\n\nRace: ");
	input_to((: InputRace :), I_NOESC);
	return;
    }
    help = (string)RACES_D->GetHelp(args);
    eventPage(explode(help, "\n"), MSG_HELP, f);
}

static void cmdList() {
    string list;

    list = format_page((string array)RACES_D->GetRaces(1), 5);
    receive(list);
    receive("\nRace: ");
    input_to((: InputRace :), I_NOESC);
}

static void cmdPick(string args) {
    if( !args || args == "" ) {
	receive("You must specify a race to pick.\n\nRace: ");
	input_to((: InputRace :), I_NOESC);
	return;
    }
    if( member_array(args = lower_case(args),
		     (string array)RACES_D->GetRaces(1)) == -1 ) {
	receive("No such race.\nRace: ");
	input_to((: InputRace :), I_NOESC);
	return;
    }
    Player->SetRace(args);
    eventEnterGame();
} 
 
static void eventTimeout() {
    if( !interactive(this_object()) ) {
	Destruct();
    }
    else if( query_idle(this_object()) > LOGON_TIMEOUT ) {
	receive("\nLogin timed out.\n");
	Destruct();
    }
    else call_out( (: eventTimeout :), LOGON_TIMEOUT );
}

varargs int eventPrint(string msg, mixed cl, mixed arg3) {
    if( !cl || !intp(cl) ) return 0;
    if( cl & MSG_NOWRAP ) receive(strip_colours(msg));
   else receive(wrap(strip_colours(msg), GetScreen()[0]));
    return 1;
}

static private void Destruct() {
    if( Player && !NetDead ) destruct(Player);
    remove_call_out();
    destruct(this_object());
}

void eventDestruct() {
    Destruct();
}

string GetKeyName() {
    if(!interactive(this_object())) return 0;
    else if(Name) return Name;
    else return "";
}

string GetCapName() {
    string tmp;

    tmp = GetKeyName();
    return (tmp ? capitalize(tmp) : "");
}

static void terminal_type(string str) {
    if( !stringp(str) ) return;
    else Terminal = lower_case(str);
}

static void window_size(int width, int height) {
    Screen = ({ width, height });
}

static void CreateGuest() {
    receive("Enter the name you wish to use: ");
    input_to( (: GetGuestName :), I_NOESC );
}

static void GetGuestName(string nom) {
    object ob;

    return;
    if( !nom || nom == "" || user_exists(convert_name(nom)) ) {
	receive("Illegal name choice, try again: ");
	return;
    }
//    ob = new(LIB_GUEST);
    ob->SetCapName(nom);
    exec(ob, this_object());
    ob->Setup();
}

int *GetScreen() {
   if( Screen ) return Screen;
   else return ({ 79, 24 });
}

void SetLastError(mapping m) {
    if (previous_object() != master()) return;
    LastError = m;
}

mapping GetLastError() {
    string caller = file_name(previous_object());
    if( caller[0..23] == "/secure/cmds/creator/dbx" ||
       caller[0..22]  == "/secure/cmds/player/bug" ) return LastError;
    error("Privilege Violation: " + caller);
}