aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2016-05-19 16:47:06 -0400
committerFranklin Wei <git@fwei.tk>2016-05-19 16:47:06 -0400
commitcb8af6e7bf5f6e70fc9722d36448213c719e83c8 (patch)
treeec9f93d6e1256d62a49fb628d8d7a3a931b58330
parent7f3ba14388a586a946d721a71eb3a9862f7f6c02 (diff)
downloadnetcosm-cb8af6e7bf5f6e70fc9722d36448213c719e83c8.zip
netcosm-cb8af6e7bf5f6e70fc9722d36448213c719e83c8.tar.gz
netcosm-cb8af6e7bf5f6e70fc9722d36448213c719e83c8.tar.bz2
netcosm-cb8af6e7bf5f6e70fc9722d36448213c719e83c8.tar.xz
implement more of dunnet
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--README.md4
-rw-r--r--export/include/world_api.h121
-rw-r--r--src/SOURCES1
-rw-r--r--src/client.c59
-rw-r--r--src/client.h1
-rw-r--r--src/client_reqs.c7
-rw-r--r--src/globals.h5
-rw-r--r--src/room.c14
-rw-r--r--src/room.h9
-rw-r--r--src/server.c10
-rw-r--r--src/server.h4
-rw-r--r--src/server_reqs.c44
-rw-r--r--src/server_reqs.h8
-rw-r--r--src/userdb.c13
-rw-r--r--src/userdb.h4
-rw-r--r--src/util.c14
-rw-r--r--src/util.h8
-rw-r--r--src/world.c11
-rw-r--r--src/world.h4
-rw-r--r--src/world_api.c113
-rw-r--r--worlds/dunnet.c343
23 files changed, 651 insertions, 149 deletions
diff --git a/.gitignore b/.gitignore
index b6b8e0f..bfcfc94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ a.out
*.d
netcosm.log
build
+*.pem
diff --git a/Makefile b/Makefile
index 372247c..0725138 100644
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ INCLUDES = -I src/ -I export/include/
WARNFLAGS = -Wall -Wextra -Wshadow -fno-strict-aliasing
OPTFLAGS = -O2
-DEBUGFLAGS = -g -fstack-protector
+DEBUGFLAGS = -g
CFLAGS = $(OPTFLAGS) $(DEBUGFLAGS) $(WARNFLAGS) -std=c99 $(INCLUDES)
diff --git a/README.md b/README.md
index fbfb8d8..07f8155 100644
--- a/README.md
+++ b/README.md
@@ -139,6 +139,10 @@ number.
* Many bugfixes
+##### 0.5.2
+
+* Support for monotonic world simulation callbacks
+
### Roadmap
#### 0.6.0
diff --git a/export/include/world_api.h b/export/include/world_api.h
index 9537c68..1c36fd2 100644
--- a/export/include/world_api.h
+++ b/export/include/world_api.h
@@ -26,3 +26,124 @@
#include "multimap.h"
#include "userdb.h"
#include "world.h"
+
+/* world modules should only call the functions provided in this
+ * structure, and those in the standard library */
+
+struct world_api {
+ /* object */
+ struct object_t *(*obj_new)(const char *class);
+ struct object_t *(*obj_dup)(struct object_t *obj); // inc. ref. count
+ struct object_t *(*obj_copy)(struct object_t *obj); // full copy
+ void (*obj_free)(void*);
+
+ /* room */
+ void (*room_user_teleport)(user_t *child, room_id id);
+ bool (*room_obj_add)(room_id room, struct object_t*);
+ bool (*room_obj_add_alias)(room_id room, struct object_t*, const char *alias);
+ bool (*room_obj_del)(room_id room, const char *name);
+ bool (*room_obj_del_by_ptr)(room_id room, struct object_t *obj);
+ const struct multimap_list *(*room_obj_get)(room_id room, const char *obj);
+ const struct multimap_list *(*room_obj_get_size)(room_id room, const char *name, size_t *n_objs);
+ size_t (*room_obj_count)(room_id room);
+ size_t (*room_obj_count_noalias)(room_id id); // doesn't count aliases
+ bool (*room_verb_add)(room_id room, struct verb_t*);
+ bool (*room_verb_del)(room_id room, const char *verbname);
+ void *(*room_verb_map)(room_id room); // hash map of local verbs
+ struct room_t *(*room_get)(room_id id);
+ room_id (*room_get_id)(const char *name);
+
+ /* world */
+ bool (*world_verb_add)(struct verb_t*);
+ bool (*world_verb_del)(struct verb_t*);
+ void *(*world_verb_map)(void); // gets hash map of global verbs
+
+ /* verb */
+ struct verb_t *(*verb_new)(const char *class);
+ void (*verb_free)(void *verb);
+
+ /* hash map */
+ unsigned (*hash_djb)(const void*);
+ int (*compare_strings)(const void*, const void*);
+ int (*compare_strings_nocase)(const void*, const void*);
+
+ void *(*hash_init)(size_t tabsz, unsigned (*hash_fn)(const void *key),
+ int (*compare_key)(const void*, const void*));
+ void (*hash_setfreedata_cb)(void*, void (*cb)(void *data));
+ void (*hash_setfreekey_cb)(void*, void (*cb)(void *key));
+ void (*hash_free)(void*);
+ void *(*hash_insert)(void*, const void *key, const void *data);
+ void (*hash_overwrite)(void*, const void *key, const void *data);
+ void *(*hash_lookup)(void*, const void *key);
+ bool (*hash_remove)(void *ptr, const void *key);
+ void *(*hash_iterate)(void *map, void **saved, void **keyptr);
+ void (*hash_insert_pairs)(void*, const struct hash_pair*, size_t pairsize, size_t n);
+ void *(*hash_getkeyptr)(void*, const void *key);
+ void *(*hash_dup)(void*);
+ void (*hash_setdupdata_cb)(void*, void *(*cb)(void*));
+
+ /* multimap */
+ void *(*multimap_init)(size_t tabsz,
+ unsigned (*hash_fn)(const void *key),
+ int (*compare_key)(const void *key_a, const void *key_b),
+ int (*compare_val)(const void *val_a, const void *val_b));
+ void (*multimap_free)(void*);
+ const struct multimap_list *(*multimap_lookup)(void *map, const void *key, size_t *n_pairs);
+ bool (*multimap_insert)(void *map, const void *key, const void *val);
+ size_t (*multimap_delete)(void *map, const void *key, const void *val);
+ size_t (*multimap_delete_all)(void *map, const void *key);
+
+ /* returns a linked list, NOT individual items of a linked list */
+ const struct multimap_list *(*multimap_iterate)(const void *map, void **save, size_t *n_pairs);
+
+ size_t (*multimap_size)(void *map);
+ void (*multimap_setfreedata_cb)(void *map, void (*)(void*));
+ void *(*multimap_dup)(void *ptr);
+ void (*multimap_setdupdata_cb)(void *ptr, void *(*cb)(void *ptr));
+ void *(*multimap_copy)(void *ptr);
+
+ /* server */
+ void (*send_msg)(user_t *child, const char *fmt, ...) __attribute__((format(printf,2,3)));
+ void (*child_toggle_rawmode)(user_t *child, void (*cb)(user_t*, char *data, size_t len));
+
+ /* userdb */
+ struct userdata_t *(*userdb_lookup)(const char *username);
+ bool (*userdb_remove)(const char *username);
+ size_t (*userdb_size)(void);
+ bool (*userdb_add)(struct userdata_t*);
+ /* (*save) should be set to NULL on the first run */
+ struct userdata_t *(*userdb_iterate)(void **save);
+ bool (*userdb_add_obj)(const char *username, struct object_t *obj);
+ bool (*userdb_del_obj)(const char *username, const char *obj_name);
+ bool (*userdb_del_obj_by_ptr)(const char *username, struct object_t *obj);
+
+ /* util */
+ void (*error)(const char *fmt, ...) __attribute__((noreturn,format(printf,1,2)));
+ void (*all_upper)(char*);
+ void (*all_lower)(char*);
+
+ void (*write_string)(int fd, const char *str);
+ char* (*read_string)(int fd);
+ void (*write_roomid)(int fd, room_id *id);
+ room_id (*read_roomid)(int fd);
+ void (*write_bool)(int fd, bool b);
+ bool (*read_bool)(int fd);
+ void (*write_uint32)(int fd, uint32_t i);
+ uint32_t (*read_uint32)(int fd);
+ void (*write_uint64)(int fd, uint64_t i);
+ uint64_t (*read_uint64)(int fd);
+ void (*write_size)(int fd, size_t);
+ size_t (*read_size)(int fd);
+ void (*write_int)(int fd, int i);
+ int (*read_int)(int fd);
+
+ bool (*is_vowel)(char c);
+ size_t (*strlcat)(char *dst, const char *src, size_t siz);
+ char *(*format_noun)(char *buf, size_t len, const char *name,
+ size_t count, bool default_article, bool capitalize);
+
+
+};
+
+/* defined in src/world_api.c */
+extern const struct world_api *nc;
diff --git a/src/SOURCES b/src/SOURCES
index 5cb3c9b..30204ab 100644
--- a/src/SOURCES
+++ b/src/SOURCES
@@ -13,3 +13,4 @@ userdb.c
util.c
verb.c
world.c
+world_api.c
diff --git a/src/client.c b/src/client.c
index 7c69708..e06058d 100644
--- a/src/client.c
+++ b/src/client.c
@@ -38,6 +38,8 @@ static volatile sig_atomic_t output_locked = 0;
char *current_user = NULL;
+bool child_rawmode = false;
+
bool poll_requests(void);
void out_raw(const void *buf, size_t len)
@@ -160,6 +162,7 @@ tryagain:
if(len <= 0)
error("lost connection");
+ /* null-terminate */
buf[CLIENT_READ_SZ - 1] = '\0';
enum telnet_status ret = telnet_parse_data((unsigned char*)buf + bufidx, len);
@@ -609,43 +612,47 @@ auth:
while(1)
{
- out(">> ");
+ if(!child_rawmode)
+ out(">> ");
char *line = client_read();
char *orig = strdup(line);
char *save = NULL;
- char *tok = strtok_r(line, WSPACE, &save);
+ if(!child_rawmode)
+ {
+ char *tok = strtok_r(line, WSPACE, &save);
- if(!tok)
- goto next_cmd;
+ if(!tok)
+ goto next_cmd;
- all_upper(tok);
+ all_upper(tok);
- const struct client_cmd *cmd = hash_lookup(cmd_map, tok);
- if(cmd && cmd->cb && (!cmd->admin_only || (cmd->admin_only && are_admin)))
- {
- int ret = cmd->cb(&save);
- switch(ret)
+ const struct client_cmd *cmd = hash_lookup(cmd_map, tok);
+ if(cmd && cmd->cb && (!cmd->admin_only || (cmd->admin_only && are_admin)))
+ {
+ int ret = cmd->cb(&save);
+ switch(ret)
+ {
+ case CMD_OK:
+ goto next_cmd;
+ case CMD_LOGOUT:
+ free(line);
+ free(orig);
+ goto auth;
+ case CMD_QUIT:
+ free(line);
+ free(orig);
+ goto done;
+ default:
+ error("client: bad callback return value");
+ }
+ }
+ else if(cmd && cmd->admin_only && !are_admin)
{
- case CMD_OK:
+ out("You are not allowed to do that.\n");
goto next_cmd;
- case CMD_LOGOUT:
- free(line);
- free(orig);
- goto auth;
- case CMD_QUIT:
- free(line);
- free(orig);
- goto done;
- default:
- error("client: bad callback return value");
}
}
- else if(cmd && cmd->admin_only && !are_admin)
- {
- out("You are not allowed to do that.\n");
- goto next_cmd;
- }
/* if we can't handle it, let the master process try */
send_master(REQ_EXECVERB, orig, strlen(orig) + 1);
diff --git a/src/client.h b/src/client.h
index 223bf86..0bd74bb 100644
--- a/src/client.h
+++ b/src/client.h
@@ -23,6 +23,7 @@
extern int client_fd, to_parent, from_parent;
extern bool are_admin;
+extern bool child_rawmode;
/* call from child process ONLY */
void send_master(unsigned char cmd, const void *data, size_t sz);
diff --git a/src/client_reqs.c b/src/client_reqs.c
index 21174c4..a7e6a01 100644
--- a/src/client_reqs.c
+++ b/src/client_reqs.c
@@ -56,7 +56,7 @@ bool poll_requests(void)
/* parent closed pipe */
if(!packetlen)
{
- debugf("master process died\n");
+ debugf("master process died, dropping client.\n");
exit(0);
}
@@ -66,6 +66,11 @@ bool poll_requests(void)
switch(cmd)
{
+ case REQ_RAWMODE:
+ {
+ child_rawmode = !child_rawmode;
+ break;
+ }
case REQ_BCASTMSG:
{
out((char*)data, datalen);
diff --git a/src/globals.h b/src/globals.h
index 6e050ee..100ec1d 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -55,11 +55,6 @@
#include <time.h>
#include <unistd.h>
-/* convenience macros */
-#define ARRAYLEN(x) (sizeof(x)/sizeof(x[0]))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#define MIN(a,b) (((a)<(b))?(a):(b))
-
/* global constants */
#define USERFILE "users.dat"
#define WORLDFILE "world.dat"
diff --git a/src/room.c b/src/room.c
index 2e7688a..19a4b73 100644
--- a/src/room.c
+++ b/src/room.c
@@ -25,6 +25,8 @@
#include "userdb.h"
#include "world.h"
+/* these do not perform hook checking on the requested action, that is
+ * the responsibility of the caller */
bool room_user_add(room_id id, struct child_data *child)
{
struct room_t *room = room_get(id);
@@ -60,6 +62,16 @@ bool room_user_del(room_id id, struct child_data *child)
return false;
}
+/* ignores hooks */
+void room_user_teleport(struct child_data *child, room_id id)
+{
+ if(child->room != id)
+ {
+ room_user_del(child->room, child);
+ room_user_add(id, child);
+ }
+}
+
void room_free(struct room_t *room)
{
if(room->data.hook_destroy)
@@ -99,7 +111,7 @@ bool room_obj_add(room_id room, struct object_t *obj)
return status;
}
-bool room_obj_add_alias(room_id room, struct object_t *obj, char *alias)
+bool room_obj_add_alias(room_id room, struct object_t *obj, const char *alias)
{
/* the primary name must be added */
if(!room_obj_get(room, obj->name))
diff --git a/src/room.h b/src/room.h
index c0304c7..62901c8 100644
--- a/src/room.h
+++ b/src/room.h
@@ -69,15 +69,19 @@ struct room_t {
/* hash maps */
void *objects; /* multimap of object name -> object */
- void *verbs;
+ void *verbs; /* name -> verb_t */
void *users; /* username -> child_data */
void *userdata;
};
/* room/world */
+
+/* none of these care about room hooks, which are the caller's
+ * responsibility */
bool room_user_add(room_id id, struct child_data *child);
bool room_user_del(room_id id, struct child_data *child);
+void room_user_teleport(struct child_data *child, room_id id);
/* On the first call, room should be a valid room id, and *save should
* point to a void pointer. On subsequent calls, room should be
@@ -92,10 +96,9 @@ const struct multimap_list *room_obj_iterate(room_id room, void **save, size_t *
*/
bool room_obj_add(room_id room, struct object_t *obj);
-bool room_obj_add_alias(room_id room, struct object_t *obj, char *alias);
+bool room_obj_add_alias(room_id room, struct object_t *obj, const char *alias);
bool room_obj_del(room_id room, const char *name);
-bool room_obj_del_alias(room_id room, struct object_t *obj, const char *alias);
bool room_obj_del_by_ptr(room_id room, struct object_t *obj);
const struct multimap_list *room_obj_get(room_id room, const char *obj);
diff --git a/src/server.c b/src/server.c
index b736124..9a28679 100644
--- a/src/server.c
+++ b/src/server.c
@@ -48,7 +48,7 @@ static char *module_handle = NULL;
/* save after every X changes to the world state */
#define SAVE_INTERVAL 10
-/* saves state periodically */
+/* saves game state periodically */
void server_save_state(bool force)
{
if(!are_child)
@@ -231,6 +231,9 @@ static void load_worldfile(void)
}
}
+ netcosm_write_userdata_cb = dlsym(module_handle, "netcosm_write_userdata_cb");
+ netcosm_read_userdata_cb = dlsym(module_handle, "netcosm_read_userdata_cb");
+
if(access(WORLDFILE, F_OK) < 0)
{
world_init(netcosm_world, netcosm_world_sz, netcosm_world_name);
@@ -484,6 +487,11 @@ static void parse_args(int argc, char *argv[])
}
}
}
+ else
+ {
+ debugf("Unknown argument `%s'\n", argv[i]);
+ exit(0);
+ }
}
}
diff --git a/src/server.h b/src/server.h
index 6d3d029..a0efb39 100644
--- a/src/server.h
+++ b/src/server.h
@@ -24,6 +24,7 @@
enum room_id;
/* everything the server needs to manage its children */
+/* aliased as user_t */
struct child_data {
pid_t pid;
@@ -40,6 +41,9 @@ struct child_data {
ev_io *io_watcher;
ev_child *sigchld_watcher;
+ /* raw mode callback (NULL if none, set by world module) */
+ void (*raw_mode_cb)(struct child_data*, char *data, size_t len);
+
/* remote IP */
struct in_addr addr;
};
diff --git a/src/server_reqs.c b/src/server_reqs.c
index ab283ca..ed2d09c 100644
--- a/src/server_reqs.c
+++ b/src/server_reqs.c
@@ -26,18 +26,29 @@
#include "world.h"
/* sends a single packet to a child, mostly reliable */
+
+/* splits REQ_BCASTMSG message into multiple packets if data length
+ * exceeds MSG_MAX, however, other requests will not be split and will
+ * cause a failed assertion */
+
static void send_packet(struct child_data *child, unsigned char cmd,
const void *data, size_t datalen)
{
- assert(datalen < MSG_MAX);
+ assert(datalen < MSG_MAX || cmd == REQ_BCASTMSG);
unsigned char pkt[MSG_MAX];
pkt[0] = cmd;
- //if((data?datalen:0) + 1 > MSG_MAX && cmd == REQ_BCASTMSG)
- //{
- // /* TODO: split long messages */
- // ;
- //}
+ if(cmd == REQ_BCASTMSG && (data?datalen:0) + 1 > MSG_MAX)
+ {
+ /* split long messages */
+ const char *ptr = data, *stop = (const char*)data + datalen;
+ while(ptr < stop)
+ {
+ send_packet(child, cmd, ptr, MIN(stop - ptr, MSG_MAX - 1));
+ ptr += MSG_MAX - 1;
+ }
+ return;
+ }
if(data && datalen)
memcpy(pkt + 1, data, datalen);
@@ -50,6 +61,19 @@ tryagain:
}
}
+void child_toggle_rawmode(struct child_data *child, void (*cb)(user_t*, char *data, size_t len))
+{
+ if(!are_child)
+ {
+ send_packet(child, REQ_RAWMODE, NULL, 0);
+ /* this pointer also indicates whether raw mode is on */
+ if(!child->raw_mode_cb)
+ child->raw_mode_cb = cb;
+ else
+ child->raw_mode_cb = NULL;
+ }
+}
+
void __attribute__((format(printf,2,3))) send_msg(struct child_data *child, const char *fmt, ...)
{
va_list ap;
@@ -495,6 +519,14 @@ static void req_listusers(unsigned char *data, size_t datalen, struct child_data
static void req_execverb(unsigned char *data, size_t datalen, struct child_data *sender)
{
(void) datalen;
+
+ /* if the child is in raw mode, pass the data to the world module */
+ if(sender->raw_mode_cb)
+ {
+ sender->raw_mode_cb(sender, (char*)data, datalen);
+ return;
+ }
+
/* first look for a room-local verb */
char *save;
char *tok = strtok_r((char*)data, " \t", &save);
diff --git a/src/server_reqs.h b/src/server_reqs.h
index 10c1755..8db6927 100644
--- a/src/server_reqs.h
+++ b/src/server_reqs.h
@@ -50,7 +50,7 @@
#define REQ_DROP 22 /* server: drop user object if allowed */
#define REQ_LISTUSERS 23 /* server: list users in USERFILE */
#define REQ_EXECVERB 24 /* server: execute a verb with its arguments */
-#define REQ_RAWMODE 25 /* child: toggle the child's processing of commands and instead sending input directly to master */
+#define REQ_RAWMODE 25 /* child: toggle the child's processing of commands and instead send input directly to master */
/* child states, sent as an int to the master */
#define STATE_INIT 0 /* initial state */
@@ -66,3 +66,9 @@ void reqmap_init(void);
void reqmap_free(void);
void send_msg(user_t *child, const char *fmt, ...) __attribute__((format(printf,2,3)));
+
+/* toggle the child into "raw mode": all commands typed by the
+ * connected client will be send to the world module;
+ * if the child is already in raw mode the callback is ignored */
+
+void child_toggle_rawmode(user_t *child, void (*cb)(user_t*, char *data, size_t len));
diff --git a/src/userdb.c b/src/userdb.c
index 0ebe159..14e9fd8 100644
--- a/src/userdb.c
+++ b/src/userdb.c
@@ -26,6 +26,7 @@
#include "server.h"
#include "server_reqs.h"
#include "userdb.h"
+#include "world.h"
static void *map = NULL;
static char *db_file = NULL;
@@ -101,6 +102,10 @@ void userdb_init(const char *file)
}
}
+ /* now we read in the world module's data, if possible */
+ if(netcosm_read_userdata_cb)
+ data->userdata = netcosm_read_userdata_cb(fd);
+
hash_insert(map, data->username, data);
}
@@ -124,8 +129,10 @@ bool userdb_write(const char *file)
if(!user)
break;
+ /* dump structure */
write(fd, user, sizeof(*user));
+ /* now go back and write what the pointers are pointing at */
size_t n_objects;
if(user->objects)
n_objects = obj_count_noalias(user->objects);
@@ -158,6 +165,12 @@ bool userdb_write(const char *file)
}
}
}
+
+ /* write world module's data, if possible */
+ if(netcosm_write_userdata_cb)
+ {
+ netcosm_write_userdata_cb(fd, user->userdata);
+ }
}
close(fd);
diff --git a/src/userdb.h b/src/userdb.h
index 25bdc7b..7958fb3 100644
--- a/src/userdb.h
+++ b/src/userdb.h
@@ -39,12 +39,16 @@ struct userdata_t {
time_t last_login;
void *objects; /* multihash of object names -> objects */
+
+ /* for use by world module */
+ void *userdata;
};
/* call before using anything else */
void userdb_init(const char *dbfile);
/* looks up a username in the DB, returns NULL upon failure */
+/* changes made to the returned structure will persist */
struct userdata_t *userdb_lookup(const char *username);
bool userdb_remove(const char *username);
diff --git a/src/util.c b/src/util.c
index 9c4b447..c5b606c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -173,6 +173,20 @@ void write_size(int fd, size_t b)
error("write failed");
}
+int read_int(int fd)
+{
+ int ret;
+ if(read(fd, &ret, sizeof(ret)) != sizeof(ret))
+ error("unexpected EOF");
+ return ret;
+}
+
+void write_int(int fd, int b)
+{
+ if(write(fd, &b, sizeof(b)) != sizeof(b))
+ error("write failed");
+}
+
bool is_vowel(char c)
{
switch(tolower(c))
diff --git a/src/util.h b/src/util.h
index 8007ec8..a6965be 100644
--- a/src/util.h
+++ b/src/util.h
@@ -23,6 +23,11 @@
#define WSPACE " \t\r\n"
+/* convenience macros */
+#define ARRAYLEN(x) (sizeof(x)/sizeof(x[0]))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
/* utility functions */
void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...);
void __attribute__((format(printf,4,5))) debugf_real(const char*, int, const char*, const char *fmt, ...);
@@ -48,6 +53,9 @@ uint64_t read_uint64(int fd);
void write_size(int fd, size_t);
size_t read_size(int fd);
+void write_int(int fd, int i);
+int read_int(int fd);
+
bool is_vowel(char c);
size_t strlcat(char *dst, const char *src, size_t siz);
diff --git a/src/world.c b/src/world.c
index d0e1711..45a1717 100644
--- a/src/world.c
+++ b/src/world.c
@@ -39,6 +39,9 @@ size_t netcosm_world_sz;
void (*netcosm_world_simulation_cb)(void) = NULL;
unsigned netcosm_world_simulation_interval = 0;
+void (*netcosm_write_userdata_cb)(int fd, void *ptr) = NULL;
+void *(*netcosm_read_userdata_cb)(int fd) = NULL;
+
const char *netcosm_world_name;
/* processed world data */
@@ -188,8 +191,6 @@ void world_free(void)
free(world);
world = NULL;
}
- if(sim_timer)
- free(sim_timer);
}
static void start_sim_callback(void)
@@ -440,6 +441,12 @@ bool world_verb_add(struct verb_t *verb)
return !hash_insert(verb_map, verb->name, verb);
}
+bool world_verb_del(struct verb_t *verb)
+{
+ init_map();
+ return hash_remove(verb_map, verb->name);
+}
+
void *world_verb_map(void)
{
init_map();
diff --git a/src/world.h b/src/world.h
index 4ce253e..f850876 100644
--- a/src/world.h
+++ b/src/world.h
@@ -45,6 +45,10 @@ extern size_t netcosm_world_sz;
extern void (*netcosm_world_simulation_cb)(void);
extern unsigned netcosm_world_simulation_interval;
+/* user data callback */
+extern void (*netcosm_write_userdata_cb)(int fd, void *ptr);
+extern void* (*netcosm_read_userdata_cb)(int fd);
+
extern const char *netcosm_world_name;
#endif
diff --git a/src/world_api.c b/src/world_api.c
new file mode 100644
index 0000000..f38f892
--- /dev/null
+++ b/src/world_api.c
@@ -0,0 +1,113 @@
+/*
+ * NetCosm - a MUD server
+ * Copyright (C) 2016 Franklin Wei
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "globals.h"
+
+#include "server.h"
+#include "server_reqs.h"
+#include "hash.h"
+#include "multimap.h"
+#include "userdb.h"
+#include "world.h"
+#include "world_api.h"
+
+static const struct world_api api = {
+ obj_new,
+ obj_dup,
+ obj_copy,
+ obj_free,
+ room_user_teleport,
+ room_obj_add,
+ room_obj_add_alias,
+ room_obj_del,
+ room_obj_del_by_ptr,
+ room_obj_get,
+ room_obj_get_size,
+ room_obj_count,
+ room_obj_count_noalias,
+ room_verb_add,
+ room_verb_del,
+ room_verb_map,
+ room_get,
+ room_get_id,
+ world_verb_add,
+ world_verb_del,
+ world_verb_map,
+ verb_new,
+ verb_free,
+ hash_djb,
+ compare_strings,
+ compare_strings_nocase,
+ hash_init,
+ hash_setfreedata_cb,
+ hash_setfreekey_cb,
+ hash_free,
+ hash_insert,
+ hash_overwrite,
+ hash_lookup,
+ hash_remove,
+ hash_iterate,
+ hash_insert_pairs,
+ hash_getkeyptr,
+ hash_dup,
+ hash_setdupdata_cb,
+ multimap_init,
+ multimap_free,
+ multimap_lookup,
+ multimap_insert,
+ multimap_delete,
+ multimap_delete_all,
+ multimap_iterate,
+ multimap_size,
+ multimap_setfreedata_cb,
+ multimap_dup,
+ multimap_setdupdata_cb,
+ multimap_copy,
+ send_msg,
+ child_toggle_rawmode,
+ userdb_lookup,
+ userdb_remove,
+ userdb_size,
+ userdb_add,
+ userdb_iterate,
+ userdb_add_obj,
+ userdb_del_obj,
+ userdb_del_obj_by_ptr,
+ error,
+ all_upper,
+ all_lower,
+ write_string,
+ read_string,
+ write_roomid,
+ read_roomid,
+ write_bool,
+ read_bool,
+ write_uint32,
+ read_uint32,
+ write_uint64,
+ read_uint64,
+ write_size,
+ read_size,
+ write_int,
+ read_int,
+ is_vowel,
+ strlcat,
+ format_noun
+};
+
+const struct world_api *nc = &api;
diff --git a/worlds/dunnet.c b/worlds/dunnet.c
index 790d0bf..acc1a5f 100644
--- a/worlds/dunnet.c
+++ b/worlds/dunnet.c
@@ -2,151 +2,165 @@
/* implements dunnet in NetCosm */
+/* user data structure: used for tracking dunnet-specific user
+ * attributes */
+
+struct dunnet_user {
+ enum { NO_CONSOLE = 0, POKEY_LOGIN, POKEY_SHELL, POKEY_FTP, GAMMA_FTP } console_state;
+ union {
+ struct {
+ bool prompt_pass;
+ bool correct_user;
+ int fails;
+ } pokey_login;
+ } state_data;
+};
+
/************ ROOM DEFINITIONS ************/
static void deadend_init(room_id id)
{
- struct object_t *new = obj_new("/generic");
+ struct object_t *new = nc->obj_new("/generic");
new->name = strdup("shovel");
new->userdata = strdup("It is a normal shovel with a price tag attached that says $19.99.");
- room_obj_add(id, new);
+ nc->room_obj_add(id, new);
- new = obj_new("/generic/notake");
+ new = nc->obj_new("/generic/notake");
new->name = strdup("trees");
new->userdata = strdup("They are palm trees with a bountiful supply of coconuts in them.");
new->hidden = true;
- room_obj_add(id, new);
- room_obj_add_alias(id, new, "tree");
- room_obj_add_alias(id, new, "palm");
- room_obj_add_alias(id, new, "palm tree");
+ nc->room_obj_add(id, new);
+ nc->room_obj_add_alias(id, new, "tree");
+ nc->room_obj_add_alias(id, new, "palm");
+ nc->room_obj_add_alias(id, new, "palm tree");
/* add global verbs */
- struct verb_t *verb = verb_new("dig");
+ struct verb_t *verb = nc->verb_new("dig");
verb->name = strdup("dig");
- world_verb_add(verb);
+ nc->world_verb_add(verb);
- verb = verb_new("put");
+ verb = nc->verb_new("put");
verb->name = strdup("put");
- world_verb_add(verb);
+ nc->world_verb_add(verb);
- verb = verb_new("eat");
+ verb = nc->verb_new("eat");
verb->name = strdup("eat");
- world_verb_add(verb);
+ nc->world_verb_add(verb);
- verb = verb_new("shake");
+ verb = nc->verb_new("shake");
verb->name = strdup("shake");
- world_verb_add(verb);
+ nc->world_verb_add(verb);
- verb = verb_new("type");
+ verb = nc->verb_new("type");
verb->name = strdup("type");
- world_verb_add(verb);
+ nc->world_verb_add(verb);
}
static void ew_road_init(room_id id)
{
- struct object_t *new = obj_new("/generic/notake");
+ struct object_t *new = nc->obj_new("/generic/notake");
new->name = strdup("large boulder");
new->userdata = strdup("It is just a boulder. It cannot be moved.");
- room_obj_add(id, new);
- room_obj_add_alias(id, new, "boulder");
- room_obj_add_alias(id, new, "rock");
+ nc->room_obj_add(id, new);
+ nc->room_obj_add_alias(id, new, "boulder");
+ nc->room_obj_add_alias(id, new, "rock");
}
static void fork_init(room_id id)
{
- room_get(id)->userdata = calloc(1, sizeof(bool));
+ nc->room_get(id)->userdata = calloc(1, sizeof(bool));
/* flag for whether the user has already dug */
- bool *b = room_get(id)->userdata;
+ bool *b = nc->room_get(id)->userdata;
*b = false;
}
static void bool_ser(room_id id, int fd)
{
- bool *b = room_get(id)->userdata;
- write_bool(fd, *b);
+ bool *b = nc->room_get(id)->userdata;
+ nc->write_bool(fd, *b);
}
static void bool_deser(room_id id, int fd)
{
bool *b = calloc(1, sizeof(bool));
- *b = read_bool(fd);
- room_get(id)->userdata = b;
+ *b = nc->read_bool(fd);
+ nc->room_get(id)->userdata = b;
}
static void bool_destroy(room_id id)
{
- free(room_get(id)->userdata);
+ free(nc->room_get(id)->userdata);
}
static void senw_init(room_id id)
{
- struct object_t *new = obj_new("/generic/dunnet/food");
+ struct object_t *new = nc->obj_new("/generic/dunnet/food");
new->name = strdup("some food");
new->userdata = strdup("It looks like some kind of meat. Smells pretty bad.");
new->default_article = false;
- room_obj_add(id, new);
- room_obj_add_alias(id, new, "food");
- room_obj_add_alias(id, new, "meat");
+ nc->room_obj_add(id, new);
+ nc->room_obj_add_alias(id, new, "food");
+ nc->room_obj_add_alias(id, new, "meat");
}
static void hangout_init(room_id id)
{
- struct object_t *new = obj_new("/generic/notake");
+ struct object_t *new = nc->obj_new("/generic/notake");
new->name = strdup("ferocious bear");
new->userdata = strdup("It looks like a grizzly to me.");
- room_obj_add(id, new);
- room_obj_add_alias(id, new, "bear");
+ nc->room_obj_add(id, new);
+ nc->room_obj_add_alias(id, new, "bear");
}
static void hidden_init(room_id id)
{
- struct object_t *new = obj_new("/generic");
+ struct object_t *new = nc->obj_new("/generic");
new->name = strdup("emerald bracelet");
new->userdata = strdup("I see nothing special about that.");
- room_obj_add(id, new);
- room_obj_add_alias(id, new, "bracelet");
+ nc->room_obj_add(id, new);
+ nc->room_obj_add_alias(id, new, "bracelet");
}
static bool building_enter(room_id id, user_t *user)
{
(void) id;
- if(multimap_lookup(userdb_lookup(user->user)->objects, "shiny brass key", NULL))
+ if(nc->multimap_lookup(userdb_lookup(user->user)->objects, "shiny brass key", NULL))
return true;
else
{
- send_msg(user, "You don't have a key that can open this door.\n");
+ nc->send_msg(user, "You don't have a key that can open this door.\n");
return false;
}
}
static void mailroom_init(room_id id)
{
- struct object_t *new = obj_new("/generic/notake");
+ struct object_t *new = nc->obj_new("/generic/notake");
new->name = strdup("bins");
new->hidden = true;
/* insert IAC NOP to prevent the extra whitespace from being dropped */
new->userdata = strdup("All of the bins are empty. Looking closely you can see that there are names written at the bottom of each bin, but most of them are faded away so that you cannot read them. You can only make out three names:\n\377\361 Jeffrey Collier\n\377\361 Robert Toukmond\n\377\361 Thomas Stock\n");
- room_obj_add(id, new);
- room_obj_add_alias(id, new, "mail bins");
+ nc->room_obj_add(id, new);
+ nc->room_obj_add_alias(id, new, "mail bins");
}
static void computer_room_init(room_id id)
{
- struct object_t *new = obj_new("/generic/notake");
+ struct object_t *new = nc->obj_new("/generic/notake");
new->name = strdup("computer");
new->userdata = strdup("I see nothing special about that.");
new->hidden = true;
- room_obj_add(id, new);
- room_obj_add_alias(id, new, "vax");
- room_obj_add_alias(id, new, "pokey");
+ nc->room_obj_add(id, new);
+ nc->room_obj_add_alias(id, new, "vax");
+ nc->room_obj_add_alias(id, new, "pokey");
/* flag for whether computer is active */
- room_get(id)->userdata = malloc(sizeof(bool));
- bool *b = room_get(id)->userdata;
+ nc->room_get(id)->userdata = malloc(sizeof(bool));
+ bool *b = nc->room_get(id)->userdata;
*b = false;
}
@@ -334,23 +348,23 @@ static bool no_take(struct object_t *obj, user_t *user)
static bool food_drop(struct object_t *obj, user_t *user)
{
- if(room_obj_get(user->room, "bear"))
+ if(nc->room_obj_get(user->room, "bear"))
{
- send_msg(user, "The bear takes the food and runs away with it. He left something behind.\n");
+ nc->send_msg(user, "The bear takes the food and runs away with it. He left something behind.\n");
room_obj_del(user->room, "ferocious bear");
room_obj_del_by_ptr(user->room, obj);
- struct object_t *new = obj_new("/generic");
+ struct object_t *new = nc->obj_new("/generic");
new->hidden = false;
new->name = strdup("shiny brass key");
new->userdata = strdup("I see nothing special about that.");
- room_obj_add(user->room, new);
- room_obj_add_alias(user->room, new, "key");
- room_obj_add_alias(user->room, new, "shiny key");
- room_obj_add_alias(user->room, new, "brass key");
+ nc->room_obj_add(user->room, new);
+ nc->room_obj_add_alias(user->room, new, "key");
+ nc->room_obj_add_alias(user->room, new, "shiny key");
+ nc->room_obj_add_alias(user->room, new, "brass key");
}
return true;
@@ -402,26 +416,26 @@ static void dig_exec(struct verb_t *verb, char *args, user_t *user)
{
(void) verb;
(void) args;
- if(!multimap_lookup(userdb_lookup(user->user)->objects, "shovel", NULL))
+ if(!nc->multimap_lookup(userdb_lookup(user->user)->objects, "shovel", NULL))
{
- send_msg(user, "You have nothing with which to dig.\n");
+ nc->send_msg(user, "You have nothing with which to dig.\n");
return;
}
- if(!strcmp(room_get(user->room)->data.name, "Fork"))
+ if(!strcmp(nc->room_get(user->room)->data.name, "Fork"))
{
- bool *b = room_get(user->room)->userdata;
+ bool *b = nc->room_get(user->room)->userdata;
if(!*b)
{
*b = true;
- struct object_t *new = obj_new("/generic");
+ struct object_t *new = nc->obj_new("/generic");
new->name = strdup("CPU card");
new->userdata = strdup("The CPU board has a VAX chip on it. It seems to have 2 Megabytes of RAM onboard.");
- room_obj_add(user->room, new);
- room_obj_add_alias(user->room, new, "cpu");
- room_obj_add_alias(user->room, new, "chip");
- room_obj_add_alias(user->room, new, "card");
- send_msg(user, "I think you found something.\n");
+ nc->room_obj_add(user->room, new);
+ nc->room_obj_add_alias(user->room, new, "cpu");
+ nc->room_obj_add_alias(user->room, new, "chip");
+ nc->room_obj_add_alias(user->room, new, "card");
+ nc->send_msg(user, "I think you found something.\n");
}
else
{
@@ -429,12 +443,12 @@ static void dig_exec(struct verb_t *verb, char *args, user_t *user)
}
}
else
- send_msg(user, "Digging here reveals nothing.\n");
+ nc->send_msg(user, "Digging here reveals nothing.\n");
return;
nothing:
- send_msg(user, "Digging here reveals nothing.\n");
+ nc->send_msg(user, "Digging here reveals nothing.\n");
}
static void put_exec(struct verb_t *verb, char *args, user_t *user)
@@ -445,16 +459,16 @@ static void put_exec(struct verb_t *verb, char *args, user_t *user)
if(!obj_name)
{
- send_msg(user, "You must supply an object\n");
+ nc->send_msg(user, "You must supply an object\n");
return;
}
args = NULL;
- const struct multimap_list *list = multimap_lookup(userdb_lookup(user->user)->objects,
+ const struct multimap_list *list = nc->multimap_lookup(userdb_lookup(user->user)->objects,
obj_name, NULL);
if(!list)
{
- send_msg(user, "You don't have that.\n");
+ nc->send_msg(user, "You don't have that.\n");
return;
}
@@ -468,34 +482,34 @@ static void put_exec(struct verb_t *verb, char *args, user_t *user)
if(!ind_obj_name)
{
- send_msg(user, "You must supply an indirect object.\n");
+ nc->send_msg(user, "You must supply an indirect object.\n");
return;
}
- list = room_obj_get(user->room, ind_obj_name);
+ list = nc->room_obj_get(user->room, ind_obj_name);
if(!list)
{
- send_msg(user, "I don't know what that indirect object is.\n");
+ nc->send_msg(user, "I don't know what that indirect object is.\n");
return;
}
struct object_t *ind_obj = list->val;
/* now execute the verb */
- if(!strcmp(obj->name, "CPU card") && !strcmp(ind_obj->name, "computer") && user->room == room_get_id("computer_room"))
+ if(!strcmp(obj->name, "CPU card") && !strcmp(ind_obj->name, "computer") && user->room == nc->room_get_id("computer_room"))
{
- userdb_del_obj_by_ptr(user->user, obj);
- send_msg(user, "As you put the CPU board in the computer, it immediately springs to life. The lights start flashing, and the fans seem to startup.\n");
- bool *b = room_get(user->room)->userdata;
+ nc->userdb_del_obj_by_ptr(user->user, obj);
+ nc->send_msg(user, "As you put the CPU board in the computer, it immediately springs to life. The lights start flashing, and the fans seem to startup.\n");
+ bool *b = nc->room_get(user->room)->userdata;
*b = true;
- free(room_get(user->room)->data.desc);
- room_get(user->room)->data.desc = strdup("You are in a computer room. It seems like most of the equipment has been removed. There is a VAX 11/780 in front of you, however, with one of the cabinets wide open. A sign on the front of the machine says: This VAX is named 'pokey'. To type on the console, use the 'type' command. The exit is to the east.\nThe panel lights are flashing in a seemingly organized pattern.");
+ free(nc->room_get(user->room)->data.desc);
+ nc->room_get(user->room)->data.desc = strdup("You are in a computer room. It seems like most of the equipment has been removed. There is a VAX 11/780 in front of you, however, with one of the cabinets wide open. A sign on the front of the machine says: This VAX is named 'pokey'. To type on the console, use the 'type' command. The exit is to the east.\nThe panel lights are flashing in a seemingly organized pattern.");
}
else
{
- send_msg(user, "I don't know how to combine those objects. Perhaps you should just try dropping it.\n");
+ nc->send_msg(user, "I don't know how to combine those objects. Perhaps you should just try dropping it.\n");
}
}
@@ -506,19 +520,19 @@ static void eat_exec(struct verb_t *verb, char *args, user_t *user)
char *obj_name = strtok_r(args, WSPACE, &save);
if(!obj_name)
{
- send_msg(user, "You must supply an object.\n");
+ nc->send_msg(user, "You must supply an object.\n");
return;
}
size_t n_objs;
- const struct multimap_list *list = multimap_lookup(userdb_lookup(user->user)->objects, obj_name, &n_objs);
+ const struct multimap_list *list = nc->multimap_lookup(userdb_lookup(user->user)->objects, obj_name, &n_objs);
if(!list)
{
- if(!room_obj_get(user->room, obj_name))
- send_msg(user, "I don't know what that is.\n");
+ if(!nc->room_obj_get(user->room, obj_name))
+ nc->send_msg(user, "I don't know what that is.\n");
else
- send_msg(user, "You don't have that.\n");
+ nc->send_msg(user, "You don't have that.\n");
return;
}
@@ -526,18 +540,18 @@ static void eat_exec(struct verb_t *verb, char *args, user_t *user)
if(!strcmp(obj->name, "some food"))
{
- send_msg(user, "That tasted horrible.\n");
+ nc->send_msg(user, "That tasted horrible.\n");
}
else
{
char buf[MSG_MAX];
- send_msg(user, "You forcibly shove %s down your throat, and start choking.\n",
- format_noun(buf, sizeof(buf), obj->name, n_objs, obj->default_article, false));
+ nc->send_msg(user, "You forcibly shove %s down your throat, and start choking.\n",
+ nc->format_noun(buf, sizeof(buf), obj->name, n_objs, obj->default_article, false));
/* TODO: kill player */
}
- userdb_del_obj(user->user, obj_name);
+ nc->userdb_del_obj(user->user, obj_name);
}
static void shake_exec(struct verb_t *verb, char *args, user_t *user)
@@ -548,18 +562,18 @@ static void shake_exec(struct verb_t *verb, char *args, user_t *user)
if(!obj_name)
{
- send_msg(user, "You must supply an object.\n");
+ nc->send_msg(user, "You must supply an object.\n");
return;
}
size_t n_objs_room, n_objs_inv;
- const struct multimap_list *list_room = room_obj_get_size(user->room, obj_name, &n_objs_room);
+ const struct multimap_list *list_room = nc->room_obj_get_size(user->room, obj_name, &n_objs_room);
- const struct multimap_list *list_inv = multimap_lookup(userdb_lookup(user->user)->objects, obj_name, &n_objs_inv);
+ const struct multimap_list *list_inv = nc->multimap_lookup(userdb_lookup(user->user)->objects, obj_name, &n_objs_inv);
if(!list_room && !list_inv)
{
- send_msg(user, "I don't know what that is.\n");
+ nc->send_msg(user, "I don't know what that is.\n");
return;
}
@@ -567,29 +581,97 @@ static void shake_exec(struct verb_t *verb, char *args, user_t *user)
{
struct object_t *obj = list_room->val;
if(!strcmp(obj->name, "trees"))
- send_msg(user, "You begin to shake a tree, and notice a coconut begin to fall from the air. As you try to get your hand up to block it, you feel the impact as it lands on your head.\n");
+ nc->send_msg(user, "You begin to shake a tree, and notice a coconut begin to fall from the air. As you try to get your hand up to block it, you feel the impact as it lands on your head.\n");
else
- send_msg(user, "You don't have that.\n");
+ nc->send_msg(user, "You don't have that.\n");
}
else if(list_inv)
{
struct object_t *obj = list_inv->val;
char buf[MSG_MAX];
- send_msg(user, "Shaking %s seems to have no effect.\n",
- format_noun(buf, sizeof(buf), obj->name,
+ nc->send_msg(user, "Shaking %s seems to have no effect.\n",
+ nc->format_noun(buf, sizeof(buf), obj->name,
n_objs_inv, obj->default_article,
false));
}
}
+static struct unix_cmd_t {
+ const char *cmd;
+ void (*cb)(user_t *user, char *saveptr);
+} cmds[] = {
+ { "ls", ls_cb },
+ { "cat", cat_cb },
+ { "exit", exit_cb },
+ { "ftp", ftp_cb },
+ { "rlogin", rlogin_cb },
+};
+
+static void pokey_unix_command(user_t *user, char *data)
+{
+ static void *cmd_map = NULL;
+ char *save;
+ char *cmd = strtok_r(data, WSPACE, &save);
+
+}
+
+/* this is called each time the user types a line at pokey */
+
+static void console_cb(user_t *user, char *data, size_t len)
+{
+ struct dunnet_user *du = userdb_lookup(user->user)->userdata;
+ /* we use their state data to decide how to interpret it */
+ switch(du->console_state)
+ {
+ case POKEY_LOGIN:
+ if(!du->state_data.pokey_login.prompt_pass)
+ {
+ if(!strcmp(data, "toukmond"))
+ du->state_data.pokey_login.correct_user = true;
+ du->state_data.pokey_login.prompt_pass = true;
+ send_msg(user, "password: ");
+ }
+ else
+ {
+ if(!strcmp(data, "robert") && du->state_data.pokey_login.correct_user)
+ {
+ du->console_state = POKEY_SHELL;
+ send_msg(user, "\n\nWelcome to Unix\n\nPlease clean up your directories. The filesystem is getting full.\nOur tcp/ip link to gamma is a little flaky, but seems to work.\nThe current version of ftp can only send files from your home\ndirectory, and deletes them after they are sent! Be careful.\n\nNote: Restricted bourne shell in use.\n\n");
+ send_msg(user, "$ ");
+ }
+ else
+ {
+ send_msg(user, "login incorrect\n");
+ if(++du->state_data.pokey_login.fails >= 3)
+ child_toggle_rawmode(user, NULL);
+ else
+ {
+ du->state_data.pokey_login.prompt_pass = false;
+ send_msg(user, "\n\n\nUNIX System V, Release 2.2 (pokey)\n\nlogin: ");
+ }
+ }
+ }
+ break;
+ case POKEY_SHELL:
+
+ pokey_unix_command(user, data);
+
+ send_msg(user, "$ ");
+ break;
+ default:
+ send_msg(user, "FIXME");
+ break;
+ }
+}
+
static void type_exec(struct verb_t *verb, char *args, user_t *user)
{
(void) verb;
(void) args;
- struct room_t *room = room_get(user->room);
+ struct room_t *room = nc->room_get(user->room);
if(strcmp(room->data.uniq_id, "computer_room"))
- send_msg(user, "There is nothing here on which you could type.\n");
+ nc->send_msg(user, "There is nothing here on which you could type.\n");
else
{
bool *b = room->userdata;
@@ -597,12 +679,43 @@ static void type_exec(struct verb_t *verb, char *args, user_t *user)
/* computer is not active */
if(!*b)
{
- send_msg(user, "You type on the keyboard, but your characters do not even echo.\n");
+ nc->send_msg(user, "You type on the keyboard, but your characters do not even echo.\n");
return;
}
else
{
- send_msg(user, "FIXME\n");
+ struct userdata_t *data = nc->userdb_lookup(user->user);
+ if(!data->userdata)
+ data->userdata = calloc(1, sizeof(struct dunnet_user));
+
+ struct dunnet_user *du = data->userdata;
+ if(du->console_state != POKEY_LOGIN &&
+ du->console_state != POKEY_SHELL &&
+ du->console_state != POKEY_FTP)
+ {
+ du->console_state = POKEY_LOGIN;
+ du->state_data.pokey_login.prompt_pass = false;
+ du->state_data.pokey_login.fails = 0;
+ send_msg(user, "\n\n\nUNIX System V, Release 2.2 (pokey)\n\nlogin: ");
+ }
+ else
+ {
+ /* print the prompts */
+ switch(du->console_state)
+ {
+ case POKEY_LOGIN:
+ if(du->state_data.pokey_login.prompt_pass)
+ send_msg(user, "password: ");
+ else
+ send_msg(user, "\n\n\nUNIX System V, Release 2.2 (pokey)\n\nlogin: ");
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* all lines typed are now passed directly to us */
+ nc->child_toggle_rawmode(user, console_cb);
}
}
}
@@ -638,5 +751,31 @@ void netcosm_world_simulation_cb(void)
return;
}
+void netcosm_write_userdata_cb(int fd, void *userdata)
+{
+ struct dunnet_user *user = userdata;
+ if(user)
+ {
+ /* we have data */
+ write_bool(fd, true);
+ write_int(fd, user->console_state);
+ }
+ else
+ /* no user data */
+ write_bool(fd, false);
+}
+
+void *netcosm_read_userdata_cb(int fd)
+{
+ if(read_bool(fd))
+ {
+ struct dunnet_user *user = calloc(1, sizeof(*user));
+ user->console_state = read_int(fd);
+ return user;
+ }
+ else
+ return NULL;
+}
+
/* 100 ms */
unsigned netcosm_world_simulation_interval = 100;