Renamed directory src to wmud

Signed-off-by: Gergely Polonkai (W00d5t0ck) <polesz@w00d5t0ck.info>
This commit is contained in:
Gergely Polonkai (W00d5t0ck)
2012-03-27 17:14:55 +02:00
parent 188ce00473
commit ae8ab4542e
23 changed files with 2 additions and 2 deletions

3
wmud/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.deps
*.o
wmud

5
wmud/Makefile.am Normal file
View File

@@ -0,0 +1,5 @@
bin_PROGRAMS = wmud
AM_CPPFLAGS = -DWMUD_STATEDIR=\""$(localstatedir)"\" -DWMUD_CONFDIR=\""$(sysconfdir)"\" $(MEMCACHED_CFLAGS) $(GLIB_CFLAGS) $(GIO_CFLAGS) $(GTHREAD_CFLAGS) $(SQLITE3_CFLAGS)
wmud_SOURCES = main.c game-networking.c interpreter.c db.c players.c maintenance.c game.c configuration.c world.c
wmud_LDADD = $(MEMCACHED_LIBS) $(GLIB_LIBS) $(GIO_LIBS) $(GTHREAD_LIBS) $(SQLITE3_LIBS)

169
wmud/configuration.c Normal file
View File

@@ -0,0 +1,169 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* configuration.c: configuration file related functions
*
* 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 2 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib.h>
#include "wmud-types.h"
#include "configuration.h"
/**
* SECTION:configuration
* @short_description: Configuration file handling functions
* @title: Configuration file handling functions
*
*/
/**
* WMUD_CONFIG_ERROR:
*
* the GQuark for the config error GError
*/
GQuark WMUD_CONFIG_ERROR = 0;
/**
* active_config:
*
* the currently active configuration directives
*/
ConfigData *active_config = NULL;
/**
* wmud_configdata_free:
* @config_data: pointer to the ConfigData struct to free
*
* Correctly free a ConfigData struct with all its members
*/
void
wmud_configdata_free(ConfigData **config_data)
{
if ((*config_data)->admin_email)
g_free((*config_data)->admin_email);
if ((*config_data)->database_file)
g_free((*config_data)->database_file);
g_free(*config_data);
*config_data = NULL;
}
/**
* wmud_config_init:
* @config_data: a pointer to a ConfigData struct. This will be filled with the
* configuration file's data
* @err: The GError in which the config handling status should be returned
*
* Parses the default configuration file, and sets different variables
* according to it.
*
* Return value: %TRUE if parsing was successful. %FALSE otherwise.
*/
gboolean
wmud_config_init(ConfigData **config_data, GError **err)
{
GString *config_file = g_string_new(WMUD_CONFDIR);
GKeyFile *config;
GError *in_err = NULL;
if (!config_data)
return FALSE;
if (*config_data)
{
g_clear_error(err);
g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_REUSE, "Configuration pointer reuse. Please file a bug report!");
return FALSE;
}
*config_data = g_new0(ConfigData, 1);
g_string_append(config_file, "/wmud.conf");
config = g_key_file_new();
/* TODO: Error checking */
g_key_file_load_from_file(config, config_file->str, 0, &in_err);
if (!g_key_file_has_group(config, "global"))
{
g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOGLOBAL, "Config file (%s) does not contain a [global] group", config_file->str);
g_key_file_free(config);
g_string_free(config_file, TRUE);
return FALSE;
}
g_clear_error(&in_err);
(*config_data)->port = g_key_file_get_integer(config, "global", "port", &in_err);
if (in_err)
{
if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
{
(*config_data)->port = DEFAULT_PORT;
}
else if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE))
{
g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_BADPORT, "Config file (%s) contains an invalid port number", config_file->str);
g_key_file_free(config);
g_string_free(config_file, TRUE);
(*config_data)->port = 0;
return FALSE;
}
return FALSE;
}
g_clear_error(&in_err);
(*config_data)->database_file = g_key_file_get_string(config, "global", "world file", &in_err);
if (in_err)
{
if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
{
g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOWORLD, "Config file (%s) does not contain a world file path", config_file->str);
g_key_file_free(config);
g_string_free(config_file, TRUE);
wmud_configdata_free(config_data);
return FALSE;
}
}
g_clear_error(&in_err);
(*config_data)->admin_email = g_key_file_get_string(config, "global", "admin email", &in_err);
if (in_err)
{
if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
{
g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOEMAIL, "Config file (%s) does not contain an admin e-mail address", config_file->str);
g_key_file_free(config);
g_string_free(config_file, TRUE);
wmud_configdata_free(config_data);
return FALSE;
}
}
g_key_file_free(config);
g_string_free(config_file, TRUE);
return TRUE;
}

48
wmud/configuration.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef __WMUD_CONFIGURATION_H__
#define __WMUD_CONFIGURATION_H__
#include <glib.h>
extern GQuark WMUD_CONFIG_ERROR;
/**
* wmudConfigError:
* @WMUD_CONFIG_ERROR_NOGLOBAL: Indicates that the config file read doesn't
* contain a [global] section
* @WMUD_CONFIG_ERROR_BADPORT: Indicates that the config file contains and
* invalid port number
* @WMUD_CONFIG_ERROR_NOWORLD: Indicates that the config file doesn't contain a
* world database file
* @WMUD_CONFIG_ERROR_NOEMAIL: Indicates that the config file doesn't contain
* an administrator e-mail address
* @WMUD_CONFIG_ERROR_REUSE: configuration data is reused (non-NULL)
*
* Error codes returned by configuration file parsing functions.
*/
typedef enum {
WMUD_CONFIG_ERROR_NOGLOBAL,
WMUD_CONFIG_ERROR_BADPORT,
WMUD_CONFIG_ERROR_NOWORLD,
WMUD_CONFIG_ERROR_NOEMAIL,
WMUD_CONFIG_ERROR_REUSE
} wmudConfigError;
/**
* ConfigData:
* @port: the port number of the game interface to listen on
* @database_file: the database file of the world associated with this
* configuration
* @admin_email: the world administrator's e-mail address
*/
typedef struct _ConfigData {
guint port;
gchar *database_file;
gchar *admin_email;
} ConfigData;
extern ConfigData *active_config;
gboolean wmud_config_init(ConfigData **config_data, GError **err);
#endif /* __WMUD_CONFIGURATION_H__ */

216
wmud/db.c Normal file
View File

