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-icecrew-userlist.c
Jesse van den Kieboom a8dadeb408 * gnoemoe/mcp/gm-mcp-icecrew-userlist.c: change the behavior for
fetching icons so that only one icon at a time is being fetched. This
	is needed to make the fetching fully async (before we checked whether
	the remove icon existed before trying to fetch it, which could block
	gnoemoe if the icon remote host was down). By only fetching one
	icon we can work around the bugs in gnome-vfs that don't allow proper
	error handling for fetching multiple files. Closes debian bug #388321
2006-09-30 13:21:47 +00:00

1248 lines
34 KiB
C

#include <glib.h>
#include <string.h>
#include <glob.h>
#include <unistd.h>
#include <errno.h>
#include "gm-mcp-icecrew-userlist.h"
#include "gm-iuserlist.h"
#include "gm-mcp-userlist-view.h"
#include "gm-mcp-icecrew-playerdb.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 "gm-triggers.h"
#define GM_MCP_ICECREW_USERLIST_GET_PRIVATE(object)( \
G_TYPE_INSTANCE_GET_PRIVATE((object), \
GM_TYPE_MCP_ICECREW_USERLIST, GmMcpIcecrewUserlistPrivate))
#define USERLIST_ICON_SIZE 22
static GmKeyValuePair default_states[] = {
{"away+idle", "ice-userlist/away+idle.svg"},
{"busy+idle", "ice-userlist/busy+idle.svg"},
{"avail+idle", "ice-userlist/avail+idle.svg"},
{"away", "ice-userlist/away.svg"},
{"busy", "ice-userlist/busy.svg"},
{NULL, NULL}
};
static GmKeyValuePair default_ranks[] = {
{"inhabitant", "ice-userlist/inhabitant.svg"},
{"programmer", "ice-userlist/programmer.svg"},
{"wizard", "ice-userlist/wizard.svg"},
{NULL, NULL}
};
struct _GmMcpIcecrewUserlistPrivate {
GList *state_icons;
GList *rank_icons;
GList *state_alternatives;
GList *rank_alternatives;
GList *key_datatags;
GmFetchHandle *rank_fetch;
GmFetchHandle *state_fetch;
gchar *rank_dir;
gchar *state_dir;
gchar **property_names;
GList *menu;
gboolean initializing;
};
static gchar *gm_mcp_icecrew_userlist_depends[] = {
"dns-nl-icecrew-playerdb",
NULL
};
static gchar *gm_mcp_icecrew_userlist_overrides[] = {
"dns-com-vmoo-userlist",
NULL
};
enum {
P_NAME,
P_RANK,
P_STATE,
P_STATE_MSG
};
static gchar *gm_mcp_icecrew_userlist_property_names0[] = {
"P_NAME",
"P_RANK",
"P_STATE",
"P_STATE_MSG"
};
static gchar *gm_mcp_icecrew_userlist_property_names1[] = {
"name",
"rank",
"state",
"state_msg"
};
/* Signals
enum {
NUM_SIGNALS
}; */
//static guint gm_mcp_icecrew_userlist_signals[NUM_SIGNALS] = {0};
static void gm_mcp_icecrew_userlist_iface_init(GmIUserlistInterface *iface);
G_DEFINE_TYPE_EXTENDED(GmMcpIcecrewUserlist, gm_mcp_icecrew_userlist, \
GM_TYPE_MCP_PACKAGE, 0, G_IMPLEMENT_INTERFACE(GM_TYPE_IUSERLIST, \
gm_mcp_icecrew_userlist_iface_init))
void on_gm_mcp_icecrew_userlist_add(GmMcpIcecrewPlayerdb *playerdb,
GmPlayerdbPlayerInfo *ppi, GmMcpIcecrewUserlist *userlist);
void on_gm_mcp_icecrew_userlist_set(GmMcpIcecrewPlayerdb *playerdb,
GmPlayerdbPlayerInfo *ppi, gchar const *key, gchar const *value,
gchar const *old, GmMcpIcecrewUserlist *userlist);
void on_gm_mcp_icecrew_userlist_delete(GmMcpIcecrewPlayerdb *playerdb,
GmPlayerdbPlayerInfo *ppi, GmMcpIcecrewUserlist *userlist);
void on_gm_mcp_icecrew_userlist_fetch_progress(GmFetchHandle *g,
GmMcpIcecrewUserlist *package);
gboolean gm_mcp_icecrew_userlist_handle_multi(GmMcpPackage *package,
gchar const *data_tag, gchar const *key, gchar const *value,
GList *all_values);
void gm_mcp_icecrew_userlist_set_session(GmMcpPackage *package,
GObject *session);
void gm_mcp_icecrew_userlist_create_view(GmMcpPackage *package,
GObject *parent);
void gm_mcp_icecrew_userlist_fetch_progress(GmFetchHandle *g,
GmMcpIcecrewUserlist *package);
GList *gm_mcp_icecrew_userlist_get_menu(GmIUserlist *userlist, gint id);
gboolean gm_mcp_icecrew_userlist_supports_status(GmIUserlist *userlist);
gchar *gm_mcp_icecrew_userlist_get_status(GmIUserlist *userlist, gint id);
gchar const *gm_mcp_icecrew_userlist_get_name(GmIUserlist *userlist, gint id);
gchar const *gm_mcp_icecrew_userlist_get_icon(GmIUserlist *userlist, gint id,
gboolean use_state);
gint gm_mcp_icecrew_userlist_get_rank_priority(GmIUserlist *userlist, gint id);
gint gm_mcp_icecrew_userlist_get_state_priority(GmIUserlist *userlist, gint id);
static void
gm_mcp_icecrew_userlist_iface_init(
GmIUserlistInterface *iface) {
iface->get_menu = gm_mcp_icecrew_userlist_get_menu;
iface->get_status = gm_mcp_icecrew_userlist_get_status;
iface->get_name = gm_mcp_icecrew_userlist_get_name;
iface->get_icon = gm_mcp_icecrew_userlist_get_icon;
iface->get_rank_priority = gm_mcp_icecrew_userlist_get_rank_priority;
iface->get_state_priority = gm_mcp_icecrew_userlist_get_state_priority;
}
void
gm_mcp_icecrew_userlist_pair_free(GmKeyValuePair *pair) {
g_free(pair->key);
g_free(pair->value);
g_free(pair);
}
void
gm_mcp_icecrew_userlist_free_list(GList *rs) {
GList *item;
for (item = rs; item; item = item->next) {
gm_mcp_icecrew_userlist_pair_free((GmKeyValuePair *)(item->data));
}
g_list_free(rs);
}
static void
gm_mcp_icecrew_userlist_free_menu(GmMcpIcecrewUserlist *obj) {
gm_mcp_icecrew_userlist_free_list(obj->priv->menu);
obj->priv->menu = NULL;
}
static void
gm_mcp_icecrew_userlist_finalize(GObject *object) {
GmMcpIcecrewUserlist *obj = GM_MCP_ICECREW_USERLIST(object);
GmMcpPackage *playerdb = gm_mcp_session_find_package(
GM_MCP_PACKAGE_SESSION(obj), "dns-nl-icecrew-playerdb");
if (playerdb) {
g_signal_handlers_disconnect_by_func(playerdb,
on_gm_mcp_icecrew_userlist_add, obj);
g_signal_handlers_disconnect_by_func(playerdb,
on_gm_mcp_icecrew_userlist_set, obj);
g_signal_handlers_disconnect_by_func(playerdb,
on_gm_mcp_icecrew_userlist_delete, obj);
}
if (obj->priv->rank_fetch) {
obj->priv->rank_fetch->aborted = TRUE;
}
if (obj->priv->state_fetch) {
obj->priv->state_fetch->aborted = TRUE;
}
gm_mcp_icecrew_userlist_free_list(obj->priv->state_icons);
gm_mcp_icecrew_userlist_free_list(obj->priv->rank_icons);
gm_mcp_icecrew_userlist_free_list(obj->priv->key_datatags);
gm_mcp_icecrew_userlist_free_menu(obj);
gm_mcp_icecrew_userlist_free_list(obj->priv->rank_alternatives);
gm_mcp_icecrew_userlist_free_list(obj->priv->state_alternatives);
g_free(obj->priv->rank_dir);
g_free(obj->priv->state_dir);
G_OBJECT_CLASS(gm_mcp_icecrew_userlist_parent_class)->finalize(object);
}
static void
gm_mcp_icecrew_userlist_class_init(GmMcpIcecrewUserlistClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS(klass);
GmMcpPackageClass *pklass = GM_MCP_PACKAGE_CLASS(klass);
object_class->finalize = gm_mcp_icecrew_userlist_finalize;
pklass->name = "dns-nl-icecrew-userlist";
pklass->depends = gm_mcp_icecrew_userlist_depends;
pklass->overrides = gm_mcp_icecrew_userlist_overrides;
pklass->min_version = 1.0;
pklass->max_version = 1.1;
pklass->set_session = &gm_mcp_icecrew_userlist_set_session;
pklass->handle_multi = &gm_mcp_icecrew_userlist_handle_multi;
pklass->create_view = &gm_mcp_icecrew_userlist_create_view;
g_type_class_add_private(object_class, sizeof(GmMcpIcecrewUserlistPrivate));
}
GmKeyValuePair *
gm_mcp_icecrew_userlist_url_map_new(gchar const *name, gchar const *filename) {
GmKeyValuePair *r = g_new(GmKeyValuePair, 1);
r->key = g_strdup(name);
r->value = g_strdup(filename);
return r;
}
GList *
gm_mcp_icecrew_userlist_find_icon_names(GList *icons, gchar const *path) {
GList *item, *res = NULL;
GmKeyValuePair *map;
if (path == NULL || icons == NULL) {
return NULL;
}
for (item = icons; item; item = item->next) {
map = (GmKeyValuePair *)(item->data);
if (map->value != NULL && strcmp(map->value, path) == 0) {
res = g_list_append(res, map->key);
}
}
return res;
}
guint
gm_mcp_icecrew_userlist_find_path(GList *icons, gchar const *name,
gchar const **path) {
GList *item;
GmKeyValuePair *map;
guint position = 0;
if (name == NULL) {
if (path != NULL) {
*path = NULL;
}
return 0;
}
for (item = icons; item; item = item->next) {
map = (GmKeyValuePair *)(item->data);
if (map->key != NULL && strcmp(map->key, name) == 0) {
if (path != NULL) {
*path = map->value;
}
return position;
}
++position;
}
if (path != NULL) {
*path = NULL;
}
return position + 1;
}
void
gm_mcp_icecrew_userlist_remove_datatag(GmMcpIcecrewUserlist *package,
gchar const *datatag) {
GList *item;
GmKeyValuePair *map;
if (datatag == NULL) {
return;
}
for (item = package->priv->key_datatags; item; item = item->next) {
map = (GmKeyValuePair *)(item->data);
if (strcmp(map->value, datatag) == 0) {
gm_mcp_icecrew_userlist_pair_free(map);
package->priv->key_datatags = g_list_remove_link(
package->priv->key_datatags, item);
g_list_free_1(item);
return;
}
}
}
gchar const *
gm_mcp_icecrew_userlist_find_key(GmMcpIcecrewUserlist *package,
gchar const *datatag) {
GList *item;
GmKeyValuePair *map;
if (datatag == NULL) {
return NULL;
}
for (item = package->priv->key_datatags; item; item = item->next) {
map = (GmKeyValuePair *)(item->data);
if (map->value != NULL && strcmp(map->value, datatag) == 0) {
return map->key;
}
}
return NULL;
}
gchar const *
gm_mcp_icecrew_userlist_find_name(gchar const *name,
GmKeyValuePair def[]) {
GmKeyValuePair *pair = def;
if (name == NULL) {
return NULL;
}
while (!(pair->key == NULL && pair->value == NULL)) {
if (pair->key != NULL && strcmp(pair->key, name) == 0) {
return pair->value;
}
++pair;
}
return NULL;
}
void
gm_mcp_icecrew_userlist_init_states(GmMcpIcecrewUserlist *package) {
GmKeyValuePair *pair = default_states;
package->priv->state_icons = NULL;
while (!(pair->key == NULL && pair->value == NULL)) {
package->priv->state_icons = g_list_append(package->priv->state_icons,
gm_mcp_icecrew_userlist_url_map_new(pair->key, pair->value));
++pair;
}
}
void
gm_mcp_icecrew_userlist_init_ranks(GmMcpIcecrewUserlist *package) {
GmKeyValuePair *pair = default_ranks;
package->priv->rank_icons = NULL;
while (!(pair->key == NULL && pair->value == NULL)) {
package->priv->rank_icons = g_list_append(package->priv->rank_icons,
gm_mcp_icecrew_userlist_url_map_new(pair->key, pair->value));
++pair;
}
}
static void
gm_mcp_icecrew_userlist_init(GmMcpIcecrewUserlist *obj) {
obj->priv = GM_MCP_ICECREW_USERLIST_GET_PRIVATE(obj);
obj->priv->rank_alternatives = NULL;
obj->priv->state_alternatives = NULL;
obj->priv->key_datatags = NULL;
obj->priv->rank_dir = NULL;
obj->priv->state_dir = NULL;
obj->priv->rank_fetch = NULL;
obj->priv->state_fetch = NULL;
gm_mcp_icecrew_userlist_init_states(obj);
gm_mcp_icecrew_userlist_init_ranks(obj);
}
GmMcpIcecrewUserlist *
gm_mcp_icecrew_userlist_new() {
GmMcpIcecrewUserlist *obj = GM_MCP_ICECREW_USERLIST(g_object_new(
GM_TYPE_MCP_ICECREW_USERLIST, NULL));
return obj;
}
gchar *
gm_mcp_icecrew_userlist_remote_to_local_path(gchar const *url,
gchar const *dirname) {
gchar *base = g_path_get_basename(url);
gchar *result;
result = g_strconcat(dirname, G_DIR_SEPARATOR_S, base, NULL);
g_free(base);
return result;
}
void
gm_mcp_icecrew_userlist_remove_alternatives(GmMcpIcecrewUserlist *package,
gchar const *path, gint n, gboolean rank) {
GList *item, **alter;
gint i;
GmKeyValuePair *map;
gchar *name, *pathd, *dir;
if (path == NULL) {
return;
}
alter = rank ? &(package->priv->rank_alternatives) :
&(package->priv->state_alternatives);
dir = rank ? package->priv->rank_dir : package->priv->state_dir;
for (item = *alter; item; item = item->next) {
map = (GmKeyValuePair *)(item->data);
pathd = gm_mcp_icecrew_userlist_remote_to_local_path(map->value, dir);
if (pathd != NULL && strcmp(pathd, path) == 0) {
name = g_strdup(map->key);
i = 0;
if (name != NULL) {
while (item && (n == 0 || i < n)) {
map = (GmKeyValuePair *)(item->data);
++i;
if (map->key != NULL && strcmp(map->key, name) == 0) {
item = item->next;
*alter = g_list_remove(*alter, map);
gm_mcp_icecrew_userlist_pair_free(map);
} else {
break;
}
}
}
g_free(name);
break;
}
g_free(pathd);
}
}
gchar const *
gm_mcp_icecrew_userlist_icon_path(GmMcpIcecrewUserlist *package,
GmPlayerdbPlayerInfo *ppi, gboolean use_state) {
gchar const *state;
gchar const *icon_path = NULL;
state = gm_playerdb_player_info_get_prop(ppi,
package->priv->property_names[P_STATE]);
if (!use_state || (state != NULL && strcmp(state, "avail") == 0)) {
gm_mcp_icecrew_userlist_find_path(package->priv->rank_icons,
gm_playerdb_player_info_get_prop(ppi,
package->priv->property_names[P_RANK]), &icon_path);
} else {
gm_mcp_icecrew_userlist_find_path(package->priv->state_icons,
state, &icon_path);
}
return icon_path;
}
void
gm_mcp_icecrew_userlist_update_rank_icon(GmPlayerdbPlayerInfo *ppi,
gpointer user_data) {
g_signal_emit_by_name(user_data, "rank-changed", ppi->id);
}
void
gm_mcp_icecrew_userlist_update_state_icon(GmPlayerdbPlayerInfo *ppi,
gpointer user_data) {
g_signal_emit_by_name(user_data, "state-changed", ppi->id);
}
void
gm_mcp_icecrew_userlist_new_rank_state_icon(GmMcpIcecrewUserlist *package,
gchar *path, gboolean rank) {
GList *names;
GList *tmp;
GmMcpPackage *playerdb;
playerdb = gm_mcp_session_find_package(GM_MCP_PACKAGE_SESSION(package),
"dns-nl-icecrew-playerdb");
g_return_if_fail(playerdb != NULL);
if (rank) {
names = gm_mcp_icecrew_userlist_find_icon_names(
package->priv->rank_icons, path);
} else {
names = gm_mcp_icecrew_userlist_find_icon_names(
package->priv->state_icons, path);
}
if (names == NULL) {
return;
}
for (tmp = names; tmp; tmp = tmp->next) {
if (rank) {
gm_mcp_icecrew_playerdb_find_players_with(
GM_MCP_ICECREW_PLAYERDB(playerdb),
package->priv->property_names[P_RANK],
(gchar *)(tmp->data),
gm_mcp_icecrew_userlist_update_rank_icon, package);
} else {
gm_mcp_icecrew_playerdb_find_players_with(
GM_MCP_ICECREW_PLAYERDB(playerdb),
package->priv->property_names[P_STATE],
(gchar *)(tmp->data),
gm_mcp_icecrew_userlist_update_state_icon, package);
}
}
g_list_free(names);
}
void
gm_mcp_icecrew_userlist_remove_not_used_icons(GList *icons, gchar *dir) {
glob_t gl;
guint i;
GList *names;
gchar *g = g_strconcat(dir, G_DIR_SEPARATOR_S, "*", NULL);
glob(g, 0, NULL, &gl);
for (i = 0; i < gl.gl_pathc; ++i) {
names = gm_mcp_icecrew_userlist_find_icon_names(icons, gl.gl_pathv[i]);
if (!names) {
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.RemoveNotUsedIcons: "
"removing %s", gl.gl_pathv[i]);
if (unlink(gl.gl_pathv[i]) == -1) {
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.RemoveNotUsedIcons: "
"error %s", strerror(errno));
}
} else {
g_list_free(names);
}
}
g_free(g);
globfree(&gl);
}
void
gm_mcp_icecrew_userlist_fetch_next_alternatives(GmMcpIcecrewUserlist *package,
gboolean rank) {
GList *source_uri = NULL, *dest_uri = NULL;
gchar *prev_name = NULL, *path;
GList *item, **alter, *iter;
GmKeyValuePair *map, *itermap;
/* Select unique name alternatives */
alter = rank ? &(package->priv->rank_alternatives) :
&(package->priv->state_alternatives);
item = *alter;
while (item) {
map = (GmKeyValuePair *)(item->data);
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.FetchNextAlternatives: "
"checking: %s", map->value);
/* Skip alternatives with names we've already stored to be fetched */
if (prev_name == NULL || (map->key != NULL &&
strcmp(map->key, prev_name) != 0)) {
prev_name = map->key;
path = gm_mcp_icecrew_userlist_remote_to_local_path(map->value,
rank ? package->priv->rank_dir :
package->priv->state_dir);
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist."
"FetchNextAlternatives: adding to be fetched: %s => %s",
map->key, map->value);
source_uri = g_list_append(source_uri, map->value);
dest_uri = g_list_append(dest_uri, path);
unlink(path);
for (iter = rank ? package->priv->rank_icons :
package->priv->state_icons; iter; iter = iter->next) {
itermap = (GmKeyValuePair *)(iter->data);
if (itermap->key != NULL &&
strcmp(itermap->key, map->key) == 0) {
g_free(itermap->value);
itermap->value = g_strdup(path);
break;
}
}
}
if (source_uri != NULL)
break;
item = item->next;
}
if (source_uri != NULL) {
if (rank) {
package->priv->rank_fetch = gm_fetch(source_uri, dest_uri,
(GFunc)gm_mcp_icecrew_userlist_fetch_progress, package);
} else {
package->priv->state_fetch = gm_fetch(source_uri, dest_uri,
(GFunc)gm_mcp_icecrew_userlist_fetch_progress, package);
}
gm_g_list_free_simple(dest_uri);
} else {
if (rank) {
gm_mcp_icecrew_userlist_remove_not_used_icons(
package->priv->rank_icons, package->priv->rank_dir);
} else {
gm_mcp_icecrew_userlist_remove_not_used_icons(
package->priv->state_icons, package->priv->state_dir);
}
}
}
void
gm_mcp_icecrew_userlist_fetch_progress(GmFetchHandle *g,
GmMcpIcecrewUserlist *package) {
gchar *path;
gboolean rank;
GdkPixbuf *pixtest;
GError *err = NULL;
if (g->aborted) {
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.FetchProgress: "
"fetch aborted!");
return;
}
rank = (package->priv->rank_fetch == g);
if (g->done) {
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.FetchProgress: "
"fetch done!");
/* Remove this one from the alternatives */
gm_mcp_icecrew_userlist_remove_alternatives(package,
gnome_vfs_uri_get_path((GnomeVFSURI *)(g->dest_uri->data)),
1, rank);
if (rank) {
package->priv->rank_fetch = NULL;
gm_mcp_icecrew_userlist_fetch_next_alternatives(package, TRUE);
} else {
package->priv->state_fetch = NULL;
gm_mcp_icecrew_userlist_fetch_next_alternatives(package, FALSE);
}
return;
}
if (g->status == GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR) {
/* Skip to the next alternative (in the next run, see on done */
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.FetchProgress: error");
}
if (g->cur_phase == GNOME_VFS_XFER_PHASE_FILECOMPLETED) {
path = gnome_vfs_get_local_path_from_uri(g->cur_file_name);
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.FetchProgress: "
"%s fetched!", path);
pixtest = gdk_pixbuf_new_from_file(path, &err);
if (pixtest) {
/* Remove alternatives which don't need to be fetched anymore */
g_object_unref(pixtest);
gm_mcp_icecrew_userlist_remove_alternatives(package, path, 0, rank);
if (rank) {
gm_mcp_icecrew_userlist_new_rank_state_icon(package, path,
TRUE);
} else {
gm_mcp_icecrew_userlist_new_rank_state_icon(package, path,
FALSE);
}
} else {
/* This failed! */
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.FetchProgress: "
"error, couldn't load file: %s", err->message);
g_error_free(err);
gm_mcp_icecrew_userlist_remove_alternatives(package, path, 1, rank);
}
g_free(path);
}
}
#define MAX_MATCHES 10
void
gm_mcp_icecrew_userlist_process_triggers(GmMcpIcecrewUserlist *package,
gchar const *username, GmTriggerConditionType condition) {
GmWorld *world;
GmTriggers *triggers;
GList const *item;
GmTrigger *trigger;
regmatch_t matches[MAX_MATCHES];
gint num;
GmMcpPackage *playerdb = gm_mcp_session_find_package(
GM_MCP_PACKAGE_SESSION(package), "dns-nl-icecrew-playerdb");
if (gm_mcp_icecrew_playerdb_initializing(
GM_MCP_ICECREW_PLAYERDB(playerdb))) {
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);
}
}
}
}
gchar *
gm_mcp_icecrew_userlist_menu_item_subst(GmMcpIcecrewUserlist *package,
gchar *str, GmPlayerdbPlayerInfo *info) {
GString *result;
gchar *ptr = str, *subst = NULL, *tmp, *prop;
gchar const *value;
gunichar ch, cnum;
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 == '$') {
tmp = subst = g_utf8_next_char(ptr);
while ((cnum = g_utf8_get_char(subst)) && (cnum == '_' ||
g_unichar_isalpha(cnum))) {
subst = g_utf8_next_char(subst);
}
prop = g_strndup(tmp, subst - tmp);
if (strcmp(prop, "ID") == 0 || strcmp(prop, "id") == 0) {
tmp = g_strdup_printf("#%d", info->id);
result = g_string_append(result, tmp);
g_free(tmp);
substituted = TRUE;
} else {
value = gm_playerdb_player_info_get_prop(info, prop);
if (value) {
for (; *value != '\0'; value = g_utf8_next_char(value)) {
ch = g_utf8_get_char(value);
if (ch == '_') {
result = g_string_append_c(result, '_');
}
result = g_string_append_unichar(result, ch);
}
substituted = TRUE;
}
}
}
if (!substituted) {
result = g_string_append_unichar(result, ch);
}
if (*ptr == '\0') {
break;
}
if (!substituted) {
ptr = g_utf8_next_char(ptr);
} else {
ptr = subst;
}
}
ptr = result->str;
g_string_free(result, FALSE);
return ptr;
}
GmKeyValuePair *
gm_mcp_icecrew_userlist_get_menu_item(GmMcpIcecrewUserlist *package,
GmKeyValuePair *menuitem, GmPlayerdbPlayerInfo *info) {
GmKeyValuePair *result = g_new0(GmKeyValuePair, 1);
if (!menuitem) {
return result;
}
result->key = gm_mcp_icecrew_userlist_menu_item_subst(package,
menuitem->key, info);
result->value = gm_mcp_icecrew_userlist_menu_item_subst(package,
menuitem->value, info);
return result;
}
/* Interface */
GList *
gm_mcp_icecrew_userlist_get_menu(GmIUserlist *userlist, gint id) {
GmMcpIcecrewUserlist *object = GM_MCP_ICECREW_USERLIST(userlist);
GmMcpIcecrewPlayerdb *playerdb = GM_MCP_ICECREW_PLAYERDB(
gm_mcp_session_find_package(GM_MCP_PACKAGE_SESSION(userlist),
"dns-nl-icecrew-playerdb"));
GmPlayerdbPlayerInfo *info = gm_mcp_icecrew_playerdb_find(playerdb, id);
GList *item, *result = NULL;
for (item = object->priv->menu; item; item = item->next) {
result = g_list_append(result, gm_mcp_icecrew_userlist_get_menu_item(
object, (GmKeyValuePair *)(item->data), info));
}
return result;
}
gchar const *
gm_mcp_icecrew_userlist_get_name(GmIUserlist *userlist, gint id) {
GmMcpIcecrewPlayerdb *playerdb = GM_MCP_ICECREW_PLAYERDB(
gm_mcp_session_find_package(GM_MCP_PACKAGE_SESSION(userlist),
"dns-nl-icecrew-playerdb"));
GmPlayerdbPlayerInfo *info = gm_mcp_icecrew_playerdb_find(playerdb, id);
return gm_playerdb_player_info_get_prop(info,
GM_MCP_ICECREW_USERLIST(userlist)->priv->property_names[P_NAME]);
}
gchar const *
gm_mcp_icecrew_userlist_get_icon(GmIUserlist *userlist, gint id,
gboolean use_state) {
GmMcpIcecrewUserlist *package = GM_MCP_ICECREW_USERLIST(userlist);
GmMcpIcecrewPlayerdb *playerdb = GM_MCP_ICECREW_PLAYERDB(
gm_mcp_session_find_package(GM_MCP_PACKAGE_SESSION(package),
"dns-nl-icecrew-playerdb"));
GmPlayerdbPlayerInfo *info = gm_mcp_icecrew_playerdb_find(playerdb, id);
return gm_mcp_icecrew_userlist_icon_path(package, info, use_state);
}
gint
gm_mcp_icecrew_userlist_get_rank_priority(GmIUserlist *userlist, gint id) {
GmMcpIcecrewUserlist *package = GM_MCP_ICECREW_USERLIST(userlist);
GmMcpIcecrewPlayerdb *playerdb = GM_MCP_ICECREW_PLAYERDB(
gm_mcp_session_find_package(GM_MCP_PACKAGE_SESSION(userlist),
"dns-nl-icecrew-playerdb"));
GmPlayerdbPlayerInfo *info = gm_mcp_icecrew_playerdb_find(playerdb, id);
gchar const *rank = gm_playerdb_player_info_get_prop(info,
package->priv->property_names[P_RANK]);
return g_list_length(package->priv->rank_icons) -
gm_mcp_icecrew_userlist_find_path(package->priv->rank_icons,
rank, NULL) - 1;
}
gint
gm_mcp_icecrew_userlist_get_state_priority(GmIUserlist *userlist, gint id) {
GmMcpIcecrewUserlist *package = GM_MCP_ICECREW_USERLIST(userlist);
GmMcpIcecrewPlayerdb *playerdb = GM_MCP_ICECREW_PLAYERDB(
gm_mcp_session_find_package(GM_MCP_PACKAGE_SESSION(userlist),
"dns-nl-icecrew-playerdb"));
GmPlayerdbPlayerInfo *info = gm_mcp_icecrew_playerdb_find(playerdb, id);
gchar const *state = gm_playerdb_player_info_get_prop(info,
package->priv->property_names[P_STATE]);
return g_list_length(package->priv->state_icons) -
gm_mcp_icecrew_userlist_find_path(package->priv->state_icons,
state, NULL) + 1;
}
gchar *
gm_mcp_icecrew_userlist_get_status(GmIUserlist *userlist, gint id) {
GmMcpIcecrewPlayerdb *playerdb = GM_MCP_ICECREW_PLAYERDB(
gm_mcp_session_find_package(GM_MCP_PACKAGE_SESSION(userlist),
"dns-nl-icecrew-playerdb"));
GmPlayerdbPlayerInfo *info = gm_mcp_icecrew_playerdb_find(playerdb, id);
GmMcpIcecrewUserlist *package = GM_MCP_ICECREW_USERLIST(userlist);
gchar const *state = gm_playerdb_player_info_get_prop(info,
package->priv->property_names[P_STATE]);
gchar const *msg = gm_playerdb_player_info_get_prop(info,
package->priv->property_names[P_STATE_MSG]);
gchar const *caption;
if (state == NULL || strcmp(state, "avail") == 0) {
return strdup(_("Available"));
}
if (strstr(state, "away") != NULL) {
caption = _("Away");
} else if (strstr(state, "busy") != NULL) {
caption = _("Busy");
} else if (strstr(state, "idle") != NULL) {
caption = _("Idle");
} else {
return NULL;
}
if (msg == NULL || *msg == '\0') {
return strdup(caption);
} else {
return g_strconcat(caption, ": ", msg, NULL);
}
}
void
gm_mcp_icecrew_userlist_handle_menu(GmMcpIcecrewUserlist *package,
GList *values) {
GmKeyValuePair *pair;
GList *item, *data;
gm_mcp_icecrew_userlist_free_menu(package);
for (item = values; item; item = item->next) {
data = (GList *)(item->data);
pair = g_new0(GmKeyValuePair, 1);
if (g_list_length(data) == 2) {
pair->key = g_strdup(data->data);
pair->value = g_strdup(data->next->data);
}
package->priv->menu = g_list_append(package->priv->menu,
pair);
}
}
void
gm_mcp_icecrew_userlist_handle_ranks_states(GmMcpIcecrewUserlist *package,
GList *values, gboolean rank) {
GList *tmp, *data, *new_list = NULL;
gchar *name, **alternatives, *path, **ptr;
gchar const *cpath;
/* Abort a previous fetch if needed */
if (rank && package->priv->rank_fetch) {
package->priv->rank_fetch = NULL;
gm_mcp_icecrew_userlist_free_list(package->priv->rank_alternatives);
package->priv->rank_alternatives = NULL;
package->priv->rank_fetch->aborted = TRUE;
} else if (!rank && package->priv->state_fetch) {
package->priv->state_fetch = NULL;
gm_mcp_icecrew_userlist_free_list(package->priv->state_alternatives);
package->priv->state_alternatives = NULL;
package->priv->state_fetch->aborted = TRUE;
}
for (tmp = values; tmp; tmp = tmp->next) {
data = (GList *)(tmp->data);
if (data == NULL ) {
continue;
}
name = (gchar *)(data->data);
gm_mcp_icecrew_userlist_find_path(new_list, name, &cpath);
if (cpath) {
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.HandleRanksStates: "
"duplicate %s, ignored!", name);
continue;
}
if (data->next == NULL) {
if (rank) {
cpath = gm_mcp_icecrew_userlist_find_name(name, default_ranks);
} else {
cpath = gm_mcp_icecrew_userlist_find_name(name, default_states);
}
if (cpath) {
new_list = g_list_append(new_list,
gm_mcp_icecrew_userlist_url_map_new(name, cpath));
} else {
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist."
"HandleRanksStates: couldn't find %s, ignored!", name);
}
} else {
alternatives = g_strsplit(g_list_nth_data(data, 1), ";", 0);
ptr = alternatives;
while (*ptr) {
/* Initialize to first alternative */
if (ptr == alternatives) {
path = gm_mcp_icecrew_userlist_remote_to_local_path(
*ptr, rank ? package->priv->rank_dir :
package->priv->state_dir);
new_list = g_list_append(new_list,
gm_mcp_icecrew_userlist_url_map_new(name, path));
g_free(path);
}
gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.HandleRanksStates: "
"adding alternative: %s => %s", name, *ptr);
if (rank) {
package->priv->rank_alternatives = g_list_append(
package->priv->rank_alternatives,
gm_mcp_icecrew_userlist_url_map_new(name,
*ptr));
} else {
package->priv->state_alternatives = g_list_append(
package->priv->state_alternatives,
gm_mcp_icecrew_userlist_url_map_new(name,
*ptr));
}
++ptr;
}
g_strfreev(alternatives);
}
}
if (rank) {
gm_mcp_icecrew_userlist_free_list(package->priv->rank_icons);
package->priv->rank_icons = new_list;
} else {
gm_mcp_icecrew_userlist_free_list(package->priv->state_icons);
package->priv->state_icons = new_list;
}
if (rank && package->priv->rank_alternatives) {
gm_mcp_icecrew_userlist_fetch_next_alternatives(package, rank);
} else if (!rank && package->priv->state_alternatives) {
gm_mcp_icecrew_userlist_fetch_next_alternatives(package, rank);
}
}
gboolean
gm_mcp_icecrew_userlist_handle_multi(GmMcpPackage *package,
gchar const *data_tag, gchar const *key, gchar const *value,
GList *all_values) {
GmMcpIcecrewUserlist *userlist = GM_MCP_ICECREW_USERLIST(package);
GList *tmp, *l, *vals = NULL;
GmKeyValuePair *m;
if (key) {
if (!gm_mcp_icecrew_userlist_find_key(userlist, data_tag)) {
m = g_new(GmKeyValuePair, 1);
m->key = g_strdup(key);
m->value = g_strdup(data_tag);
userlist->priv->key_datatags = g_list_append(
userlist->priv->key_datatags, m);
}
} else if ((key = gm_mcp_icecrew_userlist_find_key(userlist, data_tag))
!= NULL) {
for (tmp = all_values; tmp; tmp = tmp->next) {
l = gm_mcp_parse_list((gchar *)(tmp->data));
vals = g_list_append(vals, l);
}
if (strcmp(key, "rank") == 0) {
gm_mcp_icecrew_userlist_handle_ranks_states(userlist, vals, TRUE);
} else if (strcmp(key, "state") == 0) {
gm_mcp_icecrew_userlist_handle_ranks_states(userlist, vals, FALSE);
} else if (strcmp(key, "menu") == 0) {
gm_mcp_icecrew_userlist_handle_menu(userlist, vals);
}
gm_mcp_icecrew_userlist_remove_datatag(userlist, data_tag);
} else {
gm_debug_msg(DEBUG_ALWAYS, "Datatag %s not found", data_tag);
}
for (tmp = vals; tmp; tmp = tmp->next) {
gm_mcp_list_free((GList *)(tmp->data));
}
g_list_free(vals);
return FALSE;
}
void
gm_mcp_icecrew_userlist_set_session(GmMcpPackage *package, GObject *session) {
GmMcpPackageClass *parent_class = g_type_class_peek_parent(
GM_MCP_ICECREW_USERLIST_GET_CLASS(package));
gchar *icons_dir;
GmMcpPackage *playerdb;
GmMcpIcecrewUserlist *userlist = GM_MCP_ICECREW_USERLIST(package);
GmMcpSession *ses;
gdouble version;
parent_class->set_session(package, session);
ses = GM_MCP_SESSION(session);
playerdb = gm_mcp_session_find_package(ses, "dns-nl-icecrew-playerdb");
g_return_if_fail(playerdb != NULL);
version = gm_mcp_package_get_version(GM_MCP_PACKAGE(playerdb));
if (version == 1.1) {
userlist->priv->property_names =
gm_mcp_icecrew_userlist_property_names1;
} else {
userlist->priv->property_names =
gm_mcp_icecrew_userlist_property_names0;
}
icons_dir = g_strconcat(gm_world_path(GM_MCP_SESSION_WORLD(ses)),
G_DIR_SEPARATOR_S, "icons", NULL);
userlist->priv->rank_dir = g_strconcat(icons_dir, G_DIR_SEPARATOR_S,
"ranks", NULL);
userlist->priv->state_dir = g_strconcat(icons_dir, G_DIR_SEPARATOR_S,
"states", NULL);
if (!g_file_test(icons_dir, G_FILE_TEST_EXISTS))
mkdir(icons_dir, 0755);
if (!g_file_test(userlist->priv->rank_dir, G_FILE_TEST_EXISTS))
mkdir(userlist->priv->rank_dir, 0755);
if (!g_file_test(userlist->priv->state_dir, G_FILE_TEST_EXISTS))
mkdir(userlist->priv->state_dir, 0755);
g_free(icons_dir);
g_signal_connect(playerdb, "add",
G_CALLBACK(on_gm_mcp_icecrew_userlist_add), package);
g_signal_connect(playerdb, "set",
G_CALLBACK(on_gm_mcp_icecrew_userlist_set), package);
g_signal_connect(playerdb, "delete",
G_CALLBACK(on_gm_mcp_icecrew_userlist_delete), package);
}
void
gm_mcp_icecrew_userlist_create_view(GmMcpPackage *package, GObject *parent) {
gm_mcp_userlist_view_new(package, parent);
}
void
gm_mcp_icecrew_userlist_process_state_changed(GmMcpIcecrewUserlist *userlist,
GmPlayerdbPlayerInfo *ppi, gchar const *value, gchar const *old) {
gboolean was_away, was_idle;
gboolean is_away, is_idle;
gchar const *name = gm_playerdb_player_info_get_prop(ppi,
userlist->priv->property_names[P_NAME]);
was_away = (strstr(old, "away") != NULL || strstr(old, "busy") != NULL);
was_idle = (strstr(old, "idle") != NULL);
is_away = (strstr(value, "away") != NULL || strstr(value, "busy") != NULL);
is_idle = (strstr(value, "idle") != NULL);
if (was_away && !is_away) {
gm_mcp_icecrew_userlist_process_triggers(userlist, name,
TCT_USER_AWAY_OFF);
} else if (!was_away && is_away) {
gm_mcp_icecrew_userlist_process_triggers(userlist, name,
TCT_USER_AWAY);
}
if (was_idle && !is_idle) {
gm_mcp_icecrew_userlist_process_triggers(userlist, name,
TCT_USER_IDLE_OFF);
} else if (!was_idle && is_idle) {
gm_mcp_icecrew_userlist_process_triggers(userlist, name,
TCT_USER_IDLE);
}
}
/* Callbacks */
void
on_gm_mcp_icecrew_userlist_add(GmMcpIcecrewPlayerdb *playerdb,
GmPlayerdbPlayerInfo *ppi, GmMcpIcecrewUserlist *userlist) {
gchar const *name = gm_playerdb_player_info_get_prop(ppi,
userlist->priv->property_names[P_NAME]);
g_signal_emit_by_name(userlist, "player-added", ppi->id);
gm_mcp_icecrew_userlist_process_triggers(userlist, name, TCT_USER_ONLINE);
}
void
on_gm_mcp_icecrew_userlist_set(GmMcpIcecrewPlayerdb *playerdb,
GmPlayerdbPlayerInfo *ppi, gchar const *key, gchar const *value,
gchar const *old, GmMcpIcecrewUserlist *userlist) {
if (strcmp(key, userlist->priv->property_names[P_STATE]) == 0) {
g_signal_emit_by_name(userlist, "state-changed", ppi->id);
gm_mcp_icecrew_userlist_process_state_changed(userlist, ppi, value,
old);
} else if (strcmp(key, userlist->priv->property_names[P_RANK]) == 0) {
g_signal_emit_by_name(userlist, "rank-changed", ppi->id);
} else if (strcmp(key, userlist->priv->property_names[P_NAME]) == 0) {
g_signal_emit_by_name(userlist, "name-changed", ppi->id);
} else if (strcmp(key, userlist->priv->property_names[P_STATE_MSG]) == 0) {
g_signal_emit_by_name(userlist, "state-changed", ppi->id);
}
}
void
on_gm_mcp_icecrew_userlist_delete(GmMcpIcecrewPlayerdb *playerdb,
GmPlayerdbPlayerInfo *ppi, GmMcpIcecrewUserlist *userlist) {
gchar const *name = gm_playerdb_player_info_get_prop(ppi,
userlist->priv->property_names[P_NAME]);
g_signal_emit_by_name(userlist, "player-removed", ppi->id);
gm_mcp_icecrew_userlist_process_triggers(userlist, name, TCT_USER_OFFLINE);
}