/* /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);
}