2005-11-07 10:56:25 +01:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <time.h>
|
2005-11-19 14:11:50 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
#include "gm-world.h"
|
|
|
|
#include "gm-app.h"
|
|
|
|
#include "mcp/gm-mcp-session.h"
|
|
|
|
#include "gm-triggers.h"
|
|
|
|
#include "gm-marshal.h"
|
|
|
|
#include "gm-net.h"
|
|
|
|
#include "gm-support.h"
|
|
|
|
#include "gm-debug.h"
|
|
|
|
|
|
|
|
#define GM_WORLD_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
|
|
|
GM_TYPE_WORLD, GmWorldPrivate))
|
|
|
|
|
|
|
|
void gm_world_save_input_history(GmWorld *world);
|
|
|
|
void gm_world_load_input_history(GmWorld *world);
|
|
|
|
void gm_world_load_triggers(GmWorld *world);
|
|
|
|
|
|
|
|
void on_gm_world_net_state_changing(GmNet *net, GmNetState state,
|
|
|
|
GmWorld *world);
|
2005-11-15 13:00:18 +01:00
|
|
|
void on_gm_world_net_state_changed(GmNet *net, GmNetState state,
|
|
|
|
GmWorld *world);
|
2005-11-07 10:56:25 +01:00
|
|
|
void on_gm_world_net_net_error(GmNet *net, gchar *error, gint code,
|
|
|
|
GmWorld *world);
|
|
|
|
void on_gm_world_net_bytes_recv(GmNet *net, gchar *text, gint len,
|
|
|
|
GmWorld *world);
|
|
|
|
void on_gm_world_options_option_changed(GmOptions *options, gchar *key,
|
|
|
|
GmWorld *world);
|
2005-11-15 13:00:18 +01:00
|
|
|
void on_gm_world_editor_save(GmEditor *editor, GmWorld *world);
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
struct _GmWorldPrivate {
|
|
|
|
gchar *path;
|
|
|
|
gboolean loaded;
|
|
|
|
gboolean active;
|
|
|
|
guint activity;
|
|
|
|
gchar *buffer;
|
2006-01-06 00:26:10 +01:00
|
|
|
gboolean manual_disconnect;
|
|
|
|
time_t manual_disconnect_timeout;
|
|
|
|
guint reconnect_id;
|
|
|
|
time_t last_command;
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
GmOptions *options;
|
|
|
|
GmTriggers *triggers;
|
|
|
|
GmNet *net;
|
|
|
|
GmMcpSession *mcp;
|
|
|
|
GList *history;
|
|
|
|
GList *editors;
|
|
|
|
GmEditingInfo editing_info;
|
2005-11-19 14:11:50 +01:00
|
|
|
|
|
|
|
gint last_day;
|
|
|
|
gint fd_log;
|
2005-11-07 10:56:25 +01:00
|
|
|
};
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
/* Properties */
|
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
|
|
|
|
PROP_NAME,
|
|
|
|
PROP_ACTIVE,
|
|
|
|
PROP_ACTIVITY
|
|
|
|
};
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
/* Signals */
|
|
|
|
|
|
|
|
enum {
|
|
|
|
ACTIVATE_REQUEST,
|
|
|
|
LOAD,
|
|
|
|
UNLOAD,
|
|
|
|
STATE_CHANGING,
|
|
|
|
WORLD_ERROR,
|
|
|
|
TEXT_RECEIVED,
|
|
|
|
EDITOR_ADDED,
|
|
|
|
EDITOR_REMOVED,
|
2006-01-02 18:55:40 +01:00
|
|
|
HIGHLIGHT,
|
2006-01-06 00:26:10 +01:00
|
|
|
NOTIFY_MESSAGE,
|
2005-11-07 10:56:25 +01:00
|
|
|
NUM_SIGNALS
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint world_signals[NUM_SIGNALS] = {0};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(GmWorld, gm_world, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
static void
|
|
|
|
gm_world_finalize(GObject *object) {
|
|
|
|
GmWorld *world = GM_WORLD(object);
|
|
|
|
|
|
|
|
if (world->priv->path) {
|
|
|
|
gm_options_save(world->priv->options);
|
|
|
|
gm_world_save_input_history(world);
|
|
|
|
gm_triggers_save(world->priv->triggers);
|
|
|
|
}
|
|
|
|
|
2005-11-19 14:11:50 +01:00
|
|
|
if (world->priv->fd_log > 0) {
|
|
|
|
close(world->priv->fd_log);
|
|
|
|
}
|
2006-01-06 00:26:10 +01:00
|
|
|
|
|
|
|
if (world->priv->reconnect_id) {
|
|
|
|
g_source_remove(world->priv->reconnect_id);
|
|
|
|
}
|
2005-11-19 14:11:50 +01:00
|
|
|
|
2005-11-15 13:00:18 +01:00
|
|
|
gm_g_list_free_simple(world->priv->history);
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
g_free(world->priv->path);
|
|
|
|
g_free(world->priv->buffer);
|
|
|
|
g_free(world->priv->editing_info.name);
|
|
|
|
g_free(world->priv->editing_info.upload);
|
|
|
|
g_list_free(world->priv->editing_info.lines);
|
|
|
|
|
|
|
|
g_object_unref(world->priv->triggers);
|
|
|
|
g_object_unref(world->priv->options);
|
|
|
|
g_object_unref(world->priv->net);
|
|
|
|
g_object_unref(world->priv->mcp);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(gm_world_parent_class)->finalize(object);
|
|
|
|
}
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
static void
|
|
|
|
gm_world_get_property(GObject *object, guint prop_id, GValue *value,
|
|
|
|
GParamSpec *pspec) {
|
|
|
|
GmWorld *world = GM_WORLD(object);
|
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
case PROP_NAME:
|
|
|
|
g_value_set_string(value, gm_world_name(world));
|
|
|
|
break;
|
|
|
|
case PROP_ACTIVE:
|
|
|
|
g_value_set_boolean(value, world->priv->active);
|
|
|
|
break;
|
|
|
|
case PROP_ACTIVITY:
|
|
|
|
g_value_set_int(value, world->priv->activity);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
static void
|
|
|
|
gm_world_class_init(GmWorldClass *klass) {
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
|
|
|
|
|
|
|
object_class->finalize = gm_world_finalize;
|
2006-01-06 00:26:10 +01:00
|
|
|
object_class->get_property = gm_world_get_property;
|
|
|
|
|
|
|
|
g_object_class_install_property(object_class, PROP_NAME,
|
|
|
|
g_param_spec_string("name", "NAME", "The worlds name", NULL,
|
|
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property(object_class, PROP_ACTIVE,
|
|
|
|
g_param_spec_boolean("active", "ACTIVE", "If world is active",
|
|
|
|
FALSE, G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property(object_class, PROP_ACTIVITY,
|
|
|
|
g_param_spec_boolean("activity", "ACTIVITY", "Lines of activity",
|
|
|
|
0, G_PARAM_READABLE));
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
world_signals[ACTIVATE_REQUEST] =
|
|
|
|
g_signal_new("activate_request",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, activate_request),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
0);
|
|
|
|
|
|
|
|
world_signals[LOAD] =
|
|
|
|
g_signal_new("load",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, load),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
0);
|
|
|
|
|
|
|
|
world_signals[UNLOAD] =
|
|
|
|
g_signal_new("unload",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, unload),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
0);
|
|
|
|
|
|
|
|
world_signals[STATE_CHANGING] =
|
|
|
|
g_signal_new("state_changing",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, state_changing),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__UINT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_UINT);
|
|
|
|
|
|
|
|
world_signals[WORLD_ERROR] =
|
|
|
|
g_signal_new("world_error",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, world_error),
|
|
|
|
NULL, NULL,
|
|
|
|
gm_marshal_VOID__STRING_INT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
2,
|
|
|
|
G_TYPE_STRING,
|
|
|
|
G_TYPE_INT);
|
|
|
|
|
|
|
|
world_signals[TEXT_RECEIVED] =
|
|
|
|
g_signal_new("text_received",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, text_received),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_STRING);
|
|
|
|
|
|
|
|
world_signals[EDITOR_ADDED] =
|
|
|
|
g_signal_new("editor_added",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, editor_added),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
world_signals[EDITOR_REMOVED] =
|
|
|
|
g_signal_new("editor_removed",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, editor_removed),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_OBJECT);
|
|
|
|
|
2006-01-02 18:55:40 +01:00
|
|
|
world_signals[HIGHLIGHT] =
|
|
|
|
g_signal_new("highlight",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, highlight),
|
|
|
|
NULL, NULL,
|
|
|
|
gm_marshal_VOID__INT_INT_STRING,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
3,
|
|
|
|
G_TYPE_INT,
|
|
|
|
G_TYPE_INT,
|
|
|
|
G_TYPE_STRING);
|
2006-01-06 00:26:10 +01:00
|
|
|
|
|
|
|
world_signals[NOTIFY_MESSAGE] =
|
|
|
|
g_signal_new("notify_message",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, notify_message),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_STRING);
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
g_type_class_add_private(object_class, sizeof(GmWorldPrivate));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_create_default_settings(GmWorld *world) {
|
|
|
|
const gchar *loc = gm_default_charset();
|
|
|
|
|
|
|
|
world->priv->options = gm_options_new();
|
|
|
|
|
|
|
|
gm_options_set(world->priv->options, "name", "");
|
|
|
|
gm_options_set(world->priv->options, "autoload", "0");
|
|
|
|
gm_options_set(world->priv->options, "host", "");
|
|
|
|
gm_options_set(world->priv->options, "port", "1111");
|
|
|
|
gm_options_set(world->priv->options, "player_name", "");
|
|
|
|
gm_options_set(world->priv->options, "reconnect", "0");
|
|
|
|
gm_options_set(world->priv->options, "password", "");
|
|
|
|
gm_options_set(world->priv->options, "charset", (gchar *)loc);
|
|
|
|
gm_options_set(world->priv->options, "history_length", "500");
|
|
|
|
|
|
|
|
// Non configurable options
|
|
|
|
gm_options_set(world->priv->options, "pane_position", "150");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gm_world_init(GmWorld *world) {
|
|
|
|
world->priv = GM_WORLD_GET_PRIVATE(world);
|
|
|
|
|
|
|
|
gm_world_create_default_settings(world);
|
2006-01-10 01:42:09 +01:00
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
world->priv->path = NULL;
|
|
|
|
world->priv->loaded = FALSE;
|
|
|
|
world->priv->history = NULL;
|
|
|
|
world->priv->activity = 0;
|
|
|
|
world->priv->triggers = gm_triggers_new();
|
|
|
|
world->priv->net = gm_net_new();
|
|
|
|
world->priv->mcp = gm_mcp_session_new(G_OBJECT(world));
|
|
|
|
world->priv->buffer = NULL;
|
|
|
|
world->priv->editing_info.is_editing = FALSE;
|
|
|
|
|
|
|
|
g_signal_connect(world->priv->net, "state_changing",
|
|
|
|
G_CALLBACK(on_gm_world_net_state_changing), world);
|
2005-11-15 13:00:18 +01:00
|
|
|
g_signal_connect(world->priv->net, "state_changed",
|
|
|
|
G_CALLBACK(on_gm_world_net_state_changed), world);
|
2005-11-07 10:56:25 +01:00
|
|
|
g_signal_connect(world->priv->net, "net_error",
|
|
|
|
G_CALLBACK(on_gm_world_net_net_error), world);
|
|
|
|
g_signal_connect(world->priv->net, "bytes_recv",
|
|
|
|
G_CALLBACK(on_gm_world_net_bytes_recv), world);
|
|
|
|
g_signal_connect(world->priv->options, "option_changed",
|
|
|
|
G_CALLBACK(on_gm_world_options_option_changed), world);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_load_input_history(GmWorld *world) {
|
|
|
|
FILE *f;
|
|
|
|
gchar line[1024], *filename;
|
|
|
|
GString *str;
|
|
|
|
|
|
|
|
filename = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "history",
|
|
|
|
NULL);
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.LoadInputHistory: loading history "
|
|
|
|
"(%s)!", filename);
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
if ((f = fopen(filename, "r")) != NULL) {
|
|
|
|
str = g_string_new("");
|
|
|
|
|
|
|
|
while (fgets(line, 1024 - 1, f) != NULL) {
|
|
|
|
g_string_append(str, line);
|
|
|
|
if (line[strlen(line) - 1] == '\n') {
|
2006-01-06 00:26:10 +01:00
|
|
|
if (line[1] != '\0') {
|
|
|
|
// Empty lines, we don't need to process those
|
2005-11-07 10:56:25 +01:00
|
|
|
world->priv->history = g_list_append(world->priv->history,
|
|
|
|
g_strndup(str->str, strlen(str->str) - 1));
|
|
|
|
}
|
|
|
|
g_string_erase(str, 0, -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_free(str, TRUE);
|
|
|
|
fclose(f);
|
|
|
|
} else {
|
2005-12-23 17:10:11 +01:00
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.LoadInputHistory: could not "
|
|
|
|
"retrieve contents of file %s (%s)", filename, strerror(errno));
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
g_free(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_save_input_history(GmWorld *world) {
|
|
|
|
FILE *f;
|
|
|
|
gchar *filename;
|
|
|
|
GList *elem;
|
|
|
|
|
|
|
|
if (world->priv->path == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-12-23 17:10:11 +01:00
|
|
|
filename = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "history",
|
|
|
|
NULL);
|
2005-11-07 10:56:25 +01:00
|
|
|
f = fopen(filename, "w");
|
2005-12-23 17:10:11 +01:00
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
if (f) {
|
2005-12-23 17:10:11 +01:00
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.SaveInputHistory: saving input "
|
|
|
|
"history to %s", filename);
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
for (elem = world->priv->history; elem; elem = elem->next) {
|
|
|
|
fprintf(f, "%s\n", (gchar *) (elem->data));
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
chmod(filename, 0660);
|
|
|
|
} else {
|
2005-12-23 17:10:11 +01:00
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.SaveInputHistory: couldn't open "
|
|
|
|
"history file (%s) for saving: %s", filename, strerror(errno));
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
g_free(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_load_triggers(GmWorld *world) {
|
|
|
|
gchar *path;
|
|
|
|
|
|
|
|
if (world->priv->triggers) {
|
|
|
|
g_object_unref(world->priv->triggers);
|
|
|
|
}
|
|
|
|
|
|
|
|
path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "triggers", NULL);
|
|
|
|
world->priv->triggers = gm_triggers_new_from_file(path);
|
|
|
|
g_free(path);
|
|
|
|
}
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
static gboolean
|
|
|
|
gm_world_reconnect(GmWorld *world) {
|
|
|
|
world->priv->reconnect_id = 0;
|
|
|
|
const gchar *host, *port;
|
|
|
|
|
|
|
|
host = gm_net_current_host(world->priv->net);
|
|
|
|
port = gm_net_current_port(world->priv->net);
|
|
|
|
|
|
|
|
if (!host) {
|
|
|
|
host = gm_options_get(world->priv->options, "host");
|
|
|
|
}
|
|
|
|
if (!port) {
|
|
|
|
port = gm_options_get(world->priv->options, "port");
|
|
|
|
}
|
|
|
|
|
|
|
|
gm_world_connect_to(world, host, port);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2006-02-06 19:41:04 +01:00
|
|
|
void
|
|
|
|
gm_world_check_dirs(GmWorld *world) {
|
|
|
|
gchar *tmp_path;
|
|
|
|
|
|
|
|
tmp_path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "logs",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (!g_file_test(tmp_path, G_FILE_TEST_EXISTS)) {
|
|
|
|
mkdir(tmp_path, 0750);
|
|
|
|
} else {
|
|
|
|
chmod(tmp_path, 0750);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(tmp_path);
|
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
/* Public */
|
|
|
|
GmWorld *
|
|
|
|
gm_world_new(gchar *path) {
|
|
|
|
GmWorld *world = GM_WORLD(g_object_new(GM_TYPE_WORLD, NULL));
|
|
|
|
gchar *options_path;
|
|
|
|
|
|
|
|
if (path != NULL) {
|
|
|
|
options_path = g_strconcat(path, "/settings", NULL);
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.new: creating new world for %s",
|
|
|
|
path);
|
2005-11-07 10:56:25 +01:00
|
|
|
world->priv->path = g_strdup(path);
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.new: creating default world "
|
|
|
|
"settings for %s", path);
|
2005-11-07 10:56:25 +01:00
|
|
|
gm_options_load(world->priv->options, options_path);
|
|
|
|
|
|
|
|
if (strlen(gm_options_get(world->priv->options, "charset")) == 0) {
|
|
|
|
gm_options_set(world->priv->options, "charset",
|
|
|
|
gm_default_charset());
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(options_path);
|
|
|
|
|
|
|
|
gm_world_load_input_history(world);
|
|
|
|
gm_world_load_triggers(world);
|
2006-02-06 19:41:04 +01:00
|
|
|
|
|
|
|
gm_world_check_dirs(world);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* CHECK: all done? */
|
|
|
|
|
|
|
|
return world;
|
|
|
|
}
|
|
|
|
|
|
|
|
GmWorld *
|
|
|
|
gm_world_dup(GmWorld *source) {
|
|
|
|
GmWorld *copy = gm_world_new(NULL);
|
|
|
|
|
|
|
|
g_object_unref(copy->priv->options);
|
|
|
|
|
|
|
|
copy->priv->options = gm_options_dup(source->priv->options);
|
|
|
|
copy->priv->triggers = gm_triggers_dup(source->priv->triggers);
|
|
|
|
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_load(GmWorld *world) {
|
|
|
|
if (world->priv->loaded) {
|
|
|
|
g_signal_emit(world, world_signals[ACTIVATE_REQUEST], 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->priv->loaded = TRUE;
|
|
|
|
g_signal_emit(world, world_signals[LOAD], 0);
|
|
|
|
g_signal_emit(world, world_signals[ACTIVATE_REQUEST], 0);
|
|
|
|
gm_world_connect(world);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_unload(GmWorld *world) {
|
|
|
|
if (world->priv->loaded) {
|
|
|
|
world->priv->loaded = FALSE;
|
|
|
|
gm_world_disconnect(world);
|
|
|
|
|
2005-11-15 13:00:18 +01:00
|
|
|
while (world->priv->editors) {
|
|
|
|
gm_world_remove_editor(world,
|
|
|
|
GM_EDITOR(world->priv->editors->data));
|
|
|
|
}
|
2006-01-06 00:26:10 +01:00
|
|
|
|
|
|
|
if (world->priv->reconnect_id) {
|
|
|
|
g_source_remove(world->priv->reconnect_id);
|
|
|
|
world->priv->reconnect_id = 0;
|
|
|
|
}
|
2005-11-07 10:56:25 +01:00
|
|
|
|
2005-11-15 13:00:18 +01:00
|
|
|
g_signal_emit(world, world_signals[UNLOAD], 0);
|
|
|
|
}
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
GmTriggers *
|
|
|
|
gm_world_triggers(GmWorld *world) {
|
|
|
|
return world->priv->triggers;
|
|
|
|
}
|
|
|
|
|
|
|
|
GmOptions *
|
|
|
|
gm_world_options(GmWorld *world) {
|
|
|
|
return world->priv->options;
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gm_world_name(GmWorld *world) {
|
|
|
|
return gm_options_get(world->priv->options, "name");
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gm_world_path(GmWorld *world) {
|
|
|
|
return world->priv->path;
|
|
|
|
}
|
|
|
|
|
|
|
|
GList **
|
|
|
|
gm_world_history(GmWorld *world) {
|
|
|
|
return &(world->priv->history);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gm_world_loaded(GmWorld *world) {
|
|
|
|
return world->priv->loaded;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gm_world_connected(GmWorld *world) {
|
|
|
|
return gm_net_state(world->priv->net) == GM_NET_STATE_CONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gm_world_disconnected(GmWorld *world) {
|
|
|
|
return gm_net_state(world->priv->net) == GM_NET_STATE_DISCONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
GmNetState
|
|
|
|
gm_world_state(GmWorld *world) {
|
|
|
|
return gm_net_state(world->priv->net);
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gm_world_current_host(GmWorld *world) {
|
|
|
|
return gm_net_current_host(world->priv->net);
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gm_world_current_port(GmWorld *world) {
|
|
|
|
return gm_net_current_port(world->priv->net);
|
|
|
|
}
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
void
|
|
|
|
gm_world_connect_to(GmWorld *world, gchar const *host, gchar const *port) {
|
|
|
|
if (world->priv->reconnect_id) {
|
|
|
|
g_source_remove(world->priv->reconnect_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
gm_net_connect(world->priv->net, host, port);
|
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
void
|
|
|
|
gm_world_connect(GmWorld *world) {
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_world_connect_to(world,
|
2005-11-07 10:56:25 +01:00
|
|
|
gm_options_get(world->priv->options, "host"),
|
|
|
|
gm_options_get(world->priv->options, "port"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_world_disconnect(GmWorld *world) {
|
|
|
|
world->priv->manual_disconnect = TRUE;
|
|
|
|
world->priv->manual_disconnect_timeout = time(0) + 5;
|
|
|
|
gm_net_disconnect(world->priv->net);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_world_prepare_disconnect(GmWorld *world) {
|
|
|
|
world->priv->manual_disconnect = TRUE;
|
|
|
|
world->priv->manual_disconnect_timeout = time(0) + 5;
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
2005-12-23 17:10:11 +01:00
|
|
|
gboolean
|
|
|
|
gm_world_log_allowed(GmLogType type) {
|
|
|
|
GmOptions *options = gm_app_options(gm_app_instance());
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case LOG_IN:
|
|
|
|
return gm_options_get_int(options, "logging_in");
|
|
|
|
break;
|
|
|
|
case LOG_OUT:
|
|
|
|
return gm_options_get_int(options, "logging_out");
|
|
|
|
break;
|
|
|
|
case LOG_STATUS:
|
|
|
|
return gm_options_get_int(options, "logging_status");
|
|
|
|
break;
|
|
|
|
case LOG_MCP_IN:
|
|
|
|
return gm_options_get_int(options, "logging_mcp_in");
|
|
|
|
break;
|
|
|
|
case LOG_MCP_OUT:
|
|
|
|
return gm_options_get_int(options, "logging_mcp_out");
|
|
|
|
break;
|
|
|
|
case LOG_MCP_STATUS:
|
|
|
|
return gm_options_get_int(options, "logging_mcp_status");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
void
|
|
|
|
gm_world_log(GmWorld *world, GmLogType type, gchar *text) {
|
|
|
|
GString *s;
|
|
|
|
gchar *start, *log, *no_ansi;
|
|
|
|
struct tm *timet;
|
|
|
|
time_t timer;
|
2005-11-19 14:11:50 +01:00
|
|
|
gint len;
|
|
|
|
|
|
|
|
if (type == LOG_NONE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-12-23 17:10:11 +01:00
|
|
|
// Check whether to log at all
|
|
|
|
if (!gm_options_get_int(gm_app_options(gm_app_instance()),
|
|
|
|
"logging_enable")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether to log this type
|
|
|
|
if (!gm_world_log_allowed(type)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
timer = time(0);
|
|
|
|
timet = localtime(&timer);
|
|
|
|
|
2005-11-19 14:11:50 +01:00
|
|
|
if (world->priv->fd_log <= 0 || world->priv->last_day != timet->tm_mday) {
|
|
|
|
if (world->priv->fd_log > 0) {
|
|
|
|
close(world->priv->fd_log);
|
|
|
|
}
|
|
|
|
|
|
|
|
log = g_strdup_printf("%s/logs/%04d-%02d-%02d.log", world->priv->path,
|
|
|
|
timet->tm_year + 1900, timet->tm_mon + 1, timet->tm_mday);
|
|
|
|
world->priv->fd_log = open(log, O_APPEND | O_CREAT | O_RDWR,
|
|
|
|
S_IRUSR | S_IWUSR);
|
|
|
|
g_free(log);
|
|
|
|
|
|
|
|
world->priv->last_day = timet->tm_mday;
|
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
|
2005-11-19 14:11:50 +01:00
|
|
|
if (world->priv->fd_log == -1) {
|
2005-11-07 10:56:25 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = g_strdup_printf("[%02d:%02d:%02d] ", timet->tm_hour, timet->tm_min,
|
|
|
|
timet->tm_sec);
|
|
|
|
|
|
|
|
s = g_string_new(start);
|
|
|
|
g_free(start);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case LOG_IN:
|
|
|
|
s = g_string_append_c(s, '<');
|
|
|
|
break;
|
|
|
|
case LOG_OUT:
|
|
|
|
s = g_string_append_c(s, '>');
|
|
|
|
break;
|
2005-12-23 17:10:11 +01:00
|
|
|
case LOG_STATUS:
|
|
|
|
s = g_string_append_c(s, '#');
|
|
|
|
break;
|
2005-11-07 10:56:25 +01:00
|
|
|
case LOG_MCP_IN:
|
|
|
|
s = g_string_append(s, "[MCP] <");
|
|
|
|
break;
|
|
|
|
case LOG_MCP_OUT:
|
|
|
|
s = g_string_append(s, "[MCP] >");
|
|
|
|
break;
|
2005-12-23 17:10:11 +01:00
|
|
|
case LOG_MCP_STATUS:
|
|
|
|
s = g_string_append(s, "[MCP] #");
|
2005-11-07 10:56:25 +01:00
|
|
|
break;
|
2005-11-19 14:11:50 +01:00
|
|
|
default:
|
|
|
|
break;
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
s = g_string_append(s, " ");
|
|
|
|
s = g_string_append(s, text);
|
|
|
|
|
2005-11-19 14:11:50 +01:00
|
|
|
no_ansi = gm_ansi_strip(g_strdup(s->str));
|
|
|
|
len = strlen(no_ansi);
|
2005-11-07 10:56:25 +01:00
|
|
|
|
2005-11-19 14:11:50 +01:00
|
|
|
write(world->priv->fd_log, no_ansi, strlen(no_ansi));
|
|
|
|
|
|
|
|
if (no_ansi[len - 1] != '\n') {
|
|
|
|
write(world->priv->fd_log, "\n", 1);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
g_free(no_ansi);
|
|
|
|
g_string_free(s, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_parse_legacy_editing_start(GmWorld *world, gchar *line) {
|
|
|
|
gchar *name_start, *upload_start;
|
|
|
|
GmEditingInfo *einfo = &(world->priv->editing_info);
|
|
|
|
|
|
|
|
name_start = strstr(line, "name: ");
|
|
|
|
|
|
|
|
if (!name_start) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
upload_start = strstr(line, " upload: ");
|
|
|
|
|
|
|
|
if (!upload_start) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
einfo->is_editing = TRUE;
|
|
|
|
einfo->name = g_strndup(name_start + 6, (upload_start - name_start) - 6);
|
2006-01-08 17:34:24 +01:00
|
|
|
einfo->upload = g_strndup(upload_start + 9, (upload_start - line) + 9);
|
2005-11-07 10:56:25 +01:00
|
|
|
einfo->lines = NULL;
|
|
|
|
}
|
|
|
|
|
2006-01-02 18:55:40 +01:00
|
|
|
#define MAX_MATCHES 10
|
|
|
|
|
|
|
|
gchar *
|
|
|
|
gm_world_triggers_subst(gchar const *data, gchar const *text,
|
|
|
|
regmatch_t *matches) {
|
|
|
|
gchar *tmp = (gchar *)data;
|
|
|
|
gchar *p, *ptr, *tmp2;
|
|
|
|
GString *result = NULL;
|
|
|
|
gint n;
|
|
|
|
gunichar c;
|
|
|
|
|
|
|
|
result = g_string_new(NULL);
|
|
|
|
|
|
|
|
while ((p = g_utf8_strchr(tmp, -1, '\\'))) {
|
|
|
|
n = 0;
|
|
|
|
ptr = g_utf8_next_char(p);
|
|
|
|
|
|
|
|
g_string_append_len(result, tmp, g_utf8_strlen(tmp, -1) -
|
|
|
|
g_utf8_strlen(p, -1));
|
|
|
|
|
|
|
|
if (g_unichar_isdigit(g_utf8_get_char(ptr))) {
|
|
|
|
while ((c = (g_utf8_get_char(ptr))) != 0 && g_unichar_isdigit(c)) {
|
|
|
|
n = (n * 10) + g_unichar_digit_value(c);
|
|
|
|
ptr = g_utf8_next_char(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Replace it */
|
|
|
|
if (n < MAX_MATCHES) {
|
|
|
|
tmp2 = g_strndup(g_utf8_offset_to_pointer(text,
|
|
|
|
matches[n].rm_so), matches[n].rm_eo);
|
|
|
|
g_string_append(result, tmp2);
|
|
|
|
g_free(tmp2);
|
|
|
|
}
|
|
|
|
tmp = ptr;
|
|
|
|
} else {
|
|
|
|
tmp = ptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_append(result, tmp);
|
|
|
|
tmp = result->str;
|
|
|
|
g_string_free(result, FALSE);
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_apply_trigger(GmWorld *world, GmTrigger *trigger, gchar const *text,
|
|
|
|
regmatch_t *matches) {
|
|
|
|
GList *item;
|
|
|
|
GmTriggerData *data;
|
|
|
|
gint i, nargs;
|
2006-01-06 01:27:43 +01:00
|
|
|
gchar **spawn_args, *tmp;
|
|
|
|
#ifdef HAVE_RUBY
|
|
|
|
gchar *argstr;
|
|
|
|
#endif
|
2006-01-02 18:55:40 +01:00
|
|
|
|
|
|
|
for (item = trigger->actions; item; item = item->next) {
|
|
|
|
data = (GmTriggerData *)(item->data);
|
|
|
|
|
|
|
|
switch (data->type) {
|
|
|
|
case TAT_HIGHLIGHT_LINE:
|
|
|
|
g_signal_emit(world, world_signals[HIGHLIGHT], 0, -1, -1,
|
|
|
|
data->data);
|
|
|
|
break;
|
|
|
|
case TAT_HIGHLIGHT_MATCH:
|
|
|
|
for (i = 0; matches[i].rm_so != -1; ++i) {
|
|
|
|
g_signal_emit(world, world_signals[HIGHLIGHT], 0,
|
|
|
|
matches[i].rm_so, matches[i].rm_eo, data->data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TAT_BEEP:
|
|
|
|
gdk_beep();
|
|
|
|
break;
|
|
|
|
case TAT_PLAY_SOUND:
|
|
|
|
tmp = gm_world_triggers_subst(data->data, text, matches);
|
|
|
|
// TODO
|
|
|
|
g_free(tmp);
|
|
|
|
break;
|
|
|
|
case TAT_NOTIFY:
|
|
|
|
tmp = gm_world_triggers_subst(data->data, text, matches);
|
2006-01-06 00:26:10 +01:00
|
|
|
g_signal_emit(world, world_signals[NOTIFY_MESSAGE], 0, tmp);
|
2006-01-02 18:55:40 +01:00
|
|
|
g_free(tmp);
|
|
|
|
break;
|
|
|
|
case TAT_RUN_SCRIPT:
|
|
|
|
#ifdef HAVE_RUBY
|
|
|
|
tmp = gm_world_triggers_subst(data->data, text, matches);
|
|
|
|
argstr = g_utf8_strchr(tmp, -1, ' ');
|
|
|
|
|
|
|
|
if (argstr) {
|
|
|
|
*argstr = '\0';
|
|
|
|
argstr = g_utf8_next_char(argstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
gm_scripts_run(gm_app_scripts(gm_app_instance()),
|
|
|
|
world, tmp, argstr);
|
|
|
|
|
|
|
|
g_free(tmp);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case TAT_RUN:
|
|
|
|
tmp = gm_world_triggers_subst(data->data, text, matches);
|
|
|
|
|
|
|
|
if (g_shell_parse_argv(tmp, &nargs, &spawn_args, NULL)) {
|
|
|
|
g_spawn_async(NULL, spawn_args, NULL, G_SPAWN_SEARCH_PATH,
|
|
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
g_strfreev(spawn_args);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(tmp);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_process_triggers(GmWorld *world, gchar *text) {
|
|
|
|
GList const *item;
|
|
|
|
GmTrigger *trigger;
|
|
|
|
regmatch_t matches[MAX_MATCHES];
|
|
|
|
|
|
|
|
for (item = gm_triggers_list(world->priv->triggers); item;
|
|
|
|
item = item->next) {
|
|
|
|
trigger = (GmTrigger *)(item->data);
|
|
|
|
|
|
|
|
if (trigger->event == TT_OUTPUT) {
|
|
|
|
if (gm_trigger_match(trigger, text, matches, MAX_MATCHES)) {
|
|
|
|
gm_world_apply_trigger(world, trigger, text, matches);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
void
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_world_process_line(GmWorld *world, gchar *line, gint len) {
|
|
|
|
gchar *non_text_start = NULL, *from;
|
2005-11-07 10:56:25 +01:00
|
|
|
GmEditingInfo *einfo = &(world->priv->editing_info);
|
2005-11-15 13:00:18 +01:00
|
|
|
GmEditor *editor;
|
2006-01-02 18:55:40 +01:00
|
|
|
gchar *no_ansi;
|
2006-01-06 00:26:10 +01:00
|
|
|
gboolean has_ansi_start;
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
if (strncmp(line, "\x1B[0m", 4) == 0) {
|
2006-01-06 00:26:10 +01:00
|
|
|
has_ansi_start = TRUE;
|
|
|
|
from = line + 4;
|
|
|
|
|
|
|
|
if (len != -1) {
|
|
|
|
len = len - 4;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
has_ansi_start = FALSE;
|
|
|
|
from = line;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len == -1) {
|
|
|
|
non_text_start = g_strdup(from);
|
2005-11-07 10:56:25 +01:00
|
|
|
} else {
|
2006-01-06 00:26:10 +01:00
|
|
|
non_text_start = g_strndup(from, len);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (einfo->is_editing) {
|
|
|
|
if (strcmp(non_text_start, ".") == 0) {
|
2005-11-15 13:00:18 +01:00
|
|
|
editor = gm_editor_new(einfo->name, einfo->upload,
|
|
|
|
einfo->lines);
|
|
|
|
|
|
|
|
g_signal_connect(editor, "save",
|
|
|
|
G_CALLBACK(on_gm_world_editor_save), world);
|
|
|
|
|
|
|
|
gm_world_add_editor(world, editor);
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
einfo->is_editing = FALSE;
|
|
|
|
g_free(einfo->name);
|
|
|
|
einfo->name = NULL;
|
2005-11-15 13:00:18 +01:00
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
g_free(einfo->upload);
|
|
|
|
einfo->upload = NULL;
|
2005-11-15 13:00:18 +01:00
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
g_list_free(einfo->lines);
|
|
|
|
einfo->lines = NULL;
|
|
|
|
} else {
|
2006-01-02 18:55:40 +01:00
|
|
|
einfo->lines = g_list_append(einfo->lines,
|
|
|
|
g_strdup(non_text_start));
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
} else if (strncmp(non_text_start, "#$#", 3) == 0) {
|
|
|
|
if (strncasecmp(non_text_start + 3, " edit ", 6) == 0) {
|
|
|
|
gm_world_parse_legacy_editing_start(world, non_text_start + 9);
|
|
|
|
} else {
|
|
|
|
gm_mcp_session_handle_oob(world->priv->mcp, non_text_start + 3);
|
2005-11-19 14:11:50 +01:00
|
|
|
gm_world_log(world, LOG_MCP_IN, non_text_start);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!gm_world_active(world)) {
|
|
|
|
gm_world_set_activity(world, world->priv->activity + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(non_text_start, "#$\"", 3) == 0) {
|
2006-01-06 00:26:10 +01:00
|
|
|
if (has_ansi_start) {
|
2006-01-02 18:55:40 +01:00
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0,
|
|
|
|
"\x1B[0m");
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
2006-01-02 18:55:40 +01:00
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0,
|
|
|
|
non_text_start + 3);
|
2005-11-07 10:56:25 +01:00
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\n");
|
2006-01-02 18:55:40 +01:00
|
|
|
|
|
|
|
gm_world_log(world, LOG_IN, non_text_start + 3);
|
|
|
|
no_ansi = gm_ansi_strip(g_strdup(non_text_start + 3));
|
2005-11-07 10:56:25 +01:00
|
|
|
} else {
|
2006-01-06 00:26:10 +01:00
|
|
|
if (has_ansi_start) {
|
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0,
|
|
|
|
"\x1B[0m");
|
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0,
|
|
|
|
non_text_start);
|
2005-11-07 10:56:25 +01:00
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\n");
|
2006-01-02 18:55:40 +01:00
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_world_log(world, LOG_IN, non_text_start);
|
|
|
|
no_ansi = gm_ansi_strip(g_strdup(non_text_start));
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
2006-01-02 18:55:40 +01:00
|
|
|
|
|
|
|
/* Process triggers */
|
|
|
|
gm_world_process_triggers(world, no_ansi);
|
|
|
|
g_free(no_ansi);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
g_free(non_text_start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_process_input(GmWorld *world, gchar *text) {
|
|
|
|
#ifdef HAVE_RUBY
|
|
|
|
gchar *space, *script, *argstr;
|
|
|
|
gboolean script_ran = FALSE;
|
|
|
|
|
|
|
|
if (g_utf8_strlen(text, -1) > 1) {
|
|
|
|
if (text[0] == '/' && text[1] != '/') {
|
|
|
|
space = strstr(text, " ");
|
|
|
|
|
|
|
|
if (space == NULL) {
|
|
|
|
script = g_strdup(text + 1);
|
|
|
|
argstr = g_strdup("");
|
|
|
|
} else {
|
|
|
|
script = g_strndup(text + 1, (space - text) - 1);
|
|
|
|
argstr = g_strdup(space + 1);
|
|
|
|
}
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.ProcessInput: Trying script "
|
|
|
|
"%s (%s)", script, argstr);
|
2005-11-07 10:56:25 +01:00
|
|
|
script_ran = gm_scripts_run(gm_app_scripts(gm_app_instance()),
|
|
|
|
world, script, argstr);
|
|
|
|
|
|
|
|
g_free(script);
|
|
|
|
g_free(argstr);
|
|
|
|
|
|
|
|
if (script_ran) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (text[0] == '/' && text[1] == '/') {
|
|
|
|
text = text + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
gm_world_sendln(world, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_writeln(GmWorld *world, gchar *text) {
|
|
|
|
gchar *newline = g_strconcat(text, "\n", NULL);
|
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, newline);
|
|
|
|
|
|
|
|
g_free(newline);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_remove_editor(GmWorld *world, GmEditor *editor) {
|
|
|
|
g_return_if_fail(g_list_find(world->priv->editors, editor) != NULL);
|
|
|
|
|
|
|
|
world->priv->editors = g_list_remove(world->priv->editors, editor);
|
|
|
|
g_signal_emit(world, world_signals[EDITOR_REMOVED], 0, G_OBJECT(editor));
|
|
|
|
|
|
|
|
g_object_unref(editor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_add_editor(GmWorld *world, GmEditor *editor) {
|
|
|
|
world->priv->editors = g_list_append(world->priv->editors, editor);
|
|
|
|
|
2005-11-15 13:00:18 +01:00
|
|
|
g_signal_connect_swapped(editor, "close",
|
|
|
|
G_CALLBACK(gm_world_remove_editor), world);
|
|
|
|
g_signal_emit(world, world_signals[EDITOR_ADDED], 0, editor);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2005-11-19 14:11:50 +01:00
|
|
|
gm_world_sendln_log(GmWorld *world, gchar *text, GmLogType logtype) {
|
2005-11-07 10:56:25 +01:00
|
|
|
gchar *normal;
|
|
|
|
|
|
|
|
// Convert text from utf-8 to the correct locale
|
2006-02-06 19:41:04 +01:00
|
|
|
normal = gm_from_utf8_with_fallback(text, -1,
|
2005-11-07 10:56:25 +01:00
|
|
|
gm_options_get(world->priv->options, "charset"), "?");
|
|
|
|
|
|
|
|
if (!normal) {
|
2005-11-19 14:11:50 +01:00
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.SendlnLog: conversion failed!");
|
2005-11-07 10:56:25 +01:00
|
|
|
normal = g_strdup(text);
|
|
|
|
}
|
|
|
|
|
2005-11-19 14:11:50 +01:00
|
|
|
if (logtype != LOG_NONE) {
|
|
|
|
gm_world_log(world, logtype, text);
|
2005-11-15 13:00:18 +01:00
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
gm_net_send_line(world->priv->net, normal);
|
|
|
|
g_free(normal);
|
|
|
|
}
|
|
|
|
|
2005-11-15 13:00:18 +01:00
|
|
|
void
|
|
|
|
gm_world_sendln(GmWorld *world, gchar *text) {
|
2006-01-06 00:26:10 +01:00
|
|
|
world->priv->last_command = time(0);
|
2005-11-19 14:11:50 +01:00
|
|
|
gm_world_sendln_log(world, text, LOG_OUT);
|
2005-11-15 13:00:18 +01:00
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
void
|
|
|
|
gm_world_set_active(GmWorld *world, gboolean active) {
|
|
|
|
world->priv->active = active;
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
g_object_notify(G_OBJECT(world), "active");
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
if (active) {
|
|
|
|
gm_world_set_activity(world, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gm_world_active(GmWorld *world) {
|
|
|
|
return world->priv->active;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_set_activity(GmWorld *world, gint activity) {
|
|
|
|
world->priv->activity = activity;
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
g_object_notify(G_OBJECT(world), "activity");
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
gm_world_activity(GmWorld *world) {
|
|
|
|
return world->priv->activity;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_name_changed(GmWorld *world) {
|
|
|
|
gchar *tmp_path = world->priv->path ? g_strdup(world->priv->path) : NULL;
|
|
|
|
gchar *new_path = g_strconcat(gm_app_worlds_path(gm_app_instance()), "/",
|
|
|
|
gm_options_get(world->priv->options, "name"), NULL);
|
|
|
|
|
|
|
|
if (tmp_path && strcmp(tmp_path, new_path) == 0) {
|
|
|
|
g_free(new_path);
|
|
|
|
g_free(tmp_path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(world->priv->path);
|
|
|
|
world->priv->path = new_path;
|
|
|
|
|
|
|
|
if (tmp_path && g_file_test(tmp_path, G_FILE_TEST_EXISTS)) {
|
|
|
|
// Then! rename the old_path to the new_path
|
|
|
|
rename(tmp_path, world->priv->path);
|
|
|
|
} else if (!g_file_test(world->priv->path, G_FILE_TEST_EXISTS)) {
|
|
|
|
// There was no old path, so a new dir should be made
|
|
|
|
mkdir(world->priv->path, 0755);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(tmp_path);
|
|
|
|
|
|
|
|
tmp_path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "settings",
|
|
|
|
NULL);
|
|
|
|
gm_options_save_as(world->priv->options, tmp_path);
|
|
|
|
g_free(tmp_path);
|
|
|
|
|
|
|
|
tmp_path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "triggers",
|
|
|
|
NULL);
|
|
|
|
gm_triggers_save_as(world->priv->triggers, tmp_path);
|
|
|
|
g_free(tmp_path);
|
2006-02-06 19:41:04 +01:00
|
|
|
|
|
|
|
gm_world_check_dirs(world);
|
2005-11-07 10:56:25 +01:00
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
g_object_notify(G_OBJECT(world), "name");
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
2005-11-15 13:00:18 +01:00
|
|
|
GmMcpSession *
|
|
|
|
gm_world_get_mcp_session(GmWorld *world) {
|
|
|
|
return world->priv->mcp;
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
2005-11-15 13:00:18 +01:00
|
|
|
void
|
|
|
|
gm_world_auto_login(GmWorld *world) {
|
|
|
|
gchar const *player_name = gm_options_get(world->priv->options,
|
|
|
|
"player_name");
|
|
|
|
gchar const *passwd = gm_options_get(world->priv->options, "password");
|
|
|
|
gchar *sendln;
|
|
|
|
|
|
|
|
if (player_name && *player_name != '\0') {
|
|
|
|
sendln = g_strconcat("connect ", player_name, " ", passwd, NULL);
|
2005-11-19 14:11:50 +01:00
|
|
|
gm_world_sendln_log(world, sendln, LOG_NONE);
|
2005-11-15 13:00:18 +01:00
|
|
|
g_free(sendln);
|
|
|
|
}
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Callbacks */
|
|
|
|
|
2005-11-15 13:00:18 +01:00
|
|
|
void
|
|
|
|
on_gm_world_editor_save(GmEditor *editor, GmWorld *world) {
|
|
|
|
GList *line;
|
|
|
|
|
|
|
|
if (gm_net_state(world->priv->net) == GM_NET_STATE_CONNECTED) {
|
|
|
|
gm_world_sendln(world, gm_editor_upload_cmd(editor));
|
|
|
|
|
|
|
|
for (line = gm_editor_lines(editor); line; line = line->next) {
|
|
|
|
gm_world_sendln(world, (gchar *)(line->data));
|
|
|
|
}
|
|
|
|
|
|
|
|
gm_world_sendln(world, ".");
|
|
|
|
gm_editor_saved(editor);
|
|
|
|
} else {
|
|
|
|
gm_world_writeln(world, _("# Could not save editor text, world is "
|
|
|
|
"not connected at the moment"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
void
|
|
|
|
on_gm_world_net_state_changing(GmNet *net, GmNetState state, GmWorld *world) {
|
2006-01-06 00:26:10 +01:00
|
|
|
GmNetState prev_state = gm_net_state(net);
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
g_signal_emit(world, world_signals[STATE_CHANGING], 0, state);
|
2005-11-15 13:00:18 +01:00
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
if ((prev_state == GM_NET_STATE_CONNECTED ||
|
|
|
|
prev_state == GM_NET_STATE_DISCONNECTING) &&
|
|
|
|
state == GM_NET_STATE_DISCONNECTED) {
|
2005-11-15 13:00:18 +01:00
|
|
|
gm_mcp_session_reset(world->priv->mcp);
|
2006-01-06 00:26:10 +01:00
|
|
|
|
|
|
|
#ifdef HAVE_RUBY
|
|
|
|
gm_scripts_run(gm_app_scripts(gm_app_instance()), world,
|
|
|
|
"on_disconnect", NULL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!world->priv->reconnect_id &&
|
|
|
|
gm_options_get_int(world->priv->options, "reconnect")) {
|
|
|
|
|
|
|
|
// Manual disconnect timeout check
|
|
|
|
if (world->priv->manual_disconnect ||
|
|
|
|
time(0) < world->priv->manual_disconnect_timeout) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Last command send check
|
|
|
|
if (difftime(time(0), world->priv->last_command) <= 3) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->priv->reconnect_id = g_timeout_add(3000,
|
|
|
|
(GSourceFunc)gm_world_reconnect, world);
|
|
|
|
gm_world_writeln(world, _("# Reconnecting in 3 seconds..."));
|
|
|
|
}
|
2005-11-15 13:00:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
on_gm_world_net_state_changed(GmNet *net, GmNetState state, GmWorld *world) {
|
|
|
|
if (state == GM_NET_STATE_CONNECTED) {
|
2006-01-06 00:26:10 +01:00
|
|
|
world->priv->manual_disconnect = FALSE;
|
2005-11-15 13:00:18 +01:00
|
|
|
gm_world_auto_login(world);
|
2006-01-02 18:55:40 +01:00
|
|
|
|
|
|
|
#ifdef HAVE_RUBY
|
|
|
|
gm_scripts_run(gm_app_scripts(gm_app_instance()), world, "on_connect",
|
|
|
|
NULL);
|
|
|
|
#endif
|
|
|
|
}
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
on_gm_world_net_net_error(GmNet *net, gchar *error, gint code,
|
|
|
|
GmWorld *world) {
|
|
|
|
g_signal_emit(world, world_signals[WORLD_ERROR], 0, error, code);
|
2006-02-06 19:41:04 +01:00
|
|
|
gm_world_log(world, LOG_STATUS, error);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
on_gm_world_net_bytes_recv(GmNet *net, gchar *text, gint len,
|
|
|
|
GmWorld *world) {
|
2006-01-06 00:26:10 +01:00
|
|
|
gchar *all, *utext, *ptr, *start;
|
|
|
|
gunichar ch, prev;
|
2005-11-07 10:56:25 +01:00
|
|
|
|
|
|
|
utext = gm_to_utf8_with_fallback(text, len,
|
|
|
|
gm_options_get(world->priv->options, "charset"), "?");
|
|
|
|
|
|
|
|
if (!utext) {
|
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.NetBytesRecv: conversion failed!");
|
|
|
|
utext = g_strndup(text, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (world->priv->buffer != NULL) {
|
|
|
|
all = g_strconcat(world->priv->buffer, utext, NULL);
|
|
|
|
g_free(utext);
|
|
|
|
g_free(world->priv->buffer);
|
|
|
|
world->priv->buffer = NULL;
|
|
|
|
} else {
|
|
|
|
all = utext;
|
|
|
|
}
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
ptr = start = all;
|
|
|
|
prev = 0;
|
|
|
|
|
2005-11-07 10:56:25 +01:00
|
|
|
/* Find lines in `all' and process them */
|
2006-01-06 00:26:10 +01:00
|
|
|
while ((ch = g_utf8_get_char(ptr)) != '\0') {
|
|
|
|
if (ch == '\n') {
|
|
|
|
gm_world_process_line(world, start, ptr - start -
|
|
|
|
(prev == '\r' ? 1 : 0));
|
|
|
|
ptr = start = g_utf8_next_char(ptr);
|
2005-11-07 10:56:25 +01:00
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
// Skip \r
|
|
|
|
if (g_utf8_get_char(ptr) == '\r') {
|
|
|
|
ptr = start = g_utf8_next_char(ptr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ptr = g_utf8_next_char(ptr);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
2006-01-06 00:26:10 +01:00
|
|
|
|
|
|
|
prev = ch;
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
2006-01-06 00:26:10 +01:00
|
|
|
if (*start != '\0') {
|
|
|
|
world->priv->buffer = g_strdup(start);
|
2005-11-07 10:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
g_free(all);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
on_gm_world_options_option_changed(GmOptions *options, gchar *key,
|
|
|
|
GmWorld *world) {
|
|
|
|
if (strcmp(key, "name") == 0) {
|
|
|
|
gm_world_name_changed(world);
|
|
|
|
}
|
|
|
|
}
|