@@ -0,0 +1,216 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* db.c: database handling routines
*
* 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 2 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 <glib.h>
#include <sqlite3.h>
#include "main.h"
#include "db.h"
#include "players.h"
#include "configuration.h"
/**
* SECTION:db
* @short_description: Database handling
* @title: Database handling routines
*
*/
/**
* WMUD_DB_ERROR:
*
* the GQuark for the database error GError
*/
GQuark WMUD_DB_ERROR = 0;
static sqlite3 *dbh = NULL;
/**
* wmud_db_init:
* @err: a GError to put error messages in it
*
* Initializes the wMUD database system. Checks and opens database files.
*/
gboolean
wmud_db_init(GError **err)
{
GString *db_file = g_string_new(WMUD_STATEDIR);
int sqlite_code;
g_string_append_printf(db_file, "/%s", active_config->database_file);
if ((sqlite_code = sqlite3_open(db_file->str, &dbh)) != SQLITE_OK)
{
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_CANTOPEN, "Can not open databsae file (%s): %s", db_file->str, sqlite3_errmsg(dbh));
return FALSE;
}
return TRUE;
}
/**
* wmud_db_players_load:
* @err: a GError to put error messages in it
*
* Loads all player records from the database
*/
gboolean
wmud_db_players_load(GError **err)
{
sqlite3_stmt *sth = NULL;
int sqlite_code;
if (dbh == NULL)
{
if (err)
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_NOINIT, "Database backend not initialized");
return FALSE;
}
if ((sqlite_code = sqlite3_prepare_v2(dbh, "SELECT id, login, password, email FROM players", -1, &sth, NULL)) != SQLITE_OK)
{
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_BADQUERY, "Bad query in wmud_db_players_load(): %s", sqlite3_errmsg(dbh));
return FALSE;
}
while (1)
{
sqlite_code = sqlite3_step(sth);
if (sqlite_code == SQLITE_ROW)
{
wmudPlayer *player = g_new0(wmudPlayer, 1);
player->id = sqlite3_column_int(sth, 0);
player->player_name = g_strdup((gchar *)sqlite3_column_text(sth, 1));
player->cpassword = g_strdup((gchar *)sqlite3_column_text(sth, 2));
player->email = g_strdup((gchar *)sqlite3_column_text(sth, 3));
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Loaded player _%s_", player->player_name);
players = g_slist_prepend(players, player);
}
else if (sqlite_code == SQLITE_DONE)
{
break;
}
else
{
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_BADQUERY, "Query error in wmud_db_players_load(): %s", sqlite3_errmsg(dbh));
return FALSE;
}
}
sqlite3_finalize(sth);
return FALSE;
}
/**
* wmud_db_save_player:
* @player: the player record to save
* @err: a GError to put error messages in it
*
* Saves a player record to the database backend.
*
* Return value: %TRUE on success. Upon failure, %FALSE is returned, and err is
* set accordingly.
*/
gboolean
wmud_db_save_player(wmudPlayer *player, GError **err)
{
sqlite3_stmt *sth = NULL;
int sqlite_code;
if (dbh == NULL)
{
if (err)
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_NOINIT, "Database backend not initialized");
return FALSE;
}
if ((sqlite_code = sqlite3_prepare_v2(dbh, "INSERT INTO players (id, login, password, email) VALUES (NULL, ?, NULL, ?)", -1, &sth, NULL)) != SQLITE_OK)
{
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_BADQUERY, "Bad query in wmud_db_player_save(): %s", sqlite3_errmsg(dbh));
return FALSE;
}
if ((sqlite_code = sqlite3_bind_text(sth, 1, player->player_name, -1, SQLITE_STATIC)) != SQLITE_OK)
{
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_BADQUERY, "Bad parameter in wmud_db_player_save(): %s", sqlite3_errmsg(dbh));
return FALSE;
}
if ((sqlite_code = sqlite3_bind_text(sth, 2, player->email, -1, SQLITE_STATIC)) != SQLITE_OK)
{
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_BADQUERY, "Bad parameter in wmud_db_player_save(): %s", sqlite3_errmsg(dbh));
return FALSE;
}
if ((sqlite_code = sqlite3_step(sth)) != SQLITE_DONE)
{
g_set_error(err, WMUD_DB_ERROR, WMUD_DB_ERROR_BADQUERY, "Statement cannot be executed in wmud_db_player_save(): %s", sqlite3_errmsg(dbh));
return FALSE;
}
g_clear_error(err);
return TRUE;
}
gboolean
wmud_db_load_planes(GSList **planes, GError **err)
{
return FALSE;
}
gboolean
wmud_db_load_planets(GSList **planets, GError **err)
{
return FALSE;
}
gboolean
wmud_db_load_directions(GSList **directions, GError **err)
{
return FALSE;
}
gboolean
wmud_db_load_areas(GSList **areas, GError **err)
{
return FALSE;
}
gboolean
wmud_db_load_rooms(GSList **rooms, GError **err)
{
return FALSE;
}
gboolean
wmud_db_load_exits(GSList **exits, GError **err)
{
return FALSE;
}

39
wmud/db.h Normal file
View File

@@ -0,0 +1,39 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* db.h: database handling routine prototypes
*
* 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 2 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/>.
*/
#ifndef __WMUD_DB_H__
#define __WMUD_DB_H__
#include <glib.h>
#include "wmud-types.h"
extern GQuark WMUD_DB_ERROR;
gboolean wmud_db_init(GError **err);
gboolean wmud_db_players_load(GError **err);
gboolean wmud_db_save_player(wmudPlayer *player, GError **err);
gboolean wmud_db_load_planes(GSList **planes, GError **err);
gboolean wmud_db_load_planets(GSList **planets, GError **err);
gboolean wmud_db_load_directions(GSList **directions, GError **err);
gboolean wmud_db_load_areas(GSList **areas, GError **err);
gboolean wmud_db_load_rooms(GSList **rooms, GError **err);
gboolean wmud_db_load_exits(GSList **exits, GError **err);
#endif /* __WMUD__DB_H__ */

518
wmud/game-networking.c Normal file
View File

