Initial import

This commit is contained in:
Gergely Polonkai 2016-06-23 17:37:35 +02:00
commit 2f36baf323
58 changed files with 4186 additions and 0 deletions

5
Makefile.am Normal file
View File

@ -0,0 +1,5 @@
ACLOCAL_AMFLAGS=-I m4
SUBDIRS = libwmud-session libwmud-world libwmud-state-sqlite3 libwmud-protocol-telnet src doc/reference/libwmud-session doc/reference/libwmud-world
dist_doc_DATA = README
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-debug

11
README Normal file
View File

@ -0,0 +1,11 @@
What is wMUD?
=============
On one hand, wMUD is a new (well, yet another) MUD (Multi-User Dungeon)
server. It is designed to run as smoothly as possible, which is achieved by
using threads. During development I tried to eliminate everything which is not
GLib, so, although not tested yet, it should by highly portable.
On the other hand, wMUD is a learning project for GLib's several features.
This means that although I double check every byte of code, it can still have
bugs or not-so-effective code chunks. If you find one, please don't hesitate to
contact me, or send a patch!

76
TODO Normal file
View File

@ -0,0 +1,76 @@
CLIENT FLOW
===========
[X] connection arrives
[X] connection gets accept()'ed
[ ] connection is closed if the IP is banned
[X] session object created
[ ] welcome banner gets sent
[X] user sends commans
[ ] commands get processed
[X] user sends the QUIT command
[X] session gets destroyed
[X] connection gets destroyed
TO-DO LIST
==========
[X] Create own text formatting style
[o] Create converter that can convert from own style to
[X] ANSI
[ ] colourless text
[ ] HTML
[ ] Pango markup
only the first two are very important
[X] Do basic jobs for later threading support
[X] Create and run the world object in a separate thread
[X] Implement session handling
[X] Create telnet interface that can process commands and send colourful
responses. This should go in a separate thread.
[X] Plan configurable parameters and configuration file format
[X] Write configuration reading code
[o] Create XML schemas for world description
[ ] Specify a way how new attribute and object types can be inserted into
a running system
[ ] Specify state-saving backends:
[ ] SQLite3
[ ] MySQL
[ ] PostgreSQL
[ ] XML
[ ] GDBM
[ ] Specify data to be saved during state-save
[ ] Write state saving (command and timed hook) and loading (command and
startup time) code
[o] Write world description loading and reloading code
[ ] Write User Account management code (possibility of registration,
login, logout, account deletion, ban, kick and purge
[o] Write chat possibility
[ ] Write Light-calculation code
[ ] Plan initial character state (what attributes to use, look, cloths,
armour, weapon, etc.)
[ ] Create the possibility to enter the world
[ ] Create the possibility to move in the world
[ ] Create a DBus module to control the whole program
# vim: textwidth=78 : tabstop=8 : expandtab

30
configure.ac Normal file
View File

@ -0,0 +1,30 @@
AC_INIT([wmud], [1.0], [polesz@w00d5t0ck.info])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
LT_INIT
AC_ARG_ENABLE(debug, [AC_HELP_STRING([--enable-debug], [compile with debugging support. Be warned that debugging support can eat a large amount of CPU when many clients are connected. Also, debug logs can become very large!])], , enable_debug=no)
if test "x$enable_debug" = "xyes" ; then
AC_DEFINE([DEBUG], [1], [Define if debugging is enabled.])
fi
AC_PROG_CC
AC_PROG_LIBTOOL
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES([GLIB], [glib-2.0])
PKG_CHECK_MODULES([GOBJECT], [gobject-2.0])
PKG_CHECK_MODULES([GNET], [gnet-2.0])
PKG_CHECK_MODULES([EXTLIBS], [libxml-2.0, glib-2.0, gobject-2.0, gthread-2.0, gnet-2.0, gnome-vfs-2.0, sqlite3 gmodule-2.0])
GTK_DOC_CHECK([1.10])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
Makefile
libwmud-session/Makefile
libwmud-world/Makefile
libwmud-state-sqlite3/Makefile
libwmud-protocol-telnet/Makefile
src/Makefile
doc/reference/libwmud-session/Makefile
doc/reference/libwmud-world/Makefile
])
AC_OUTPUT

0
data/state.sql Normal file
View File

68
data/wmud.conf Normal file
View File

@ -0,0 +1,68 @@
# general options
[general]
# log can be "syslog" (to log through the syslog facility), "file:<filename>"
# to log to the specified file, "console" (to log to the console), or "none"
# (for no logging at all). console can be used only if compiled with debug
# support. If logging is set to console, wMUD cannot be daemonized!
log = console
# if you wish, you can send debug, info, warning and error message to different
# destinations by defining a "debug log", an "info log", a "warning log" and an
# "error log" respectively
#debug log = file:/home/polesz/Projektek/wMUD/data/debug.log
info log = console
warning log = console
error log = console
chat = yes
dbus = yes
# after initialization, send into the background. This setting is automatically
# set to "no" if logging is set to "console". However, if daemonize is set to
# "force", wMUD will be sent to the background, and will be forced to log
# through the syslog facilty
daemonize = no
# wMUD is highly extensible with the use of modules
[modules]
# modules dir sets the place where module files can be found
modules dir = /home/polesz/Projektek/wMUD/modules
# the statesave module is used to save all the state of a running wMUD server.
# Only one module can be specified here, and one MUST be specified. Without
# such a module, wMUD won't be able to save character states, thus won't start
# without one
statesave = sqlite3
# wMUD doesn't speak any protocols on its own. Of course, several protocol
# handler modules are provided with wMUD, and these can be loaded here. Module
# names (thus, protocol names) can be separated by colons. At least one
# protocol module must be loaded here. After startup, a client with
# administrator privileges can load up more modules
protocol = telnet:irc
# statesave * groups can have any keys and values, they won't get checked
# during the configfile read. They are only processed by the state saving
# module loaded in the modules group
[statesave sqlite3]
# for the sqlite3 state saving module, only a state file must be specified
state file = /home/polesz/Projektek/wMUD/data/state.sql
# similar to the statesave modules, protocol settings are also not checked
# during initialization, only while actually loading up the modules.
# telnet interface on all interfaces' port 4000, with the timeout value of 10
# minutes
[protocol telnet global]
port = 4000
timeout = 600
# telnet interface on localhost's port 9683 with the timeout value of 10
# minutes
[protocol telnet local]
address = 127.0.0.1
port = 9683
timeout = 600
# IRC interface listening on all interfaces' port 6667, with no timeout value
[protocol irc global]
port = 6667
# vim: ft=dosini

6
data/world.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<wmud>
<world id="1">
<name>Iminiru</name>
</world>
</wmud>

29
doc/markup.txt Normal file
View File

@ -0,0 +1,29 @@
All texts must conform to the following standards:
They must provide a valid XML is wrapped with this template:
<?xml version="1.0" encoding="utf-8"?>
<wmud>
<formatted-text>
THE TEXT ITSELF
</formatted-text>
</wmud>
Text can be formatted with the following tags:
<normal>TEXT</normal> - provides normal text (clears all formatting)
<bold>TEXT</bold> - provides bold text
<underline>TEXT</underline> - provides underlined text
<COLOUR>TEXT</COLOUR> - provides coloured text in the given colour, see below for exact tag names
Possible values for COLOUR:
* black
* red
* green
* yellow
* blue
* magenta
* cyan
* white
Please note that although most MUD clients support the above text formatting, some older terminals not.
Also, for telnet-like clients, the text is wrapped into 78 columns after formatting has been applied.

View File

