Initial import into SVN

This commit is contained in:
Jesse van den Kieboom 2005-11-06 15:57:34 +00:00
parent b7a9743460
commit 31a3086b85
11 changed files with 1502 additions and 0 deletions

12
src/mcp/Makefile.include Normal file
View File

@ -0,0 +1,12 @@
## Process this file with automake to produce Makefile.in
mcpdir = mcp
gnoemoe_SOURCES += $(mcpdir)/gm-mcp-classes.c \
$(mcpdir)/gm-mcp.c $(mcpdir)/gm-mcp.h \
$(mcpdir)/gm-mcp-session.c $(mcpdir)/gm-mcp-session.h \
$(mcpdir)/gm-mcp-package.c $(mcpdir)/gm-mcp-package.h \
$(mcpdir)/gm-mcp-negotiate.c $(mcpdir)/gm-mcp-negotiate.h
$(mcpdir)/gm-mcp-classes.c: $(mcpdir)/packages.defs
( cd $(srcdir) && ./$(mcpdir)/mcpinit.rb \
$(mcpdir)/packages.defs $(mcpdir)/gm-mcp-classes ) > $@

295
src/mcp/gm-mcp-negotiate.c Normal file
View File

@ -0,0 +1,295 @@
#include <glib-object.h>
#include <string.h>
#include "gm-mcp-negotiate.h"
#include "gm-mcp.h"
#include "gm-mcp-session.h"
#include "gm-mcp-package.h"
#include "../debug.h"
#include "../gm-support.h"
#define GM_MCP_NEGOTIATE_GET_PRIVATE(object)( \
G_TYPE_INSTANCE_GET_PRIVATE((object), \
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiatePrivate))
typedef struct _PackageInfo {
GmMcpPackageClass *klass;
gdouble version;
} PackageInfo;
struct _GmMcpNegotiatePrivate {
GList *packages;
};
/* Signals
enum {
PROTO
NUM_SIGNALS
};
static guint gm_mcp_negotiate_signals[NUM_SIGNALS] = {0};*/
void gm_mcp_negotiate_handle_simple(GmMcpPackage *package, gchar *suffix,
GList *fields);
static void gm_mcp_negotiate_init(GmMcpNegotiate *self);
static void gm_mcp_negotiate_class_init(GmMcpNegotiateClass *klass);
//static void gm_mcp_negotiate_class_finalize(gpointer klass,
// gpointer klass_data);
static gpointer gm_mcp_negotiate_parent_class = NULL;
static void gm_mcp_negotiate_class_intern_init(gpointer klass) {
gm_mcp_negotiate_parent_class = g_type_class_peek_parent(klass);
gm_mcp_negotiate_class_init((GmMcpNegotiateClass *) klass);
}
GType
gm_mcp_negotiate_get_type() {
static GType g_define_type_id = 0;
if (G_UNLIKELY(g_define_type_id == 0)) {
static const GTypeInfo g_define_type_info = {
sizeof (GmMcpNegotiateClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gm_mcp_negotiate_class_intern_init,
(GClassFinalizeFunc) NULL, //gm_mcp_negotiate_class_finalize,
NULL, /* class_data */
sizeof (GmMcpNegotiate),
0, /* n_preallocs */
(GInstanceInitFunc) gm_mcp_negotiate_init,
NULL /* value_table */
};
g_define_type_id = g_type_register_static(GM_TYPE_MCP_PACKAGE,
"GmMcpNegotiate", &g_define_type_info, (GTypeFlags) 0);
}
return g_define_type_id; \
}
static void
gm_mcp_negotiate_finalize(GObject *object) {
//GmMcpNegotiate *obj = GM_MCP_NEGOTIATE(object);
G_OBJECT_CLASS(gm_mcp_negotiate_parent_class)->finalize(object);
}
/*static void
gm_mcp_negotiate_class_finalize(gpointer klass, gpointer klass_data) {
GmMcpPackageClass *pklass = GM_MCP_PACKAGE_CLASS(klass);
g_list_free(pklass->depends);
g_list_free(pklass->overrides);
}*/
static void
gm_mcp_negotiate_class_init(GmMcpNegotiateClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS(klass);
GmMcpPackageClass *pklass = GM_MCP_PACKAGE_CLASS(klass);
object_class->finalize = gm_mcp_negotiate_finalize;
/*gm_mcp_negotiate_signals[PROTO] =
g_signal_new("proto",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GmMcpNegotiateClass, proto),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);*/
pklass->name = "mcp-negotiate";
pklass->handle_simple = &gm_mcp_negotiate_handle_simple;
g_type_class_add_private(object_class, sizeof(GmMcpNegotiatePrivate));
}
static void
gm_mcp_negotiate_init(GmMcpNegotiate *obj) {
obj->priv = GM_MCP_NEGOTIATE_GET_PRIVATE(obj);
obj->priv->packages = NULL;
}
PackageInfo *
gm_mcp_negotiate_find_package(GmMcpNegotiate *package, gchar *name) {
PackageInfo *pinfo;
GList *elem;
for (elem = package->priv->packages; elem; elem = elem->next) {
pinfo = (PackageInfo *)(elem->data);
if (strcasecmp(pinfo->klass->name, name) == 0) {
return pinfo;
}
}
return NULL;
}
void
gm_mcp_negotiate_fix_overrides(GmMcpNegotiate *package) {
GList *l, *item, *over;
PackageInfo *pinfo, *pover;
gchar *name;
l = g_list_copy(package->priv->packages);
for (item = l; item; item = item->next) {
pinfo = (PackageInfo *)(item);
for (over = pinfo->klass->overrides; over; over = over->next) {
name = (gchar *)(over->data);
if ((pover = gm_mcp_negotiate_find_package(package, name))) {
debug_msg(2, "GmMcpNegotiate.FixOverrides: package %s "
"overrides %s", pinfo->klass->name, pover->klass->name);
package->priv->packages = g_list_remove(
package->priv->packages, pover);
}
}
}
g_list_free(l);
}
void
gm_mcp_negotiate_fix_depends(GmMcpNegotiate *package) {
PackageInfo *pinfo, *pdep;
GList *l, *item, *dep;
gchar *name;
l = g_list_copy(package->priv->packages);
for (item = l; item; item = item->next) {
pinfo = (PackageInfo *)(item->data);
for (dep = pinfo->klass->depends; dep; dep = dep->next) {
name = (gchar *)(dep->data);
if (!(pdep = gm_mcp_negotiate_find_package(package, name))) {
debug_msg(2, "GmMcpNegotiate.FixDepends: package %s depends "
"on %s, but %s is not supported", pinfo->klass->name,
name, name);
// Remove package because depencendies are not met
package->priv->packages = g_list_remove(
package->priv->packages, pinfo);
break;
} else {
// Make sure this dependency is loaded before the package
package->priv->packages = g_list_remove(
package->priv->packages, pdep);
package->priv->packages = g_list_insert_before(
package->priv->packages,
g_list_find(package->priv->packages, pinfo), pdep);
}
}
}
g_list_free(l);
}
/* Public */
GmMcpNegotiate *
gm_mcp_negotiate_new() {
GmMcpNegotiate *obj = GM_MCP_NEGOTIATE(g_object_new(GM_TYPE_MCP_NEGOTIATE,
NULL));
return obj;
}
/* Private */
gboolean
gm_mcp_negotiate_send_can(GmMcpPackageClass *klass, gpointer user_data) {
GmMcpNegotiate *package = GM_MCP_NEGOTIATE(user_data);
gchar *min_v, *max_v;
min_v = g_strdup_printf("%'.1f", klass->min_version);
gm_fix_decimal_point_rev(min_v, strlen(min_v));
max_v = g_strdup_printf("%'.1f", klass->max_version);
gm_fix_decimal_point_rev(max_v, strlen(max_v));
gm_mcp_session_send_simple(GM_MCP_PACKAGE_SESSION(package),
"mcp-negotiate-can", "package", klass->name, "min-version",
min_v, "max-version", max_v, NULL);
g_free(min_v);
g_free(max_v);
return FALSE;
}
void
gm_mcp_negotiate_handle_simple(GmMcpPackage *package, gchar *suffix,
GList *fields) {
gchar const *pname;
GmMcpPackageClass *pklass;
GmMcpNegotiate *negotiate = GM_MCP_NEGOTIATE(package);
PackageInfo *pinfo;
double version;
gchar const *min_v, *max_v;
gchar *cmin, *cmax;
GList *elem;
if (strcasecmp(suffix, "can") == 0) {
// Fields has package, min-version, max-version
pname = gm_mcp_find_value(fields, "package");
pklass = gm_mcp_session_find_package_class(pname);
if (pklass) {
min_v = gm_mcp_find_value(fields, "min-version");
cmin = gm_fix_decimal_point(g_strdup(min_v), strlen(min_v));
max_v = gm_mcp_find_value(fields, "max-version");
cmax = gm_fix_decimal_point(g_strdup(max_v), strlen(max_v));
version = gm_mcp_get_version(pklass->min_version,
pklass->max_version, g_ascii_strtod(min_v, NULL),
g_ascii_strtod(max_v, NULL));
g_free(cmin);
g_free(cmax);
if (version > 0.0) {
debug_msg(2, "GmMcpNegotiate.HandleSimple: %s, "
"package is supported", pname);
pinfo = g_new(PackageInfo, 1);
pinfo->klass = pklass;
pinfo->version = version;
negotiate->priv->packages = g_list_append(
negotiate->priv->packages, pinfo);
} else {
debug_msg(2, "GmMcpNegotiate.HandleSimple: %s, package "
"supported but wrong version!", pname);
}
} else {
debug_msg(2, "GmMcpNegotiate.HandleSimple: %s, package is not "
"supported!", pname);
}
} else if (strcasecmp(suffix, "end") == 0) {
gm_mcp_session_package_class_for_each(gm_mcp_negotiate_send_can,
(gpointer)(negotiate));
gm_mcp_session_send_simple(GM_MCP_PACKAGE_SESSION(negotiate),
"mcp-negotiate-end", NULL);
gm_mcp_negotiate_fix_overrides(negotiate);
gm_mcp_negotiate_fix_depends(negotiate);
for (elem = negotiate->priv->packages; elem; elem = elem->next) {
pinfo = (PackageInfo *)(elem->data);
gm_mcp_session_create_package(GM_MCP_PACKAGE_SESSION(negotiate),
pinfo->klass, pinfo->version);
g_free(pinfo);
}
g_list_free(negotiate->priv->packages);
negotiate->priv->packages = NULL;
}
}

View File

@ -0,0 +1,57 @@
#ifndef __GM_MCP_NEGOTIATE_H__
#define __GM_MCP_NEGOTIATE_H__
#include <glib-object.h>
#include "gm-mcp-package.h"
G_BEGIN_DECLS
/*
* Type checking and casting macros
*/
#define GM_TYPE_MCP_NEGOTIATE (gm_mcp_negotiate_get_type())
#define GM_MCP_NEGOTIATE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiate))
#define GM_MCP_NEGOTIATE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiate const))
#define GM_MCP_NEGOTIATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiateClass))
#define GM_IS_MCP_NEGOTIATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
GM_TYPE_MCP_NEGOTIATE))
#define GM_IS_MCP_NEGOTIATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
GM_TYPE_MCP_NEGOTIATE))
#define GM_MCP_NEGOTIATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
GM_TYPE_MCP_NEGOTIATE, GmMcpNegotiateClass))
/* Private structure type */
typedef struct _GmMcpNegotiatePrivate GmMcpNegotiatePrivate;
/*
* Main object structure
*/
typedef struct _GmMcpNegotiate GmMcpNegotiate;
struct _GmMcpNegotiate {
GmMcpPackage parent;
/*< private > */
GmMcpNegotiatePrivate *priv;
};
/*
* Class definition
*/
typedef struct _GmMcpNegotiateClass GmMcpNegotiateClass;
struct _GmMcpNegotiateClass {
GmMcpPackageClass parent_class;
/* Signals
void (* proto) (GmMcpNegotiate *obj); */
};
GType gm_mcp_negotiate_get_type(void) G_GNUC_CONST;
GmMcpNegotiate *gm_mcp_negotiate_new(void);
G_END_DECLS
#endif /* __GM_MCP_NEGOTIATE_H__ */