@@ -0,0 +1,518 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* game-networking.c: basic networking functions
*
* 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 2 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 <glib.h>
#include <gio/gio.h>
#include <string.h>
#include <stdarg.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "main.h"
#include "game-networking.h"
#include "interpreter.h"
#include "players.h"
#include "db.h"
#include "configuration.h"
/**
* SECTION:game-networking
* @short_description: Game related networking code
*
* Functions to handle game connections
*/
struct AcceptData {
GMainContext *context;
GSocketListener *listener;
};
GSList *clients;
void wmud_client_interpret_newplayer_email(wmudClient *client);
void wmud_client_interpret_newplayer_mailconfirm(wmudClient *client);
/**
* wmud_client_close:
* @client: the client whose connection should be dropped
* @send_goodbye: if set to %TRUE, we will send a nice good-bye message to the
* client before dropping the connection
*
* Closes a client connection. If send_goodbye is set to %TRUE, a good-bye
* message will be sent to the client.
*/
void
wmud_client_close(wmudClient *client, gboolean send_goodbye)
{
if (send_goodbye)
wmud_client_send(client, "\r\nHave a nice real-world day!\r\n\r\n");
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Connection closed.");
g_socket_close(client->socket, NULL);
clients = g_slist_remove(clients, client);
wmud_player_free(&(client->player));
if (client->buffer)
g_string_free(client->buffer, TRUE);
g_source_destroy(client->socket_source);
g_free(client);
}
/**
* wmud_client_callback:
* @client: the socket of the client on which the data arrived
* @condition: the condition available on the client socket
* @client: the wmudClient structure of the client
*
* Processes incoming client data, and client hangup
*/
static gboolean
wmud_client_callback(GSocket *client_socket, GIOCondition condition, wmudClient *client)
{
GError *err = NULL;
/* TODO: Error checking */
GRegex *email_regex = g_regex_new("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$", G_REGEX_CASELESS, 0, NULL);
if (condition & G_IO_HUP)
{
wmud_client_close(client, FALSE);
return FALSE;
}
else if ((condition & G_IO_IN) || (condition & G_IO_PRI))
{
gssize len;
gchar *buf2;
gchar *buf = g_malloc0(sizeof(gchar) * (MAX_RECV_LEN + 1));
/* TODO: Error checking */
if ((len = g_socket_receive(client_socket, buf, MAX_RECV_LEN, NULL, &err)) == 0)
{
g_free(buf);
wmud_client_close(client, FALSE);
return FALSE;
}
buf2 = buf;
while (TRUE)
{
char *r = strchr((char *)buf2, '\r'),
*n = strchr((char *)buf2, '\n');
if (r || n)
{
gint i,
sloc = -1;
if ((r < n) && r)
{
if (client->buffer->len > 0)
g_string_append_len(client->buffer, buf2, (r - buf2));
else
g_string_overwrite_len(client->buffer, 0, buf2, (r - buf2));
buf2 = r;
}
else if (n)
{
if (client->buffer->len > 0)
g_string_append_len(client->buffer, buf2, (n - buf2));
else
g_string_overwrite_len(client->buffer, 0, buf2, (n - buf2));
buf2 = n;
}
/* Remove telnet codes from the string */
for (i = 0; i < client->buffer->len; i++)
{
guchar c = (client->buffer->str)[i];
if ((c >= 240) || (c == 1))
{
if (sloc == -1)
sloc = i;
}
else
{
if (sloc != -1)
{
g_string_erase(client->buffer, sloc, i - sloc);
sloc = -1;
}
}
}
if (sloc != -1)
{
g_string_erase(client->buffer, sloc, -1);
}
switch (client->state)
{
case WMUD_CLIENT_STATE_FRESH:
if (*(client->buffer->str))
{
wmudPlayer *player;
if ((player = wmud_player_exists(client->buffer->str)) != NULL)
{
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Trying to login with playername '%s'\n", client->buffer->str);
if (player->cpassword == NULL)
{
wmud_client_send(client, "Your registration is not finished yet.\r\n");
wmud_client_close(client, TRUE);
}
else
{
client->state = WMUD_CLIENT_STATE_PASSWAIT;
client->player = player;
wmud_client_send(client, "Please provide us your password: %c%c%c", TELNET_IAC, TELNET_WILL, TELNET_ECHO);
}
}
else
{
client->player = g_new0(wmudPlayer, 1);
client->player->player_name = g_strdup(client->buffer->str);
client->state = WMUD_CLIENT_STATE_NEWCHAR;
wmud_client_send(client, "Is %s new to this game? [Y/N] ", client->buffer->str);
}
}
break;
case WMUD_CLIENT_STATE_PASSWAIT:
if (*(client->buffer->str))
{
if (wmud_player_auth(client))
{
wmud_client_send(client, "%c%c%c\r\nLogin"
" successful.\r\n", TELNET_IAC,
TELNET_WONT, TELNET_ECHO);
client->authenticated = TRUE;
/* TODO: Send fail count if non-zero */
client->state = WMUD_CLIENT_STATE_MENU;
/* TODO: send MOTD */
/* TODO: send menu items */
/* TODO: send menu prologue */
}
else
{
wmud_client_send(client, "%c%c%cThis"
" password doesn't seem to be valid."
" Let's try it again...\r\nBy what"
" name would you like to be called? ",
TELNET_IAC, TELNET_WONT, TELNET_ECHO);
client->state = WMUD_CLIENT_STATE_FRESH;
client->login_try_count++;
if (client->login_try_count == 3)
{
wmud_client_send(client, "You are"
" trying these bad passwords for"
" too many times. Please stop"
" that!\r\n");
wmud_client_close(client, TRUE);
/* TODO: Increase IP fail count, and ban IP if it's too high */
}
/* TODO: Increase and save login fail count */
client->player = NULL;
}
}
else
{
wmud_client_send(client, "\r\nEmpty passwords are"
" not valid.\r\nTry again: ");
}
break;
case WMUD_CLIENT_STATE_MENU:
//wmud_client_interpret_menu_command(client);
break;
case WMUD_CLIENT_STATE_INGAME:
wmud_interpret_game_command(client);
break;
case WMUD_CLIENT_STATE_QUITWAIT:
//wmud_interpret_quit_answer(client);
break;
case WMUD_CLIENT_STATE_NEWCHAR:
if (g_ascii_strcasecmp(client->buffer->str, "n") == 0)
{
wmud_client_send(client, "What is your player-name, then? ");
client->state = WMUD_CLIENT_STATE_FRESH;
}
else if (g_ascii_strcasecmp(client->buffer->str, "y") == 0)
{
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Creating new player\n");
wmud_client_send(client, "Welcome to this MUD!\r\nPlease enter your e-mail address: ");
client->state = WMUD_CLIENT_STATE_REGISTERING;
}
else
{
wmud_client_send(client, "Sorry, but for this question I only understand 'Y' or 'N'.\r\nIs %s a new player here? [Y/N] ", client->player->player_name);
}
break;
case WMUD_CLIENT_STATE_REGISTERING:
if (!*(client->buffer->str))
{
if (client->bademail)
{
wmud_client_close(client, TRUE);
}
}
if (g_regex_match(email_regex, client->buffer->str, 0, NULL))
{
client->player->email = g_strdup(client->buffer->str);
client->state = WMUD_CLIENT_STATE_REGEMAIL_CONFIRM;
wmud_client_send(client, "It seems to be a valid address to me, but could you write it again? ");
}
else
{
wmud_client_send(client, "\r\nSorry, but this e-mail address doesn't seem to be valid to me.\r\n\r\nIf you think this is a valid address, simply press enter to quit, and send an e-mail to %s from that address, so we can fix our e-mail validation code.\r\n\r\nIf you just mistyped your address, type it now: ", active_config->admin_email);
if (*(client->buffer->str))
client->bademail = TRUE;
}
break;
case WMUD_CLIENT_STATE_REGEMAIL_CONFIRM:
if (g_ascii_strcasecmp(client->player->email, client->buffer->str) == 0)
{
g_clear_error(&err);
if (wmud_db_save_player(client->player, &err))
{
wmud_client_send(client, "Good. We will generate the password for this player name, and send it to you\r\nvia e-mail. Please come back to us, if you get that code, so you can log\r\nin.\r\n");
players = g_slist_prepend(players, wmud_player_dup(client->player));
}
else
{
g_critical("wmud_db_save_player() error: %s", err->message);
wmud_client_send(client, "There was an error during the database update. Please try again later!\r\n");
}
wmud_client_close(client, TRUE);
}
else
{
g_free(client->player->email);
client->player->email = NULL;
wmud_client_send(client, "This is not the same as you entered before.\r\nLet's just try it again: ");
client->state = WMUD_CLIENT_STATE_REGISTERING;
}
break;
}
g_string_erase(client->buffer, 0, -1);
for (; ((*buf2 == '\r') || (*buf2 == '\n')) && *buf2; buf2++);
if (!*buf2)
break;
}
else
{
if (client->buffer->len > 0)
g_string_append(client->buffer, buf2);
else
g_string_overwrite(client->buffer, 0, buf2);
break;
}
}
g_free(buf);
}
return TRUE;
}
/**
* game_source_callback:
* @socket: the listener socket on which the new connection arrived
* @condition: not used
* @accept_data: the AcceptData structure of the game listener
*
* Callback function to be called when a new connection is available on the
* game listener socket.
*
* Return value: this function always returns %TRUE
*/
gboolean
game_source_callback(GSocket *socket, GIOCondition condition, struct AcceptData *accept_data)
{
GSocket *client_socket;
GSource *client_source;
GError *err = NULL;
wmudClient *client;
/* TODO: Error checking */
client_socket = g_socket_listener_accept_socket(accept_data->listener, NULL, NULL, &err);
client = g_new0(wmudClient, 1);
client->socket = client_socket;
client->buffer = g_string_new("");
client->state = WMUD_CLIENT_STATE_FRESH;
clients = g_slist_prepend(clients, client);
client_source = g_socket_create_source(client_socket, G_IO_IN | G_IO_OUT | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL, NULL);
client->socket_source = client_source;
g_source_set_callback(client_source, (GSourceFunc)wmud_client_callback, client, NULL);
g_source_attach(client_source, accept_data->context);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "New connection.");
wmud_client_send(client, "By what name shall we call you? ");
return TRUE;
}
/**
* wmud_networking_init:
* @port_number: the port number on which the game listener should listen
* @game_context: the #GMainContext of the game thread
* @err: the GError in which possible errors will be reported
*
* Initializes the game network listener
*
* Return value: Returns %TRUE on success. Upon failure, %FALSE is return, and
* err is set accordingly (if not NULL)
*/
gboolean
wmud_networking_init(guint port_number, GMainContext *game_context, GError **err)
{
struct AcceptData *accept_data;
GSocketListener *game_listener;
gboolean need_ipv4_socket = TRUE;
GSocket *game_socket6,
*game_socket4;
GError *in_err = NULL;
GSource *game_net_source4 = NULL,
*game_net_source6 = NULL;
clients = NULL;
game_listener = g_socket_listener_new();
/* The following snippet is borrowed from GLib 2.30's gsocketlistener.c
* code, to create the necessary sockets to listen on both IPv4 and
* IPv6 address */
if ((game_socket6 = g_socket_new(G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &in_err)) != NULL)
{
GInetAddress *inet_address;
GSocketAddress *address;
gboolean result;
inet_address = g_inet_address_new_any(G_SOCKET_FAMILY_IPV6);
address = g_inet_socket_address_new(inet_address, port_number);
g_object_unref(inet_address);
g_socket_set_listen_backlog(game_socket6, 10);
result = g_socket_bind(game_socket6, address, TRUE, &in_err)
&& g_socket_listen(game_socket6, &in_err);
g_object_unref(address);
if (!result)
{
g_object_unref(game_socket6);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Unable to create listener IPv6 socket");
return FALSE;
}
if (g_socket_speaks_ipv4(game_socket6))
need_ipv4_socket = FALSE;
game_net_source6 = g_socket_create_source(game_socket6, G_IO_IN, NULL);
/* TODO: error checking */
g_socket_listener_add_socket(game_listener, game_socket6, NULL, &in_err);
}
/* TODO: else { error checking } */
if (need_ipv4_socket)
{
if ((game_socket4 = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &in_err)) != NULL)
{
GInetAddress *inet_address;
GSocketAddress *address;
gboolean result;
inet_address = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
address = g_inet_socket_address_new(inet_address, port_number);
g_object_unref(inet_address);
g_socket_set_listen_backlog(game_socket4, 10);
result = g_socket_bind(game_socket4, address, TRUE, &in_err)
&& g_socket_listen(game_socket4, &in_err);
g_object_unref(address);
if (!result)
{
g_object_unref(game_socket4);
if (!game_socket6)
g_object_unref(game_socket6);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Unable to create listener IPv4 socket!\n");
return FALSE;
}
game_net_source4 = g_socket_create_source(game_socket4, G_IO_IN, NULL);
/* TODO: error checking */
g_socket_listener_add_socket(game_listener, game_socket4, NULL, &in_err);
}
/* TODO: else { error checking } */
}
else
{
if (game_socket6 != NULL)
g_clear_error(&in_err);
else
return FALSE;
}
accept_data = g_new(struct AcceptData, 1);
accept_data->listener = game_listener;
accept_data->context = game_context;
if (game_net_source6)
{
g_source_set_callback(game_net_source6, (GSourceFunc)game_source_callback, (gpointer)accept_data, NULL);
g_source_attach(game_net_source6, game_context);
}
if (game_net_source4)
{
g_source_set_callback(game_net_source4, (GSourceFunc)game_source_callback, (gpointer)accept_data, NULL);
g_source_attach(game_net_source4, game_context);
}
return TRUE;
}
/**
* wmud_client_send:
* @client: the client to which the message will be sent
* @fmt: the printf() style format string of the message
* @...: optional parameters to the format string
*
* Sends a formatted message to a game client
*/
void
wmud_client_send(wmudClient *client, const gchar *fmt, ...)
{
va_list ap;
GString *buf = g_string_new("");
va_start(ap, fmt);
g_string_vprintf(buf, fmt, ap);
va_end(ap);
/* TODO: error checking */
g_socket_send(client->socket, buf->str, buf->len, NULL, NULL);
g_string_free(buf, TRUE);
}

