aboutsummaryrefslogblamecommitdiffstats
path: root/plugins/mono/mono-plugin.c
blob: 5c5182e378fab16cabcc01eb07e660ccc5e5b4d0 (plain) (tree)



















                                                                               

                      









                                        
                














                                                                            

                                                             






























                                                                                            

                                                                                          
























                                                                                                                           
                        
                                                              
                                          

                                                                                           








                                                                                                              
                         


                                                                                 






























































                                                                                                      





















                                                         



                                                   


      
                                                     

                              
 







                                                                                                          

                                                                                         


                                                    
 

                                      
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with the program; if not, see <http://www.gnu.org/licenses/>  
 *
 *
 * Authors:
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

#include <sys/types.h>
#include <string.h>

#include "mono-plugin.h"

#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/object.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/assembly.h>
#include <mono/jit/jit.h>

#define d(x) (x)

static MonoDomain *domain;

/* ********************************************************************** */
static void *epm_parent_class;

typedef struct _EPluginMonoPrivate {
    MonoAssembly *assembly;
    MonoClass *klass;
    MonoObject *plugin;
    GHashTable *methods;
} EPluginMonoPrivate;

#define epm ((EPluginMono *)ep)

void * load_plugin_type_register_function (void *a, void *b);

static char *
get_xml_prop(xmlNodePtr node, const char *id)
{
    char *p = xmlGetProp(node, id);
    char *out = NULL;

    if (p) {
        out = g_strdup(p);
        xmlFree(p);
    }

    return out;
}

/*
  Two approaches:
   You can have a Evolution.Plugin implementation which has every callback as methods on it.
   Or you can just use static methods for everything.

   All methods take a single (structured) argument.
*/

static void *
epm_invoke(EPlugin *ep, const char *name, void *data)
{
    EPluginMonoPrivate *p = epm->priv;
    MonoMethodDesc *d;
    MonoMethod *m;
    MonoObject *x = NULL, *res;
    void **params;

    g_print ("\n\a epm_invoke in mono-plugin.c in mono plugin loader is called \n\a");

    /* we need to do this every time since we may be called from any thread for some uses */
    mono_thread_attach(domain);

    if (p->assembly == NULL) {
        p->assembly = mono_domain_assembly_open(domain, epm->location);
        if (p->assembly == NULL) {
            g_warning("can't load assembly '%s'", epm->location);
            return NULL;
        }

        if (epm->handler == NULL
            || (p->klass = mono_class_from_name(mono_assembly_get_image(p->assembly), "", epm->handler)) == NULL) {
            d(printf("Using static callbacks only"));
        } else {
            p->plugin = mono_object_new(domain, p->klass);
            /* could conceivably init with some context too */
            mono_runtime_object_init(p->plugin);
        }
    }

    m = g_hash_table_lookup(p->methods, name);
    if (m == NULL) {
        if (p->klass) {
            d(printf("looking up method '%s' in class\n", name));
            /* class method */
            
            d = mono_method_desc_new(name, FALSE);
            /*if (d == NULL) {
                g_warning("Can't create method descriptor for '%s'", name);
                return NULL;
            }*/
            
            gpointer iter = NULL;
            MonoMethod* mono_method;

            d(printf ("\n\a About to get methods in klass\n\a"));
                   
            while ((mono_method = mono_class_get_methods (p->klass, &iter))) {
                g_print ("\n\a Method name is : <%s>\n\a", mono_method_get_name(mono_method));
            }
            d(printf ("\n\a Got methods in klass \n\a"));
//mono_class_get_method_from_name
            m = mono_class_get_method_from_name (p->klass, name, -1);
            if (m == NULL) {
                g_warning("Can't find method callback '%s'", name);
                return NULL;
            }
        } else {
            d(printf("looking up static method '%s'\n", name));
            /* static method */
            d = mono_method_desc_new(name, FALSE);
            if (d == NULL) {
                g_warning("Can't create method descriptor for '%s'", name);
                return NULL;
            }

            m = mono_method_desc_search_in_image(d, mono_assembly_get_image(p->assembly));
            if (m == NULL) {
                g_warning("Can't find method callback '%s'", name);
                return NULL;
            }
        }

        g_hash_table_insert(p->methods, g_strdup(name), m);
    }

    params = g_malloc0(sizeof(*params)*1);
    params[0] = &data;
    res = mono_runtime_invoke(m, p->plugin, params, &x);
    /* do i need to free params?? */

    if (x)
        mono_print_unhandled_exception(x);

    if (res) {
        void **p = mono_object_unbox(res);
        d(printf("mono method returned '%p' %ld\n", *p, (long int)*p));
        return *p;
    } else
        return NULL;
}

static int
epm_construct(EPlugin *ep, xmlNodePtr root)
{
    if (((EPluginClass *)epm_parent_class)->construct(ep, root) == -1)
        return -1;

    epm->location = get_xml_prop(root, "location");
    epm->handler = get_xml_prop(root, "handler");

    if (epm->location == NULL)
        return -1;

    return 0;
}

static void
epm_finalise(GObject *o)
{
    EPlugin *ep = (EPlugin *)o;
    EPluginMonoPrivate *p = epm->priv;

    g_free(epm->location);
    g_free(epm->handler);

    g_hash_table_destroy(p->methods);

    g_free(epm->priv);

    ((GObjectClass *)epm_parent_class)->finalize(o);
}

static void
epm_class_init(EPluginClass *klass)
{
    ((GObjectClass *)klass)->finalize = epm_finalise;
    klass->construct = epm_construct;
    klass->invoke = epm_invoke;
    klass->type = "mono";
}

static void
epm_init(GObject *o)
{
    EPlugin *ep = (EPlugin *)o;

    epm->priv = g_malloc0(sizeof(*epm->priv));
    epm->priv->methods = g_hash_table_new_full(
        g_str_hash, g_str_equal,
        (GDestroyNotify) g_free,
        (GDestroyNotify) NULL);
}

void *
load_plugin_type_register_function (void *a, void *b)
{
    static GType type = 0;

    if (!type) {
        static const GTypeInfo info = {
            sizeof(EPluginMonoClass), NULL, NULL, (GClassInitFunc) epm_class_init, NULL, NULL,
            sizeof(EPluginMono), 0, (GInstanceInitFunc) epm_init,
        };

        epm_parent_class = g_type_class_ref(e_plugin_get_type());
        type = g_type_register_static(e_plugin_get_type(), "EPluginMono", &info, 0);
        e_plugin_register_type (type);
        d(printf("\nType EPluginMono registered from the mono-plugin-loader\n"));
        domain = mono_jit_init("Evolution");
        mono_thread_attach(domain);
    }

    return GUINT_TO_POINTER(type);
}