140
src/mcp/gm-mcp-package.c Normal file
View File

@ -0,0 +1,140 @@
#include <glib-object.h>
#include "gm-mcp-session.h"
#include "gm-mcp-package.h"
#include "../gm-support.h"
#define GM_MCP_PACKAGE_GET_PRIVATE(object)( \
G_TYPE_INSTANCE_GET_PRIVATE((object), \
GM_TYPE_MCP_PACKAGE, GmMcpPackagePrivate))
struct _GmMcpPackagePrivate {
GmMcpSession *session;
gdouble version;
};
/* Signals
enum {
PROTO
NUM_SIGNALS
};
static guint gm_mcp_package_signals[NUM_SIGNALS] = {0};*/
G_DEFINE_TYPE(GmMcpPackage, gm_mcp_package, G_TYPE_OBJECT)
static void
gm_mcp_package_finalize(GObject *object) {
//GmMcpPackage *package = GM_MCP_PACKAGE(object);
G_OBJECT_CLASS(gm_mcp_package_parent_class)->finalize(object);
}
static void
gm_mcp_package_class_init(GmMcpPackageClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = gm_mcp_package_finalize;
/*gm_mcp_package_signals[PROTO] =
g_signal_new("proto",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GmMcpPackageClass, proto),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);*/
klass->handle_simple = NULL;
klass->handle_multi = NULL;
klass->depends = NULL;
klass->overrides = NULL;
klass->name = NULL;
klass->min_version = 1.0;
klass->max_version = 1.0;
g_type_class_add_private(object_class, sizeof(GmMcpPackagePrivate));
}
static void
gm_mcp_package_init(GmMcpPackage *obj) {
obj->priv = GM_MCP_PACKAGE_GET_PRIVATE(obj);
obj->priv->session = NULL;
obj->priv->version = 1.0;
}
/* Public */
GmMcpPackage *
gm_mcp_package_new() {
GmMcpPackage *obj = GM_MCP_PACKAGE(g_object_new(GM_TYPE_MCP_PACKAGE, NULL));
return obj;
}
void
gm_mcp_package_handle_simple(GmMcpPackage *package, gchar *suffix,
GList *fields) {
return GM_MCP_PACKAGE_GET_CLASS(package)->handle_simple(package,
suffix, fields);
}
gboolean
gm_mcp_package_can_handle_simple(GmMcpPackage *package) {
return (GM_MCP_PACKAGE_GET_CLASS(package)->handle_simple != NULL);
}
gboolean
gm_mcp_package_handle_multi(GmMcpPackage *package, gchar *data_tag,
gchar *key, gchar *value, GList *allValues) {
return GM_MCP_PACKAGE_GET_CLASS(package)->handle_multi(package,
data_tag, key, value, allValues);
}
gboolean
gm_mcp_package_can_handle_multi(GmMcpPackage *package) {
return (GM_MCP_PACKAGE_GET_CLASS(package)->handle_multi != NULL);
}
void
gm_mcp_package_set_session(GmMcpPackage *package, GObject *session) {
package->priv->session = GM_MCP_SESSION(session);
}
GObject *
gm_mcp_package_get_session(GmMcpPackage *package) {
return G_OBJECT(package->priv->session);
}
void
gm_mcp_package_set_version(GmMcpPackage *package, gdouble version) {
package->priv->version = version;
}
gdouble
gm_mcp_package_get_version(GmMcpPackage *package) {
return package->priv->version;
}
gchar const *
gm_mcp_package_get_name(GmMcpPackage *package) {
return GM_MCP_PACKAGE_GET_CLASS(package)->name;
}
GList const *
gm_mcp_package_get_depends(GmMcpPackage *package) {
return GM_MCP_PACKAGE_GET_CLASS(package)->depends;
}
GList const *
gm_mcp_package_get_overrides(GmMcpPackage *package) {
return GM_MCP_PACKAGE_GET_CLASS(package)->overrides;
}
gdouble
gm_mcp_package_get_min_version(GmMcpPackage *package) {
return GM_MCP_PACKAGE_GET_CLASS(package)->min_version;
}
gdouble
gm_mcp_package_get_max_version(GmMcpPackage *package) {
return GM_MCP_PACKAGE_GET_CLASS(package)->max_version;
}

