From db8e8bebcf2cdf638030bf86fc591c5280b83205 Mon Sep 17 00:00:00 2001 From: Ilya Belyy Date: Mon, 28 Apr 2008 16:19:35 +0900 Subject: [PATCH] Implemented game profiles --- Makefile | 2 +- games.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ games.h | 25 +++++++++++++++ menu.c | 86 ++++++++++++++++++++++++++++++++++++++++++++------ sessions.c | 66 +++++++++++++++++++++++++++++++++------ sessions.h | 6 ++-- users.c | 10 +++++- 7 files changed, 274 insertions(+), 25 deletions(-) create mode 100644 games.c create mode 100644 games.h diff --git a/Makefile b/Makefile index 9f9e349..2c40041 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ OBJDIR = ./obj SERVER = ./server OBJS = $(OBJDIR)/telnet.o $(OBJDIR)/vt100.o \ - $(OBJDIR)/sessions.o $(OBJDIR)/menu.o $(OBJDIR)/users.o \ + $(OBJDIR)/sessions.o $(OBJDIR)/menu.o $(OBJDIR)/users.o $(OBJDIR)/games.o \ $(OBJDIR)/server.o diff --git a/games.c b/games.c new file mode 100644 index 0000000..05fee2d --- /dev/null +++ b/games.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include "games.h" + +#define GAME_FILE "./games" + + +static int parse_game (game_info *g, char *str) +{ + char *s; + if ((s = strstr(str, ":")) == NULL) return 0; + *s = 0; + + // id + strncpy (g->id, str, GAME_ID_LEN); + g->id[GAME_ID_LEN - 1] = 0; + + str = s + 1; + if ((s = strstr(str, ":")) == NULL) return 0; + *s = 0; + + // name + strncpy (g->name, str, GAME_NAME_LEN); + g->name[GAME_NAME_LEN - 1] = 0; + + str = s + 1; + if ((s = strstr(str, ":")) == NULL) return 0; + *s = 0; + + // dir + strncpy (g->dir, str, GAME_DIR_LEN); + g->dir[GAME_DIR_LEN - 1] = 0; + + str = s + 1; + if ((s = strstr(str, "\n")) != NULL) *s = 0; // remove optional \n at the end + + // command + strncpy (g->command, str, GAME_COMMAND_LEN); + g->command[GAME_COMMAND_LEN - 1] = 0; + + return 1; +} + + +#define BUF_SIZE 1 * 1024 + +game_info* load_gamelist (void) +{ + game_info *gamelist = NULL, *lg = NULL; + char buf[BUF_SIZE]; + FILE *f; + + + if ((f = fopen(GAME_FILE, "r")) == NULL) return NULL; + + while (1) + { + game_info *g; + + // end of file + if (fgets(buf, BUF_SIZE, f) == NULL) break; + + // skip comments and empty strings + if (buf[0] == '#' || buf[0] == 0) continue; + + g = (game_info*)malloc(sizeof(game_info)); + if (g == NULL) break; + + if (!parse_game(g, buf)) + { + free (g); + continue; + } + + // add game to the list + g->next = NULL; + if (gamelist == NULL) gamelist = g; + if (lg != NULL) lg->next = g; + g->prev = lg; + lg = g; + } + + fclose (f); + return gamelist; +} + + + +void free_gamelist (game_info *gamelist) +{ + game_info *g = gamelist; + + while (g != NULL) + { + game_info *g2 = g; + + g = g->next; + + free (g2); + } +} + + diff --git a/games.h b/games.h new file mode 100644 index 0000000..3758b5f --- /dev/null +++ b/games.h @@ -0,0 +1,25 @@ +#ifndef __GAMES__ +#define __GAMES__ + +#define GAME_ID_LEN 8 +#define GAME_NAME_LEN 32 +#define GAME_DIR_LEN 32 +#define GAME_COMMAND_LEN 100 + + +typedef struct game_info +{ + char id[GAME_ID_LEN]; + char name[GAME_NAME_LEN]; + char dir[GAME_DIR_LEN]; + char command[GAME_COMMAND_LEN]; + + struct game_info *prev, *next; +} game_info; + + +game_info* load_gamelist (void); +void free_gamelist (game_info *gamelist); + + +#endif diff --git a/menu.c b/menu.c index aa41732..40261a2 100644 --- a/menu.c +++ b/menu.c @@ -7,6 +7,7 @@ #include #include "telnet.h" #include "users.h" +#include "games.h" #include "server.h" @@ -91,7 +92,7 @@ static int register_menu (session_info *sess) int id, r; const char *const prompts[REG_INPUTS] = { - "\r\nUser name (3-16 chars, latin alphabet and digits only): ", + "\r\nUser name (3-16 chars, latin alphabet and digits only, start with a letter): ", "\r\nPassword (4-16 chars, keep in mind that it is insecure connection): ", "\r\nEmail (optional): " }; @@ -210,8 +211,8 @@ static int observe (session_info *sess) static int observer_menu (session_info *sess) { - char header[] = TELNET_CLS "\tUser\t\t\t Idle\t\tTerminal\r\n"; - uint8_t buf[BUF_SIZE]; + char header[] = TELNET_CLS "\tGame\t\t\t\tUser\t\t Idle\t\tTerminal\r\n"; + char buf[BUF_SIZE]; session_info *s; int n, l, count = 0; time_t now; @@ -225,12 +226,18 @@ static int observer_menu (session_info *sess) now = time(NULL); for (s = sessionlist; s != NULL; s = s->next) { - if (s->game_id == -1) continue; - int idle = now - s->last_activity; - int nml = 20 - strlen(s->user_name); - l = sprintf(buf, "%3d\t%s", count + 1, s->user_name); + int idle; + + if (s->game[0] == 0) continue; + + idle = now - s->last_activity; + + l = sprintf(buf, "%3d\t%s", count + 1, s->game); + for (; l < 4 * 8; l++) buf[l] = ' '; + + l += sprintf(&buf[l], "\t%s", s->user_name); + for (; l < 6 * 8; l++) buf[l] = ' '; - l += nml; l += sprintf(&buf[l], "\t%3dm %02ds\t%dx%d\r\n", idle / 60, idle % 60, s->term_wid, s->term_hgt); if (send(sess->socket, buf, l, 0) == -1) return -1; count++; @@ -263,6 +270,63 @@ static int observer_menu (session_info *sess) +static int play_menu (session_info *sess) +{ + const char msg[] = TELNET_CLS "Select a game to play by entering its id\r\n"; + game_info *gamelist, *g; + char buf[BUF_SIZE]; + int n; + char inp[20]; + + + gamelist = load_gamelist(); + //if (gamelist == NULL) return -1; + + if (send(sess->socket, msg, sizeof(msg), 0) == -1) + { + free_gamelist (gamelist); + return -1; + } + + g = gamelist; + while (g != NULL) + { + int l = sprintf(buf, "%8s: %s\r\n", g->id, g->name); + + if (send(sess->socket, buf, l, 0) == -1) + { + free_gamelist (gamelist); + return -1; + } + + g = g->next; + } + + + // get id + n = recv_input(sess, inp, 20); + if (n == -1) return -1; + + // find and run game with such id + g = gamelist; + while (g != NULL) + { + if (strcmp(inp, g->id) == 0) + { + run_game (sess, g); + free_gamelist (gamelist); + return 1; + } + + g = g->next; + } + + free_gamelist (gamelist); + return 0; +} + + + static int print_main_menu (session_info *sess) { char msg[BUF_SIZE]; @@ -292,6 +356,7 @@ static int print_main_menu (session_info *sess) } + int main_menu (session_info *sess) { if (print_main_menu(sess) == -1) return -1; @@ -307,8 +372,9 @@ int main_menu (session_info *sess) { if (buf[0] == 'p' && sess->user_id >= 0) { - run_game (sess); - return 1; + int p = play_menu(sess); + if (p == -1 || p == 1) return p; + if (print_main_menu(sess) == -1) return -1; } if (buf[0] == 'l' && sess->user_id < 0) diff --git a/sessions.c b/sessions.c index f17db9c..d7f32ac 100644 --- a/sessions.c +++ b/sessions.c @@ -34,7 +34,7 @@ session_info* add_session (int sock) ps->socket = sock; ps->user_id = -1; ps->user_name[0] = 0; - ps->game_id = -1; + ps->game[0] = 0; ps->term = NULL; ps->term_wid = 80; ps->term_hgt = 24; @@ -136,7 +136,6 @@ void stop_observing (session_info *sess) -#include int add_observer (int n, int sock) { session_info *s; @@ -146,7 +145,7 @@ int add_observer (int n, int sock) for (s = sessionlist; s != NULL; s = s->next) { - if (s->game_id == -1) continue; + if (s->game[0] == 0) continue; if (i++ != n) continue; pthread_mutex_lock (&s->mutex); @@ -289,10 +288,58 @@ static void play_game (session_info *sess) -#define CMD "./fdepths" -//#define CMD "./defender.py" -//#define CMD "sh" -void run_game (session_info *sess) +#define MAX_ARGS 32 +static void exec_game (session_info *sess, const game_info *game) +{ + const char user_str[] = "$USER$"; + char buf[BUF_SIZE]; // assume BUF_SIZE > GAME_COMMAND_LEN + USER_NAME_LEN + char *arg[MAX_ARGS]; + int i, b, a = 0; + + + // change to the specified directory + if (game->dir[0]) chdir (game->dir); + + // copy command line to bufer, substituting user name + for (i = b = 0; game->command[i] != 0; i++, b++) + { + if (strncmp(&game->command[i], user_str, sizeof(user_str) - 1) == 0) + { + const char *u = sess->user_name; + while ((buf[b++] = *(u++))); + i += sizeof(user_str) - 1 - 1; + b -= 2; + } + else + { + buf[b] = game->command[i]; + } + } + buf[b] = 0; + + // break buf[] into zero-terminated strings, filling arg[] with pointers to them + // TODO: add quotes or \ to escape spaces + arg[a++] = &buf[0]; + for (b = 0; buf[b] != 0; b++) + { + if (buf[b] == ' ') + { + buf[b] = 0; + if (buf[b + 1] != 0 && a < MAX_ARGS - 1) + { + arg[a++] = &buf[b + 1]; + } + } + } + + arg[a] = NULL; + + execvp (arg[0], arg); +} + + + +void run_game (session_info *sess, const game_info *game) { int pty_master, pty_slave; int pid; @@ -327,8 +374,7 @@ void run_game (session_info *sess) close (pty_slave); close (pty_master); -//execlp ("angband", "angband", "-mgcu", NULL); - execlp (CMD, CMD, NULL); + exec_game (sess, game); // exec should never return perror ("child failed"); @@ -342,7 +388,7 @@ void run_game (session_info *sess) sess->pty_master = pty_master; sess->child_pid = pid; - sess->game_id = 1; //XXX + strcpy (sess->game, game->name); play_game (sess); diff --git a/sessions.h b/sessions.h index 72f6d35..c235260 100644 --- a/sessions.h +++ b/sessions.h @@ -3,8 +3,8 @@ #include #include - #include "users.h" +#include "games.h" struct vt100; @@ -14,7 +14,7 @@ typedef struct session_info int socket; int user_id; // or -1 char user_name[USER_NAME_LEN]; - int game_id; // -1 for observer + char game[GAME_NAME_LEN]; time_t last_activity; // to display idle time int term_wid, term_hgt; // terminal size @@ -38,7 +38,7 @@ void remove_session (session_info *sess); int add_observer (int n, int sock); void stop_observing (session_info *sess); -void run_game (session_info *sess); +void run_game (session_info *sess, const game_info *game); void close_sessions (void); void release_sessions (void); diff --git a/users.c b/users.c index 9948955..7a5dc31 100644 --- a/users.c +++ b/users.c @@ -12,7 +12,10 @@ static int check_user_name (const char *name) { int i; - for (i = 0; name[i] != 0; i++) + + if (!isalpha(name[i])) return 0; + + for (i = 1; name[i] != 0; i++) { if (!isalnum(name[i])) return 0; } @@ -81,13 +84,18 @@ static int find_user (const char *name, user *usr, FILE *f, int *max_id) // end of file if (fgets(buf, BUF_SZ, f) == NULL) break; + // skip comments and empty lines + if (buf[0] == '#' || buf[0] == 0) continue; + if (!parse_user(usr, buf)) { continue; } + // logins are case-insensitive if (strcasecmp(name, usr->name) == 0) return usr->id; + // update max id if (usr->id > m) m = usr->id; } -- 2.11.4.GIT