@ -0,0 +1,102 @@
## Process this file with automake to produce Makefile.in
# We require automake 1.6 at least.
AUTOMAKE_OPTIONS = 1.6
# This is a blank Makefile.am for using gtk-doc.
# Copy this to your project's API docs directory and modify the variables to
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
# of using the various options.
# The name of the module, e.g. 'glib'.
DOC_MODULE=wmud-session
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
DOC_MODULE_VERSION=1
# The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# The directory containing the source code. Relative to $(srcdir).
# gtk-doc will search all .c & .h files beneath here for inline comments
# documenting the functions and macros.
# e.g. DOC_SOURCE_DIR=../../../gtk
DOC_SOURCE_DIR=$(top_srcdir)/libwmud-session
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS=
# Extra options to supply to gtkdoc-scan.
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
SCAN_OPTIONS=
# Extra options to supply to gtkdoc-mkdb.
# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
MKDB_OPTIONS=--sgml-mode --output-format=xml
# Extra options to supply to gtkdoc-mktmpl
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
MKTMPL_OPTIONS=
# Extra options to supply to gtkdoc-mkhtml
MKHTML_OPTIONS=
# Extra options to supply to gtkdoc-fixref. Not normally needed.
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
FIXXREF_OPTIONS=
# Used for dependencies. The docs will be rebuilt if any of these change.
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
HFILE_GLOB=
CFILE_GLOB=
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
EXTRA_HFILES=
# Header files to ignore when scanning. Use base file name, no paths
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
IGNORE_HFILES=
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES=
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
content_files=
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files
# e.g. expand_content_files=running.sgml
expand_content_files=
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
# signals and properties.
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=$(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(GNET_CFLAGS)
GTKDOC_LIBS=$(GLIB_LIBS) $(GOBJECT_LIBS) $(GNET_LIBS) -L$(top_srcdir)/libwmud-session -lwmud-session-1.0
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make
# Other files to distribute
# e.g. EXTRA_DIST += version.xml.in
EXTRA_DIST +=
# Files not to distribute
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
#DISTCLEANFILES +=
# Comment this out if you want your docs-status tested during 'make check'
if ENABLE_GTK_DOC
#TESTS_ENVIRONMENT = cd $(srcsrc) &&
#TESTS = $(GTKDOC_CHECK)
endif
-include $(top_srcdir)/git.mk

View File

@ -0,0 +1,32 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
[
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<book id="index">
<bookinfo>
<title>wmud-session Reference Manual</title>
<releaseinfo>
for wmud-session [VERSION].
The latest version of this documentation can be found on-line at
<ulink role="online-location" url="http://[SERVER]/wmud-session/index.html">http://[SERVER]/wmud-session/</ulink>.
</releaseinfo>
</bookinfo>
<chapter>
<title>[Insert title here]</title>
<xi:include href="xml/wmud-session.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</book>

View File

@ -0,0 +1,19 @@
<SECTION>
<FILE>wmud-session</FILE>
<TITLE>wMUDSession</TITLE>
wMUDSession
wMUDSessionClass
wMUDSessionPrivate
wmud_session_new
wmud_session_new_with_connection
wmud_session_set_connection
<SUBSECTION Standard>
WMUD_SESSION
WMUD_IS_SESSION
WMUD_TYPE_SESSION
wmud_session_get_type
WMUD_SESSION_CLASS
WMUD_IS_SESSION_CLASS
WMUD_SESSION_GET_CLASS
</SECTION>

View File

@ -0,0 +1,102 @@
## Process this file with automake to produce Makefile.in
# We require automake 1.6 at least.
AUTOMAKE_OPTIONS = 1.6
# This is a blank Makefile.am for using gtk-doc.
# Copy this to your project's API docs directory and modify the variables to
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
# of using the various options.
# The name of the module, e.g. 'glib'.
DOC_MODULE=wmud-world
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
DOC_MODULE_VERSION=1
# The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# The directory containing the source code. Relative to $(srcdir).
# gtk-doc will search all .c & .h files beneath here for inline comments
# documenting the functions and macros.
# e.g. DOC_SOURCE_DIR=../../../gtk
DOC_SOURCE_DIR=$(top_srcdir)/libwmud-world
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS=
# Extra options to supply to gtkdoc-scan.
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
SCAN_OPTIONS=
# Extra options to supply to gtkdoc-mkdb.
# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
MKDB_OPTIONS=--sgml-mode --output-format=xml
# Extra options to supply to gtkdoc-mktmpl
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
MKTMPL_OPTIONS=
# Extra options to supply to gtkdoc-mkhtml
MKHTML_OPTIONS=
# Extra options to supply to gtkdoc-fixref. Not normally needed.
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
FIXXREF_OPTIONS=
# Used for dependencies. The docs will be rebuilt if any of these change.
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
HFILE_GLOB=
CFILE_GLOB=
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
EXTRA_HFILES=
# Header files to ignore when scanning. Use base file name, no paths
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
IGNORE_HFILES=
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES=
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
content_files=
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files
# e.g. expand_content_files=running.sgml
expand_content_files=
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
# signals and properties.
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=$(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(GNET_CFLAGS)
GTKDOC_LIBS=$(GLIB_LIBS) $(GOBJECT_LIBS) $(GNET_LIBS) -L$(top_srcdir)/libwmud-world -lwmud-world-1.0
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make
# Other files to distribute
# e.g. EXTRA_DIST += version.xml.in
EXTRA_DIST +=
# Files not to distribute
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
#DISTCLEANFILES +=
# Comment this out if you want your docs-status tested during 'make check'
if ENABLE_GTK_DOC
#TESTS_ENVIRONMENT = cd $(srcsrc) &&
#TESTS = $(GTKDOC_CHECK)
endif
-include $(top_srcdir)/git.mk

View File

@ -0,0 +1,32 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
[
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<book id="index">
<bookinfo>
<title>wmud-world Reference Manual</title>
<releaseinfo>
for wmud-world [VERSION].
The latest version of this documentation can be found on-line at
<ulink role="online-location" url="http://[SERVER]/wmud-world/index.html">http://[SERVER]/wmud-world/</ulink>.
</releaseinfo>
</bookinfo>
<chapter>
<title>[Insert title here]</title>
<xi:include href="xml/wmud-world.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</book>

View File

@ -0,0 +1,17 @@
<SECTION>
<FILE>wmud-world</FILE>
<TITLE>wMUDWorld</TITLE>
wMUDWorld
wMUDWorldClass
wMUDWorldPrivate
wmud_world_new
<SUBSECTION Standard>
WMUD_WORLD
WMUD_IS_WORLD
WMUD_TYPE_WORLD
wmud_world_get_type
WMUD_WORLD_CLASS
WMUD_IS_WORLD_CLASS
WMUD_WORLD_GET_CLASS
</SECTION>

1
doc/world.xsd Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?>

View File

@ -0,0 +1,6 @@
LIBWMUD_PROTOCOL_TELNET_VERSION=1:0:0
lib_LTLIBRARIES = libwmud-protocol-telnet-1.0.la
libwmud_protocol_telnet_1_0_la_SOURCES = wmud-protocol-telnet.c
libwmud_protocol_telnet_1_0_la_CFLAGS = $(CFLAGS) $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(GNET_CFLAGS) -Wall -I../src -I../libwmud-session
libwmud_protocol_telnet_1_0_la_LIBADD = $(LIBS) $(GLIB_LIBS) $(GOBJECT_LIBS) $(GNET_LIBS)
libwmud_protocol_telnet_1_0_la_LDFLAGS = -version-info $(LIBWMUD_PROTOCOL_TELNET_VERSION)

View File

@ -0,0 +1,102 @@
#include "wmud-module.h"
gboolean
wmud_protocol_telnet_load(wMUDConfiguration *configuration)
{
/*
GSList *temp;
wMUDConfigurationInterface *interface;
gchar *iface_name;
struct _wMUDIfaceFinder *finder;
finder = g_new0(struct _wMUDIfaceFinder, 1);
finder->type = WMUD_SESSION_TYPE_TELNET;
finder->name = iface_name = g_utf8_offset_to_pointer(group, 7);
Context;
temp = g_slist_find_custom(conf->interfaces, finder, _wmud_find_iface);
Context;
g_free(finder);
if (temp == NULL)
{
Context;
interface = (wMUDConfigurationInterface *)g_new0(wMUDConfigurationInterface, 1);
interface->name = g_strdup(iface_name);
interface->type = WMUD_SESSION_TYPE_TELNET;
conf->interfaces = g_slist_append(conf->interfaces, interface);
}
else
{
Context;
interface = (wMUDConfigurationInterface *)(temp->data);
}
if (g_utf8_collate("port", key) == 0)
{
guint64 portnumber;
gchar *endptr;
portnumber = g_ascii_strtoull(value, &endptr, 10);
if ((endptr != NULL) && (*endptr != 0))
{
wmud_log_error("Error in configuration file. Value of port can only contain numbers in group [%s]!", group);
}
if (interface->inetaddr == NULL)
{
interface->inetaddr = gnet_inetaddr_new("0.0.0.0", portnumber);
}
else
{
gnet_inetaddr_set_port(interface->inetaddr, (gint)portnumber);
}
g_pattern_spec_free(group_ptn);
return TRUE;
}
if (g_utf8_collate("address", key) == 0)
{
GInetAddr *temp = gnet_inetaddr_new(value, 0);
if (interface->inetaddr)
{
gnet_inetaddr_set_port(temp, gnet_inetaddr_get_port(interface->inetaddr));
gnet_inetaddr_unref(interface->inetaddr);
interface->inetaddr = NULL;
}
interface->inetaddr = temp;
g_pattern_spec_free(group_ptn);
return TRUE;
}
if (g_utf8_collate("timeout", key) == 0)
{
guint64 timeout;
gchar *endptr;
timeout = g_ascii_strtoull(value, &endptr, 10);
if ((endptr != NULL) && (*endptr != 0))
{
wmud_log_error("Error in configuration file. Value of timeout can only contain numbers! in group [%s]", group);
}
interface->timeout = (guint)timeout;
g_pattern_spec_free(group_ptn);
return TRUE;
}
*/
return TRUE;
}
void
wmud_protocol_telnet_unload(void)
{
}

View File

@ -0,0 +1,6 @@
LIBWMUD_SESSION_VERSION=1:0:0
lib_LTLIBRARIES = libwmud-session-1.0.la
libwmud_session_1_0_la_SOURCES = wmud-session.c
libwmud_session_1_0_la_CFLAGS = $(CFLAGS) $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(GNET_CFLAGS) -Wall
libwmud_session_1_0_la_LIBADD = $(LIBS) $(GLIB_LIBS) $(GOBJECT_LIBS) $(GNET_LIBS)
libwmud_session_1_0_la_LDFLAGS = -version-info $(LIBWMUD_SESSION_VERSION)

View File

@ -0,0 +1,304 @@
/* wMUDSession - wMUD Session handler object
* Copyright (C) 2010, Gergely Polonkai
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gnet.h>
#include "wmud-session.h"
/** SECTION:objects
* @short_description: wMUD Session object
* @title: wMUD Session handler object
*
* wMUDSession is an object to store session-related information in
* wMUD
*/
/* --- macros --- */
#define WMUD_SESSION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WMUD_TYPE_SESSION, wMUDSessionPrivate))
/* --- structures --- */
struct _wMUDSessionPrivate
{
GConn *connection;
wMUDSessionType type;
};
/* --- signals --- */
/* --- properties --- */
enum
{
PROP_0,
PROP_CONNECTION,
PROP_TYPE
};
/* --- prototypes --- */
static void wmud_session_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
static void wmud_session_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
static void wmud_session_dispose(GObject *object);
static void wmud_session_finalize(GObject *object);
static void wmud_session_class_init(wMUDSessionClass *klass);
static void wmud_session_init(wMUDSession *self);
wMUDSession *wmud_session_new(void);
wMUDSession *wmud_session_new_with_connection(GConn *connection);
GConn *wmud_session_get_connection(wMUDSession *session);
void wmud_session_set_connection(wMUDSession *session, GConn *connection);
wMUDSessionType wmud_session_get_session_type(wMUDSession *session);
void wmud_session_set_session_type(wMUDSession *session, wMUDSessionType type);
/* --- variables --- */
/* --- functions --- */
G_DEFINE_TYPE(wMUDSession, wmud_session, G_TYPE_OBJECT);
#define WMUD_TYPE_SESSION_TYPE wmud_session_type_get_type()
static GType
wmud_session_type_get_type(void)
{
static GType wmud_session_type_type = 0;
static const GEnumValue wmud_session_types[] = {
{ WMUD_SESSION_TYPE_UNKNOWN, "Unknown session type", "unknown" },
{ WMUD_SESSION_TYPE_TELNET, "Telnet session", "telnet" },
{ 0, NULL, NULL }
};
if (!wmud_session_type_type)
{
wmud_session_type_type = g_enum_register_static("wMUDSessionType", wmud_session_types);
}
return wmud_session_type_type;
}
static void
wmud_session_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
wMUDSession *self = WMUD_SESSION(object);
switch (property_id)
{
case PROP_CONNECTION:
if (self->priv->connection)
{
gnet_conn_unref(self->priv->connection);
}
self->priv->connection = (GConn *)g_value_get_pointer(value);
if (self->priv->connection)
{
gnet_conn_ref(self->priv->connection);
}
break;
case PROP_TYPE:
self->priv->type = g_value_get_enum(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void
wmud_session_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
wMUDSession *self = WMUD_SESSION(object);
switch (property_id)
{
case PROP_CONNECTION:
g_value_set_pointer(value, self->priv->connection);
break;
case PROP_TYPE:
g_value_set_enum(value, self->priv->type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void
wmud_session_dispose(GObject *object)
{
G_OBJECT_CLASS(wmud_session_parent_class)->dispose(object);
}
static void
wmud_session_finalize(GObject *object)
{
wMUDSession *self = WMUD_SESSION(object);
if (self->priv->connection)
{
gnet_conn_disconnect(self->priv->connection);
gnet_conn_unref(self->priv->connection);
self->priv->connection = NULL;
}
G_OBJECT_CLASS(wmud_session_parent_class)->finalize(object);
}
static void
wmud_session_class_init(wMUDSessionClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GParamSpec *wmud_session_param_spec;
gobject_class->set_property = wmud_session_set_property;
gobject_class->get_property = wmud_session_get_property;
gobject_class->dispose = wmud_session_dispose;
gobject_class->finalize = wmud_session_finalize;
g_type_class_add_private(klass, sizeof(wMUDSessionPrivate));
wmud_session_param_spec = g_param_spec_pointer("connection", "Connection handle", "GConn * handle of the connection", G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property(gobject_class, PROP_CONNECTION, wmud_session_param_spec);
wmud_session_param_spec = g_param_spec_enum("type", "SessionType", "Type of the session's connection", WMUD_TYPE_SESSION_TYPE, WMUD_SESSION_TYPE_UNKNOWN, G_PARAM_READWRITE);
g_object_class_install_property(gobject_class, PROP_TYPE, wmud_session_param_spec);
}
static void
wmud_session_init(wMUDSession *self)
{
wMUDSessionPrivate *priv;
self->priv = priv = WMUD_SESSION_GET_PRIVATE(self);
priv->connection = NULL;
}
/**
* wmud_session_new:
*
* Creates a new wMUDSession object
*
* Returns: a new instance of wMUDSession
*/
wMUDSession *
wmud_session_new(void)
{
wMUDSession *new_session = g_object_new(WMUD_TYPE_SESSION, NULL);
return new_session;
}
/**
* wmud_session_new_with_connection:
* @connection: the connection this session is bound to. This object is
* g_unref()'d when the Session object is disposed
*
* Returns: a new instance of wMUDSession with the connection property set
*/
wMUDSession *
wmud_session_new_with_connection(GConn *connection)
{
wMUDSession *new_session = g_object_new(WMUD_TYPE_SESSION, "connection", connection, NULL);
wmud_session_set_connection(new_session, connection);
return new_session;
}
GConn *
wmud_session_get_connection(wMUDSession *session)
{
GConn *connection = NULL;
GValue value = {0};
g_value_init(&value, G_TYPE_POINTER);
wmud_session_get_property(G_OBJECT(session), PROP_CONNECTION, &value, NULL);
connection = g_value_get_pointer(&value);
g_value_unset(&value);
return connection;
}
/**
* wmud_session_set_connection:
* @session: the object which should receive the new connection
* @connection: the connection this session should be bound to. This object is g_unref()'d when the Session object is disposed
*/
void
wmud_session_set_connection(wMUDSession *session, GConn *connection)
{
GValue value = {0};
g_value_init(&value, G_TYPE_POINTER);
g_value_set_pointer(&value, (gpointer)connection);
wmud_session_set_property(G_OBJECT(session), PROP_CONNECTION, &value, NULL);
g_value_unset(&value);
}
/**
* wmud_session_has_connection:
* @session: the object which should be inspected
* @connection: the connection we are looking for
*
* Checks if the given #wMUDSession has the given #GConn connection
*
* Returns: %TRUE, if the connection is owned by this session, %FALSE otherwise
*/
gboolean
wmud_session_has_connection(wMUDSession *session, GConn *connection)
{
if (session->priv->connection == connection)
return TRUE;
return FALSE;
}
wMUDSessionType
wmud_session_get_session_type(wMUDSession *session)
{
GValue value = {0};
g_value_init(&value, WMUD_TYPE_SESSION_TYPE);
wmud_session_get_property(G_OBJECT(session), PROP_TYPE, &value, NULL);
return g_value_get_enum(&value);
}
void
wmud_session_set_session_type(wMUDSession *session, wMUDSessionType type)
{
GValue value = {0, };
g_value_init(&value, WMUD_TYPE_SESSION_TYPE);
g_value_set_enum(&value, type);
wmud_session_set_property(G_OBJECT(session), PROP_TYPE, &value, NULL);
}
wMUDSession *
wmud_session_ref(wMUDSession *session)
{
return WMUD_SESSION(g_object_ref(G_OBJECT(session)));
}
void
wmud_session_unref(wMUDSession *session)
{
g_object_unref(G_OBJECT(session));
}

View File

@ -0,0 +1,53 @@
#ifndef __WMUD_SESSION_H__
#define __WMUD_SESSION_H__
#include <glib.h>
#include <glib-object.h>
#include <gnet.h>
#define WMUD_TYPE_SESSION wmud_session_get_type()
#define WMUD_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WMUD_TYPE_SESSION, wMUDSession))
#define WMUD_IS_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WMUD_TYPE_SESSION))
#define WMUD_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WMUD_TYPE_SESSION, wMUDSessionClass))
#define WMUD_IS_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WMUD_TYPE_SESSION))
#define WMUD_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WMUD_TYPE_SESSION, wMUDSessionClass))
typedef enum
{
WMUD_SESSION_TYPE_UNKNOWN,
WMUD_SESSION_TYPE_TELNET,
WMUD_SESSION_TYPE_IRC,
WMUD_SESSION_TYPE_HTTP
} wMUDSessionType;
typedef struct _wMUDSession wMUDSession;
typedef struct _wMUDSessionClass wMUDSessionClass;
typedef struct _wMUDSessionPrivate wMUDSessionPrivate;
struct _wMUDSession
{
GObject parent_object;
wMUDSessionPrivate *priv;
};
struct _wMUDSessionClass
{
GObjectClass parent_class;
};
GType wmud_session_get_type(void);
wMUDSession *wmud_session_new(void);
wMUDSession *wmud_session_new_with_connection(GConn *connection);
gboolean wmud_session_has_connection(wMUDSession *session, GConn *connection);
wMUDSession *wmud_session_ref(wMUDSession *session);
void wmud_session_unref(wMUDSession *session);
GConn *wmud_session_get_connection(wMUDSession *session);
void wmud_session_set_connection(wMUDSession *session, GConn *connection);
wMUDSessionType wmud_session_get_session_type(wMUDSession *session);
void wmud_session_set_session_type(wMUDSession *session, wMUDSessionType type);
#endif /* __WMUD_SESSION_H__ */

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: wMUDSession
Description: Library to handle wMUD sessions
Requires: glib-2.0 gobject-2.0
Version: PACKAGE_VERSION
Libs: -L${libdir} -lwmud-session-1.0
Cflags: -I${includedir}/wmud-session -I${libdir}/wmud-session/include

View File

@ -0,0 +1,6 @@
LIBWMUD_STATE_SQLITE3_VERSION=1:0:0
lib_LTLIBRARIES = libwmud-state-sqlite3-1.0.la
libwmud_state_sqlite3_1_0_la_SOURCES = wmud-state-sqlite3.c
libwmud_state_sqlite3_1_0_la_CFLAGS = $(CFLAGS) $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(GNET_CFLAGS) -Wall -I../src -I../libwmud-session
libwmud_state_sqlite3_1_0_la_LIBADD = $(LIBS) $(GLIB_LIBS) $(GOBJECT_LIBS) $(GNET_LIBS)
libwmud_state_sqlite3_1_0_la_LDFLAGS = -version-info $(LIBWMUD_STATE_SQLITE3_VERSION)

View File

@ -0,0 +1,91 @@
#include <glib.h>
#include <sqlite3.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "module.h"
static gchar *state_file = NULL;
static sqlite3 *statesave_connection = NULL;
gboolean
wmud_statesave_sqlite3_is_statesave(void)
{
return TRUE;
}
static gint
_wmud_statesave_sqlite3_find_config_group(gconstpointer list_data, gconstpointer lookup_data)
{
wMUDConfigurationGroup *group = (wMUDConfigurationGroup *)list_data;
gchar *name_to_find = (gchar *)lookup_data;
Context return g_utf8_collate(group->name, name_to_find);
}
static void
_wmud_statesave_sqlite3_parse_config(gpointer data, gpointer userdata)
{
wMUDConfigurationValue *parameter = (wMUDConfigurationValue *)data;
if (g_utf8_collate("state file", parameter->key) == 0)
{
state_file = g_strdup(parameter->value);
}
}
gboolean
wmud_statesave_sqlite3_load(wMUDConfiguration *config)
{
GSList *statesave_params;
wMUDConfigurationGroup *config_group;
wmud_log_debug("Initializing SQLite3 state saving module...");
if (!sqlite3_threadsafe())
{
wmud_log_error("SQLite3 library is not compiled in a thread-safe manner.");
return FALSE;
}
Context statesave_params = g_slist_find_custom(config->statesave_parameters, "sqlite3", _wmud_statesave_sqlite3_find_config_group);
if (statesave_params == NULL)
{
wmud_log_error("Cannot find group [statesave sqlite3] in configfile!");
return FALSE;
}
config_group = (wMUDConfigurationGroup *)(statesave_params->data);
g_slist_foreach(config_group->datalist, _wmud_statesave_sqlite3_parse_config, NULL);
if (state_file == NULL)
{
wmud_log_error("Cannot find state file parameter in configuration file (should be under group [statesave sqlite3]");
return FALSE;
}
wmud_log_debug("Will save state into SQLite3 file %s", state_file);
switch (sqlite3_open(state_file, &statesave_connection))
{
case SQLITE_OK:
wmud_log_info("State file opened successfully");
break;
default:
wmud_log_error("Unprocessed return value from sqlite3_open()!");
return FALSE;
break;
}
return TRUE;
}
void
wmud_statesave_sqlite3_unload(void)
{
sqlite3_close(statesave_connection);
}

View File

@ -0,0 +1,4 @@
lib_LTLIBRARIES = libwmud-world-1.0.la
libwmud_world_1_0_la_SOURCES = wmud-world.c
libwmud_world_1_0_la_CFLAGS = $(CFLAGS) $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(GNET_CFLAGS) -Wall
libwmud_world_1_0_la_LIBADD = $(LIBS) $(GLIB_LIBS) $(GOBJECT_LIBS) $(GNET_LIBS)

104
libwmud-world/wmud-world.c Normal file
View File

@ -0,0 +1,104 @@
#include "wmud-world.h"
#define WMUD_WORLD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WMUD_TYPE_WORLD, wMUDWorldPrivate))
struct _wMUDWorldPrivate
{
gchar *name;
};
enum
{
PROP_0,
PROP_NAME
};
G_DEFINE_TYPE(wMUDWorld, wmud_world, G_TYPE_OBJECT);
static void
wmud_world_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
wMUDWorld *self = WMUD_WORLD(object);
switch (property_id)
{
case PROP_NAME:
g_free(self->priv->name);
self->priv->name = g_value_dup_string(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void
wmud_world_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
wMUDWorld *self = WMUD_WORLD(object);
switch (property_id)
{
case PROP_NAME:
g_value_set_string(value, self->priv->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void
wmud_world_dispose(GObject *object)
{
G_OBJECT_CLASS(wmud_world_parent_class)->dispose(object);
}
static void
wmud_world_finalize(GObject *object)
{
wMUDWorld *self = WMUD_WORLD(object);
if (self->priv->name)
{
g_free(self->priv->name);
}
G_OBJECT_CLASS(wmud_world_parent_class)->finalize(object);
}
static void
wmud_world_class_init(wMUDWorldClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GParamSpec *wmud_world_param_spec;
gobject_class->set_property = wmud_world_set_property;
gobject_class->get_property = wmud_world_get_property;
gobject_class->dispose = wmud_world_dispose;
gobject_class->finalize = wmud_world_finalize;
g_type_class_add_private(klass, sizeof(wMUDWorldPrivate));
wmud_world_param_spec = g_param_spec_string("name", "World name", "Set the name of the world", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property(gobject_class, PROP_NAME, wmud_world_param_spec);
}
static void
wmud_world_init(wMUDWorld *self)
{
wMUDWorldPrivate *priv;
self->priv = priv = WMUD_WORLD_GET_PRIVATE(self);
priv->name = NULL;
}
wMUDWorld *
wmud_world_new(void)
{
wMUDWorld *new_world = g_object_new(WMUD_TYPE_WORLD, NULL);
return new_world;
}

View File

@ -0,0 +1,34 @@
#ifndef __WMUD_WORLD_H__
#define __WMUD_WORLD_H__
#include <glib-object.h>
#define WMUD_TYPE_WORLD wmud_world_get_type()
#define WMUD_WORLD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WMUD_TYPE_WORLD, wMUDWorld))
#define WMUD_IS_WORLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WMUD_TYPE_WORLD))
#define WMUD_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WMUD_TYPE_WORLD, wMUDWorldClass))
#define WMUD_IS_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WMUD_TYPE_WORLD))
#define WMUD_WORLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WMUD_TYPE_WORLD, wMUDWorldClass))
typedef struct _wMUDWorld wMUDWorld;
typedef struct _wMUDWorldClass wMUDWorldClass;
typedef struct _wMUDWorldPrivate wMUDWorldPrivate;
struct _wMUDWorld
{
GObject parent_object;
wMUDWorldPrivate *priv;
};
struct _wMUDWorldClass
{
GObjectClass parent_class;
};
GType wmud_world_get_type(void);
wMUDWorld *wmud_world_new(void);
#endif /* __WMUD_WORLD_H__ */

4
src/Makefile.am Normal file
View File

@ -0,0 +1,4 @@
bin_PROGRAMS = wmud
wmud_SOURCES = wmud.c logger.c ansi.c networking.c world.c sessions.c configfile.c commands.c chat.c irc.c modules.c
wmud_CFLAGS = $(CFLAGS) $(EXTLIBS_CFLAGS) -I../libwmud-session -I../libwmud-world -Wall
wmud_LDADD = $(LIBS) $(EXTLIBS_LIBS) -L../libwmud-session -lwmud-session-1.0 -L../libwmud-world -lwmud-world-1.0

104
src/ansi.c Normal file
View File

@ -0,0 +1,104 @@
#include <glib.h>
#include <string.h>
#include "ansi.h"
typedef struct _wmud_tag_to_ansi {
gchar *open_tag;
gint open_tag_length;
gchar *close_tag;
gint close_tag_length;
gchar *ansi_sequence;
} wmud_tag_to_ansi;
static wmud_tag_to_ansi tags[] = {
{ "<bold>", 6, "</bold>", 7, ANSI_BOLD },
{ "<underline>", 11, "</underline>", 12, ANSI_UNDERLINE },
{ "<normal>", 8, "</normal>", 9, ANSI_NORMAL },
{ "<black>", 7, "</black>", 8, ANSI_COLOR_BLACK },
{ "<red>", 5, "</red>", 6, ANSI_COLOR_RED },
{ "<green>", 7, "</green>", 8, ANSI_COLOR_GREEN },
{ "<yellow>", 8, "</yellow>", 9, ANSI_COLOR_YELLOW },
{ "<blue>", 6, "</blue>", 7, ANSI_COLOR_BLUE },
{ "<magenta>", 9, "</magenta>", 10, ANSI_COLOR_MAGENTA },
{ "<cyan>", 6, "</cyan>", 7, ANSI_COLOR_CYAN },
{ "<white>", 7, "</colour>", 8, ANSI_COLOR_WHITE },
};
static void
_str_append_string(gchar **dest, gchar *src)
{
gchar *temp;
temp = g_strdup(*dest);
*dest = g_strdup_printf("%s%s", temp, src);
g_free(temp);
}
static void
_str_append_char(gchar **dest, gchar src)
{
gchar *temp;
temp = g_strdup(*dest);
*dest = g_strdup_printf("%s%c", temp, src);
g_free(temp);
}
static void
_add_remaining_formatters(gpointer element, gpointer data)
{
_str_append_string(data, (gchar *)element);
}
gboolean
wmud_text_to_ansi(gchar *text, gchar **result)
{
gchar *a;
GSList *current_formatters = NULL;
gchar *r = g_strdup("");
for (a = text; *a; a++)
{
gint i;
gboolean found = FALSE;
for (i = 0; i < sizeof(tags) / sizeof(wmud_tag_to_ansi); i++)
{
if (g_strncasecmp(a, tags[i].open_tag, tags[i].open_tag_length) == 0)
{
_str_append_string(&r, tags[i].ansi_sequence);
current_formatters = g_slist_append(current_formatters, tags[i].ansi_sequence);
a += tags[i].open_tag_length - 1;
found = TRUE;
break;
}
if (g_strncasecmp(a, tags[i].close_tag, tags[i].close_tag_length) == 0)
{
_str_append_string(&r, ANSI_NORMAL);
current_formatters = g_slist_delete_link(current_formatters, g_slist_last(current_formatters));
g_slist_foreach(current_formatters, _add_remaining_formatters, &r);
a += tags[i].close_tag_length - 1;
found = TRUE;
break;
}
}
if (found)
{
continue;
}
_str_append_char(&r, *a);
}
_str_append_string(&r, ANSI_NORMAL);
*result = r;
return TRUE;
}

20
src/ansi.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef __WMUD_CORE_ANSI_H__
#define __WMUD_CORE_ANSI_H__
#define ANSI_CSI "\x1b["
#define ANSI_NORMAL ANSI_CSI "0m"
#define ANSI_BOLD ANSI_CSI "1m"
#define ANSI_UNDERLINE ANSI_CSI "4m"
#define ANSI_COLOR_BLACK ANSI_CSI "30m"
#define ANSI_COLOR_RED ANSI_CSI "31m"
#define ANSI_COLOR_GREEN ANSI_CSI "32m"
#define ANSI_COLOR_YELLOW ANSI_CSI "33m"
#define ANSI_COLOR_BLUE ANSI_CSI "34m"
#define ANSI_COLOR_MAGENTA ANSI_CSI "35m"
#define ANSI_COLOR_CYAN ANSI_CSI "36m"
#define ANSI_COLOR_WHITE ANSI_CSI "37m"
gboolean wmud_text_to_ansi(gchar *text, gchar **result);
#endif /* __WMUD_CODE__ANSI_H__ */

42
src/chat.c Normal file
View File

@ -0,0 +1,42 @@
#include <glib.h>
#include "wmud.h"
#include "logger.h"
gpointer
wmud_chat_thread(gpointer data)
{
wMUDThreadData *thread_data = (wMUDThreadData *)data;
Context wmud_log_info("Initializing chat layer...");
/* g_main_context_get_thread_default() is only available since GLib 2.22;
* use g_main_context_new() otherwise
*/
#if (((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION >= 22)) || (GLIB_MAJOR_VERSION > 2))
thread_data->main_context = g_main_context_get_thread_default();
#else
thread_data->main_context = g_main_context_new();
#endif
thread_data->main_loop = g_main_loop_new(thread_data->main_context, FALSE);
/* Do the real initialization work here */
/* End of initialization */
wmud_log_info("Chat layer initialized");
Context;
thread_data->running = TRUE;
g_main_loop_run(thread_data->main_loop);
wmud_log_info("Chat layer shutting down");
g_main_loop_unref(thread_data->main_loop);
thread_data->main_loop = NULL;
thread_data->running = FALSE;
Context;
return NULL;
}

7
src/chat.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef __WMUD_CORE_CHAT_H__
#define __WMUD_CORE_CHAT_H__
gpointer wmud_chat_thread(gpointer data);
#endif /* __WMUD_CORE_CHAT_H__ */

265
src/commands.c Normal file
View File

@ -0,0 +1,265 @@
#include <glib.h>
#include <gnet.h>
#include <string.h>
#include "wmud.h"
#include "logger.h"
#include "networking.h"
#include "sessions.h"
#include "wmud-session.h"
#define COMMAND_DELIMITERS " \t\n\r"
#define WMUD_COMMAND_ERROR g_quark_from_string("wMUDCommandError")
enum {
WMUD_COMMAND_ERROR_SUCCESS /* Will never be used */
};
/* Internal command callback function for prototypes and function headers. If
* you modify this, don't forget to modify the wMUDCommandCallback type!
*/
#define WMUD_INTERNAL_COMMAND(x) gboolean x (wMUDSession *session, gchar **params, GError **error)
/* Internal command callback function type to be usd in the wMUDCommand struct.
* If you modify this, don't forget to modify the WMUD_INTERNAL_COMMAND(x)
* macro!
*/
typedef gboolean (*wMUDCommandCallback)(wMUDSession *session, gchar **params, GError **error);
typedef struct _wMUDCommand
{
gchar *cmd;
gchar *collate_key;
gint min_params;
gint max_params;
wMUDCommandCallback callback;
} wMUDCommand;
struct _wMUDSplitHelper
{
gchar **list;
gint position;
};
WMUD_INTERNAL_COMMAND(_wmud_command_internal_quit);
static wMUDCommand _wmud_command_list[] = {
{ "QUIT", NULL, 0, 0, _wmud_command_internal_quit },
{ NULL, NULL, 0, 0, NULL }
};
WMUD_INTERNAL_COMMAND(_wmud_command_internal_quit)
{
wmud_log_debug("Here in the QUIT function");
wmud_finish_session(session, "Good bye");
return TRUE;
}
static void
_add_words(gpointer data, gpointer user_data)
{
struct _wMUDSplitHelper *split_data = (struct _wMUDSplitHelper *)user_data;
gchar *word = (gchar *)data;
Context split_data->list[split_data->position] = word;
split_data->position++;
}
static void
_free_words(gpointer data, gpointer user_data)
{
g_free(data);
}
static gint
_wmud_split_command(gchar *command, gchar ***list)
{
gchar *a;
gint word_started_at = 0;
gint apos_at = -1;
gint quot_at = -1;
gboolean was_in_word = FALSE;
gboolean in_string = TRUE;
GSList *word_list = NULL;
gchar **ret;
struct _wMUDSplitHelper split_data;
gint word_count;
for (a = command; in_string; a++)
{
if (*a == 0)
{
in_string = FALSE;
}
if (
(*a == 0)
|| (
(quot_at == -1)
&& (*a == '\'')
)
|| (
(apos_at == -1)
&& (*a == '"')
)
|| (
(apos_at != -1)
&& (*a == '\'')
)
|| (
(quot_at != -1)
&& (*a == '"')
)
|| (
(apos_at == -1)
&& (quot_at == -1)
&& strchr(COMMAND_DELIMITERS, *a)
)
)
{
if (was_in_word)
{
was_in_word = FALSE;
word_list = g_slist_append(word_list, g_strndup((command + word_started_at), (a - command) - word_started_at));
word_started_at = (a - command);
}
if ((apos_at == -1) && (*a == '"'))
{
if (quot_at == -1)
{
quot_at = (a - command) - 1;
if (quot_at == -1)
{
quot_at = 0;
}
}
else
{
quot_at = -1;
}
}
if ((quot_at == -1) && (*a == '\''))
{
if (apos_at == -1)
{
apos_at = (a - command) - 1;
if (apos_at == -1)
{
apos_at = 0;
}
}
else
{
apos_at = -1;
}
}
word_started_at++;
continue;
}
was_in_word = TRUE;
}
if ((quot_at != -1) || (apos_at != -1))
{
wmud_log_debug("Got illegal string: %s", command);
g_slist_foreach(word_list, _free_words, NULL);
g_slist_free(word_list);
return -1;
}
word_count = g_slist_length(word_list);
Context ret = g_new0(gchar *, word_count + 1);
split_data.list = ret;
split_data.position = 0;
Context g_slist_foreach(word_list, _add_words, &split_data);
g_slist_free(word_list);
if (list != NULL)
{
Context *list = ret;
}
return word_count;
}
void
wmud_process_command(GConn *connection, gchar *command)
{
gchar **command_parts = NULL,
*command_casefold,
*command_key;
gint word_count;
wMUDCommand *command_rec;
gboolean command_found = FALSE;
wMUDSession *session;
session = wmud_session_for_connection(connection);
if (session == NULL)
{
wmud_log_error("Processing command for a non-existant session!");
return;
}
Context;
wmud_log_debug("Processing command %s", command);
Context word_count = _wmud_split_command(command, &command_parts);
if (word_count == -1)
{
Context wmud_connection_send(connection, "Illegal command. Maybe you forgot a closing apostroph or quote?");
Context return;
}
if (word_count == 0)
{
wmud_log_debug("Got an empty line");
return;
}
command_casefold = g_utf8_casefold(command_parts[0], -1);
command_key = g_utf8_collate_key(command_casefold, -1);
g_free(command_casefold);
for (command_rec = _wmud_command_list; command_rec->cmd; command_rec++)
{
if (command_rec->collate_key == NULL)
{
gchar *temp;
temp = g_utf8_casefold(command_rec->cmd, -1);
command_rec->collate_key = g_utf8_collate_key(temp, -1);
g_free(temp);
}
if (strcmp(command_key, command_rec->collate_key) == 0)
{
gint param_count = g_strv_length(command_parts) - 1;
GError *error = NULL;
command_found = TRUE;
if ((param_count < command_rec->min_params) || (param_count > command_rec->max_params))
{
Context wmud_connection_send(connection, "Wrong number of parameters. Maybe you should try HELP %s", command_rec->cmd);
}
wmud_log_debug("Executing command %s, having %d parameters", command_rec->cmd, param_count);
(command_rec->callback)(session, command_parts + 1, &error);
break;
}
}
g_free(command_key);
if (!command_found)
{
/* TODO: command prediction (Maybe you wanted to type...) */
Context wmud_connection_send(connection, "Unknown command.");
}
Context g_strfreev(command_parts);
}

9
src/commands.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __WMUD_CORE_COMMANDS_H
#define __WMUD_CORE_COMMANDS_H
#include <gnet.h>
void wmud_process_command(GConn *connection, gchar *command);
#endif /* __WMUD_CORE_COMMANDS_H */

75
src/configfile-module.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef __WMUD_MODULE_CONFIGFILE_H__
#define __WMUD_MODULE_CONFIGFILE_H__
#include "wmud-session.h"
typedef enum {
WMUD_CONF_LOG_NONE,
WMUD_CONF_LOG_SYSLOG,
WMUD_CONF_LOG_FILE,
WMUD_CONF_LOG_CONSOLE
} wMUDConfigurationLogging;
typedef enum {
WMUD_CONF_DAEMONIZE_YES,
WMUD_CONF_DAEMONIZE_NO,
WMUD_CONF_DAEMONIZE_FORCE
} wMUDConfigurationDaemonize;
typedef struct {
/* A GSList of _wMUDConfigurationInterfaces */
GSList *interfaces;
wMUDConfigurationLogging log_dest;
gchar *logfile;
gboolean log_found;
wMUDConfigurationLogging debug_log_dest;
gchar *debug_logfile;
gboolean debug_log_found;
wMUDConfigurationLogging info_log_dest;
gchar *info_logfile;
gboolean info_log_found;
wMUDConfigurationLogging warning_log_dest;
gchar *warning_logfile;
gboolean warning_log_found;
wMUDConfigurationLogging error_log_dest;
gchar *error_logfile;
gboolean error_log_found;
wMUDConfigurationDaemonize daemonize;
gboolean chat_enabled;
gboolean dbus_enabled;
gchar *modules_dir;
gchar *statesave_module;
gchar **protocol_modules;
GSList *statesave_parameters;
GSList *protocol_parameters;
} wMUDConfiguration;
typedef struct {
wMUDSessionType type;
gchar *name;
GInetAddr *inetaddr;
guint timeout;
} wMUDConfigurationInterface;
typedef struct {
gchar *name;
GSList *datalist;
} wMUDConfigurationGroup;
typedef struct {
gchar *key;
gchar *value;
} wMUDConfigurationValue;
#endif /* __WMUD_MODULE_CONFIGFILE_H__ */

901
src/configfile.c Normal file
View File

@ -0,0 +1,901 @@
#include <glib.h>
#include <gnet.h>
#include <string.h>
#include "wmud.h"
#include "configfile.h"
#include "logger.h"
struct _wMUDIfaceFinder {
wMUDSessionType type;
gchar *name;
};
static gint
_wmud_find_keyed_member(gconstpointer this_group, gconstpointer group_to_find)
{
wMUDConfigurationGroup *group_data = (wMUDConfigurationGroup *)this_group;
gchar *name = (gchar *)group_to_find;
return g_utf8_collate(group_data->name, name);
}
static gint
_wmud_find_iface(gconstpointer iface, gconstpointer iffinder)
{
wMUDConfigurationInterface *interface = (wMUDConfigurationInterface *)iface;
gchar *name_to_find = ((struct _wMUDIfaceFinder *)iffinder)->name;
wMUDSessionType type = ((struct _wMUDIfaceFinder *)iffinder)->type;
return ((g_utf8_collate(interface->name, name_to_find) == 0) && (interface->type == type)) ? 0 : 1;
}
gboolean
_wmud_config_process_value(wMUDConfiguration *conf, gchar *group, gchar *key, gchar *value)
{
GPatternSpec *group_ptn;
if (g_utf8_collate("general", group) == 0)
{
if (
(g_utf8_collate("log", key) == 0)
|| (g_utf8_collate("debug log", key) == 0)
|| (g_utf8_collate("info log", key) == 0)
|| (g_utf8_collate("warning log", key) == 0)
|| (g_utf8_collate("error log", key) == 0)
)
{
if (g_utf8_collate("none", value) == 0)
{
if (g_utf8_collate("log", key) == 0)
{
conf->log_found = TRUE;
conf->log_dest = WMUD_CONF_LOG_NONE;
if (conf->logfile)
{
g_free(conf->logfile);
conf->logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("debug log", key) == 0)
{
conf->debug_log_found = TRUE;
conf->debug_log_dest = WMUD_CONF_LOG_NONE;
if (conf->debug_logfile)
{
g_free(conf->debug_logfile);
conf->debug_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("info log", key) == 0)
{
conf->info_log_found = TRUE;
conf->info_log_dest = WMUD_CONF_LOG_NONE;
if (conf->info_logfile)
{
g_free(conf->info_logfile);
conf->info_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("warning log", key) == 0)
{
conf->warning_log_found = TRUE;
conf->warning_log_dest = WMUD_CONF_LOG_NONE;
if (conf->warning_logfile)
{
g_free(conf->warning_logfile);
conf->warning_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("error log", key) == 0)
{
conf->error_log_found = TRUE;
conf->error_log_dest = WMUD_CONF_LOG_NONE;
if (conf->error_logfile)
{
g_free(conf->error_logfile);
conf->error_logfile = NULL;
}
return TRUE;
}
}
if (strncmp("file:", value, 5) == 0)
{
if (g_utf8_collate("log", key) == 0)
{
gchar *temp_file;
wMUDConfigurationLogging temp_logging;
gboolean temp_found;
temp_logging = conf->log_dest;
temp_file = conf->logfile;
temp_found = conf->log_found;
conf->logfile = g_strdup(value + 5);
if (!*(conf->logfile))
{
wmud_log_error("Log file name must contain a string for %s/%s!", group, key);
conf->logfile = temp_file;
return FALSE;
}
if (temp_file)
{
g_free(temp_file);
}
conf->log_dest = WMUD_CONF_LOG_FILE;
conf->log_found = TRUE;
return TRUE;
}
else if (g_utf8_collate("debug log", key) == 0)
{
gchar *temp_file;
wMUDConfigurationLogging temp_logging;
gboolean temp_found;
temp_logging = conf->debug_log_dest;
temp_file = conf->debug_logfile;
temp_found = conf->debug_log_found;
conf->debug_logfile = g_strdup(value + 5);
if (!*(conf->debug_logfile))
{
wmud_log_error("Debug log file name must contain a string for %s/%s!", group, key);
conf->debug_logfile = temp_file;
return FALSE;
}
if (temp_file)
{
g_free(temp_file);
}
conf->debug_log_dest = WMUD_CONF_LOG_FILE;
conf->debug_log_found = TRUE;
return TRUE;
}
else if (g_utf8_collate("info log", key) == 0)
{
gchar *temp_file;
wMUDConfigurationLogging temp_logging;
gboolean temp_found;
temp_logging = conf->info_log_dest;
temp_file = conf->info_logfile;
temp_found = conf->info_log_found;
conf->info_logfile = g_strdup(value + 5);
if (!*(conf->info_logfile))
{
wmud_log_error("Info log file name must contain a string for %s/%s!", group, key);
conf->info_log_dest = temp_logging;
conf->info_logfile = temp_file;
conf->info_log_found = temp_found;
return FALSE;
}
if (temp_file)
{
g_free(temp_file);
}
conf->info_log_dest = WMUD_CONF_LOG_FILE;
conf->info_log_found = TRUE;
return TRUE;
}
else if (g_utf8_collate("warning log", key) == 0)
{
gchar *temp_file;
wMUDConfigurationLogging temp_logging;
gboolean temp_found;
temp_logging = conf->warning_log_dest;
temp_file = conf->warning_logfile;
temp_found = conf->warning_log_found;
conf->warning_logfile = g_strdup(value + 5);
if (!*(conf->warning_logfile))
{
wmud_log_error("Warning log file name must contain a string for %s/%s!", group, key);
conf->warning_logfile = temp_file;
return FALSE;
}
if (temp_file)
{
g_free(temp_file);
}
conf->warning_log_dest = WMUD_CONF_LOG_FILE;
conf->warning_log_found = TRUE;
return TRUE;
}
else if (g_utf8_collate("error log", key) == 0)
{
gchar *temp_file;
wMUDConfigurationLogging temp_logging;
gboolean temp_found;
temp_logging = conf->error_log_dest;
temp_file = conf->error_logfile;
temp_found = conf->error_log_found;
conf->error_logfile = g_strdup(value + 5);
if (!*(conf->error_logfile))
{
wmud_log_error("Error log file name must contain a string for %s/%s!", group, key);
conf->error_logfile = temp_file;
return FALSE;
}
if (temp_file)
{
g_free(temp_file);
}
conf->error_log_dest = WMUD_CONF_LOG_FILE;
conf->error_log_found = TRUE;
return TRUE;
}
}
if (
(g_utf8_collate("syslog", value) == 0)
|| (
(conf->daemonize == WMUD_CONF_DAEMONIZE_FORCE)
&& (g_utf8_collate("console", value) == 0)
)
)
{
if (g_utf8_collate("log", key) == 0)
{
conf->log_dest = WMUD_CONF_LOG_SYSLOG;
conf->log_found = TRUE;
if (conf->logfile)
{
g_free(conf->logfile);
conf->logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("debug log", key) == 0)
{
conf->debug_log_dest = WMUD_CONF_LOG_SYSLOG;
conf->debug_log_found = TRUE;
if (conf->debug_logfile)
{
g_free(conf->debug_logfile);
conf->debug_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("info log", key) == 0)
{
conf->info_log_dest = WMUD_CONF_LOG_SYSLOG;
conf->info_log_found = TRUE;
if (conf->info_logfile)
{
g_free(conf->info_logfile);
conf->info_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("warning log", key) == 0)
{
conf->warning_log_dest = WMUD_CONF_LOG_SYSLOG;
conf->warning_log_found = TRUE;
if (conf->warning_logfile)
{
g_free(conf->warning_logfile);
conf->warning_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("error log", key) == 0)
{
conf->error_log_dest = WMUD_CONF_LOG_SYSLOG;
conf->error_log_found = TRUE;
if (conf->error_logfile)
{
g_free(conf->error_logfile);
conf->error_logfile = NULL;
}
return TRUE;
}
}
if ((g_utf8_collate("console", value) == 0) && (conf->daemonize != WMUD_CONF_DAEMONIZE_FORCE))
{
if (g_utf8_collate("log", key) == 0)
{
conf->log_dest = WMUD_CONF_LOG_CONSOLE;
conf->log_found = TRUE;
if (conf->logfile)
{
g_free(conf->logfile);
conf->logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("debug log", key) == 0)
{
conf->debug_log_dest = WMUD_CONF_LOG_CONSOLE;
conf->debug_log_found = TRUE;
if (conf->debug_logfile)
{
g_free(conf->debug_logfile);
conf->debug_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("info log", key) == 0)
{
conf->info_log_dest = WMUD_CONF_LOG_CONSOLE;
conf->info_log_found = TRUE;
if (conf->info_logfile)
{
g_free(conf->info_logfile);
conf->info_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("warning log", key) == 0)
{
conf->warning_log_dest = WMUD_CONF_LOG_CONSOLE;
conf->warning_log_found = TRUE;
if (conf->warning_logfile)
{
g_free(conf->warning_logfile);
conf->warning_logfile = NULL;
}
return TRUE;
}
else if (g_utf8_collate("error log", key) == 0)
{
conf->error_log_dest = WMUD_CONF_LOG_CONSOLE;
conf->error_log_found = TRUE;
if (conf->error_logfile)
{
g_free(conf->error_logfile);
conf->error_logfile = NULL;
}
return TRUE;
}
}
wmud_log_error("Found the log option with an unknown value of %s", value);
return FALSE;
}
if (g_utf8_collate("daemonize", key) == 0)
{
if (g_utf8_collate("yes", value) == 0)
{
conf->daemonize = WMUD_CONF_DAEMONIZE_YES;
return TRUE;
}
else if (g_utf8_collate("no", value) == 0)
{
conf->daemonize = WMUD_CONF_DAEMONIZE_NO;
return TRUE;
}
else if (g_utf8_collate("force", value) == 0)
{
conf->daemonize = WMUD_CONF_DAEMONIZE_FORCE;
return TRUE;
}
wmud_log_error("Daemonize must have the values yes, no or force");
return FALSE;
}
if (g_utf8_collate("chat", key) == 0)
{
if (g_utf8_collate("yes", value) == 0)
{
conf->chat_enabled = TRUE;
return TRUE;
}
else if (g_utf8_collate("no", value) == 0)
{
conf->chat_enabled = FALSE;
return TRUE;
}
wmud_log_error("Chat must have the value yes or no");
return FALSE;
}
if (g_utf8_collate("dbus", key) == 0)
{
if (g_utf8_collate("yes", value) == 0)
{
conf->dbus_enabled = TRUE;
return TRUE;
}
else if (g_utf8_collate("no", value) == 0)
{
conf->dbus_enabled = TRUE;
return TRUE;
}
wmud_log_error("DBus must have the value yes or no");
return FALSE;
}
wmud_log_error("Unknown key (%s) found in configuration file in group [%s]", key, group);
return FALSE;
}
if (g_utf8_collate("modules", group) == 0)
{
if (g_utf8_collate("modules dir", key) == 0)
{
if (conf->modules_dir)
{
g_free(conf->modules_dir);
}
conf->modules_dir = g_strdup(value);
return TRUE;
}
if (g_utf8_collate("statesave", key) == 0)
{
if (conf->statesave_module)
{
g_free(conf->statesave_module);
}
conf->statesave_module = g_strdup(value);
return TRUE;
}
if (g_utf8_collate("protocol", key) == 0)
{
if (conf->protocol_modules)
{
g_strfreev(conf->protocol_modules);
}
conf->protocol_modules = g_strsplit(value, ":", 0);
return TRUE;
}
wmud_log_error("Unknown key (%s) found in configuration file in group [%s]", key, group);
return FALSE;
}
group_ptn = g_pattern_spec_new("statesave *");
if (g_pattern_match(group_ptn, strlen(group), group, NULL))
{
GSList *statesave_member;
wMUDConfigurationGroup *conf_group;
wMUDConfigurationValue *conf_data;
statesave_member = g_slist_find_custom(conf->statesave_parameters, group + 10, _wmud_find_keyed_member);
if (statesave_member == NULL)
{
conf_group = g_new0(wMUDConfigurationGroup, 1);
conf_group->name = g_strdup(group + 10);
conf_group->datalist = NULL;
conf->statesave_parameters = g_slist_append(conf->statesave_parameters, conf_group);
}
else
{
conf_group = (wMUDConfigurationGroup *)(statesave_member->data);
}
conf_data = g_new0(wMUDConfigurationValue, 1);
conf_data->key = g_strdup(key);
conf_data->value = g_strdup(value);
conf_group->datalist = g_slist_append(conf_group->datalist, conf_data);
return TRUE;
}
g_pattern_spec_free(group_ptn);
group_ptn = g_pattern_spec_new("protocol * *");
if (g_pattern_match(group_ptn, strlen(group), group, NULL))
{
GSList *protocol_member;
wMUDConfigurationGroup *conf_group;
wMUDConfigurationValue *conf_data;
protocol_member = g_slist_find_custom(conf->protocol_parameters, group + 10, _wmud_find_keyed_member);
if (protocol_member == NULL)
{
conf_group = g_new0(wMUDConfigurationGroup, 1);
conf_group->name = g_strdup(group + 10);
conf_group->datalist = NULL;
conf->protocol_parameters = g_slist_append(conf->protocol_parameters, conf_group);
}
else
{
conf_group = (wMUDConfigurationGroup *)(protocol_member->data);
}
conf_data = g_new0(wMUDConfigurationValue, 1);
conf_data->key = g_strdup(key);
conf_data->value = g_strdup(value);
conf_group->datalist = g_slist_append(conf_group->datalist, conf_data);
return TRUE;
}
g_pattern_spec_free(group_ptn);
group_ptn = g_pattern_spec_new("irc *");
if (g_pattern_match(group_ptn, strlen(group), group, NULL))
{
GSList *temp;
wMUDConfigurationInterface *interface;
gchar *iface_name;
struct _wMUDIfaceFinder *finder;
finder = g_new0(struct _wMUDIfaceFinder, 1);
finder->type = WMUD_SESSION_TYPE_IRC;
finder->name = iface_name = g_utf8_offset_to_pointer(group, 4);
Context;
temp = g_slist_find_custom(conf->interfaces, finder, _wmud_find_iface);
Context;
g_free(finder);
if (temp == NULL)
{
Context;
interface = (wMUDConfigurationInterface *)g_new0(wMUDConfigurationInterface, 1);
interface->name = g_strdup(iface_name);
interface->type = WMUD_SESSION_TYPE_IRC;
conf->interfaces = g_slist_append(conf->interfaces, interface);
}
else
{
Context;
interface = (wMUDConfigurationInterface *)(temp->data);
}
if (g_utf8_collate("port", key) == 0)
{
guint64 portnumber;
gchar *endptr;
portnumber = g_ascii_strtoull(value, &endptr, 10);
if ((endptr != NULL) && (*endptr != 0))
{
wmud_log_error("Error in configuration file. Value of port can only contain numbers in group [%s]!", group);
}
if (interface->inetaddr == NULL)
{
interface->inetaddr = gnet_inetaddr_new("0.0.0.0", portnumber);
}
else
{
gnet_inetaddr_set_port(interface->inetaddr, (gint)portnumber);
}
g_pattern_spec_free(group_ptn);
return TRUE;
}
wmud_log_error("Unknown key (%s) found in configuration file in group [%s]", key, group);
g_pattern_spec_free(group_ptn);
return FALSE;
}
g_pattern_spec_free(group_ptn);
wmud_log_error("Unknown group (%s) found in configuration file", group);
return FALSE;
}
static void
_wmud_configuration_free_interface(gpointer data, gpointer user_data)
{
wMUDConfigurationInterface *iface = (wMUDConfigurationInterface *)data;
if (iface->name)
{
g_free(iface->name);
}
if (iface->inetaddr)
{
gnet_inetaddr_unref(iface->inetaddr);
}
g_free(data);
}
static void
_wmud_configuration_free_value(gpointer data, gpointer user_data)
{
wMUDConfigurationValue *v = (wMUDConfigurationValue *)data;
if (v->key)
{
g_free(v->key);
}
if (v->value)
{
g_free(v->value);
}
}
static void
_wmud_configuration_free_parameters(gpointer data, gpointer user_data)
{
wMUDConfigurationGroup *group = (wMUDConfigurationGroup *)data;
g_slist_foreach(group->datalist, _wmud_configuration_free_value, NULL);
g_slist_free(group->datalist);
if (group->name)
{
g_free(group->name);
}
}
void
wmud_configuration_free(wMUDConfiguration **configuration)
{
g_slist_foreach((*configuration)->interfaces, _wmud_configuration_free_interface, NULL);
g_slist_free((*configuration)->interfaces);
g_slist_foreach((*configuration)->statesave_parameters, _wmud_configuration_free_parameters, NULL);
g_slist_free((*configuration)->statesave_parameters);
g_slist_foreach((*configuration)->protocol_parameters, _wmud_configuration_free_parameters, NULL);
g_slist_free((*configuration)->protocol_parameters);
if ((*configuration)->logfile)
{
g_free((*configuration)->logfile);
}
if ((*configuration)->debug_logfile)
{
g_free((*configuration)->debug_logfile);
}
if ((*configuration)->info_logfile)
{
g_free((*configuration)->info_logfile);
}
if ((*configuration)->warning_logfile)
{
g_free((*configuration)->warning_logfile);
}
if ((*configuration)->error_logfile)
{
g_free((*configuration)->error_logfile);
}
if ((*configuration)->modules_dir)
{
g_free((*configuration)->modules_dir);
}
if ((*configuration)->statesave_module)
{
g_free((*configuration)->statesave_module);
}
if ((*configuration)->protocol_modules)
{
g_strfreev((*configuration)->protocol_modules);
}
g_free((*configuration));
*configuration = NULL;
}
gboolean
wmud_configfile_read(gchar *filename, wMUDConfiguration **configuration, GError **error)
{
GKeyFile *configfile;
GError *file_error = NULL;
gchar **grouplist,
**group;
wMUDConfiguration *conf;
*configuration = NULL;
Context;
if (filename == NULL)
{
return FALSE;
}
conf = g_new0(wMUDConfiguration, 1);
wmud_log_debug("Reading configuration file %s", filename);
configfile = g_key_file_new();
if (!g_key_file_load_from_file(configfile, filename, G_KEY_FILE_NONE, &file_error))
{
if (file_error->domain == G_FILE_ERROR)
{
wmud_log_error("Unable to open configuration file (%s): %s", filename, file_error->message);
}
if (file_error->domain == G_KEY_FILE_ERROR)
{
wmud_log_error("Unable to parse configuration file (%s): %s", filename, file_error->message);
}
g_key_file_free(configfile);
return FALSE;
}
grouplist = g_key_file_get_groups(configfile, NULL);
for (group = grouplist; *group; group++)
{
gchar **keylist,
**key;
wmud_log_debug("Processing group: [%s]", *group);
keylist = g_key_file_get_keys(configfile, *group, NULL, NULL);
for (key = keylist; *key; key++)
{
gchar *value;
gboolean line_processed;
value = g_key_file_get_value(configfile, *group, *key, NULL);
line_processed = _wmud_config_process_value(conf, *group, *key, value);
g_free(value);
if (!line_processed)
{
g_strfreev(keylist);
g_strfreev(grouplist);
g_key_file_free(configfile);
return FALSE;
}
}
g_strfreev(keylist);
}
g_strfreev(grouplist);
g_key_file_free(configfile);
/* If one of the logging options not found, fall back to the "log"
* option. If neither log can be found, configuration is invalid
*/
#ifdef DEBUG
if (!conf->debug_log_found)
{
if (!conf->log_found)
{
wmud_log_error("Debug log not found in configuration file");
wmud_configuration_free(&conf);
return FALSE;
}
else
{
conf->debug_log_found = TRUE;
conf->debug_log_dest = conf->log_dest;
conf->debug_logfile = (conf->logfile == NULL) ? NULL : g_strdup(conf->logfile);
}
}
#endif
if (!conf->info_log_found)
{
if (!conf->log_found)
{
wmud_log_error("Info log not found in configuration file");
wmud_configuration_free(&conf);
return FALSE;
}
else
{
conf->info_log_found = TRUE;
conf->info_log_dest = conf->log_dest;
conf->info_logfile = (conf->logfile == NULL) ? NULL : g_strdup(conf->logfile);
}
}
if (!conf->warning_log_found)
{
if (!conf->log_found)
{
wmud_log_error("Warning log not found in configuration file");
wmud_configuration_free(&conf);
return FALSE;
}
else
{
conf->warning_log_found = TRUE;
conf->warning_log_dest = conf->log_dest;
conf->warning_logfile = (conf->logfile == NULL) ? NULL : g_strdup(conf->logfile);
}
}
if (!conf->error_log_found)
{
if (!conf->log_found)
{
wmud_log_error("Error log not found in configuration file");
wmud_configuration_free(&conf);
return FALSE;
}
else
{
conf->error_log_found = TRUE;
conf->error_log_dest = conf->log_dest;
conf->error_logfile = (conf->logfile == NULL) ? NULL : g_strdup(conf->logfile);
}
}
/* If daemonizing is forced, we cannot log to the console. However,
* daemonizing is not supported if DEBUG is turned on
*/
#ifdef DEBUG
if ((conf->daemonize == WMUD_CONF_DAEMONIZE_FORCE) || (conf->daemonize == WMUD_CONF_DAEMONIZE_YES))
{
wmud_log_warning("Cannot daemonize in DEBUG mode");
conf->daemonize = WMUD_CONF_DAEMONIZE_NO;
}
#endif
if (conf->daemonize == WMUD_CONF_DAEMONIZE_FORCE)
{
#ifdef DEBUG
if (conf->debug_log_dest == WMUD_CONF_LOG_CONSOLE)
{
wmud_log_warning("Cannot log to console when daemonized. Debug log is falling back to syslog");
conf->debug_log_dest = WMUD_CONF_LOG_SYSLOG;
}
#endif
if (conf->info_log_dest == WMUD_CONF_LOG_CONSOLE)
{
wmud_log_warning("Cannot log to console when daemonized. Info log is falling back to syslog");
conf->info_log_dest = WMUD_CONF_LOG_SYSLOG;
}
if (conf->warning_log_dest == WMUD_CONF_LOG_CONSOLE)
{
wmud_log_warning("Cannot log to console when daemonized. Warning log is falling back to syslog");
conf->warning_log_dest = WMUD_CONF_LOG_SYSLOG;
}
if (conf->error_log_dest == WMUD_CONF_LOG_CONSOLE)
{
wmud_log_warning("Cannot log to console when daemonized. Error log is falling back to syslog");
conf->error_log_dest = WMUD_CONF_LOG_SYSLOG;
}
}
#ifdef DEBUG
wmud_log_warning("Logging must be sent to the console in debug mode!");
if (conf->debug_log_dest != WMUD_CONF_LOG_CONSOLE)
{
if (conf->debug_logfile)
{
g_free(conf->debug_logfile);
conf->debug_logfile = NULL;
}
conf->debug_log_dest = WMUD_CONF_LOG_CONSOLE;
}
if (conf->info_log_dest != WMUD_CONF_LOG_CONSOLE)
{
if (conf->info_logfile)
{
g_free(conf->info_logfile);
conf->info_logfile = NULL;
}
conf->info_log_dest = WMUD_CONF_LOG_CONSOLE;
}
if (conf->warning_log_dest != WMUD_CONF_LOG_CONSOLE)
{
if (conf->warning_logfile)
{
g_free(conf->warning_logfile);
conf->warning_logfile = NULL;
}
conf->warning_log_dest = WMUD_CONF_LOG_CONSOLE;
}
if (conf->error_log_dest != WMUD_CONF_LOG_CONSOLE)
{
if (conf->error_logfile)
{
g_free(conf->error_logfile);
conf->error_logfile = NULL;
}
conf->error_log_dest = WMUD_CONF_LOG_CONSOLE;
}
#endif
*configuration = conf;
return TRUE;
}

16
src/configfile.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __WMUD_CORE_CONFIGFILE_H__
#define __WMUD_CORE_CONFIGFILE_H__
#include <glib.h>
#include "wmud-session.h"
#include "configfile-module.h"
extern wMUDConfiguration *wmud_configuration;
gboolean wmud_configfile_read(gchar *filename, wMUDConfiguration **configuration, GError **error);
void wmud_configuration_free(wMUDConfiguration **configuration);
#endif /* __WMUD_CORE_CONFIGFILE_H__ */

107
src/irc.c Normal file
View File

@ -0,0 +1,107 @@
#include <string.h>
#include <glib.h>
#include <gnet.h>
#include "wmud.h"
#include "logger.h"
#define COMMAND_DELIMITERS " \t\n\r"
struct _wMUDSplitHelper
{
gchar **list;
gint position;
};
static void
_add_words(gpointer data, gpointer user_data)
{
struct _wMUDSplitHelper *split_data = (struct _wMUDSplitHelper *)user_data;
gchar *word = (gchar *)data;
split_data->list[split_data->position] = word;
split_data->position++;
}
static gint
_wmud_split_irc_line(gchar *command, gchar ***list)
{
gchar *a;
gint word_started_at = 0;
gboolean was_in_word = FALSE;
gboolean in_string = TRUE;
guint colon_at = -1;
GSList *word_list = NULL;
gchar **ret;
struct _wMUDSplitHelper split_data;
gint word_count;
Context;
for (a = command; in_string; a++)
{
if (*a == 0)
{
in_string = FALSE;
}
if (
(*a == 0)
|| (
(colon_at == -1)
&& strchr(COMMAND_DELIMITERS, *a)
)
|| (
(colon_at == -1)
&& (*a == ':')
)
)
{
if (was_in_word)
{
was_in_word = FALSE;
word_list = g_slist_append(word_list, g_strndup((command + word_started_at), (a - command) - word_started_at));
word_started_at = (a - command);
}
if ((*a == ':') && (colon_at == -1))
{
colon_at = (a - command) - 1;
if (colon_at == -1)
{
colon_at = 0;
}
}
word_started_at++;
continue;
}
was_in_word = TRUE;
}
word_count = g_slist_length(word_list);
Context ret = g_new0(gchar *, word_count + 1);
split_data.list = ret;
split_data.position = 0;
g_slist_foreach(word_list, _add_words, &split_data);
g_slist_free(word_list);
if (list != NULL)
{
Context *list = ret;
}
return word_count;
}
void
wmud_process_irc_command(GConn *connection, gchar *command)
{
gchar **command_parts;
gint word_count;
word_count = _wmud_split_irc_line(command, &command_parts);
wmud_log_debug("Got command '%s' with %d parts", command, word_count);
}

10
src/irc.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __WMUD_CORE_IRC_H__
#define __WMUD_CORE_IRC_H__
#include <glib.h>
#include <gnet.h>
void wmud_process_irc_command(GConn *connection, gchar *command);
#endif /* __WMUD_CORE_IRC_H__ */

22
src/logger-module.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef __WMUD_MODULE_LOGGER_H__
#define __WMUD_MODULE_LOGGER_H__
typedef enum
{
WMUD_LOG_DEBUG,
WMUD_LOG_INFO,
WMUD_LOG_WARN,
WMUD_LOG_ERROR
} wMUDLogLevelType;
#define wmud_log_info(x, ...) wmud_log(WMUD_LOG_INFO, __FILE__, __LINE__, x, ## __VA_ARGS__)
#define wmud_log_warning(x, ...) wmud_log(WMUD_LOG_WARN, __FILE__, __LINE__, x, ## __VA_ARGS__)
#define wmud_log_error(x, ...) wmud_log(WMUD_LOG_ERROR, __FILE__, __LINE__, x, ## __VA_ARGS__)
#if DEBUG
#define wmud_log_debug(x, ...) wmud_log(WMUD_LOG_DEBUG, __FILE__, __LINE__, x, ## __VA_ARGS__)
#else /* ! DEBUG */
#define wmud_log_debug(x, ...)
#endif /* DEBUG */
#endif /* __WMUD_MODULE_LOGGER_H__ */

232
src/logger.c Normal file
View File

@ -0,0 +1,232 @@
#include <glib.h>
#include <stdarg.h>
#include <string.h>
#include <syslog.h>
#include <stdio.h>
#include <libgnomevfs/gnome-vfs.h>
#include "wmud.h"
#include "configfile.h"
#include "logger.h"
enum {
_LOG_DEST_STDOUT,
_LOG_DEST_STDERR
};
typedef struct _wmud_message_level {
int colorcode;
const char *prefix;
int debug_dest;
wMUDConfigurationLogging dest;
GnomeVFSHandle *logfile;
} wMUDMessageLevelType;
wMUDMessageLevelType wMUDMessageLevels[] = {
{ 35, "debug", _LOG_DEST_STDERR, WMUD_CONF_LOG_CONSOLE, NULL }, /* LOG_DEBUG */
{ 32, "info", _LOG_DEST_STDOUT, WMUD_CONF_LOG_CONSOLE, NULL }, /* LOG_INFO */
{ 33, "warn", _LOG_DEST_STDOUT, WMUD_CONF_LOG_CONSOLE, NULL }, /* LOG_WARN */
{ 31, "error", _LOG_DEST_STDERR, WMUD_CONF_LOG_CONSOLE, NULL } /* LOG_ERROR */
};
#define wmud_message_level_count (sizeof(wmud_message_levels) / sizeof(wmud_message_level))
static void
_wmud_log_message(wMUDLogLevelType level, const char *filename, const int linenum, const char *fmt, va_list args)
{
char *format,
*final_string;
wMUDMessageLevelType level_info = wMUDMessageLevels[level];
int syslog_level;
static char *timestamp = NULL;
time_t now;
if (timestamp == NULL)
{
timestamp = g_malloc0(17 * sizeof(char));
}
switch (level_info.dest)
{
case WMUD_CONF_LOG_NONE:
return;
case WMUD_CONF_LOG_FILE:
now = time(NULL);
Context strftime(timestamp, 16, "%b %e %H:%M:%S", localtime(&now));
Context gnome_vfs_seek(level_info.logfile, GNOME_VFS_SEEK_END, 0);
format = g_strdup_printf("%s wMUD[%d]: [%s] %s:%d: %s\n", timestamp, wmud_pid, level_info.prefix, filename, linenum, fmt);
final_string = g_strdup_vprintf(format, args);
g_free(format);
gnome_vfs_write(level_info.logfile, final_string, strlen(final_string), NULL);
g_free(final_string);
break;
case WMUD_CONF_LOG_SYSLOG:
switch (level)
{
case WMUD_LOG_DEBUG:
syslog_level = LOG_DEBUG;
break;
case WMUD_LOG_INFO:
syslog_level = LOG_INFO;
break;
case WMUD_LOG_WARN:
syslog_level = LOG_WARNING;
break;
case WMUD_LOG_ERROR:
syslog_level = LOG_ERR;
break;
default:
syslog_level = LOG_CRIT;
break;
}
format = g_strdup_printf("[%s] %s:%d: %s\n", level_info.prefix, filename, linenum, fmt);
vsyslog(LOG_USER | syslog_level, format, args);
g_free(format);
break;
case WMUD_CONF_LOG_CONSOLE:
format = g_strdup_printf("\x1b[%dm\x1b[1m[%s] %s:%d: %s\x1b[0m\n", level_info.colorcode, level_info.prefix, filename, linenum, fmt);
vfprintf((level_info.debug_dest == _LOG_DEST_STDERR) ? stderr : stdout, format, args);
g_free(format);
break;
}
}
void
wmud_log(wMUDLogLevelType level, const char *filename, const int linenum, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
_wmud_log_message(level, filename, linenum, fmt, args);
va_end(args);
}
gboolean
wmud_logger_init(wMUDConfiguration *config)
{
gchar *full_logfile_uri;
GnomeVFSURI *log_uri;
g_assert(config != NULL);
if (config->debug_log_dest == WMUD_CONF_LOG_FILE)
{
GnomeVFSResult state;
full_logfile_uri = gnome_vfs_get_uri_from_local_path(config->debug_logfile);
log_uri = gnome_vfs_uri_new(full_logfile_uri);
g_free(full_logfile_uri);
switch (gnome_vfs_open_uri(&(wMUDMessageLevels[WMUD_LOG_DEBUG].logfile), log_uri, GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_RANDOM))
{
case GNOME_VFS_ERROR_NOT_FOUND:
if ((state = gnome_vfs_create_uri(&(wMUDMessageLevels[WMUD_LOG_DEBUG].logfile), log_uri, GNOME_VFS_OPEN_WRITE, FALSE, 0640)) != GNOME_VFS_OK)
{
wmud_log_error("Unable to open debug logfile (%s)", config->debug_logfile);
wmud_shutdown();
return FALSE;
}
break;
case GNOME_VFS_OK:
break;
default:
wmud_log_error("Unprocessed return state from gnome_vfs_open_uri()");
break;
}
gnome_vfs_uri_unref(log_uri);
}
wMUDMessageLevels[WMUD_LOG_DEBUG].dest = config->debug_log_dest;
if (config->info_log_dest == WMUD_CONF_LOG_FILE)
{
GnomeVFSResult state;
full_logfile_uri = gnome_vfs_get_uri_from_local_path(config->info_logfile);
log_uri = gnome_vfs_uri_new(full_logfile_uri);
g_free(full_logfile_uri);
switch (gnome_vfs_open_uri(&(wMUDMessageLevels[WMUD_LOG_INFO].logfile), log_uri, GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_RANDOM))
{
case GNOME_VFS_ERROR_NOT_FOUND:
if ((state = gnome_vfs_create_uri(&(wMUDMessageLevels[WMUD_LOG_INFO].logfile), log_uri, GNOME_VFS_OPEN_WRITE, FALSE, 0640)) != GNOME_VFS_OK)
{
wmud_log_error("Unable to open info logfile (%s)", config->info_logfile);
wmud_shutdown();
return FALSE;
}
break;
case GNOME_VFS_OK:
break;
default:
wmud_log_error("Unprocessed return state from gnome_vfs_open_uri()");
break;
}
gnome_vfs_uri_unref(log_uri);
}
wMUDMessageLevels[WMUD_LOG_INFO].dest = config->info_log_dest;
if (config->warning_log_dest == WMUD_CONF_LOG_FILE)
{
GnomeVFSResult state;
full_logfile_uri = gnome_vfs_get_uri_from_local_path(config->warning_logfile);
log_uri = gnome_vfs_uri_new(full_logfile_uri);
g_free(full_logfile_uri);
switch (gnome_vfs_open_uri(&(wMUDMessageLevels[WMUD_LOG_WARN].logfile), log_uri, GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_RANDOM))
{
case GNOME_VFS_ERROR_NOT_FOUND:
if ((state = gnome_vfs_create_uri(&(wMUDMessageLevels[WMUD_LOG_WARN].logfile), log_uri, GNOME_VFS_OPEN_WRITE, FALSE, 0640)) != GNOME_VFS_OK)
{
wmud_log_error("Unable to open warning logfile (%s)", config->warning_logfile);
wmud_shutdown();
return FALSE;
}
break;
case GNOME_VFS_OK:
break;
default:
wmud_log_error("Unprocessed return state from gnome_vfs_open_uri()");
break;
}
gnome_vfs_uri_unref(log_uri);
}
wMUDMessageLevels[WMUD_LOG_WARN].dest = config->warning_log_dest;
if (config->error_log_dest == WMUD_CONF_LOG_FILE)
{
GnomeVFSResult state;
full_logfile_uri = gnome_vfs_get_uri_from_local_path(config->error_logfile);
log_uri = gnome_vfs_uri_new(full_logfile_uri);
g_free(full_logfile_uri);
switch (gnome_vfs_open_uri(&(wMUDMessageLevels[WMUD_LOG_ERROR].logfile), log_uri, GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_RANDOM))
{
case GNOME_VFS_ERROR_NOT_FOUND:
if ((state = gnome_vfs_create_uri(&(wMUDMessageLevels[WMUD_LOG_ERROR].logfile), log_uri, GNOME_VFS_OPEN_WRITE, FALSE, 0640)) != GNOME_VFS_OK)
{
wmud_log_error("Unable to open error logfile (%s)", config->error_logfile);
wmud_shutdown();
return FALSE;
}
break;
case GNOME_VFS_OK:
break;
default:
wmud_log_error("Unprocessed return state from gnome_vfs_open_uri()");
break;
}
gnome_vfs_uri_unref(log_uri);
}
wMUDMessageLevels[WMUD_LOG_ERROR].dest = config->error_log_dest;
if (
(config->debug_log_dest == WMUD_CONF_LOG_SYSLOG)
|| (config->info_log_dest == WMUD_CONF_LOG_SYSLOG)
|| (config->warning_log_dest == WMUD_CONF_LOG_SYSLOG)
|| (config->error_log_dest == WMUD_CONF_LOG_SYSLOG)
)
{
openlog("wMUD", LOG_PID, LOG_USER);
}
return TRUE;
}

16
src/logger.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __WMUD_CORE_LOGGER_H__
#define __WMUD_CORE_LOGGER_H__
#include <stdarg.h>
#include <glib.h>
#include "configfile.h"
#include "logger-module.h"
#include "wmud-module.h"
void wmud_log(wMUDLogLevelType level, const char *filename, const int linenum, const char *fmt, ...);
gboolean wmud_logger_init(wMUDConfiguration *config);
#endif /* __WMUD_CORE_LOGGER_H__ */

10
src/module.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __WMUD_MODULE_H__
#define __WMUD_MODULE_H__
#include "wmud-module.h"
#define wmud_log(level, filename, linenum, fmt, ...) ((void (*)(wMUDLogLevelType, const char *, const int, const char *, ...))(wMUDCallables[WMUD_CALLABLE_WMUD_LOG]))(level, filename, linenum, fmt, ## __VA_ARGS__)
#define wmud_print_context(filename, linenum) ((void (*)(char *, int))(wMUDCallables[WMUD_CALLABLE_WMUD_PRINT_CONTEXT]))(filename, linenum)
#endif /* __WMUD_MODULE_H__ */

112
src/modules.c Normal file
View File

@ -0,0 +1,112 @@
#include <glib.h>
#include <gmodule.h>
#if HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "modules.h"
#include "configfile.h"
#include "logger.h"
#include "wmud.h"
#include "wmud-module.h"
static GModule *statesave_module = NULL;
gboolean (*wmud_save_state)(GError **error) = NULL;
gpointer wMUDCallables[WMUD_CALLABLE_LAST];
void
wmud_fill_callable_table(void)
{
wMUDCallables[WMUD_CALLABLE_WMUD_LOG] = wmud_log;
#ifdef DEBUG
wMUDCallables[WMUD_CALLABLE_WMUD_PRINT_CONTEXT] = wmud_print_context;
#endif /* DEBUG */
wMUDCallables[WMUD_CALLABLE_LAST] = NULL;
}
gboolean
wmud_load_config_modules(wMUDConfiguration *config)
{
gchar *statesave_module_short_name,
*statesave_module_file,
*func_name;
gboolean (*module_is_statesaving)(void);
gboolean (*module_load)(wMUDConfiguration *config);
if (!g_module_supported())
{
wmud_log_error("Module loading is not supported!");
return FALSE;
}
Context;
if (config->modules_dir == NULL)
{
wmud_log_error("Module directory must be set in the configfile!");
return FALSE;
}
if (config->statesave_module == NULL)
{
wmud_log_error("State saving module must be set in the configfile!");
return FALSE;
}
statesave_module_short_name = g_strdup_printf("state-%s", config->statesave_module);
statesave_module_file = g_module_build_path(config->modules_dir, statesave_module_short_name);
g_free(statesave_module_short_name);
wmud_log_debug("Trying to load \"%s\" as state-saving module", statesave_module_file);
if ((statesave_module = g_module_open(statesave_module_file, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)) == NULL)
{
wmud_log_error("Unable to load state saving module %s", statesave_module_file);
return FALSE;
}
func_name = g_strdup_printf("wmud_statesave_%s_is_statesave", config->statesave_module);
if (g_module_symbol(statesave_module, func_name, (gpointer *)&module_is_statesaving))
{
if (!module_is_statesaving())
{
wmud_log_error("Module %s is not marked as statesaving!", statesave_module_file);
g_module_close(statesave_module);
g_free(func_name);
return FALSE;
}
}
else
{
wmud_log_error("Undefined symbol \"%s\" in statesave module %s", func_name, statesave_module_file);
g_module_close(statesave_module);
g_free(func_name);
return FALSE;
}
g_free(func_name);
func_name = g_strdup_printf("wmud_statesave_%s_load", config->statesave_module);
if (g_module_symbol(statesave_module, func_name, (gpointer *)&module_load))
{
if (!module_load(config))
{
wmud_log_error("Module initialization failed for %s", statesave_module_file);
g_module_close(statesave_module);
g_free(func_name);
return FALSE;
}
}
else
{
wmud_log_error("Undefined symbol \"%s\" in statesave module %s", func_name, statesave_module_file);
g_module_close(statesave_module);
g_free(func_name);
return FALSE;
}
g_free(statesave_module_file);
return TRUE;
}

12
src/modules.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __WMUD_CORE_MODULES_H__
#define __WMUD_CORE_MODULES_H__
#include <glib.h>
#include "configfile.h"
void wmud_fill_callable_table(void);
gboolean wmud_load_config_modules(wMUDConfiguration *config);
#endif /* __WMUD_CORE_MODULES_H__ */

427
src/networking.c Normal file
View File

@ -0,0 +1,427 @@
#include <glib.h>
#include <gnet.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "wmud.h"
#include "logger.h"
#include "sessions.h"
#include "networking.h"
#include "configfile.h"
#include "commands.h"
#include "irc.h"
#define LISTEN_PORT 4000
GSList *_wmud_active_interfaces = NULL;
/**
* _wmud_telnet_event:
* @connection: the #GConn on which this event occured
* @event: type of event
* @user_data: user data arrived with this function call. Currently it is not used
*
* Callback function which gets called whenever a new event occurs on a telnet-type socket
*/
static void
_wmud_telnet_event(GConn *connection, GConnEvent *event, gpointer user_data)
{
gchar *command;
GError *error = NULL;
//Context;
switch (event->type)
{
case GNET_CONN_READABLE:
command = NULL;
gsize term_pos;
gsize length;
switch (g_io_channel_read_line(connection->iochannel, &command, &length, &term_pos, &error))
{
case G_IO_STATUS_ERROR:
wmud_log_error("Telnet read error: %s", error->message);
break;
case G_IO_STATUS_NORMAL:
wmud_log_debug("Accepted data");
break;
case G_IO_STATUS_EOF:
wmud_log_info("Client disconnected");
wmud_connection_disconnect(connection);
break;
case G_IO_STATUS_AGAIN:
wmud_log_debug("Telnet read terminated, trying again");
break;
default:
break;
}
if (command)
{
*(command + term_pos) = 0;
wmud_log_debug("Got command: %s", command);
wmud_process_command(connection, command);
*(command + term_pos) = '\n';
g_free(command);
}
break;
case GNET_CONN_TIMEOUT:
wmud_log_info("Telnet connection timeout");
wmud_connection_disconnect(connection);
break;
case GNET_CONN_ERROR:
wmud_log_error("Unprocessed connection event CONN_ERROR");
break;
case GNET_CONN_CONNECT:
wmud_log_error("Unprocessed connection event CONN_CONNECT");
break;
case GNET_CONN_CLOSE:
wmud_log_error("Unprocessed connection event CONN_CLOSE");
break;
case GNET_CONN_READ:
wmud_log_error("Unprocessed connection event CONN_READ");
break;
case GNET_CONN_WRITE:
wmud_log_error("Unprocessed connection event CONN_WRITE");
break;
case GNET_CONN_WRITABLE:
wmud_log_error("Unprocessed connection event CONN_WRITABLE");
break;
default:
wmud_log_error("Got an unknown connction event from GNet!");
break;
}
}
static void
_wmud_irc_event(GConn *connection, GConnEvent *event, gpointer user_data)
{
gchar *command;
GError *error = NULL;
switch (event->type)
{
case GNET_CONN_READABLE:
command = NULL;
gsize term_pos;
gsize length;
switch (g_io_channel_read_line(connection->iochannel, &command, &length, &term_pos, &error))
{
case G_IO_STATUS_ERROR:
wmud_log_error("IRC read error: %s", error->message);
break;
case G_IO_STATUS_NORMAL:
wmud_log_debug("Accepted data");
break;
case G_IO_STATUS_EOF:
wmud_log_info("Client disconnected");
wmud_connection_disconnect(connection);
break;
case G_IO_STATUS_AGAIN:
wmud_log_debug("IRC read terminated, trying again");
break;
default:
break;
}
if (command)
{
*(command + term_pos) = 0;
wmud_log_debug("Got command: %s", command);
wmud_process_irc_command(connection, command);
*(command + term_pos) = '\n';
g_free(command);
}
break;
case GNET_CONN_TIMEOUT:
wmud_log_info("IRC connection timeout");
wmud_connection_disconnect(connection);
break;
case GNET_CONN_ERROR:
wmud_log_error("Unprocessed connection event CONN_ERROR");
break;
case GNET_CONN_CONNECT:
wmud_log_error("Unprocessed connection event CONN_CONNECT");
break;
case GNET_CONN_CLOSE:
wmud_log_error("Unprocessed connection event CONN_CLOSE");
break;
case GNET_CONN_READ:
wmud_log_error("Unprocessed connection event CONN_READ");
break;
case GNET_CONN_WRITE:
wmud_log_error("Unprocessed connection event CONN_WRITE");
break;
case GNET_CONN_WRITABLE:
wmud_log_error("Unprocessed connection event CONN_WRITABLE");
break;
default:
wmud_log_error("Got an unknown connction event from GNet!");
break;
}
}
void
wmud_connection_send(GConn *connection, gchar *fmt, ...)
{
va_list args;
gchar *buffer,
*send_buffer;
gsize len;
GError *error = NULL;
GIOStatus status;
va_start(args, fmt);
Context buffer = g_strdup_vprintf(fmt, args);
va_end(args);
Context send_buffer = g_strdup_printf("%s%s", buffer, wmud_connection_get_linebreak(connection));
Context g_free(buffer);
/* TODO: Error checking! */
Context;
switch ((status = g_io_channel_write_chars(connection->iochannel, send_buffer, -1, &len, &error)))
{
case G_IO_STATUS_ERROR:
wmud_log_error("Error during g_io_channel_write_chars(): %s", error->message);
break;
case G_IO_STATUS_NORMAL:
wmud_log_debug("Message sent");
break;
case G_IO_STATUS_EOF:
wmud_log_warning("EOF during g_io_channel_write_chars()???");
break;
case G_IO_STATUS_AGAIN:
wmud_log_warning("Resource temporarily unavailable while sending message to client");
break;
default:
wmud_log_error("Unknown return value from g_io_channel_write_chars()!");
break;
}
if (error != NULL)
{
g_error_free(error);
error = NULL;
}
Context g_free(send_buffer);
switch ((status = g_io_channel_flush(connection->iochannel, &error)))
{
case G_IO_STATUS_ERROR:
wmud_log_error("Error during g_io_channel_flush(): %s", error->message);
break;
case G_IO_STATUS_NORMAL:
wmud_log_debug("IOChannel flushed");
break;
case G_IO_STATUS_EOF:
wmud_log_warning("EOF during g_io_channel_flush()???");
break;
case G_IO_STATUS_AGAIN:
wmud_log_warning("Resource temporarily unavailable while sending message to client");
break;
default:
wmud_log_error("Unknown return value from g_io_channel_flush()!");
break;
}
if (error != NULL)
{
g_error_free(error);
error = NULL;
}
Context;
}
const gchar *
wmud_connection_get_linebreak(GConn *connection)
{
wMUDSession *session;
Context session = wmud_session_for_connection(connection);
if (session)
{
switch (wmud_session_get_session_type(session))
{
case WMUD_SESSION_TYPE_TELNET:
Context return "\r\n";
break;
case WMUD_SESSION_TYPE_IRC:
Context return "\r\n";
break;
default:
wmud_log_warning("Looling for linebreak for unknown session type");
return "";
}
}
else
{
Context;
}
return "";
}
/**
* _wmud_accept_telnet:
* @server: the #GServer object that has an incoming connection
* @connection: The #GConn created to hold the new connection
* @user_data: user data arrived with this function call. Currently it is not used
*
* Callback function which gets called whenever a new connection arrived on a server socket
*/
static void
_wmud_accept_telnet(GServer *server, GConn *connection, gpointer user_data)
{
wMUDConfigurationInterface *interface = (wMUDConfigurationInterface *)user_data;
/* If the connection is not created for some reason, log an error and return */
if (connection == NULL)
{
wmud_log_error("Error while accepting connection");
return;
}
/* TODO: Disconnect if the IP is banned */
/* Log a message that a new connection has arrived */
wmud_log_info("Accepted telnet connection from [%s]", gnet_inetaddr_get_canonical_name(connection->inetaddr));
/* Set the parameters of this connection */
/* The connection should be buffered, so it is easier to handle */
g_io_channel_set_buffered(connection->iochannel, TRUE);
/* The function to call, whenever an event occurs */
gnet_conn_set_callback(connection, _wmud_telnet_event, NULL);
/* Watch for readable events */
gnet_conn_set_watch_readable(connection, TRUE);
/* Timeout interval */
gnet_conn_timeout(connection, interface->timeout * 1000);
Context;
if (!wmud_new_session(connection, WMUD_SESSION_TYPE_TELNET))
{
Context;
g_io_channel_write_chars(connection->iochannel, "Unable to create a session for you. If you experience this problem for more than once, please contact us!", -1, NULL, NULL);
gnet_conn_disconnect(connection);
}
Context;
}
static void
_wmud_accept_irc(GServer *server, GConn *connection, gpointer user_data)
{
wMUDConfigurationInterface *interface = (wMUDConfigurationInterface *)user_data;
if (connection == NULL)
{
wmud_log_error("Error while accepting connection");
return;
}
/* TODO: Disconnect if the IP is banned */
/* Log a message that a new connection has arrived */
wmud_log_info("Accepted IRC connection from [%s]", gnet_inetaddr_get_canonical_name(connection->inetaddr));
/* Set the parameters of this connection */
/* The connection should be buffered, so it is easier to handle */
g_io_channel_set_buffered(connection->iochannel, TRUE);
/* The function to call, whenever an event occurs */
gnet_conn_set_callback(connection, _wmud_irc_event, NULL);
/* Watch for readable events */
gnet_conn_set_watch_readable(connection, TRUE);
/* Timeout interval */
gnet_conn_timeout(connection, interface->timeout * 1000);
Context;
if (!wmud_new_session(connection, WMUD_SESSION_TYPE_TELNET))
{
Context;
g_io_channel_write_chars(connection->iochannel, "Unable to create a session for you. If you experience this problem for more than once, please contact us!", -1, NULL, NULL);
gnet_conn_disconnect(connection);
}
Context;
}
static void
_wmud_create_interface(gpointer data, gpointer user_data)
{
GServer *server;
wMUDConfigurationInterface *interface = (wMUDConfigurationInterface *)data;
wmud_log_debug("Creating new interface '%s'", interface->name);
switch (interface->type)
{
case WMUD_SESSION_TYPE_TELNET:
server = gnet_server_new(interface->inetaddr, gnet_inetaddr_get_port(interface->inetaddr), _wmud_accept_telnet, interface);
_wmud_active_interfaces = g_slist_append(_wmud_active_interfaces, (gpointer)server);
break;
case WMUD_SESSION_TYPE_IRC:
server = gnet_server_new(interface->inetaddr, gnet_inetaddr_get_port(interface->inetaddr), _wmud_accept_irc, interface);
_wmud_active_interfaces = g_slist_append(_wmud_active_interfaces, (gpointer)server);
break;
default:
wmud_log_error("Unknown type of interface!");
break;
}
}
void
wmud_connection_disconnect(GConn *connection)
{
gnet_conn_disconnect(connection);
}
gpointer
wmud_networking_thread(gpointer data)
{
wMUDThreadData *thread_data = (wMUDThreadData *)data;
Context;
wmud_log_info("Initializing network layer...");
/* g_main_context_get_thread_default() is only available since GLib 2.22;
* use g_main_context_new() otherwise
*/
#if (((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION >= 22)) || (GLIB_MAJOR_VERSION > 2))
thread_data->main_context = g_main_context_get_thread_default();
#else
thread_data->main_context = g_main_context_new();
#endif
thread_data->main_loop = g_main_loop_new(thread_data->main_context, FALSE);
/* Do the real initialization work here */
Context g_slist_foreach(wmud_configuration->interfaces, _wmud_create_interface, NULL);
/* End of initialization */
wmud_log_info("Network layer initialized");
Context;
thread_data->running = TRUE;
g_main_loop_run(thread_data->main_loop);
wmud_log_info("Network layer shutting down");
wmud_destroy_all_sessions("Server is shutting down.");
g_main_loop_unref(thread_data->main_loop);
thread_data->main_loop = NULL;
thread_data->running = FALSE;
Context;
return NULL;
}

13
src/networking.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __WMUD_CORE_NETWORKING_H__
#define __WMUD_CORE_NETWORKING_H__
#include <glib.h>
#include <gnet.h>
gpointer wmud_networking_thread(gpointer data);
void wmud_connection_disconnect(GConn *connection);
void wmud_connection_send(GConn *connection, gchar *fmt, ...);
const gchar *wmud_connection_get_linebreak(GConn *connection);
#endif /* __WMUD_CORE_NETWORKING_H__ */

15
src/protocols-module.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __WMUD_MODULE_PROTOCOLS_H__
#define __WMUD_MODULE_PROTOCOLS_H__
#include <glib.h>
enum {
WMUD_ERROR_PROTOCOL_OK,
WMUD_ERROR_PROTOCOL_EXISTS
};
#define WMUD_ERROR_PROTOCOL g_quark_from_string("WMUD PROTOCOL ERROR")
GQuark wmud_register_protocol(gchar *name, GError **error);
#endif /* __WMUD_MODULE_PROTOCOLS_H__ */

32
src/protocols.c Normal file
View File

@ -0,0 +1,32 @@
#include <glib.h>
#include "protocols.h"
guint wmud_current_protocol_number = 0;
GQuark
wmud_register_protocol(gchar *name, GError **error)
{
gchar *full_protocol_name;
if (name == NULL)
{
return g_quark_from_string(NULL);
}
full_protocol_name = g_strdup_printf("WMUD PROTO %s", name);
if (g_quark_try_string(full_protocol_name) != 0)
{
/* Quark already exists => protocol is already registered */
if (*error)
{
*error = g_error_new(WMUD_ERROR_PROTOCOL, WMUD_ERROR_PROTOCOL_EXISTS, "Protocol %s is already registered", name);
}
return 0;
}
return g_quark_from_string(full_protocol_name);
}

9
src/protocols.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __WMUD_CORE_PROTOCOLS_H__
#define __WMUD_CORE_PROTOCOLS_H__
#include <glib.h>
#include "protocols-module.h"
#endif /* __WMUD_CORE_PROTOCOLS_H__ */

101
src/sessions.c Normal file
View File

@ -0,0 +1,101 @@
#include <glib.h>
#include <gnet.h>
#include "wmud.h"
#include "sessions.h"
#include "networking.h"
#include "logger.h"
#include "wmud-session.h"
GSList *wmud_session_list = NULL;
gboolean
wmud_new_session(GConn *connection, wMUDSessionType type)
{
wMUDSession *session;
Context;
if ((session = wmud_session_new_with_connection(connection)) == NULL)
{
return FALSE;
}
Context wmud_session_set_session_type(session, type);
Context;
wmud_session_list = g_slist_append(wmud_session_list, session);
Context;
return TRUE;
}
static gint
_wmud_find_session_with_connection(gconstpointer list_element, gconstpointer connection)
{
wMUDSession *session = (wMUDSession *)list_element;
GConn *conn = (GConn *)connection;
g_assert(WMUD_IS_SESSION(list_element));
Context return (wmud_session_has_connection(session, conn)) ? 0 : 1;
}
wMUDSession *
wmud_session_for_connection(GConn *connection)
{
GSList *temp;
Context temp = g_slist_find_custom(wmud_session_list, connection, _wmud_find_session_with_connection);
if (temp)
{
return temp->data;
}
return NULL;
}
void
wmud_finish_session(wMUDSession *session, gchar *message)
{
if ((session == NULL) || (!WMUD_IS_SESSION(session)))
{
return;
}
GConn *connection = wmud_session_get_connection(session);
if (connection)
{
wmud_log_debug("Destroying session with connection");
if (message)
{
wmud_connection_send(connection, message);
}
wmud_connection_disconnect(connection);
wmud_session_set_connection(session, NULL);
}
wmud_session_list = g_slist_remove_all(wmud_session_list, session);
wmud_session_unref(session);
}
static void
_wmud_destroy_session(gpointer sess, gpointer msg)
{
wMUDSession *session = (wMUDSession *)sess;
gchar *message = (gchar *)msg;
wmud_log_debug("Shutting down session %lx", sess);
wmud_finish_session(session, message);
}
void
wmud_destroy_all_sessions(gchar *message)
{
g_slist_foreach(wmud_session_list, _wmud_destroy_session, message);
}

17
src/sessions.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef __WMUD_CORE_SESSIONS_H__
#define __WMUD_CORE_SESSIONS_H__
#include <glib.h>
#include <gnet.h>
#include "wmud-session.h"
extern GSList *wmud_session_list;
gboolean wmud_new_session(GConn *connection, wMUDSessionType type);
wMUDSession *wmud_session_for_connection(GConn *connection);
void wmud_finish_session(wMUDSession *session, gchar *message);
void wmud_destroy_all_sessions(gchar *message);
#endif /* __WMUD_CORE_SESSIONS_H__ */

27
src/wmud-module.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef __WMUD_MODULE_WMUD_H__
#define __WMUD_MODULE_WMUD_H__
#include <glib.h>
#include "protocols-module.h"
#include "configfile-module.h"
#include "logger-module.h"
enum _wMUDCallableNum {
WMUD_CALLABLE_WMUD_LOG,
#ifdef DEBUG
WMUD_CALLABLE_WMUD_PRINT_CONTEXT,
#endif /* DEBUG */
WMUD_CALLABLE_LAST
};
extern gpointer wMUDCallables[];
#if DEBUG
#define Context wmud_print_context(__FILE__, __LINE__);
#else
#define Context
#endif
#endif /* __WMUD_MODULE_WMUD_H__ */

244
src/wmud.c Normal file
View File

@ -0,0 +1,244 @@
#include <glib.h>
#include <glib-object.h>
#include <gnet.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgnomevfs/gnome-vfs.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "wmud.h"
#include "logger.h"
#include "ansi.h"
#include "networking.h"
#include "world.h"
#include "configfile.h"
#include "chat.h"
#include "modules.h"
/* TODO: Make this configurable via configure, and/or countable based on sysconfdir */
#define DEFAULT_CONFIGFILE "/home/polesz/Projektek/wMUD/data/wmud.conf"
GSList *wmud_running_threads = NULL;
gchar *wmud_option_configfile = NULL;
wMUDConfiguration *wmud_configuration = NULL;
GMainLoop *wmud_main_loop = NULL;
gboolean wmud_is_running = FALSE;
pid_t wmud_pid;
static GOptionEntry option_entries[] = {
{ "configfile", 'c', G_OPTION_FLAG_FILENAME, G_OPTION_ARG_FILENAME, &wmud_option_configfile, "Configuration file to parse instead of the default one", "filename" },
{ NULL },
};
#if DEBUG
void
wmud_print_context(char *filename, int linenum)
{
fprintf(stderr, "\x1b[34m\x1b[1m[DEBUG CONTEXT] %s:%d\x1b[0m\n", filename, linenum);
}
#endif
void
_fatal_signal_handler(int signum)
{
fprintf(stderr, "Segmentation fault.\n");
exit(1);
}
void
_terminating_signal_handler(int signum)
{
switch (signum)
{
case SIGINT:
wmud_shutdown();
break;
default:
return;
}
}
void
_wmud_shutdown_thread(gpointer data, gpointer user_data)
{
wMUDThreadData *thread = (wMUDThreadData *)data;
wmud_log_debug("Shutting down %s thread", thread->name);
if (thread->main_loop)
{
Context;
wmud_log_debug("Stopping %s thread's main loop", thread->name);
g_main_loop_quit(thread->main_loop);
while (1)
{
if (!thread->running)
{
break;
}
usleep(200);
}
}
Context;
}
void
wmud_shutdown(void)
{
wmud_log_info("Shutting down...");
Context g_slist_foreach(wmud_running_threads, _wmud_shutdown_thread, NULL);
if (wmud_main_loop)
{
Context g_main_loop_quit(wmud_main_loop);
g_main_loop_unref(wmud_main_loop);
wmud_main_loop = NULL;
}
wmud_is_running = FALSE;
Context wmud_log_info("Shutdown complete");
}
void
wmud_parse_options(gint *argc, gchar ***argv)
{
GOptionContext *options_context;
GError *error = NULL;
options_context = g_option_context_new("wMUD server");
g_option_context_add_main_entries(options_context, option_entries, NULL);
if (!g_option_context_parse(options_context, argc, argv, &error))
{
g_log(NULL, G_LOG_FLAG_FATAL | G_LOG_LEVEL_ERROR, "Failed parsing options: %s\n", error->message);
}
}
static GThread *
_new_thread(GThreadFunc thread_func, GError **error, gchar *thread_name, gboolean fatal_if_fail)
{
GThread *thread;
wMUDThreadData *thread_data;
/* Create and initialize thread data */
thread_data = g_new0(wMUDThreadData, 1);
thread_data->main_loop = NULL;
thread_data->main_context = NULL;
thread_data->thread = NULL;
thread_data->name = g_strdup(thread_name);
thread_data->running = FALSE;
if ((thread = g_thread_create(thread_func, thread_data, FALSE, error)) == NULL)
{
wmud_log_error("Unable to start %s thread!", thread_name);
if (fatal_if_fail)
{
wmud_shutdown();
}
g_free(thread_data);
}
else
{
thread_data->thread = thread;
wmud_running_threads = g_slist_append(wmud_running_threads, thread_data);
}
return thread;
}
int
main(int argc, char **argv)
{
GError *error;
GThread *thread;
struct sigaction signal_action;
wmud_pid = getpid();
wmud_log_info("wMUD v%s starting up", PACKAGE_VERSION);
signal_action.sa_handler = _fatal_signal_handler;
sigemptyset(&signal_action.sa_mask);
signal_action.sa_flags = 0;
sigaction(SIGSEGV, &signal_action, NULL);
signal_action.sa_handler = _terminating_signal_handler;
sigemptyset(&signal_action.sa_mask);
signal_action.sa_flags = 0;
sigaction(SIGINT, &signal_action, NULL);
Context g_type_init();
Context gnet_init();
gnome_vfs_init();
Context wmud_parse_options(&argc, &argv);
Context;
/* TODO: Make this configurable via configure, and/or countable based on sysconfdir */
if (wmud_option_configfile == NULL)
{
wmud_option_configfile = g_strdup(DEFAULT_CONFIGFILE);
}
if (!wmud_configfile_read(wmud_option_configfile, &wmud_configuration, &error))
{
return 1;
}
if (wmud_configuration == NULL)
{
return 1;
}
Context g_free(wmud_option_configfile);
Context wmud_fill_callable_table();
Context wmud_load_config_modules(wmud_configuration);
return 0;
if (wmud_logger_init(wmud_configuration))
{
wmud_log_debug("Logger initialized");
Context if (!g_thread_supported())
{
g_thread_init(NULL);
}
Context thread = _new_thread(wmud_networking_thread, &error, "networking", TRUE);
Context thread = _new_thread(wmud_world_thread, &error, "world", TRUE);
Context thread = _new_thread(wmud_chat_thread, &error, "chat", TRUE);
Context;
wmud_main_loop = g_main_loop_new(NULL, FALSE);
wmud_is_running = TRUE;
g_main_loop_run(wmud_main_loop);
}
wmud_configuration_free(&wmud_configuration);
if (wmud_is_running)
{
wmud_shutdown();
}
Context gnome_vfs_shutdown();
wmud_log_debug("Good bye...");
return 0;
}

32
src/wmud.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef __WMUD_CORE_WMUD_H__
#define __WMUD_CODE_WMUD_H__
#include <glib.h>
/* DEBUG is defined in config.h, if present.
* DEBUG is needed for Context, so let's include config.h here.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <sys/types.h>
typedef struct _wMUDThreadData
{
GMainContext *main_context;
GMainLoop *main_loop;
GThread *thread;
gchar *name;
gboolean running;
} wMUDThreadData;
extern pid_t wmud_pid;
void wmud_shutdown(void);
#ifdef DEBUG
void wmud_print_context(char *filename, int linenum);
#endif /* DEBUG */
#endif /* __WMUD_CORE_WMUD_H__ */

47
src/world.c Normal file
View File

@ -0,0 +1,47 @@
#include <glib.h>
#include "wmud-world.h"
#include "wmud.h"
#include "logger.h"
gpointer
wmud_world_thread(gpointer data)
{
wMUDWorld *world;
wMUDThreadData *thread_data = (wMUDThreadData *)data;
wmud_log_info("Initializing world...");
/* g_main_context_get_thread_default() is only available since GLib 2.22;
* use g_main_context_new() otherwise
*/
#if (((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION >= 22)) || (GLIB_MAJOR_VERSION > 2))
thread_data->main_context = g_main_context_get_thread_default();
#else
thread_data->main_context = g_main_context_new();
#endif
thread_data->main_loop = g_main_loop_new(thread_data->main_context, FALSE);
/* TODO: Do the real initialization here */
world = wmud_world_new();
wmud_log_info("World initialized");
thread_data->running = TRUE;
g_main_loop_run(thread_data->main_loop);
g_main_loop_unref(thread_data->main_loop);
thread_data->main_loop = NULL;
wmud_log_info("World layer shutting down...");
thread_data->running = FALSE;
return NULL;
}

7
src/world.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef __WMUD_CORE_WORLD_H__
#define __WMUD_CORE_WORLD_H__
gpointer wmud_world_thread(gpointer data);
#endif /* __WMUD_CORE_WORLD_H__ */