89
src/mcp/gm-mcp-package.h Normal file
View File

@ -0,0 +1,89 @@
#ifndef __GM_MCP_PACKAGE_H__
#define __GM_MCP_PACKAGE_H__
#include <glib-object.h>
G_BEGIN_DECLS
/*
* Type checking and casting macros
*/
#define GM_TYPE_MCP_PACKAGE (gm_mcp_package_get_type())
#define GM_MCP_PACKAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GM_TYPE_MCP_PACKAGE, GmMcpPackage))
#define GM_MCP_PACKAGE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
GM_TYPE_MCP_PACKAGE, GmMcpPackage const))
#define GM_MCP_PACKAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
GM_TYPE_MCP_PACKAGE, GmMcpPackageClass))
#define GM_IS_MCP_PACKAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
GM_TYPE_MCP_PACKAGE))
#define GM_IS_MCP_PACKAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
GM_TYPE_MCP_PACKAGE))
#define GM_MCP_PACKAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
GM_TYPE_MCP_PACKAGE, GmMcpPackageClass))
#define GM_MCP_PACKAGE_SESSION(obj) (GM_MCP_SESSION( \
gm_mcp_package_get_session(GM_MCP_PACKAGE(obj))))
/* Private structure type */
typedef struct _GmMcpPackagePrivate GmMcpPackagePrivate;
/*
* Main object structure
*/
typedef struct _GmMcpPackage GmMcpPackage;
struct _GmMcpPackage {
GObject parent;
/*< private > */
GmMcpPackagePrivate *priv;
};
/*
* Class definition
*/
typedef struct _GmMcpPackageClass GmMcpPackageClass;
struct _GmMcpPackageClass {
GObjectClass parent_class;
gchar *name;
gdouble min_version;
gdouble max_version;
GList *depends;
GList *overrides;
void (* handle_simple)(GmMcpPackage *package, gchar *suffix, GList *fields);
gboolean (* handle_multi)(GmMcpPackage *package, gchar *data_tag,
gchar *key, gchar *value, GList *allValues);
/* Signals
void (* proto) (GmMcpPackage *obj); */
};
/* Public */
GType gm_mcp_package_get_type(void) G_GNUC_CONST;
GmMcpPackage *gm_mcp_package_new();
void gm_mcp_package_set_session(GmMcpPackage *package, GObject *session);
void gm_mcp_package_handle_simple(GmMcpPackage *package, gchar *suffix,
GList *fields);
gboolean gm_mcp_package_can_handle_simple(GmMcpPackage *package);
gboolean gm_mcp_package_handle_multi(GmMcpPackage *package, gchar *data_tag,
gchar *key, gchar *value, GList *allValues);
gboolean gm_mcp_package_can_handle_multi(GmMcpPackage *package);
void gm_mcp_package_set_version(GmMcpPackage *package, gdouble version);
gdouble gm_mcp_package_get_version(GmMcpPackage *package);
GObject *gm_mcp_package_get_session(GmMcpPackage *package);
/* Class getters */
gchar const *gm_mcp_package_get_name(GmMcpPackage *package);
GList const *gm_mcp_package_get_depends(GmMcpPackage *package);
GList const *gm_mcp_package_get_overrides(GmMcpPackage *package);
gdouble gm_mcp_package_get_min_version(GmMcpPackage *package);
gdouble gm_mcp_package_get_max_version(GmMcpPackage *package);
G_END_DECLS
#endif /* __GM_MCP_PACKAGE_H__ */

