This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/gnoemoe/gm-world.c

964 lines
23 KiB
C

#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#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-bogus.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);
void on_gm_world_net_state_changed(GmNet *net, GmNetState state,
GmWorld *world);
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);
void on_gm_world_editor_save(GmEditor *editor, GmWorld *world);
struct _GmWorldPrivate {
gchar *path;
gboolean loaded;
gboolean active;
guint activity;
gchar *buffer;
GmOptions *options;
GmTriggers *triggers;
GmNet *net;
GmMcpSession *mcp;
GList *history;
GList *editors;
GmEditingInfo editing_info;
gint last_day;
gint fd_log;
};
/* Signals */
enum {
ACTIVATE_REQUEST,
LOAD,
UNLOAD,
STATE_CHANGING,
WORLD_ERROR,
TEXT_RECEIVED,
EDITOR_ADDED,
EDITOR_REMOVED,
NAME_CHANGED,
ACTIVE_CHANGED,
ACTIVITY_CHANGED,
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);
gchar *tmp_dir;
if (world->priv->path) {
gm_options_save(world->priv->options);
gm_world_save_input_history(world);
gm_triggers_save(world->priv->triggers);
// Removing all tmp files
tmp_dir = g_strconcat(world->priv->path, "/tmp", NULL);
gm_directory_remove_all(tmp_dir, FALSE);
g_free(tmp_dir);
}
if (world->priv->fd_log > 0) {
close(world->priv->fd_log);
}
gm_g_list_free_simple(world->priv->history);
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);
}
static void
gm_world_class_init(GmWorldClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = gm_world_finalize;
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);
world_signals[NAME_CHANGED] =
g_signal_new("name_changed",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GmWorldClass, name_changed),
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
world_signals[ACTIVE_CHANGED] =
g_signal_new("active_changed",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GmWorldClass, active_changed),
NULL, NULL,
g_cclosure_marshal_VOID__BOOLEAN,
G_TYPE_NONE,
1,
G_TYPE_BOOLEAN);
world_signals[ACTIVITY_CHANGED] =
g_signal_new("activity_changed",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GmWorldClass, activity_changed),
NULL, NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1,
G_TYPE_INT);
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);
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);
g_signal_connect(world->priv->net, "state_changed",
G_CALLBACK(on_gm_world_net_state_changed), world);
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);
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.LoadInputHistory: loading history (%s)!", filename);
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') {
if (line[1] != '\0') { // Empty lines, we don't need to process those
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 {
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.LoadInputHistory: could not retrieve contents of "
"file %s (%s)", filename, strerror(errno));
}
g_free(filename);
}
void
gm_world_save_input_history(GmWorld *world) {
FILE *f;
gchar *filename;
GList *elem;
if (world->priv->path == NULL) {
return;
}
filename = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "history", NULL);
f = fopen(filename, "w");
if (f) {
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.SaveInputHistory: saving input history to %s",
filename);
for (elem = world->priv->history; elem; elem = elem->next) {
fprintf(f, "%s\n", (gchar *) (elem->data));
}
fclose(f);
chmod(filename, 0660);
} else {
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.SaveInputHistory: couldn't open history file (%s)"
" for saving: %s", filename, strerror(errno));
}
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);
}
/* 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);
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.new: creating new world for %s", path);
world->priv->path = g_strdup(path);
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.new: creating default world settings for %s", path);
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);
}
/* 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) {
//GList *w;
if (world->priv->loaded) {
world->priv->loaded = FALSE;
gm_world_disconnect(world);
while (world->priv->editors) {
gm_world_remove_editor(world,
GM_EDITOR(world->priv->editors->data));
}
g_signal_emit(world, world_signals[UNLOAD], 0);
}
}
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);
}
void
gm_world_connect(GmWorld *world) {
/*if (strlen(gm_options_get(world->priv->options, "host")) == 0) {
g_signal_emit(world, world_signals[WORLD_ERROR], 0,
_("World has no host, please fill in a host first"));
} else if (strlen(gm_options_get(world->priv->options, "port")) == 0) {
g_signal_emit(world, world_signals[WORLD_ERROR], 0,
_("World has no port, please fill in a port first"));
} else {*/
gm_net_connect(world->priv->net,
gm_options_get(world->priv->options, "host"),
gm_options_get(world->priv->options, "port"));
//}
}
void
gm_world_connect_to(GmWorld *world, gchar *host, gchar *port) {
gm_net_connect(world->priv->net, host, port);
}
void
gm_world_disconnect(GmWorld *world) {
gm_net_disconnect(world->priv->net);
}
void
gm_world_log(GmWorld *world, GmLogType type, gchar *text) {
GString *s;
gchar *start, *log, *no_ansi;
struct tm *timet;
time_t timer;
gint len;
if (type == LOG_NONE) {
return;
}
timer = time(0);
timet = localtime(&timer);
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;
}
if (world->priv->fd_log == -1) {
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;
case LOG_MCP_IN:
s = g_string_append(s, "[MCP] <");
break;
case LOG_MCP_OUT:
s = g_string_append(s, "[MCP] >");
break;
case LOG_STATUS:
s = g_string_append_c(s, '#');
break;
default:
break;
}
s = g_string_append(s, " ");
s = g_string_append(s, text);
no_ansi = gm_ansi_strip(g_strdup(s->str));
len = strlen(no_ansi);
write(world->priv->fd_log, no_ansi, strlen(no_ansi));
if (no_ansi[len - 1] != '\n') {
write(world->priv->fd_log, "\n", 1);
}
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);
einfo->upload = g_strndup(upload_start + 9, (upload_start - line) + 9);
GM_DEBUG("Editing info: %s %s", einfo->name, einfo->upload);
einfo->lines = NULL;
}
void
gm_world_process_line(GmWorld *world, gchar *line) {
gchar *non_text_start = NULL;
GmEditingInfo *einfo = &(world->priv->editing_info);
GmEditor *editor;
if (strncmp(line, "\x1B[0m", 4) == 0) {
non_text_start = g_strdup(line + 4);
} else {
non_text_start = g_strdup(line);
}
if (einfo->is_editing) {
if (strcmp(non_text_start, ".") == 0) {
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);
einfo->is_editing = FALSE;
g_free(einfo->name);
einfo->name = NULL;
g_free(einfo->upload);
einfo->upload = NULL;
g_list_free(einfo->lines);
einfo->lines = NULL;
} else {
einfo->lines = g_list_append(einfo->lines, g_strdup(non_text_start));
}
} 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);
gm_world_log(world, LOG_MCP_IN, non_text_start);
}
} else {
if (!gm_world_active(world)) {
gm_world_set_activity(world, world->priv->activity + 1);
}
if (strncmp(non_text_start, "#$\"", 3) == 0) {
if (strlen(non_text_start) != strlen(line)) {
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\x1B[0m");
}
gm_world_log(world, LOG_IN, non_text_start + 3);
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, non_text_start + 3);
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\n");
} else {
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, line);
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\n");
gm_world_log(world, LOG_IN, line);
}
}
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);
}
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.ProcessInput: Trying script %s (%s)", script,
argstr);
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);
g_signal_connect_swapped(editor, "close",
G_CALLBACK(gm_world_remove_editor), world);
g_signal_emit(world, world_signals[EDITOR_ADDED], 0, editor);
}
void
gm_world_sendln_log(GmWorld *world, gchar *text, GmLogType logtype) {
gchar *normal;
// Convert text from utf-8 to the correct locale
normal = gm_to_utf8_with_fallback(text, -1,
gm_options_get(world->priv->options, "charset"), "?");
if (!normal) {
gm_debug_msg(DEBUG_DEFAULT, "GmWorld.SendlnLog: conversion failed!");
normal = g_strdup(text);
}
if (logtype != LOG_NONE) {
gm_world_log(world, logtype, text);
}
gm_net_send_line(world->priv->net, normal);
g_free(normal);
}
void
gm_world_sendln(GmWorld *world, gchar *text) {
gm_world_sendln_log(world, text, LOG_OUT);
}
void
gm_world_set_active(GmWorld *world, gboolean active) {
world->priv->active = active;
g_signal_emit(world, world_signals[ACTIVE_CHANGED], 0, active);
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;
g_signal_emit(world, world_signals[ACTIVITY_CHANGED], 0, activity);
}
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);
g_signal_emit(world, world_signals[NAME_CHANGED], 0,
gm_options_get(world->priv->options, "name"));
}
GmMcpSession *
gm_world_get_mcp_session(GmWorld *world) {
return world->priv->mcp;
}
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);
gm_world_sendln_log(world, sendln, LOG_NONE);
g_free(sendln);
}
}
/* Callbacks */
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"));
}
}
void
on_gm_world_net_state_changing(GmNet *net, GmNetState state, GmWorld *world) {
g_signal_emit(world, world_signals[STATE_CHANGING], 0, state);
if (state == GM_NET_STATE_DISCONNECTED) {
gm_mcp_session_reset(world->priv->mcp);
}
}
void
on_gm_world_net_state_changed(GmNet *net, GmNetState state, GmWorld *world) {
if (state == GM_NET_STATE_CONNECTED) {
gm_world_auto_login(world);
}
}
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);
}
void
on_gm_world_net_bytes_recv(GmNet *net, gchar *text, gint len,
GmWorld *world) {
gchar *all, *utext, *ptr, *line, *p;
gint i;
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;
}
// TODO: UTF-8 compliant
line = (gchar *)(malloc((strlen(all) * sizeof(gchar)) + 1));
i = 0;
p = all;
/* Find lines in `all' and process them */
for (ptr = all; *ptr != '\0'; ptr++) {
if (*ptr == '\n') {
line[i] = '\0';
line[i + 1] = '\0';
gm_world_process_line(world, line);
p = ptr + 1;
i = 0;
} else if (*ptr != '\r') {
line[i] = *ptr;
i++;
}
}
if (i > 0) {
world->priv->buffer = g_strdup(p);
}
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);
}
}