diff --git a/README.md b/README.md index 1676442..988bcd8 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ This is the working structure of the 9p filesystem: * `/slot`: After loading the cartridge, its ROM is read from here; Read-only. -* `/data/`: Any supporting data that comes with the cartridge will be found here; They are in three parts: `sprite`, `audio`, and `text`. Because `uxn` is limited to 64-128kb input files, the filesizes of these data blobs should be 64kb max, and the `chunk` command should be used to page different files into the service when needed. The files on the server should be like `TYPE_dataN` where `TYPE` is one of `sprite`, `audio`, and `text`, and `N` is a nonnegative integer. `data0` is the default loaded if no specific chunk has been requested. Inputting a command `chunk sprite 2` will make `sprite_data2` available under `data/sprite`, and so on. +* `/data/`: Any supporting data that comes with the cartridge will be found here; They are in three parts: `sprite`, `audio`, and `text`. Because `uxn` is limited to 64-128kb input files, the filesizes of these data blobs should be 64kb max, and the `chunk` command should be used to page different files into the service when needed. The files on the server should be like `TYPEN` where `TYPE` is one of `sprite`, `audio`, and `text`, and `N` is any sequence of characters (canonically a nonnegative integer). When first loading the cartridge, `N == 0`. Issuing the command `chunk TYPE XXX` will attempt to load data from file `carts/CART_NAME/data/TYPEXXX` into the correct data file. If `TYPE` is not one of `sprite`, `audio`, or `text`, or the ifle `TYPEXXX` doesn't exist in the data directory, the `chunk` command does nothing. * `/realms`: Open/saved realms, read-only. Realms and their associated universe are backed by real files on the server so that they can be preserved across service instantiations, in a directory structure like: `carts/CART_NAME/realms/REALM_NAME/{realm, universe}`. Realms can either be solo, open, or protected; Open or protected realms can have limited member numbers. Depending on the cartridge, these settings can be user-managed or managed by the cartridge itself. Realms are listed per line upon reading the file like: `REALM_NAME 1 4 1`. First would obviously be the name of the realm. The first number is number of members, second is member limit, third is 1 if protected, 0 if not. `0 1 1` represents a protected solo realm that is empty (saved game with password). `0 1 0` represents an unprotected solo realm that is empty (saved game with no password). diff --git a/cart.c b/cart.c index ba4081c..df808fa 100644 --- a/cart.c +++ b/cart.c @@ -24,13 +24,13 @@ Cart* create_cart(char* name) { cart->rom = cart_data; scpy(path, file, 64); - scat(file, "/data/sprites"); + scat(file, "/data/sprites0"); cart->sprite_data = read_bytes(file); scpy(path, file, 64); - scat(file, "/data/text"); + scat(file, "/data/text0"); cart->txt_data = read_bytes(file); scpy(path, file, 64); - scat(file, "/data/audio"); + scat(file, "/data/audio0"); cart->audio_data = read_bytes(file); return cart; @@ -49,6 +49,44 @@ Cart* find_cart(UserInfo* table, char* name) { return nil; } +int get_chunk(UserInfo* table, char* uname, char* chunk) { + UserInfo* u = find_user(table, uname); + char type[8] = {0}; + char chunk_id[64] = {0}; + char* c = chunk; + char* data; + + if (u == nil || u->cart == nil) + return 0; + + while (*c && *c != ' ') { + ccat(type, *c++); + } + if (*c == ' ') + c++; + + scat(chunk_id, "carts/"); + scat(chunk_id, u->cart->name); + ccat(chunk_id, '/'); + scat(chunk_id, type); + scat(chunk_id, c); + + data = read_bytes(chunk_id); + if (data == nil) { + return 0; + } + + if (scmp(type, "sprite")) { + u->cart->sprite_data = data; + } else if (scmp(type, "audio")) { + u->cart->audio_data = data; + } else { + u->cart->txt_data = data; + } + + return 1; +} + uint count_carts(UserInfo* table, char* name) { UserInfo* u = table; uint i, j; diff --git a/cart.h b/cart.h index e07c6b0..d305ad3 100644 --- a/cart.h +++ b/cart.h @@ -11,5 +11,6 @@ typedef struct Cart { Cart* create_cart(char* name); Cart* find_cart(UserInfo* table, char* name); +int get_chunk(UserInfo* table, char* uname, char* chunk); uint count_carts(UserInfo* table, char* name); void destroy_cart(Cart* self); \ No newline at end of file diff --git a/realm.c b/realm.c index 296d8d6..fddb4ef 100644 --- a/realm.c +++ b/realm.c @@ -69,7 +69,12 @@ Realm* parse_realm(char* cart, char* name) { if (f != nil) { if (fgets(buf, 256, f)) { self = malloc(sizeof(Realm)); - sscanf(buf, "%hu %32s %llu", &(self->max), self->master, &(self->password)); + sscanf( + buf, + "%hu %32s %llu", + &(self->max), + self->master, + &(self->password)); fclose(f); } else { return nil; diff --git a/user.c b/user.c index 47dfa7a..c636b19 100644 --- a/user.c +++ b/user.c @@ -19,24 +19,74 @@ UserInfo* find_user(UserInfo* table, char* uname) { return nil; } -int load_cart(UserInfo* table, char* uname, char* cart_name) { - Cart* c = find_cart(table, cart_name); +int login(UserInfo* table, char* uname, char* password) { UserInfo* u = find_user(table, uname); if (u == nil) return 0; - if (c != nil) { - u->cart = c; + u->password = hash(password, 0); + return 1; +} + +int logout(UserInfo* table, char* uname) { + UserInfo* u = table; + + if (u == nil) + return 0; + + *(u->name) = 0; + u->password = 0; + + if (u->scope != nil) { + free(u->scope); + u->scope = nil; + } + + u->random = 0; + + if (u->realm != nil) + leave_realm(table, uname); + + if (u->cart != nil) + unload_cart(table, uname); + + return 1; +} + +int protect_realm(UserInfo* table, char* uname, char* password) { + UserInfo* u = find_user(table, uname); + + if (u != nil && u->realm != nil && scmp(uname, u->realm->master)) { + u->realm->password = hash(password, 0); return 1; + } + return 0; +} + +int transfer_realm(UserInfo* table, char* from, char* to) { + UserInfo* old_user = find_user(table, from); + UserInfo* new_user = find_user(table, to); + + if (old_user == nil || new_user == nil || old_user->realm == nil) + return 0; + + scpy(to, old_user->realm->master, 32); + return 1; +} + +int load_cart(UserInfo* table, char* uname, char* cart_name) { + UserInfo* u = find_user(table, uname); + + if (u == nil) + return 0; + + u->cart = create_cart(cart_name); + if (u->cart == nil) { + fprintf(stderr, "failed creating cart\n"); + return 0; } else { - u->cart = create_cart(cart_name); - if (u->cart == nil) { - fprintf(stderr, "failed creating cart\n"); - return 0; - } else { - return 1; - } + return 1; } } @@ -105,17 +155,11 @@ int leave_realm(UserInfo* table, char* uname) { int unload_cart(UserInfo* table, char* uname) { UserInfo* u = find_user(table, uname); - Cart* c; - if (u == nil) - return 0; - - c = u->cart; - if (c == nil) + if (u == nil || u->cart == nil) return 0; + destroy_cart(u->cart); u->cart = nil; - if (find_cart(table, c->name) == nil) - destroy_cart(c); return 1; } \ No newline at end of file diff --git a/user.h b/user.h index 19fdde2..71ac1cb 100644 --- a/user.h +++ b/user.h @@ -10,6 +10,10 @@ typedef struct UserInfo { } UserInfo; UserInfo* find_user(UserInfo* table, char* uname); +int login(UserInfo* table, char* uname, char* password); +int logout(UserInfo* table, char* uname); +int protect_realm(UserInfo* table, char* uname, char* password); +int transfer_realm(UserInfo* table, char* from, char* to); int load_cart(UserInfo* table, char* uname, char* cart_name); int enter_realm(UserInfo* table, char* uname, char* realm_name); int leave_realm(UserInfo* table, char* uname); diff --git a/xrxs.c b/xrxs.c index e9a09aa..c7dd77c 100644 --- a/xrxs.c +++ b/xrxs.c @@ -32,15 +32,10 @@ void xrxs_attach(Req* r) { * or the attach will never complete. We have logout() for now... */ int i = 0; - int l = 0; int vacancy = 0; char* usr; char* username = r->ifcall.uname; - usr = username; - while (*usr) { - l++; - usr++; - } + for (i = 0; i < 64; i++) { usr = users_table[i].name; if (scmp(usr, username)) { @@ -48,7 +43,7 @@ void xrxs_attach(Req* r) { return; } if (*usr == 0) { - scpy(username, usr, l + 1); + scpy(username, usr, 32); vacancy = 1; break; } @@ -60,47 +55,6 @@ void xrxs_attach(Req* r) { } } -void login(char* uname, char* password) { - int i; - for (i = 0; i < 64; i++) { - if (scmp(uname, users_table[i].name)) { - users_table[i].password = hash(password, 0); - } - } -} - -int logout(char* uname) { - int i; - UserInfo* u = users_table; - - for (i = 0; i < 64; i++) { - if (scmp(uname, u->name)) { - *(u->name) = 0; - u->password = 0; - if (u->scope != nil) { - free(u->scope); - u->scope = nil; - } - u->random = 0; - if (u->realm != nil) - leave_realm(users_table, uname); - if (u->cart != nil) - unload_cart(users_table, uname); - return 1; - } - u++; - } - return 0; -} - -void protect(char* uname, char* password) { - UserInfo* u = find_user(users_table, uname); - - if (u != nil && u->realm != nil && scmp(uname, u->realm->master)) { - u->realm->password = hash(password, 0); - } -} - void write_ctl(Req* r) { char cmd[16] = {0}; char* c = r->ifcall.data; @@ -117,22 +71,23 @@ void write_ctl(Req* r) { uvlong const cmd_hashv = hash(cmd, 0); switch (cmd_hashv) { case LOGIN: - login(r->fid->uid, c); + login(users_table, r->fid->uid, c); break; case LOAD: load_cart(users_table, r->fid->uid, c); break; case CHUNK: - // get_chunk(users_table, r->fid->uid, c); + get_chunk(users_table, r->fid->uid, c); break; case CREATE: create_realm(users_table, r->fid->uid, c); break; case PROTECT: - protect(r->fid->uid, c); + protect_realm(users_table, r->fid->uid, c); break; case TRANSFER: - // transfer(r->fid->uid, c); + transfer_realm(users_table, r->fid->uid, c); + break; case ENTER: enter_realm(users_table, r->fid->uid, c); break; @@ -140,7 +95,7 @@ void write_ctl(Req* r) { leave_realm(users_table, r->fid->uid); break; case LOGOUT: - logout(r->fid->uid); + logout(users_table, r->fid->uid); break; case SAVE: // save(r->fid->uid); @@ -242,7 +197,7 @@ String** list_dir(char* path) { while ((ent = readdir(dir)) != NULL) { if (i = size) { size *= 2; - self = reallloc(self, size * sizeof(String*)); + self = realloc(self, size * sizeof(String*)); } c = ent->d_name; if (scmp(c, ".") || scmp(c, "..")) { @@ -272,19 +227,12 @@ void s_freemany(String** ss) { free(ss); } -String* s_putmanyc(String* s, char* c) { - String* tmp = s_copy(c); - s_append(s, tmp); - s_free(tmp); - return s; -} - void read_carts(Req* r) { String** carts = list_dir(CARTSPATH); String** c = carts; - string* data = s_new(); + String* data = s_new(); while (*c != nil) { - s_append(data, *c); + s_append(data, (*c)->base); s_putc(data, '\n'); c++; } @@ -352,7 +300,7 @@ void read_realms(Req* r) { rr = realms; while (*rr != nil) { - s_append(data, *rr); + s_append(data, (*rr)->base); s_putc(data, ' '); realm = parse_realm(user->cart->name, (*rr)->base); @@ -366,13 +314,13 @@ void read_realms(Req* r) { u++; } itoa(u, ubuf, 10); - s_putmanyc(data, ubuf); + s_append(data, ubuf); s_putc(data, ' '); itoa(m, mbuf, 10); - s_putmanyc(data, mbuf); + s_append(data, mbuf); s_putc(data, ' '); itoa(p, pbuf, 10); - s_putmanyc(data, pbuf); + s_append(data, pbuf); s_putc(data, '\n'); rr++; } @@ -390,19 +338,19 @@ void read_universe(Req* r) { Universe* universe; Atom* a; int i; - + if (u == nil || u->realm == nil) { respond(r, nil); return; } - + universe = u->realm->universe; for (i = 0; i < 256; i++) { - a = universe[i]; + a = universe->atoms[i]; while (a != nil) { - s_putmanyc(data, a->name); - s_putmanyc(data, " = "); - s_putmanyc(data, a->value); + s_append(data, a->name); + s_append(data, " = "); + s_append(data, a->value); s_putc(data, '\n'); a = a->next; }