493
src/mcp/gm-mcp-session.c Normal file
View File

@ -0,0 +1,493 @@
#include <glib-object.h>
#include <string.h>
#include "gm-mcp-session.h"
#include "gm-mcp-classes.h"
#include "gm-mcp.h"
#include "../gm-world.h"
#include "../gm-support.h"
#include "../debug.h"
#include "../gm-options.h"
#define GM_MCP_SESSION_GET_PRIVATE(object)( \
G_TYPE_INSTANCE_GET_PRIVATE((object), \
GM_TYPE_MCP_SESSION, GmMcpSessionPrivate))
struct _GmMcpSessionPrivate {
GmWorld *world;
gchar *authkey;
gdouble version;
GList *packages;
GList *multiline;
};
/* Signals
enum {
PROTO
NUM_SIGNALS
};
static guint gm_mcp_session_signals[NUM_SIGNALS] = {0};*/
G_DEFINE_TYPE(GmMcpSession, gm_mcp_session, G_TYPE_OBJECT)
static void
gm_mcp_session_finalize(GObject *object) {
//GmMcpSession *obj = GM_MCP_SESSION(object);
G_OBJECT_CLASS(gm_mcp_session_parent_class)->finalize(object);
}
static void
gm_mcp_session_class_init(GmMcpSessionClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = gm_mcp_session_finalize;
klass->available_packages = gm_mcp_classes_initialize();
/*gm_mcp_session_signals[PROTO] =
g_signal_new("proto",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GmMcpSessionClass, proto),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);*/
g_type_class_add_private(object_class, sizeof(GmMcpSessionPrivate));
}
static void
gm_mcp_session_init(GmMcpSession *obj) {
obj->priv = GM_MCP_SESSION_GET_PRIVATE(obj);
obj->priv->packages = NULL;
obj->priv->version = -1;
obj->priv->authkey = NULL;
obj->priv->multiline = NULL;
}
void
gm_mcp_session_handle_open(GmMcpSession *session, gchar *line) {
GList *fields = gm_mcp_process_key_values(line);
GmMcpPackage *p;
GmMcpPackageClass *pklass;
gchar const *min_version = gm_mcp_find_value(fields, "version");
gchar const *max_version = gm_mcp_find_value(fields, "to");
gchar *minc, *maxc;
double min_v, max_v, version;
if (!(min_version && max_version)) {
debug_msg(2, "GmMcpSession.HandleOpen: invalid opening, minVersion OR "
"maxVersion not found!");
return;
}
minc = gm_fix_decimal_point(g_strdup(min_version), strlen(min_version));
maxc = gm_fix_decimal_point(g_strdup(max_version), strlen(max_version));
min_v = g_ascii_strtod(minc, NULL);
max_v = g_ascii_strtod(maxc, NULL);
g_free(minc);
g_free(maxc);
version = gm_mcp_get_version(MCP_MIN_VERSION, MCP_MAX_VERSION,
min_v, max_v);
if (version > 0.0) {
session->priv->authkey = gm_mcp_generate_auth_key();
session->priv->version = version;
gm_mcp_session_send_simple(session, "mcp", "authentication-key",
session->priv->authkey, "version", "2.1", "to", "2.1", NULL);
pklass = gm_mcp_session_find_package_class("mcp-negotiate");
p = gm_mcp_session_create_package(session, pklass,
pklass->max_version);
} else {
debug_msg(2, "GmMcpSession.HandleOpen: mcp server version does not "
"match client version!");
}
}
void
gm_mcp_session_invoke_multiline_handle(GmMcpSession *session, gchar *data_tag,
gchar *key, gchar *value) {
GList *elem;
GmMcpPackage *p;
McpMultilineInfo *minfo;
gboolean handle_all = FALSE;
// Now find the data_tag and emit the handle_multiline
for (elem = session->priv->multiline; elem; elem = elem->next) {
minfo = (McpMultilineInfo *)(elem->data);
if (strcmp(minfo->data_tag, data_tag) == 0) {
p = minfo->package;
if (gm_mcp_package_can_handle_multi(p)) {
if (key) {
if (!gm_mcp_package_handle_multi(p, data_tag, key, value,
NULL)) {
// Not handled a single value, store it for later
minfo->data = g_list_append(minfo->data,
g_strdup(value));
}
} else {
handle_all = gm_mcp_package_handle_multi(p, data_tag, NULL,
NULL, minfo->data);
}
}
if (!key) {
// This is the end, remove the minfo
g_free(minfo->data_tag);
g_free(minfo->key);
// Lines should only be freed when allValues is not handled!
if (!handle_all) {
g_list_free_simple(minfo->data);
} else {
g_list_free(minfo->data);
}
session->priv->multiline = g_list_remove(
session->priv->multiline, minfo);
g_free(minfo);
}
return;
}
}
}
void
gm_mcp_session_handle_multiline(GmMcpSession *session, gchar *line) {
gchar *data_tag, *key, *value, *ptr = line, *key_start;
gm_string_skip_nonspace(&ptr);
if (*ptr == '\0') {
return;
}
data_tag = g_strndup(line, ptr - line);
gm_string_skip_space(&ptr);
key_start = ptr;
gm_string_skip_nonspace(&ptr);
if (*ptr) {
return;
}
key = g_strndup(key_start, (ptr - key_start) - 1);
value = g_strdup(ptr + 1);
gm_mcp_session_invoke_multiline_handle(session, data_tag, key, value);
g_free(data_tag);
g_free(key);
g_free(value);
}
void
gm_mcp_session_handle_multiline_end(GmMcpSession *session, gchar *line) {
gchar *ptr = line;
gchar *data_tag;
while (*ptr != '\0' && g_unichar_isspace(g_utf8_get_char(ptr))) {
ptr = g_utf8_next_char(ptr);
}
data_tag = g_strndup(line, ptr - line);
gm_mcp_session_invoke_multiline_handle(session, data_tag, NULL, NULL);
g_free(data_tag);
}
/* Public */
GmMcpSession *
gm_mcp_session_new(GObject *world) {
GmMcpSession *obj = GM_MCP_SESSION(g_object_new(GM_TYPE_MCP_SESSION, NULL));
obj->priv->world = GM_WORLD(world);
return obj;
}
GList const *
gm_mcp_session_get_packages(GmMcpSession *session) {
return session->priv->packages;
}
GmMcpPackageClass *
gm_mcp_session_package_class_for_each(GmPackageClassFunc func,
gpointer user_data) {
GmMcpSessionClass *klass = g_type_class_peek(GM_TYPE_MCP_SESSION);
GList *item;
GmMcpPackageClass *package_klass;
for (item = klass->available_packages; item; item = item->next) {
package_klass = GM_MCP_PACKAGE_CLASS(item->data);
if (func(package_klass, user_data)) {
return package_klass;
}
}
return NULL;
}
void
gm_mcp_session_send_multiline(GmMcpSession *session, gchar const *data_tag,
gchar const *key, GList const *lines) {
gchar *msg = g_strconcat("#$#* ", data_tag, " ", key, ": ", NULL);
gchar *msg_line = NULL;
while (lines) {
msg_line = g_strconcat(msg, (gchar *)(lines->data), NULL);
gm_world_sendln(session->priv->world, msg_line);
gm_world_log(session->priv->world, LOG_MCP_OUT, msg_line);
g_free(msg_line);
lines = lines->next;
}
g_free(msg);
msg_line = g_strconcat("#$#: ", data_tag, NULL);
gm_world_sendln(session->priv->world, msg_line);
gm_world_log(session->priv->world, LOG_MCP_OUT, msg_line);
g_free(msg_line);
}
void
gm_mcp_session_send_simple(GmMcpSession *session, gchar const *pname,
gchar const *first_key, ...) {
GString *msg = NULL;
va_list args;
gchar const *key, *value;
gchar *esvalue;
msg = g_string_new("#$#");
msg = g_string_append(msg, pname);
if (strcasecmp(pname, "mcp") != 0) {
msg = g_string_append(msg, " ");
msg = g_string_append(msg, session->priv->authkey);
}
msg = g_string_append(msg, " ");
if (first_key != NULL) {
va_start(args, first_key);
key = first_key;
while (key) {
value = va_arg(args, gchar *);
if (value) {
msg = g_string_append(msg, key);
msg = g_string_append(msg, ": ");
esvalue = gm_mcp_escape_if_needed(value);
msg = g_string_append(msg, esvalue);
g_free(esvalue);
msg = g_string_append(msg, " ");
key = va_arg(args, gchar *);
} else {
key = NULL;
}
}
va_end(args);
}
gm_world_sendln(session->priv->world, msg->str);
gm_world_log(session->priv->world, LOG_MCP_OUT, msg->str);
g_string_free(msg, TRUE);
}
GmMcpPackage *
gm_mcp_session_has_package_of_class(GmMcpSession *session,
GmMcpPackageClass *klass) {
GList *item;
GmMcpPackage *package;
GType klass_type = G_TYPE_FROM_CLASS(klass);
for (item = session->priv->packages; item; item = item->next) {
package = (GmMcpPackage *)(item->data);
if (G_TYPE_FROM_CLASS(GM_MCP_PACKAGE_GET_CLASS(package)) ==
klass_type) {
return package;
}
}
return NULL;
}
GmMcpPackage *
gm_mcp_session_find_package(GmMcpSession *session, gchar const *pname) {
GList *elem;
GmMcpPackage *package;
GmMcpPackageClass *package_klass;
for (elem = session->priv->packages; elem; elem = elem->next) {
package = (GmMcpPackage *) (elem->data);
package_klass = GM_MCP_PACKAGE_GET_CLASS(package);
if (strncasecmp(pname, package_klass->name,
strlen(package_klass->name)) == 0 && (strlen(pname) ==
strlen(package_klass->name) ||
pname[strlen(package_klass->name)] == '-')) {
return package;
}
}
return NULL;
}
GmMcpPackage *
gm_mcp_session_create_package(GmMcpSession *session, GmMcpPackageClass *klass,
gdouble version) {
GmMcpPackage *package;
if (!klass) {
return NULL;
}
if (!gm_mcp_session_has_package_of_class(session, klass)) {
package = g_object_new(G_TYPE_FROM_CLASS(G_OBJECT_CLASS(klass)), NULL);
gm_mcp_package_set_session(package, G_OBJECT(session));
gm_mcp_package_set_version(package, version);
session->priv->packages = g_list_append(session->priv->packages,
package);
return package;
} else {
debug_msg(2, "GmMcpSession.CreatePackage: package (%s) is already "
"registered for %s", klass->name,
gm_options_get(gm_world_options(session->priv->world), "name"));
return NULL;
}
}
gboolean
gm_mcp_session_find_package_class_real(GmMcpPackageClass *klass,
gpointer user_data) {
gchar *name = (gchar *)(user_data);
return strcmp(name, klass->name) == 0;
}
GmMcpPackageClass *
gm_mcp_session_find_package_class(gchar const *name) {
return gm_mcp_session_package_class_for_each(
&gm_mcp_session_find_package_class_real, (gpointer)(name));
}
void
gm_mcp_session_handle_oob(GmMcpSession *session, gchar *line) {
McpMessageInfo info;
GmMcpPackage *package;
McpMultilineInfo *minfo;
gchar *suffix;
gchar const *value, *full;
debug_msg(2, "GmMcpSession.HandleOob: %s", line);
info.fields = NULL;
info.authkey = NULL;
info.name = NULL;
if (strncmp(line, "mcp ", 4) == 0 && session->priv->version == -1) {
gm_mcp_session_handle_open(session, line + 3);
} else if (session->priv->version == -1) {
// No session, drop
debug_msg(2, "GmMcpSession.HandleOob: No session found for %s, "
"ignoring out of bound command!", gm_options_get(
gm_world_options(session->priv->world), "name"));
} else if (strncmp(line, "* ", 2) == 0) {
// Multiline
gm_mcp_session_handle_multiline(session, line + 2);
} else if (strncmp(line, ": ", 2) == 0) {
// Multiline end
gm_mcp_session_handle_multiline_end(session, line + 2);
} else {
if (gm_mcp_parse_line(line, &info)) {
// Line is valid mcp
if (strcmp(info.authkey, session->priv->authkey) == 0) {
// Valid authentication
if ((package = gm_mcp_session_find_package(session,
info.name))) {
// Find package
if ((value = gm_mcp_find_multiline_tag(info.fields))) {
// This is multiline start!
if (gm_mcp_find_value(info.fields,
"_data-tag")) {
// This package requests a multiline opening!
minfo = g_new(McpMultilineInfo, 1);
minfo->key = g_strdup(value);
minfo->data_tag = g_strdup(
gm_mcp_find_value(info.fields,
"_data-tag"));
minfo->data = NULL;
minfo->package = package;
session->priv->multiline = g_list_append(
session->priv->multiline, minfo);
debug_msg(2, "GmMcpSession.HandleOob: multiline "
"opening detected and stored "
"(data_tag = %s, key = %s)",
minfo->data_tag,
minfo->key);
} else {
debug_msg(2, "GmMcpSession.HandleOob: multiline "
"opening detected, but no _data-tag specified, "
"ignore message");
}
}
if (gm_mcp_package_can_handle_simple(package)) {
full = gm_mcp_package_get_name(package);
if (strlen(full) < strlen(info.name)) {
suffix = info.name + (strlen(full) + 1);
} else {
suffix = NULL;
}
gm_mcp_package_handle_simple(package, suffix,
info.fields);
}
} else {
debug_msg(2, "GmMcpSession.HandleOob: unsupported package "
"%s, ignore message", info.name);
}
} else {
debug_msg(2, "GmMcpSession.HandleOob: invalid authentication "
"key %s instead of %s, ignore message", info.authkey,
session->priv->authkey);
}
} else {
debug_msg(2, "GmMcpSession.HandleOob: invalid message "
"(could not parse), ignore message");
}
// Free the info
if (info.authkey) {
g_free(info.authkey);
}
if (info.name) {
g_free(info.name);
}
if (info.fields) {
gm_mcp_destroy_fields(info.fields);
}
}
}

