/* Copyright (c) 1993 Stephen F. White */
#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include "config.h"
#include "cool.h"
#include "proto.h"
#include "sys_proto.h"
#include "netio.h"
#include "execute.h"
#ifdef PROTO
time_t time(time_t *t);
#endif
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 */
srandom((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, "r"))) {
writelog();
perror(fname);
return -1;
}
str = string_new(0);
while ((c = getc(f)) != EOF) {
str = string_catc(str, c);
}
fclose(f);
welcome = str->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;
if (!(sys = retrieve(sys_obj))) {
writelog();
fprintf(stderr, "SYS_OBJ: #%d not found\n", SYS_OBJ);
return E_OBJNF;
} else if (var_assign_global(sys, string_cpy(var), value) == E_TYPE) {
writelog();
fprintf(stderr, "SYS_OBJ: #%d.%s assignment: type mismatch\n",
SYS_OBJ, var);
return E_TYPE;
} else {
return E_NONE;
}
}
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
&& !cool_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[random() % strlen(saltstuff)];
salt[1] = saltstuff[random() % 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 */
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, GENPTR 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);
}