68
wmud/game-networking.h Normal file
View File

@@ -0,0 +1,68 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* game-networking.h: basic networking function headers, variables and defines
*
* 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 2 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/>.
*/
#ifndef __WMUD_NETWORKING_H__
# define __WMUD_NETWORKING_H__
#include <glib.h>
#include "wmud-types.h"
/**
* TELNET_IAC:
*
* Telnet IAC code
*/
#define TELNET_IAC '\xff'
/**
* TELNET_WONT:
*
* Telnet WON'T code
*/
#define TELNET_WONT '\xfc'
/**
* TELNET_WILL:
*
* Telnet WILL code
*/
#define TELNET_WILL '\xfb'
/**
* TELNET_DO:
*
* Telnet DO code
*/
#define TELNET_DO '\xfd'
/**
* TELNET_DONT:
*
* Telnet DONT code
*/
#define TELNET_DONT '\xfe'
/**
* TELNET_ECHO:
*
* Telnet ECHO code
*/
#define TELNET_ECHO '\x01'
extern GSList *clients;
gboolean wmud_networking_init(guint port_number, GMainContext *game_context, GError **err);
void wmud_client_send(wmudClient *client, const gchar *fmt, ...);
#endif

123
wmud/game.c Normal file
View File

@@ -0,0 +1,123 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* game.c: Game Thread related functions
*
* 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 2 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 <glib.h>
#include "main.h"
#include "game.h"
/**
* SECTION:game-thread
* @short_description: Game related functions
* @title: The Game Thread
*
* The game thread is supposed to serve game client connections. Also,
* maintaining the loaded game world is the objective ot this thread.
*
* This thread has to serve all the game clients after a connection is
* estabilished. Player login, menu interaction and play are both the tasks of
* this thread.
*
* The other main objective is to maintain the loaded world. Moving and
* resetting the mobs, cleaning up areas and many other things belong here.
*/
/**
* elapsed_seconds:
*
* the number of seconds elapsed since game boot. May be inaccurate, as it
* simply gets updated by a timeout function which should run every second
*/
guint32 elapsed_seconds = 0;
/**
* elapsed_cycle:
*
* yes, I'm optimistic. This counter is increased if, for some reason,
* #elapsed_seconds reaches the maximum value
*/
guint32 elapsed_cycle = 0;
/**
*
* rl_sec_elapsed:
* @user_data: non-used pointer to callback's user data
*
* Keeps track of elapsed real-world time. It is inaccurate by design, but it
* doesn't actually matter.
*/
gboolean
rl_sec_elapsed(gpointer user_data)
{
elapsed_seconds++;
if (elapsed_seconds == G_MAXUINT32)
{
elapsed_seconds = 0;
elapsed_cycle++;
}
if (elapsed_seconds % 30 == 0)
{
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "Heartbeat");
}
return TRUE;
}
/**
* game_thread_func:
* @game_loop: the main loop to be associated with the game thread
*
* The game thread's main function.
*
* Return value: This function always returns %NULL.
*/
gpointer
game_thread_func(GMainLoop *game_loop)
{
/* Run the game loop */
g_main_loop_run(game_loop);
return NULL;
}
gboolean
wmud_game_init(GThread **game_thread, GMainContext **game_context)
{
GMainLoop *game_loop;
GSource *timeout_source;
GError *err = NULL;
/* Create the game context and main loop */
*game_context = g_main_context_new();
game_loop = g_main_loop_new(*game_context, FALSE);
/* Create the timeout source which keeps track of elapsed real-world
* time */
timeout_source = g_timeout_source_new(1000);
g_source_set_callback(timeout_source, rl_sec_elapsed, NULL, NULL);
g_source_attach(timeout_source, *game_context);
g_source_unref(timeout_source);
g_clear_error(&err);
*game_thread = g_thread_create((GThreadFunc)game_thread_func, game_loop, TRUE, &err);
return TRUE;
}