87
src/mcp/gm-mcp-session.h Normal file
View File

@ -0,0 +1,87 @@
#ifndef __GM_MCP_SESSION_H__
#define __GM_MCP_SESSION_H__
#include <glib-object.h>
#include "gm-mcp-package.h"
G_BEGIN_DECLS
/*
* Type checking and casting macros
*/
#define GM_TYPE_MCP_SESSION (gm_mcp_session_get_type())
#define GM_MCP_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GM_TYPE_MCP_SESSION, GmMcpSession))
#define GM_MCP_SESSION_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
GM_TYPE_MCP_SESSION, GmMcpSession const))
#define GM_MCP_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
GM_TYPE_MCP_SESSION, GmMcpSessionClass))
#define GM_IS_MCP_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
GM_TYPE_MCP_SESSION))
#define GM_IS_MCP_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
GM_TYPE_MCP_SESSION))
#define GM_MCP_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
GM_TYPE_MCP_SESSION, GmMcpSessionClass))
typedef struct _McpMultilineInfo {
gchar *key;
gchar *data_tag;
GList *data;
GmMcpPackage *package;
} McpMultilineInfo;
typedef gboolean (* GmPackageClassFunc) (GmMcpPackageClass *klass,
gpointer user_data);
/* Private structure type */
typedef struct _GmMcpSessionPrivate GmMcpSessionPrivate;
/*
* Main object structure
*/
typedef struct _GmMcpSession GmMcpSession;
struct _GmMcpSession {
GObject parent;
/*< private > */
GmMcpSessionPrivate *priv;
};
/*
* Class definition
*/
typedef struct _GmMcpSessionClass GmMcpSessionClass;
struct _GmMcpSessionClass {
GObjectClass parent_class;
GList *available_packages;
/* Signals
void (* proto) (GmMcpSession *obj); */
};
GType gm_mcp_session_get_type(void) G_GNUC_CONST;
GmMcpSession *gm_mcp_session_new(GObject *world);
GList const *gm_mcp_session_get_packages(GmMcpSession *session);
void gm_mcp_session_handle_oob(GmMcpSession *session, gchar *line);
GmMcpPackage *gm_mcp_session_has_package_of_class(GmMcpSession *session,
GmMcpPackageClass *klass);
GmMcpPackageClass *gm_mcp_session_find_package_class(gchar const *name);
GmMcpPackage *gm_mcp_session_find_package(GmMcpSession *session,
gchar const *pname);
GmMcpPackageClass *gm_mcp_session_package_class_for_each(
GmPackageClassFunc func, gpointer user_data);
GmMcpPackage *gm_mcp_session_create_package(GmMcpSession *session,
GmMcpPackageClass *klass, gdouble version);
void gm_mcp_session_send_simple(GmMcpSession *session, gchar const *pname,
gchar const *first_key, ...);
void gm_mcp_session_send_multiline(GmMcpSession *session, gchar const *data_tag,
gchar const *key, GList const *lines);
G_END_DECLS
#endif /* __GM_MCP_SESSION_H__ */

