/* Copyright (c) 1993 Stephen F. White */
#include "cool.h"
#include "proto.h"
#include "netio.h"
#include "execute.h"
int promiscuous = 0;
int corefile = 0;
int compiler = 0;
int registration = 0;
int verify_servers = 0;
Objid sys_obj; /* shortcut, d00d */
static int read_welcome (const char *fname);
Playerid find_player (const char *name);
void panic (const char *s)
{
writelog ();
fprintf (stderr, "PANIC: %s\n", s);
shutdown_server ();
}
/*
* init()
*
* Initializes the database and dumpfile, loads and connects to
* remote servers (if possible). Also calls SYSOBJ.boot_server() in
* the newly-loaded database.
*/
int init (const char *dbfilename, int send_boot, int db_must_exist)
{
char buf[MAX_PATH_LEN];
/* sys_obj is a global to save shoving SYS_OBJ in a local var each time */
sys_obj.server = 0;
sys_obj.id = SYS_OBJ;
/* read config file */
sprintf (buf, "%s.cfg", dbfilename);
writelog ();
fprintf (stderr, "Reading config file from %s\n", buf);
if (read_config (buf)) {
writelog ();
fprintf (stderr, "Couldn't read config file\n");
return -2;
} /* if */
sprintf (buf, "%s.welcome", dbfilename);
if (read_welcome (buf)) {
return -3;
}
/* if */
/* initialize db and cache */
writelog ();
fprintf (stderr, "Initializing db\n");
dddb_setfile (dbfilename);
if (dddb_init (db_must_exist)) {
return -4;
}
writelog ();
fprintf (stderr, "Initializing cache\n");
if (cache_init ()) {
return -5;
}
/* initialize system symbol table */
sym_init_sys ();
/* initialize random number generator */
SRAND ((int) time ((time_t *) 0));
/* initialize opcode table */
opcode_init ();
/* call SYS_OBJ.boot_server() */
if (send_boot) {
send_message (-1, 0, 0, sys_obj, sys_obj, sys_obj,
sym_sys (BOOT_SERVER), list_dup (empty_list), 0, sys_obj);
}
return 0;
}
static int read_welcome (const char *fname)
{
FILE *f;
String *str;
int c;
if (!(f = fopen (fname, "rb"))) {
writelog ();
perror (fname);
return -1;
}
str = string_new (0);
while ((c = getc (f)) != EOF) {
str = string_catc (str, c);
}
fclose (f);
welcome = str_dup (str->str);
string_free (str);
return 0;
}
void shutdown_server (void)
{
writelog ();
fprintf (stderr, "Syncing cache\n");
cache_sync ();
writelog ();
fprintf (stderr, "Closing database\n");
dddb_close ();
}
Error sys_get_global (const char *var, Var * r)
{
Object *sys;
if (!(sys = retrieve (sys_obj))) {
writelog ();
fprintf (stderr, "SYS_OBJ: #%d not found\n", SYS_OBJ);
return E_OBJNF;
} else if (var_get_global (sys, var, r) == E_VARNF) {
writelog ();
fprintf (stderr, "SYS_OBJ: #%d.%s missing\n", SYS_OBJ, var);
return E_VARNF;
} else {
return E_NONE;
}
}
Error sys_assign_global (const char *var, Var value)
{
Object *sys;
String *name = string_cpy (var);
Error r;
if (!(sys = retrieve (sys_obj))) {
writelog ();
fprintf (stderr, "SYS_OBJ: #%d not found\n", SYS_OBJ);
r = E_OBJNF;
} else if (var_assign_global (sys, name, value) == E_TYPE) {
writelog ();
fprintf (stderr, "SYS_OBJ: #%d.%s assignment: type mismatch\n",
SYS_OBJ, var);
r = E_TYPE;
} else {
r = E_NONE;
}
string_free (name);
return r;
}
Playerid find_player (const char *name)
{
Object *p;
Var players, pname;
int i;
Playerid player = NOTHING;
if (sys_get_global ("players", &players) != E_NONE) {
return NOTHING;
} else if (players.type != LIST) {
writelog ();
fprintf (stderr, "SYS_OBJ: #%d.players is not a list\n", SYS_OBJ);
return NOTHING;
} else {
players = var_dup (players); /* in case sysobj gets swapped out (!) */
for (i = 0; i < players.v.list->len; i++) {
if (players.v.list->el[i].type == OBJ
&& (p = retrieve (players.v.list->el[i].v.obj))
&& var_get_global (p, "name", &pname) == E_NONE
&& pname.type == STR && !strcasecmp (pname.v.str->str, name)) {
player = p->id.id;
break;
}
cache_reset ();
}
var_free (players);
}
return player;
}
static void do_connect (Objid player)
{
List *args = list_new (1);
args->el[0].type = OBJ;
args->el[0].v.obj = player;
send_message (-1, 0, 0, player, sys_obj, sys_obj,
sym_sys (CONNECT_PLAYER), args, 0, sys_obj);
}
Playerid connect_player (const char *name, const char *password)
{
Objid player;
Var ppassword;
Object *p;
char salt[3];
player.server = 0;
if (!name || !*name || !password) {
return NOTHING;
} else if ((player.id = find_player (name)) == NOTHING) {
return NOTHING;
} else if (!(p = retrieve (player))) {
return NOTHING;
} else if (var_get_global (p, "password", &ppassword) == E_VARNF
|| ppassword.type != STR || !ppassword.v.str->str[0]) {
do_connect (player);
cache_reset ();
return player.id;
}
salt[0] = ppassword.v.str->str[0];
salt[1] = ppassword.v.str->str[1];
salt[2] = '\0';
if (!strcmp (crypt (password, salt), ppassword.v.str->str)) {
do_connect (player);
cache_reset ();
return player.id;
} else {
return NOTHING;
}
}
Playerid create_player (const char *name, const char *password)
{
Var strv, pclass;
Object *p;
char salt[3];
static char saltstuff[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
List *args;
struct timeval cur_time;
salt[0] = saltstuff[RAND () % strlen (saltstuff)];
salt[1] = saltstuff[RAND () % strlen (saltstuff)];
salt[2] = '\0';
if (!name || !*name || !password || !*password) {
return NOTHING;
} else if (sys_get_global ("player_class", &pclass) != E_NONE) {
return NOTHING;
} else if (pclass.type != OBJ) {
writelog ();
fprintf (stderr, "SYS_OBJ: #%d.player_class is not an obj\n", SYS_OBJ);
return NOTHING;
}
if (find_player (name) != NOTHING) {
return NOTHING;
}
p = clone (pclass.v.obj);
if (!p) {
writelog ();
fprintf (stderr, "SYS_OBJ: couldn't clone #%d\n", pclass.v.obj.id);
return NOTHING;
}
(void) send_message (-1, 0, 0, sys_obj, sys_obj, p->id,
sym_sys (INIT), list_dup (empty_list), 0, p->id);
gettimeofday (&cur_time, 0);
process_queues (cur_time, &cur_time); /* do player init */
strv.type = STR;
strv.v.str = string_cpy (name);
(void) var_assign_global (p, sym_sys (NAME), strv);
strv.v.str = string_cpy (crypt (password, salt));
(void) var_assign_global (p, sym_sys (PASSWORD), strv);
args = list_new (1);
args->el[0].type = OBJ;
args->el[0].v.obj = p->id;
send_message (-1, 0, 0, p->id, sys_obj, sys_obj,
sym_sys (CREATE_PLAYER), args, 0, sys_obj);
return p->id.id;
}
void disconnect_player (Playerid who)
{
List *args;
Objid player;
player.id = who;
player.server = 0;
args = list_new (1);
args->el[0].type = OBJ;
args->el[0].v.obj = player;
send_message (-1, 0, 0, player, sys_obj, sys_obj,
sym_sys (DISCONNECT_PLAYER), args, 0, sys_obj);
}
void connect_server (Serverid server)
{
List *args;
args = list_new (1);
args->el[0].type = OBJ;
args->el[0].v.obj.id = 0;
args->el[0].v.obj.server = server;
(void) send_message (-1, 0, 0, sys_obj, sys_obj, sys_obj,
sym_sys (CONNECT_SERVER), args, 0, sys_obj);
}
void disconnect_server (Serverid server)
{
List *args;
args = list_new (1);
args->el[0].type = OBJ;
args->el[0].v.obj.id = 0;
args->el[0].v.obj.server = server;
(void) send_message (-1, 0, 0, sys_obj, sys_obj, sys_obj,
sym_sys (DISCONNECT_SERVER), args, 0, sys_obj);
}
static Playerid progr; /* programmer */
int prog_getc (void);
void prog_ungetc (int c);
void prog_error (const char *s); /* error function */
static FILE *progfile;
int prog_getc (void)
{
return getc (progfile);
}
void prog_ungetc (int c)
{
ungetc (c, progfile);
}
void prog_error (const char *s)
{
tell (progr, s);
}
void do_compile (Playerid player, FILE * pf, void *progwhat)
{
int *data = (int *) progwhat;
Objid obj;
String *method;
int nerrors;
Object *new;
obj.server = 0;
obj.id = data[0];
method = (String *) data[1];
progr = player;
progfile = pf;
if (obj.id < 0) { /* multiple objects */
nerrors = compile (player, prog_getc, prog_ungetc, prog_error,
0, 0, 0, 0, 0);
} else { /* single method */
if (!(new = retrieve (obj))) {
tell (player, "Object no longer exists!");
} else {
nerrors = compile (player, prog_getc, prog_ungetc, prog_error, 1,
new, method, 0, 0);
}
string_free (method);
}
cache_reset ();
FREE (progwhat);
}