25
wmud/game.h Normal file
View File

@@ -0,0 +1,25 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* game.h: Game Thread related functions
*
* 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 2 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/>.
*/
#ifndef __WMUD_GAME_H__
#define __WMUD_GAME_H__
gboolean wmud_game_init(GThread **game_thread, GMainContext **game_context);
#endif /* __WMUD_GAME_H__ */

207
wmud/interpreter.c Normal file
View File

@@ -0,0 +1,207 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* interpreter.c: game command interpreter routines
*
* 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 2 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 <glib.h>
#include <gio/gio.h>
#include <string.h>
#include "interpreter.h"
#include "game-networking.h"
#include "main.h"
/**
* SECTION:interpreter
* @short_description: Game command interpreter
*
* Functions to interpret and execute in-game commands
*/
WMUD_COMMAND(quit);
static wmudCommand command_list[] = {
{ "quit", gcmd_quit },
{ NULL, NULL },
};
/**
* destroy_string:
* @string: a GString to destroy
*
* Callback function to destroy a list of GStrings
*/
static void
destroy_string(GString *string)
{
g_string_free(string, TRUE);
}
/**
* wmud_interpret_game_command:
* @client: the wmudClient whose command should be processed
*
* Processes a wmudClient's buffer, and executes the game command if there is
* one
*/
void
wmud_interpret_game_command(wmudClient *client)
{
GSList *command_parts = NULL;
gchar *a,
*start,
*end;
gchar str_delim = 0;
wmudCommand *cmd;
int command_parts_count = 0,
match_count = 0;
GSList *matches = NULL;
if (strchr(client->buffer->str, '\r') || strchr(client->buffer->str, '\n'))
{
/* TODO: We should NEVER reach this point! */
return;
}
a = client->buffer->str;
GString *token;
while (*a)
{
for (start = a; *start; start++)
{
if (!str_delim)
{
if ((*start == '"') || (*start == '\''))
{
str_delim = *start;
start++;
break;
}
else if (g_ascii_isspace(*start) || (!*start))
{
break;
}
}
}
for (end = start; *end; end++)
{
if (!str_delim && strchr("'\" \t", *end))
{
break;
}
else if (str_delim && (*end == str_delim))
{
str_delim = 0;
break;
}
else if (!*end)
{
break;
}
}
if (*start)
{
token = g_string_new_len(start, end - start);
command_parts = g_slist_prepend(command_parts, token);
command_parts_count++;
}
a = end;
if (((*a == '"') || (*a == '\'')) && str_delim)
a++;
}
if (str_delim)
{
wmud_client_send(client, "You should close quotes of any kind, like %c, shouldn't you?\r\n", str_delim);
#if GLIB_CHECK_VERSION(2, 28, 0)
g_slist_free_full(command_parts, (GDestroyNotify)destroy_string);
#else
g_slist_foreach(command_parts, (GFunc)destroy_string, NULL);
g_slist_free(command_parts);
#endif
return;
}
if (command_parts_count == 0)
{
/* TODO: handle empty command */
return;
}
command_parts = g_slist_reverse(command_parts);
for (cmd = command_list; cmd->command; cmd++)
{
GString *input = (GString *)(command_parts->data);
gint cmp;
if (((cmp = g_ascii_strncasecmp(input->str, cmd->command, input->len)) == 0) && !cmd->command[input->len])
{
g_slist_free(matches);
match_count = 1;
matches = NULL;
matches = g_slist_prepend(matches, cmd);
break;
}
else if (cmp == 0)
{
matches = g_slist_prepend(matches, cmd);
match_count++;
}
}
switch (match_count)
{
case 0:
switch (random_number(1, 3))
{
case 1:
wmud_client_send(client, "Huh?\r\n");
break;
case 2:
wmud_client_send(client, "What?\r\n");
break;
case 3:
wmud_client_send(client, "I can hardly understand you...\r\n");
break;
}
break;
case 1:
((wmudCommand *)(matches->data))->commandFunc(client, ((GString *)(command_parts->data))->str, command_parts->next);
break;
default:
wmud_client_send(client, "This command could mean several things, please try a more exact form!\r\n");
}
g_slist_free(matches);
}
/**
* gcmd_quit:
*
* The QUIT game command's handler
*/
WMUD_COMMAND(quit)
{
wmud_client_send(client, "Are you sure you want to get back to that freaky other reality? [y/N] ");
client->state = WMUD_CLIENT_STATE_QUITWAIT;
}