266
src/mcp/gm-mcp.c Normal file
View File

@ -0,0 +1,266 @@
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "gm-mcp.h"
#include "../gm-support.h"
#define MCP_MIN_VERSION 2.1
#define MCP_MAX_VERSION 2.1
gdouble
gm_mcp_get_version(gdouble client_min, gdouble client_max, gdouble server_min,
gdouble server_max) {
if (client_max >= server_min && server_max >= client_min) {
if (client_max < server_max) {
return server_max;
} else {
return client_max;
}
} else {
return 0.0;
}
}
gchar const *
gm_mcp_find_value(GList const *fields, gchar const *key) {
GmKeyValuePair *tmp;
while (fields) {
tmp = (GmKeyValuePair *)(fields->data);
if (strcasecmp(key, tmp->key) == 0) {
return tmp->value;
}
fields = fields->next;
}
return NULL;
}
gchar *
gm_mcp_escape_if_needed(gchar const *line) {
GString *new_line;
gchar const *ptr = line;
gchar *result;
if (*line == '\0') {
return g_strdup("\"\"");
}
if (g_utf8_strchr(line, -1, ' ') || g_utf8_strchr(line, -1, '"') ||
g_utf8_strchr(line, -1, '\\')) {
new_line = g_string_new("\"");
while (*ptr != '\0') {
if (*ptr == '"' || *ptr == '\\') {
new_line = g_string_append_c(new_line, '\\');
}
new_line = g_string_append_c(new_line, *ptr);
++ptr;
}
new_line = g_string_append_c(new_line, '"');
result = new_line->str;
g_string_free(new_line, FALSE);
return result;
} else {
return g_strdup(line);
}
}
gchar *
gm_mcp_un_escape(gchar *line) {
gchar *ptri = line, *ptrj = line;
gboolean shifted = FALSE;
while (*ptri != '\0') {
if (*ptri == '\\') {
shifted = TRUE;
++ptri;
}
if (shifted) {
*ptrj = *ptri;
}
++ptrj;
++ptri;
}
*ptrj = '\0';
return line;
}
gchar *
gm_mcp_process_keyval(GList **info, gchar *line) {
gchar *keystart;
gchar *valuestart;
int keylen, valuelen;
GmKeyValuePair *newKeyValue;
if (*line != ' ' || line[1] == '\0' || line[1] == ' ') {
return NULL;
}
keystart = line + 1;
gm_string_skip_till(&line, ": ");
if (*line != ':') {
return NULL;
}
keylen = line - keystart - 1;
line = g_utf8_next_char(line);
if (line[1] == '\0' || *line != ' ') {
return NULL;
}
line = g_utf8_next_char(line);
if (*line == ' ') {
return NULL;
}
valuestart = line;
if (*line == '"') {
++valuestart;
++line;
while (*line != '\0' && *line != '"') {
if (*line == '\\') {
++line;
}
++line;
}
valuelen = line - valuestart;
if (*line != '"') {
--valuelen;
} else {
++line;
}
} else {
gm_string_skip_nonspace(&line);
valuelen = line - valuestart;
}
newKeyValue = g_new(GmKeyValuePair, 1);
newKeyValue->key = g_strndup(keystart, keylen);
newKeyValue->value = gm_mcp_un_escape(g_strndup(valuestart, valuelen));
*info = g_list_append(*info, newKeyValue);
return line;
}
GList *
gm_mcp_process_key_values(gchar *line) {
GList *result = NULL;
while (line && *line != '\0') {
line = gm_mcp_process_keyval(&result, line);
}
return result;
}
gboolean
gm_mcp_parse_line(gchar *line, McpMessageInfo *info) {
gchar *p = g_utf8_strchr(line, -1, ' ');
if (!p || p == line) {
return FALSE;
}
info->name = g_strndup(line, (p - line));
line = p + 1;
// Now there should be a authentication key!
p = g_utf8_strchr(line, -1, ' ');
if (!p) {
p = line + strlen(line);
}
info->authkey = g_strndup(line, (p - line));
// Now process the keyvals
info->fields = gm_mcp_process_key_values(p);
return TRUE;
}
gchar *
gm_mcp_generate_key(gint len) {
gchar *s = g_malloc(len + 1);
gchar ref[] =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
gint n = strlen(ref);
gint i;
srand((int) time(NULL));
for (i = 0; i < len; i++) {
s[i] = ref[rand() % n];
}
s[i] = 0;
return s;
}
gchar *
gm_mcp_generate_data_tag() {
return gm_mcp_generate_key(10);
}
gchar *
gm_mcp_generate_auth_key() {
return gm_mcp_generate_key(6);
}
gchar const *
gm_mcp_find_multiline_tag(GList const *fields) {
GmKeyValuePair *data;
gunichar last;
while (fields) {
data = (GmKeyValuePair *)(fields->data);
last = g_utf8_get_char(g_utf8_prev_char(data->key + strlen(data->key)));
if (last == '*') {
return data->key;
}
fields = fields->next;
}
return NULL;
}
void
gm_mcp_destroy_fields(GList *fields) {
GmKeyValuePair *tmp;
GList *elem = fields;
while (elem) {
tmp = (GmKeyValuePair *) (elem->data);
g_free(tmp->key);
g_free(tmp->value);
g_free(elem->data);
elem->data = NULL;
elem = elem->next;
}
g_list_free(fields);
}

