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/mcp/gm-mcp-vmoo-userlist.c

826 lines
19 KiB
C

#include <strings.h>
#include <string.h>
#include "gm-mcp-vmoo-userlist.h"
#include "gm-mcp-userlist-view.h"
#include "gm-iuserlist.h"
#include "gm-mcp-session.h"
#include "gm-mcp.h"
#include "gm-support.h"
#include "gm-marshal.h"
#include "gm-debug.h"
#include "gm-world.h"
#include "list.h"
#define GM_MCP_VMOO_USERLIST_GET_PRIVATE(object)( \
G_TYPE_INSTANCE_GET_PRIVATE((object), \
GM_TYPE_MCP_VMOO_USERLIST, GmMcpVmooUserlistPrivate))
static const GmKeyValuePair icon_mapping[] = {
{"newbie", "userlist/newbie.svg"},
{"inhabitant", "userlist/inhabitant.svg"},
{"inhabitant+", "userlist/inhabitantplus.svg"},
{"schooled", "userlist/schooled.svg"},
{"key", "userlist/key.svg"},
{"star", "userlist/star.svg"},
{"wizard", "userlist/wizard.svg"},
{NULL, NULL}
};
typedef enum _UserState {
U_NORMAL,
U_AWAY,
U_IDLE,
U_IDLEAWAY
} UserState;
typedef struct _UserInfo {
gint nr;
guint icon;
gchar *name;
UserState state;
} UserInfo;
struct _GmMcpVmooUserlistPrivate {
gint you;
GList *fields;
GList *icons;
GList *users;
GList *menu;
gboolean initializing;
};
/* Signals
enum {
NUM_SIGNALS
};*/
//static guint gm_mcp_vmoo_userlist_signals[NUM_SIGNALS] = {0};
static void gm_mcp_vmoo_userlist_iface_init(GmIUserlistInterface *iface);
G_DEFINE_TYPE_EXTENDED(GmMcpVmooUserlist, gm_mcp_vmoo_userlist, \
GM_TYPE_MCP_PACKAGE, 0, G_IMPLEMENT_INTERFACE(GM_TYPE_IUSERLIST, \
gm_mcp_vmoo_userlist_iface_init))
void gm_mcp_vmoo_userlist_handle_simple(GmMcpPackage *package,
gchar *suffix, GList *fields);
gboolean gm_mcp_vmoo_userlist_handle_multi(GmMcpPackage *package,
gchar const *data_tag, gchar const *key, gchar const *value,
GList *all_values);
void gm_mcp_vmoo_userlist_create_view(GmMcpPackage *package,
GObject *parent);
GList *gm_mcp_vmoo_userlist_get_menu(GmIUserlist *userlist, gint id);
gchar const *gm_mcp_vmoo_userlist_get_name(GmIUserlist *userlist, gint id);
gchar const *gm_mcp_vmoo_userlist_get_icon(GmIUserlist *userlist, gint id,
gboolean use_state);
gchar *gm_mcp_vmoo_userlist_get_status(GmIUserlist *userlist, gint id);
gint gm_mcp_vmoo_userlist_get_rank_priority(GmIUserlist *userlist, gint id);
gint gm_mcp_vmoo_userlist_get_state_priority(GmIUserlist *userlist, gint id);
static void
gm_mcp_vmoo_userlist_iface_init(
GmIUserlistInterface *iface) {
iface->get_menu = gm_mcp_vmoo_userlist_get_menu;
iface->get_name = gm_mcp_vmoo_userlist_get_name;
iface->get_status = gm_mcp_vmoo_userlist_get_status;
iface->get_icon = gm_mcp_vmoo_userlist_get_icon;
iface->get_rank_priority = gm_mcp_vmoo_userlist_get_rank_priority;
iface->get_state_priority = gm_mcp_vmoo_userlist_get_state_priority;
}
void
gm_mcp_vmoo_userlist_remove_users(GmMcpVmooUserlist *package) {
GList *users = g_list_copy(package->priv->users);
GList *field;
UserInfo *info;
for (field = users; field; field = field->next) {
info = (UserInfo *)(field->data);
package->priv->users = g_list_remove(package->priv->users, field->data);
g_free(info->name);
g_free(info);
}
g_list_free(users);
}
static void
gm_mcp_vmoo_userlist_free_menu(GmMcpVmooUserlist *obj) {
GList *field;
GmKeyValuePair *pair;
for (field = obj->priv->menu; field; field = field->next) {
pair = (GmKeyValuePair *)(field->data);
g_free(pair->key);
g_free(pair->value);
g_free(pair);
}
obj->priv->menu = NULL;
}
static void
gm_mcp_vmoo_userlist_finalize(GObject *object) {
GmMcpVmooUserlist *obj = GM_MCP_VMOO_USERLIST(object);
GList *field;
for (field = obj->priv->fields; field; field = field->next) {
g_free(field->data);
}
g_list_free(obj->priv->fields);
for (field = obj->priv->icons; field; field = field->next) {
g_free(field->data);
}
g_list_free(obj->priv->icons);
gm_mcp_vmoo_userlist_free_menu(obj);
gm_mcp_vmoo_userlist_remove_users(obj);
g_list_free(obj->priv->users);
G_OBJECT_CLASS(gm_mcp_vmoo_userlist_parent_class)->finalize(object);
}
static void
gm_mcp_vmoo_userlist_class_init(GmMcpVmooUserlistClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS(klass);
GmMcpPackageClass *pklass = GM_MCP_PACKAGE_CLASS(klass);
object_class->finalize = gm_mcp_vmoo_userlist_finalize;
pklass->name = "dns-com-vmoo-userlist";
pklass->handle_simple = &gm_mcp_vmoo_userlist_handle_simple;
pklass->handle_multi = &gm_mcp_vmoo_userlist_handle_multi;
pklass->create_view = &gm_mcp_vmoo_userlist_create_view;
g_type_class_add_private(object_class, sizeof(GmMcpVmooUserlistPrivate));
}
static void
gm_mcp_vmoo_userlist_init(GmMcpVmooUserlist *obj) {
obj->priv = GM_MCP_VMOO_USERLIST_GET_PRIVATE(obj);
obj->priv->you = 0;
obj->priv->fields = NULL;
obj->priv->icons = NULL;
obj->priv->users = NULL;
}
GmMcpVmooUserlist *
gm_mcp_vmoo_userlist_new() {
GmMcpVmooUserlist *obj = GM_MCP_VMOO_USERLIST(g_object_new( \
GM_TYPE_MCP_VMOO_USERLIST, NULL));
return obj;
}
#define MAX_MATCHES 10
void
gm_mcp_vmoo_userlist_process_triggers(GmMcpVmooUserlist *package,
gchar const *username, GmTriggerConditionType condition) {
GmWorld *world;
GmTriggers *triggers;
GList const *item;
GmTrigger *trigger;
gint num;
regmatch_t matches[MAX_MATCHES];
if (package->priv->initializing) {
return;
}
world = GM_MCP_SESSION_WORLD(GM_MCP_PACKAGE_SESSION(package));
triggers = gm_world_triggers(world);
for (item = gm_triggers_list(triggers); item; item = item->next) {
trigger = (GmTrigger *)(item->data);
if (trigger->event == TT_USERS) {
if ((num = gm_trigger_match_user(trigger, username, condition,
matches, MAX_MATCHES))) {
gm_world_apply_trigger(world, trigger, username, matches, num);
}
}
}
}
void
gm_mcp_vmoo_userlist_handle_fields(GmMcpVmooUserlist *package, MOOVar *list) {
MOOVar *field;
for (field = list->list; field; field = field->next) {
if (field->type == STRING) {
package->priv->fields = g_list_append(package->priv->fields,
g_strdup(field->s));
}
}
}
gchar const *
gm_mcp_vmoo_userlist_icon_path(GmMcpVmooUserlist *package, UserInfo *ui,
gboolean use_state) {
gchar *field;
guint index = ui->icon;
GmKeyValuePair const *pair;
if (index < 1 || index > g_list_length(package->priv->icons)) {
return NULL;
} else {
if (!use_state || ui->state == U_NORMAL) {
field = (gchar *)(g_list_nth_data(package->priv->icons,
index - 1));
pair = icon_mapping;
while (!(pair->key == NULL && pair->value == NULL)) {
if (strcasecmp(pair->key, field) == 0) {
return pair->value;
}
++pair;
}
} else {
switch (ui->state) {
case U_IDLE:
return "userlist/idle.svg";
break;
case U_AWAY:
return "userlist/away.svg";
break;
case U_IDLEAWAY:
return "userlist/idleaway.svg";
break;
default:
break;
}
}
}
return NULL;
}
void
gm_mcp_vmoo_userlist_handle_icons(GmMcpVmooUserlist *package, MOOVar *list) {
MOOVar *field;
for (field = list->list; field; field = field->next) {
if (field->type == STRING) {
package->priv->icons = g_list_append(package->priv->icons,
g_strdup(field->s));
}
}
}
void
gm_mcp_vmoo_userlist_handle_menu(GmMcpVmooUserlist *package, MOOVar *list) {
MOOVar *field;
GmKeyValuePair *pair;
for (field = list->list; field; field = field->next) {
pair = g_new0(GmKeyValuePair, 1);
if (field->type == LIST && field->i == 2) {
pair->key = g_strdup(field->list->s);
pair->value = g_strdup(field->list->next->s);
package->priv->menu = g_list_append(package->priv->menu,
pair);
} else if (field->type != LIST) {
package->priv->menu = g_list_append(package->priv->menu, pair);
} else {
g_free(pair);
}
}
}
gchar *
gm_mcp_vmoo_userlist_get_string(GmMcpVmooUserlist *package, MOOVar *v,
MOOType type, gchar *cmp) {
GList *fields = package->priv->fields;
while (fields && strcasecmp(((gchar *) (fields->data)), cmp) != 0) {
fields = fields->next;
if (v) {
v = v->next;
}
}
if (v && v->type == type) {
return g_strdup(v->s);
}
return NULL;
}
gint
gm_mcp_vmoo_userlist_get_int(GmMcpVmooUserlist *package, MOOVar *v, MOOType type,
gchar *cmp) {
GList *fields = package->priv->fields;
while (fields && strcasecmp(((gchar *) (fields->data)), cmp) != 0) {
fields = fields->next;
if (v) {
v = v->next;
}
}
if (v && v->type == type) {
return v->i;
}
return 0;
}
UserInfo *
gm_mcp_vmoo_userlist_find_user(GmMcpVmooUserlist *package, gint nr) {
UserInfo *result;
GList *users;
for (users = package->priv->users; users; users = users->next) {
result = (UserInfo *) (users->data);
if (result->nr == nr) {
return result;
}
}
return NULL;
}
gchar *
gm_mcp_vmoo_userlist_menu_item_subst(GmMcpVmooUserlist *package,
gchar *str, UserInfo *info) {
GString *result;
gchar *ptr = str, *subst, *tmp;
gunichar ch, cnum;
gint num;
gboolean substituted;
if (str == NULL) {
return NULL;
}
result = g_string_sized_new(strlen(str));
while ((ch = g_utf8_get_char(ptr)) != '\0') {
substituted = FALSE;
if (ch == '&') {
result = g_string_append_c(result, '_');
substituted = TRUE;
} else if (ch == '$') {
subst = g_utf8_next_char(ptr);
if (g_utf8_get_char(subst) == '(') {
subst = g_utf8_next_char(subst);
num = 0;
while (g_unichar_isdigit((cnum = g_utf8_get_char(subst)))) {
num = (num * 10) + g_unichar_digit_value(cnum);
subst = g_utf8_next_char(subst);
}
if (g_utf8_get_char(subst) == ')') {
switch (num) {
case 1:
tmp = g_strdup_printf("#%d", info->nr);
result = g_string_append(result, tmp);
g_free(tmp);
break;
case 2:
for (tmp = info->name; *tmp != '\0';
tmp = g_utf8_next_char(tmp)) {
ch = g_utf8_get_char(tmp);
if (ch == '_') {
result = g_string_append_c(result, '_');
}
result = g_string_append_unichar(result, ch);
}
break;
default:
break;
}
ptr = subst;
substituted = TRUE;
}
}
}
if (!substituted) {
result = g_string_append_unichar(result, ch);
}
ptr = g_utf8_next_char(ptr);
}
ptr = result->str;
g_string_free(result, FALSE);
return ptr;
}
GmKeyValuePair *
gm_mcp_vmoo_userlist_get_menu_item(GmMcpVmooUserlist *package,
GmKeyValuePair *menuitem, UserInfo *info) {
GmKeyValuePair *result = g_new0(GmKeyValuePair, 1);
if (!menuitem) {
return result;
}
result->key = gm_mcp_vmoo_userlist_menu_item_subst(package,
menuitem->key, info);
result->value = gm_mcp_vmoo_userlist_menu_item_subst(package,
menuitem->value, info);
return result;
}
GList *
gm_mcp_vmoo_userlist_get_menu(GmIUserlist *userlist, gint id) {
GmMcpVmooUserlist *package = (GmMcpVmooUserlist *)(userlist);
UserInfo *info = gm_mcp_vmoo_userlist_find_user(package, id);
GList *item, *menu = NULL;
GmKeyValuePair *pair;
if (!info) {
return NULL;
}
for (item = package->priv->menu; item; item = item->next) {
pair = (GmKeyValuePair *)(item->data);
menu = g_list_append(menu, gm_mcp_vmoo_userlist_get_menu_item(package,
pair, info));
}
return menu;
}
gchar const *
gm_mcp_vmoo_userlist_get_name(GmIUserlist *userlist, gint id) {
GmMcpVmooUserlist *package = GM_MCP_VMOO_USERLIST(userlist);
UserInfo *info = gm_mcp_vmoo_userlist_find_user(package, id);
return info->name;
}
gchar *
gm_mcp_vmoo_userlist_get_status(GmIUserlist *userlist, gint id) {
GmMcpVmooUserlist *package = GM_MCP_VMOO_USERLIST(userlist);
UserInfo *info = gm_mcp_vmoo_userlist_find_user(package, id);
switch (info->state) {
case U_AWAY:
return g_strdup(_("Away"));
break;
case U_IDLE:
return g_strdup(_("Idle"));
break;
case U_IDLEAWAY:
return g_strdup(_("Idle and away"));
break;
default:
return NULL;
break;
}
}
gchar const *
gm_mcp_vmoo_userlist_get_icon(GmIUserlist *userlist, gint id,
gboolean use_state) {
GmMcpVmooUserlist *package = GM_MCP_VMOO_USERLIST(userlist);
UserInfo *info = gm_mcp_vmoo_userlist_find_user(package, id);
return gm_mcp_vmoo_userlist_icon_path(package, info, use_state);
}
gint
gm_mcp_vmoo_userlist_get_rank_priority(GmIUserlist *userlist, gint id) {
GmMcpVmooUserlist *package = GM_MCP_VMOO_USERLIST(userlist);
UserInfo *info = gm_mcp_vmoo_userlist_find_user(package, id);
return g_list_length(package->priv->icons) - info->icon;
}
gint
gm_mcp_vmoo_userlist_get_state_priority(GmIUserlist *userlist, gint id) {
GmMcpVmooUserlist *package = GM_MCP_VMOO_USERLIST(userlist);
UserInfo *info = gm_mcp_vmoo_userlist_find_user(package, id);
return info->state;
}
void
gm_mcp_vmoo_userlist_remove_user(GmMcpVmooUserlist *package, gint nr) {
GList *elem;
UserInfo *ui;
for (elem = package->priv->users; elem; elem = elem->next) {
ui = (UserInfo *) (elem->data);
if (ui->nr == nr) {
gm_mcp_vmoo_userlist_process_triggers(package, ui->name,
TCT_USER_OFFLINE);
package->priv->users = g_list_remove(package->priv->users, ui);
break;
}
}
g_signal_emit_by_name(package, "player-removed", nr);
}
void
gm_mcp_vmoo_userlist_handle_user_update(GmMcpVmooUserlist *package, MOOVar *v) {
gint nr = gm_mcp_vmoo_userlist_get_int(package, v, OBJECT, "object");
gchar *name = gm_mcp_vmoo_userlist_get_string(package, v, STRING, "name");
gint icon = gm_mcp_vmoo_userlist_get_int(package, v, INT, "icon");
UserInfo *ui;
if ((ui = gm_mcp_vmoo_userlist_find_user(package, nr)) == NULL) {
// Add the user
ui = g_new(UserInfo, 1);
ui->name = name;
ui->state = U_NORMAL;
ui->icon = icon;
ui->nr = nr;
package->priv->users = g_list_append(package->priv->users, ui);
g_signal_emit_by_name(package, "player-added", nr);
gm_mcp_vmoo_userlist_process_triggers(package, ui->name,
TCT_USER_ONLINE);
} else {
if (ui->name || strcmp(ui->name, name) != 0) {
g_free(ui->name);
ui->name = name;
g_signal_emit_by_name(package, "name-changed", nr);
} else {
g_free(name);
}
if (ui->icon != (guint)icon) {
ui->icon = (guint)icon;
g_signal_emit_by_name(package, "rank-changed", nr);
}
}
}
void
gm_mcp_vmoo_userlist_handle_set(GmMcpVmooUserlist *package, MOOVar *v) {
MOOVar *ui;
if (v->type != LIST) {
return;
}
package->priv->initializing = TRUE;
gm_mcp_vmoo_userlist_remove_users(package);
for (ui = v->list; ui; ui = ui->next) {
if (ui->type != LIST) {
return;
}
gm_mcp_vmoo_userlist_handle_user_update(package, ui->list);
}
package->priv->initializing = FALSE;
}
void
gm_mcp_vmoo_userlist_handle_add(GmMcpVmooUserlist *package, MOOVar *v) {
if (v->type != LIST) {
return;
}
gm_mcp_vmoo_userlist_handle_user_update(package, v->list);
}
void
gm_mcp_vmoo_userlist_handle_remove(GmMcpVmooUserlist *package, MOOVar *v) {
MOOVar *nr;
if (v->type != LIST) {
return;
}
for (nr = v->list; nr; nr = nr->next) {
if (nr->type == OBJECT) {
gm_mcp_vmoo_userlist_remove_user(package, nr->i);
}
}
}
void
gm_mcp_vmoo_userlist_handle_update(GmMcpVmooUserlist *package, MOOVar *v) {
if (v->type != LIST) {
return;
}
gm_mcp_vmoo_userlist_handle_user_update(package, v->list);
}
void
gm_mcp_vmoo_userlist_handle_state(GmMcpVmooUserlist *package, MOOVar *v,
UserState state, gboolean onOff) {
MOOVar *nr;
UserInfo *u;
GmTriggerConditionType condition = 0;
if (v->type != LIST) {
return;
}
for (nr = v->list; nr; nr = nr->next) {
if (nr->type == OBJECT) {
if ((u = gm_mcp_vmoo_userlist_find_user(package, nr->i))) {
switch (state) {
case U_IDLE:
if (u->state == U_IDLEAWAY && !onOff) {
u->state = U_AWAY;
} else if (u->state == U_AWAY && onOff) {
u->state = U_IDLEAWAY;
} else if (onOff) {
u->state = U_IDLE;
} else if (u->state == U_IDLE) {
u->state = U_NORMAL;
}
if (onOff) {
condition = TCT_USER_IDLE;
} else {
condition = TCT_USER_IDLE_OFF;
}
break;
case U_AWAY:
if (u->state == U_IDLEAWAY && !onOff) {
u->state = U_IDLE;
} else if (u->state == U_IDLE && onOff) {
u->state = U_IDLEAWAY;
} else if (onOff) {
u->state = U_AWAY;
} else if (u->state == U_AWAY) {
u->state = U_NORMAL;
}
if (onOff) {
condition = TCT_USER_AWAY;
} else {
condition = TCT_USER_AWAY_OFF;
}
break;
default:
break;
}
g_signal_emit_by_name(package, "state-changed", u->nr);
if (condition != 0) {
gm_mcp_vmoo_userlist_process_triggers(package, u->name,
condition);
}
} else {
gm_debug_msg(DEBUG_MCP, "User %d does not exist!", nr->i);
}
} else {
gm_debug_msg(DEBUG_MCP, "Nr is not an object: %d", nr->type);
}
}
}
void
gm_mcp_vmoo_userlist_handle_simple(GmMcpPackage *package, gchar *suffix,
GList *fields) {
MOOVar *v = NULL;
GmMcpVmooUserlist *userlist = GM_MCP_VMOO_USERLIST(package);
gchar const *value;
if (suffix) {
if (strcmp(suffix, "you") == 0) {
v = MOOVar_parse(gm_mcp_find_value(fields, "nr"));
if (v->type == OBJECT) {
userlist->priv->you = v->i;
} else {
gm_debug_msg(DEBUG_MCP, "GmMcpVmooUserlist.HandleSimple: "
"you is not an object!");
}
} else if (strcmp(suffix, "menu") == 0) {
value = gm_mcp_find_value(fields, "menu");
v = MOOVar_parse(value);
if (!v || v->type != LIST) {
gm_debug_msg(DEBUG_MCP, "GmMcpVmooUserlist.HandleMulti: "
"invalid value: %s", value);
} else {
gm_mcp_vmoo_userlist_free_menu(userlist);
gm_mcp_vmoo_userlist_handle_menu(userlist, v);
}
}
}
if (v) {
MOOVar_free(v);
}
}
gboolean
gm_mcp_vmoo_userlist_handle_multi(GmMcpPackage *package,
gchar const *data_tag, gchar const *key, gchar const *value,
GList *all_values) {
MOOVar *v = NULL;
GmMcpVmooUserlist *userlist = GM_MCP_VMOO_USERLIST(package);
if (key) {
if (strcmp(key, "fields") == 0) {
v = MOOVar_parse(value);
if (!v || v->type != LIST) {
gm_debug_msg(DEBUG_MCP, "GmMcpVmooUserlist.HandleMulti: "
"invalid value: %s", value);
} else {
gm_mcp_vmoo_userlist_handle_fields(userlist, v);
}
} else if (strcmp(key, "icons") == 0) {
v = MOOVar_parse(value);
if (!v || v->type != LIST) {
gm_debug_msg(DEBUG_MCP, "GmMcpVmooUserlist.HandleMulti: "
"invalid value: %s", value);
} else {
gm_mcp_vmoo_userlist_handle_icons(userlist, v);
}
} else if (strcmp(key, "d") == 0) {
v = MOOVar_parse(value + 1);
if (!v) {
gm_debug_msg(DEBUG_MCP, "GmMcpVmooUserlist.HandleMulti: "
"invalid value: %s", value + 1);
} else {
switch (*value) {
case '=':
gm_mcp_vmoo_userlist_handle_set(userlist, v);
break;
case '+':
gm_mcp_vmoo_userlist_handle_add(userlist, v);
break;
case '-':
gm_mcp_vmoo_userlist_handle_remove(userlist, v);
break;
case '*':
gm_mcp_vmoo_userlist_handle_update(userlist, v);
break;
case '<':
gm_mcp_vmoo_userlist_handle_state(userlist, v, U_IDLE,
TRUE);
break;
case '>':
gm_mcp_vmoo_userlist_handle_state(userlist, v, U_IDLE,
FALSE);
break;
case '[':
gm_mcp_vmoo_userlist_handle_state(userlist, v, U_AWAY,
TRUE);
break;
case ']':
gm_mcp_vmoo_userlist_handle_state(userlist, v, U_AWAY,
FALSE);
break;
case '(':
gm_mcp_vmoo_userlist_handle_remove(userlist, v);
break;
default:
break;
}
}
}
}
if (v) {
MOOVar_free(v);
}
return TRUE;
}
void
gm_mcp_vmoo_userlist_create_view(GmMcpPackage *package, GObject *parent) {
gm_mcp_userlist_view_new(package, parent);
}