57
wmud/interpreter.h Normal file
View File

@@ -0,0 +1,57 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* interpreter.h: game command interpreter prototypes and variables
*
* 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 2 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/>.
*/
#ifndef __WMUD_INTERPRETER_H__
# define __WMUD_INTERPRETER_H__
#include "game-networking.h"
/**
* wmudCommandFunc:
* @client: the client from whom the command arrived
* @command: the command itself
* @token_list: the command arguments
*
* Command handler function type
*/
typedef void (*wmudCommandFunc)(wmudClient *client, gchar *command, GSList *token_list);
/**
* WMUD_COMMAND:
* @name: the name of the command. Should be in lowercase
*
* Shorthand to create the function header for command handlers
*/
#define WMUD_COMMAND(name) void gcmd_ ## name(wmudClient *client, gchar *command, GSList *token_list)
/**
* wmudCommand:
* @command: the command itself. Should be in uppercase, but doesn't actually
* matter
* @commandFunc: the command handler function for this command
*
* This structure holds the different properties of the in-game commands.
*/
typedef struct _wmudCommand {
gchar *command;
wmudCommandFunc commandFunc;
} wmudCommand;
void wmud_interpret_game_command(wmudClient *client);
#endif /* __WMUD_INTERPRETER_H__ */

207
wmud/main.c Normal file
View File

@@ -0,0 +1,207 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* main.c: main and uncategorized functions
*
* 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 2 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib.h>
#include <gio/gio.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#include "wmud-types.h"
#include "main.h"
#include "game-networking.h"
#include "interpreter.h"
#include "db.h"
#include "players.h"
#include "maintenance.h"
#include "game.h"
#include "configuration.h"
/**
* SECTION:utils
* @short_description: Utilities and uncategorized functions
* @title: Utility and uncategorized functions
*
*/
/**
* debug_context_loc:
*
* This variable holds the location of the last context marker
*/
struct {
char *file;
int line;
} debug_context_loc = {NULL, 0};
/**
* wmud_random_string:
* @len: the desired length of the generated random string
*
* Generates a random string of %len characters.
*/
gchar *
wmud_random_string(gint len)
{
gchar *ret = g_malloc0(len + 1);
gint i;
for (i = 0; i < len; i++)
{
gchar c = 0;
/* Include only printable characters, but exclude $ because of
* salt generation */
while (!g_ascii_isprint(c) || (c == '$'))
c = random_number(1, 127);
ret[i] = c;
}
return ret;
}
#ifdef DEBUG
void
/**
* debug_context:
* @file: the source file name, where the context marker was found
* @line: the line number where the context marker was found
*
* This function keeps track of the code flow in some way. It can help with
* debugging, as during a SIGSEGV or such signal this will print out the last
* place of DebugContext in the code.
*
* THIS FUNCTION SHOULD NEVER BE CALLED DIRECTLY!
*/
debug_context(char *file, int line)
{
if (debug_context_loc.file != NULL)
g_free(debug_context_loc.file);
debug_context_loc.file = g_strdup(file);
debug_context_loc.line = line;
}
/**
* DebugContext:
*
* Marks the current line of the source file with a context marker. Deadly
* signals should print the place of the last marker.
*/
#define DebugContext debug_context(__FILE__, __LINE__)
#else
#define DebugContext
#endif
/**
* wmud_type_init:
*
* Initializes the wMUD types.
*/
void
wmud_type_init(void)
{
WMUD_CONFIG_ERROR = g_quark_from_string("wmud_config_error");
WMUD_DB_ERROR = g_quark_from_string("wmud_db_error");
}
/**
* main:
* @argc: The number of arguments on the command line
* @argv: The command line arguments themselves
*
* The Main Function (TM)
*/
int
main(int argc, char **argv)
{
GError *err = NULL;
GThread *game_thread;
GMainContext *game_context;
/* Initialize the thread and type system */
g_thread_init(NULL);
g_type_init();
wmud_type_init();
/* TODO: Command line parsing */
/* TODO: Create signal handlers! */
if (!wmud_config_init(&active_config, &err))
{
if (err)
{
g_critical("Config file parsing error: %s", err->message);
}
else
{
g_critical("Config file parsing error!");
}
return 1;
}
g_clear_error(&err);
if (!wmud_db_init(&err))
{
if (err)
{
g_critical("Database initialization error: %s", err->message);
}
else
{
g_critical("Database initialization error!");
}
return 1;
}
g_clear_error(&err);
wmud_db_players_load(&err);
/* Initialization ends here */
wmud_game_init(&game_thread, &game_context);
g_clear_error(&err);
if (!wmud_networking_init(active_config->port, game_context, &err))
{
if (err)
{
g_critical("Database initialization error: %s", err->message);
}
else
{
g_critical("Database initialization error!");
}
return 1;
}
wmud_maintenance_init();
/* Initialize other threads here */
g_thread_join(game_thread);
return 0;
}

21
wmud/main.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef __WMUD_MAIN_H__
# define __WMUD_MAIN_H__
# include <glib.h>
extern GMainContext *game_context;
extern guint32 elapsed_seconds;
/**
* random_number:
* @min: Minimum value for random number
* @max: Maximum value for random number
*
* Generates a random number between min and max
*/
#define random_number(min, max) g_random_int_range((min), (max) + 1)
gchar *wmud_random_string(gint len);
#endif /* __WMUD_MAIN_H__ */

132
wmud/maintenance.c Normal file
View File

