Initial import into SVN
This commit is contained in:
parent
b7a9743460
commit
31a3086b85
|
@ -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 ) > $@
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
Negotiate
|
Reference in New Issue