28
src/mcp/gm-mcp.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef __GM_MCP_H__
#define __GM_MCP_H__
#include <glib.h>
#include "gm-mcp.h"
#define MCP_MIN_VERSION 2.1
#define MCP_MAX_VERSION 2.1
typedef struct _McpMessageInfo {
gchar *name;
gchar *authkey;
GList *fields;
} McpMessageInfo;
gdouble gm_mcp_get_version(gdouble client_min, gdouble client_max,
gdouble server_min, gdouble server_max);
gchar const *gm_mcp_find_value(GList const *fields, gchar const *key);
gchar *gm_mcp_escape_if_needed(gchar const *line);
gchar *gm_mcp_un_escape(gchar *line);
GList *gm_mcp_process_key_values(gchar *line);
gboolean gm_mcp_parse_line(gchar *line, McpMessageInfo *info);
gchar *gm_mcp_generate_data_tag();
gchar *gm_mcp_generate_auth_key();
gchar const *gm_mcp_find_multiline_tag(GList const *fields);
void gm_mcp_destroy_fields(GList *fields);
#endif /* __GM_MCP_H__ */

34
src/mcp/mcpinit.rb Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/ruby
begin
defs = File.readlines(ARGV[0])
defs.collect! {|elem| elem.chomp}
fout = File.open(ARGV[1] + '.c', 'w')
includes = ['<glib-object.h>']
content = "GList *\ngm_mcp_classes_initialize() {\n\tGList *result = NULL;\n\n"
defs.each do |line|
ucase = line.gsub(/[A-Z]+[a-z]+/) do |s|
s.upcase + '_'
end
ucase.chop!
mcase = ucase.downcase.gsub('_', '-')
includes << '"gm-mcp-' + mcase + '.h"'
content += "\tresult = g_list_append(result, \n\t\t\tg_type_class_ref(GM_TYPE_MCP_" + ucase + "));\n"
end
includes.each {|inc| fout.write('#include ' + inc + "\n")}
fout.write("\n" + content + "\treturn result;\n}\n")
fout.close
fout = File.open(ARGV[1] + '.h', 'w')
fout.write("GList *gm_mcp_classes_initialize();\n")
fout.close
rescue StandardError => boom
p boom
exit(1)
end

1
src/mcp/packages.defs Normal file
View File

@ -0,0 +1 @@
Negotiate