@@ -0,0 +1,132 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* maintenance.c: game maintenance and self-check functions
*
* 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 2 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#include "wmud-types.h"
#include "maintenance.h"
#include "main.h"
#include "players.h"
/**
* SECTION:maintenance-thread
* @short_description: Runtime maintenance functions
* @title: Runtime maintenance functions
*
*/
/**
* wmud_maintenance_check_new_players:
* @player: #wmudPLayer structure of the player record to check
* @user_data: not used
*
* Callback called from within the maintenance loop. Checks if the player has
* an unset password, and generate one for them, if so.
*/
void
wmud_maintenance_check_new_players(wmudPlayer *player, gpointer user_data)
{
if (player->cpassword == NULL)
{
gchar *pw,
*salt,
*cpw;
GString *full_salt;
pw = wmud_random_string(8);
salt = wmud_random_string(8);
full_salt = g_string_new("$1$");
g_string_append(full_salt, salt);
cpw = g_strdup(crypt(pw, full_salt->str));
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Player %s has no"
" password set", player->player_name);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "New password will be %s", pw);
player->cpassword = cpw;
/* TODO: Send e-mail about the new password. Upon completion,
* set it in the database */
g_free(pw);
g_free(salt);
g_string_free(full_salt, TRUE);
}
}
/**
* wmud_maintenance:
* @user_data: not used
*
* Timeout source function for maintenance tasks
*/
gboolean
wmud_maintenance(gpointer user_data)
{
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Starting maintenance...");
/* Run through the player list, and generate a random password for each
* newly registered player */
g_slist_foreach(players, (GFunc)wmud_maintenance_check_new_players, NULL);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Finished maintenance...");
return TRUE;
}
/**
* maint_thread_func:
* @main_loop: the main loop to be associated with the maintenance thread
*
* The maintenance thread's main function.
*
* Return value: This function always returns %NULL.
*/
gpointer
maint_thread_func(GMainLoop *maint_loop)
{
g_main_loop_run(maint_loop);
return NULL;
}
void
wmud_maintenance_init(void)
{
GSource *timeout_source;
GMainLoop *maint_loop;
GMainContext *maint_context;
GError *err = NULL;
/* Create the maintenance context and main loop */
maint_context = g_main_context_new();
maint_loop = g_main_loop_new(maint_context, FALSE);
/* Create the timeout source which will do the maintenance tasks */
timeout_source = g_timeout_source_new_seconds(3);
g_source_set_callback(timeout_source, wmud_maintenance, NULL, NULL);
g_source_attach(timeout_source, maint_context);
g_source_unref(timeout_source);
g_thread_create((GThreadFunc)maint_thread_func, maint_loop, FALSE, &err);
}

1
wmud/maintenance.h Normal file
View File

@@ -0,0 +1 @@
void wmud_maintenance_init(void);

139
wmud/players.c Normal file
View File

@@ -0,0 +1,139 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* players.c: player structure related functions
*
* 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 2 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#include "game-networking.h"
#include "players.h"
/**
* SECTION:player
* @short_description: Player database handling
*
* Functions to handle player database records
*/
/**
* players:
*
* GSList of all loaded players. Stores #wmudPlayer structures.
*/
GSList *players = NULL;
/**
* wmud_player_auth:
* @client: The client to be authenticated. The authentication password comes
* from the client's buffer.
*
* Tries to authenticate a client based on the associated player structure, and
* the password stored in the client's buffer.
*
* Return value: %TRUE if the password is valid, %FALSE otherwise.
*/
gboolean
wmud_player_auth(wmudClient *client)
{
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Player entered %s as password", client->buffer->str);
if (g_strcmp0(crypt(client->buffer->str, client->player->cpassword), client->player->cpassword) == 0)
return TRUE;
return FALSE;
}
static gint
find_player_by_name(wmudPlayer *player, gchar *player_name)
{
return g_ascii_strcasecmp(player->player_name, player_name);
}
/**
* wmud_player_exists:
* @player_name: The login name of the player to check
*
* Check if the player with the given name already exists.
*
* Return value: the wmudPlayer structure for the given player name, or %NULL
* if it can not be found.
*/
wmudPlayer *
wmud_player_exists(gchar *player_name)
{
GSList *player_elem;
if ((player_elem = g_slist_find_custom(players, player_name, (GCompareFunc)find_player_by_name)) == NULL)
return NULL;
return player_elem->data;
}
/**
* wmud_player_dup:
* @player: the player structure to duplicate
*
* Duplicates a #wmudPlayer structure.
*
* Return value: the new, duplicated player structure. It must be freed with wmud_player_free().
*/
wmudPlayer *
wmud_player_dup(wmudPlayer *player)
{
wmudPlayer *new_player;
if (!player)
return NULL;
new_player = g_new0(wmudPlayer, 1);
new_player->id = player->id;
new_player->player_name = g_strdup(player->player_name);
new_player->cpassword = g_strdup(player->cpassword);
new_player->email = g_strdup(player->email);
return new_player;
}
/**
* wmud_player_free:
* @player: A pointer to the player structure to be freed
*
* Frees a #wmudPlayer structure with all its fields, and sets the structure
* variable to %NULL.
*/
void
wmud_player_free(wmudPlayer **player)
{
if (!*player)
return;
if ((*player)->player_name)
g_free((*player)->player_name);
if ((*player)->cpassword)
g_free((*player)->cpassword);
if ((*player)->email)
g_free((*player)->email);
g_free(*player);
*player = NULL;
}

33
wmud/players.h Normal file
View File

@@ -0,0 +1,33 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* players.h: player structure related prototypes and variables
*
* 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 2 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/>.
*/
#ifndef __WMUD_PLAYERS_H__
#define __WMUD_PLAYERS_H__
#include <glib.h>
#include "wmud-types.h"
extern GSList *players;
gboolean wmud_player_auth(wmudClient *client);
wmudPlayer *wmud_player_exists(gchar *player_name);
void wmud_player_free(wmudPlayer **player);
wmudPlayer *wmud_player_dup(wmudPlayer *player);
#endif /* __WMUD_PLAYERS_H__ */

127
wmud/wmud-types.h Normal file
View File

