Initial import into SVN
This commit is contained in:
parent
b7a9743460
commit
31a3086b85
11 changed files with 1502 additions and 0 deletions
12
src/mcp/Makefile.include
Normal file
12
src/mcp/Makefile.include
Normal 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
295
src/mcp/gm-mcp-negotiate.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
57
src/mcp/gm-mcp-negotiate.h
Normal file
57
src/mcp/gm-mcp-negotiate.h
Normal 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
140
src/mcp/gm-mcp-package.c
Normal 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
89
src/mcp/gm-mcp-package.h
Normal 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
493
src/mcp/gm-mcp-session.c
Normal 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
87
src/mcp/gm-mcp-session.h
Normal 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
266
src/mcp/gm-mcp.c
Normal 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
28
src/mcp/gm-mcp.h
Normal 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
34
src/mcp/mcpinit.rb
Executable 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
1
src/mcp/packages.defs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Negotiate
|
Reference in a new issue