@@ -0,0 +1,127 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* wmud-types.h: Common wMUD data types
*
* 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 2 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/>.
*/
#ifndef __WMUD_TYPES_H__
#define __WMUD_TYPES_H__
#include <glib.h>
#include <gio/gio.h>
/**
* SECTION:types
* @short_description: wMUD Data Types
* @title: wMUD's Data Types
*
*/
/**
* wmudClientState:
* @WMUD_CLIENT_STATE_FRESH: Client is newly connected. Waiting for a login
* player name
* @WMUD_CLIENT_STATE_PASSWAIT: Login player name is entered, waiting for a
* login password
* @WMUD_CLIENT_STATE_MENU: Authentication was successful, player is now in the
* main game menu
* @WMUD_CLIENT_STATE_INGAME: Character login was successful, player is now
* in-game
* @WMUD_CLIENT_STATE_QUITWAIT: Player entered the in-game QUIT command, and we
* are now waiting for an answer if they really want to quit
* Will be removed soon, this should work totally different (TODO)
* @WMUD_CLIENT_STATE_NEWCHAR: Player name entered on the login screen was
* invalid. Waiting for answer if this is a new player
* @WMUD_CLIENT_STATE_REGISTERING: Registering a new player. Waiting for the
* e-mail address to be given
* @WMUD_CLIENT_STATE_REGEMAIL_CONFIRM: E-mail address entered séms valid,
* waiting for confirmation
*
* Game client states.
*/
typedef enum {
WMUD_CLIENT_STATE_FRESH,
WMUD_CLIENT_STATE_PASSWAIT,
WMUD_CLIENT_STATE_MENU,
WMUD_CLIENT_STATE_INGAME,
WMUD_CLIENT_STATE_QUITWAIT,
WMUD_CLIENT_STATE_NEWCHAR,
WMUD_CLIENT_STATE_REGISTERING,
WMUD_CLIENT_STATE_REGEMAIL_CONFIRM
} wmudClientState;
/**
* wmudPlayer:
* @id: Player's database ID
* @player_name: Player's login name
* @cpassword: crypt()ed password of the player. This is NULL for newly
* registered players, who have no password generated for them by the
* maintenance loop
* @email: E-mail address of the player
*
* The <structname>wmudPlayer</structname> structure contains all information of
* a player.
*/
typedef struct _wmudPlayer {
guint32 id;
gchar *player_name;
gchar *cpassword;
gchar *email;
} wmudPlayer;
/**
* wmudClient:
* @socket: The assigned GSocket object
* @buffer: The client receive buffer. It may hold partial or multiple lines
* until processed
* @state: The state of the client
* @authenticated: TRUE if the client is an authenticated game player
* @player: The associatec player structure. It is also used during
* registration, so it should be always checked if the player is a saved
* database user
* @bademail: indicates that the entered e-mail address is invalid
* @socket_source: the #GSource associated with the client socket
* @login_try_count: the failed login count of the client
*
* <structname>wmudClient</structname> contains all properties of a connected
* game client.
*/
typedef struct _wmudClient {
GSocket *socket;
GSource *socket_source;
GString *buffer;
wmudClientState state;
gboolean authenticated;
wmudPlayer *player;
gboolean bademail;
gint login_try_count;
} wmudClient;
/**
* wmudDbError:
* @WMUD_DB_ERROR_CANTOPEN: Database file cannot be opened
* @WMUD_DB_ERROR_NOINIT: Database system was not initialized
* @WMUD_DB_ERROR_BADQUERY: Invalid database query
*
* Error codes returned by database handling functions.
*/
typedef enum {
WMUD_DB_ERROR_CANTOPEN,
WMUD_DB_ERROR_NOINIT,
WMUD_DB_ERROR_BADQUERY
} wmudDbError;
#endif /* __WMUD_TYPES_H__ */

155
wmud/world.c Normal file
View File

@@ -0,0 +1,155 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* world.c: world loading and building functions
*
* 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 2 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 <glib.h>
#include "world.h"
#include "db.h"
/**
* SECTION:world
* @short_description: World loading and building functions
* @title: Game world manipulation
*
*/
gboolean
wmud_world_check_planes(GSList *planes, GError **err)
{
return FALSE;
}
gboolean
wmud_world_check_planets(GSList *planets, GError **err)
{
return FALSE;
}
gboolean
wmud_world_check_areas(GSList *areas, GError **err)
{
return FALSE;
}
gboolean
wmud_world_check_exits(GSList *exits, GError **err)
{
return FALSE;
}
gboolean
wmud_world_assoc_planets_planes(GSList *planets, GSList *planes, GError **err)
{
return FALSE;
}
gboolean
wmud_world_assoc_rooms_areas(GSList *rooms, GSList *areas, GError **err)
{
return FALSE;
}
gboolean
wmud_world_assoc_rooms_planets(GSList *rooms, GSList *planets, GError **err)
{
return FALSE;
}
gboolean
wmud_world_assoc_exits_rooms(GSList *exits, GSList *rooms, GError **err)
{
return FALSE;
}
/**
* wmud_world_load:
* @err: a #GError to put error messages into
*
* Load the world from the database backend without activating it.
*/
gboolean
wmud_world_load(GError **err)
{
GSList *planes = NULL,
*planets = NULL,
*directions = NULL,
*areas = NULL,
*rooms = NULL,
*exits = NULL;
GError *in_err = NULL;
/* Load directions from the database */
wmud_db_load_directions(&directions, &in_err);
/* Load planes from the database */
wmud_db_load_planes(&planes, &in_err);
/* Check if the loaded planes conform to the rules */
g_clear_error(&in_err);
wmud_world_check_planes(planes, &in_err);
/* Load planets from the database */
g_clear_error(&in_err);
wmud_db_load_planets(&planets, &in_err);
/* Check if the planets conform to the rules */
g_clear_error(&in_err);
wmud_world_check_planets(planets, &in_err);
/* Put the planets on the planes */
g_clear_error(&in_err);
wmud_world_assoc_planets_planes(planets, planes, &in_err);
/* Load areas from the database */
g_clear_error(&in_err);
wmud_db_load_areas(&areas, &in_err);
/* Check if the areas conform to the rules */
g_clear_error(&in_err);
wmud_world_check_areas(areas, &in_err);
/* Load rooms from the database */
g_clear_error(&in_err);
wmud_db_load_rooms(&rooms, &in_err);
/* Associate rooms with the areas */
g_clear_error(&in_err);
wmud_world_assoc_rooms_areas(rooms, areas, &in_err);
/* Associate rooms with planets */
g_clear_error(&in_err);
wmud_world_assoc_rooms_planets(rooms, planets, &in_err);
/* Load room exits from the database */
g_clear_error(&in_err);
wmud_db_load_exits(&exits, &in_err);
/* Check if the exits conform to the rules */
g_clear_error(&in_err);
wmud_world_check_exits(exits, &in_err);
/* Associate exits with rooms */
g_clear_error(&in_err);
wmud_world_assoc_exits_rooms(exits, rooms, &in_err);
g_clear_error(&in_err);
return TRUE;
}

33
wmud/world.h Normal file
View File

@@ -0,0 +1,33 @@
/* wMUD - Yet another MUD codebase by W00d5t0ck
* Copyright (C) 2012 - Gergely POLONKAI
*
* world.h: world loading and building functions
*
* 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 2 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/>.
*/
#ifndef __WMUD_WORLD_H__
#define __WMUD_WORLD_H__
gboolean wmud_world_check_planes(GSList *planes, GError **err);
gboolean wmud_world_check_planets(GSList *planets, GError **err);
gboolean wmud_world_check_areas(GSList *areas, GError **err);
gboolean wmud_world_check_exits(GSList *exits, GError **err);
gboolean wmud_world_assoc_planets_planes(GSList *planets, GSList *planes, GError **err);
gboolean wmud_world_assoc_rooms_areas(GSList *rooms, GSList *areas, GError **err);
gboolean wmud_world_assoc_rooms_planets(GSList *rooms, GSList *planets, GError **err);
gboolean wmud_world_assoc_exits_rooms(GSList *exits, GSList *rooms, GError **err);
#endif /* __WMUD_WORLD_H__ */