aboutsummaryrefslogblamecommitdiffstats
path: root/e-util/e-import.c
blob: ab3afc9f339d4ad2828bb17a90e987a0a59c4974 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
  



                                                                
  



                                                                    
  
                                                                   
                                                                             
  
  



                                                        


   



                    






                    
                    
 

                     
                       
 
            
 
                                                  

                          

                                  
                      

  



                      

           
                                 
 
                                            
 
                            
 
                                                      
                                                                  


           

                                          
 
                               
                                   
                                                                  
 

                                     
                        

                      

         


                                         


           
                                         
 
                                   
 

                                                 
 
                                                

 

                               
 





                                   
  
                                                              
  

                                 
                                                          
 
                               



                  

                              
 


                                                    
 
                                               

 

                   
                       



                                                                 
                                          
  
                                                              
                                                               





                                                            





                                          
 
                                      
 


                                 
 
                                   

 



                                     

                       
                                           



                       
                       

                                 
  

                                                              
                                       
  


                                                             
           


                                           
 

                                                    
 
                                                   


   

























                                                              
                     
                       
                                                    
  


                                                              


                                         
 

                                                         

 




                                       
 

                                                                     



                          

                             
  
                                                              


                                                                 
  



                                                                    

                                              
 
                                 





                                                   
 

                                                          

                                                                                  
                 

                                          






                                                                            









                                                               






                                                           
  

    



                                                          
 
                               
 
                                         


                                  
 


                                                        

 




                                     
  


                                                                      
        


                                 


                         
                                            


                                                                     
 
                             
                       
                          
                       
                                   







                              
  



                                                                     

                                  


                             
                                                                        

 



                                              
 
                            
 
                                                                           

                                         



                 
                   
                                          
 
                                    
                                                                          
 





                                                                            



















                                                         
 











                                                       




                           



                                     
 
                                                                        

                                          
                                                                                     

 



                                      
 
                                                                        

                                          
                                                                              

 



                                  
 
                                                                        

                                          
                                                                   

 



                                  
 
                                                                        

                                          
                                                                   


           

                                       
 
                                                                
 



                                   


                                    

                                          


                                          
                                                                                

                   

                                               
 
                                                                   

                           

                                                           



                                      



                                                                  
 

                                                                             














                                                            
                                
                                                           



                    


                                 

                        
                            
 
                                             
 

                                                              

                          
                                                            


                              
                                                                    

                                                           
                                                                    
                                    




                                                                  










                                  
                                                  
 

                                            
 


                                                                 







                                              

                                                                       
 

                                                                             

 

                                      
 




                                      
                                         






                                                                    


                                                                    
 

                                                                         
 
/*
 * 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:
 *      Michael Zucchi <notzed@ximian.com>
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_IMPORT_H
#include <import.h>
#endif

#include <string.h>
#include <stdlib.h>

#include <gtk/gtk.h>

#include "e-import.h"

#include <glib/gi18n.h>

#define d(x)

typedef struct _EImportImporters EImportImporters;

struct _EImportImporters {
    EImportImporter *importer;
    EImportImporterFunc free;
    gpointer data;
};

G_DEFINE_TYPE (
    EImport,
    e_import,
    G_TYPE_OBJECT)

static void
import_finalize (GObject *object)
{
    EImport *import = E_IMPORT (object);

    g_free (import->id);

    /* Chain up to parent's finalize () method. */
    G_OBJECT_CLASS (e_import_parent_class)->finalize (object);
}

static void
import_target_free (EImport *import,
                    EImportTarget *target)
{
    switch (target->type) {
    case E_IMPORT_TARGET_URI: {
        EImportTargetURI *s = (EImportTargetURI *) target;

        g_free (s->uri_src);
        g_free (s->uri_dest);
        break; }
    default:
        break;
    }

    g_datalist_clear (&target->data);
    g_free (target);
    g_object_unref (import);
}

static void
e_import_class_init (EImportClass *class)
{
    GObjectClass *object_class;

    object_class = G_OBJECT_CLASS (class);
    object_class->finalize = import_finalize;

    class->target_free = import_target_free;
}

static void
e_import_init (EImport *import)
{
}

/**
 * e_import_construct:
 * @ep: The instance to initialise.
 * @id: The name of the instance.
 *
 * Used by implementing classes to initialise base parameters.
 *
 * Return value: @ep is returned.
 **/
EImport *e_import_construct (EImport *ep, const gchar *id)
{
    ep->id = g_strdup (id);

    return ep;
}

EImport *
e_import_new (const gchar *id)
{
    EImport *import;

    import = g_object_new (E_TYPE_IMPORT, NULL);

    return e_import_construct (import, id);
}

/**
 * e_import_import:
 * @import: an #EImport
 * @t: Target to import.
 * @im: Importer to use.
 * @status: Status callback, called with progress information.
 * @done: Complete callback, will always be called once complete.
 * @data: user data for callback functions
 *
 * Run the import function of the selected importer.  Once the
 * importer has finished, it MUST call the e_import_complete ()
 * function.  This allows importers to run in synchronous or
 * asynchronous mode.
 *
 * When complete, the @done callback will be called.
 **/
void
e_import_import (EImport *import,
                 EImportTarget *t,
                 EImportImporter *im,
                 EImportStatusFunc status,
                 EImportCompleteFunc done,
                 gpointer data)
{
    g_return_if_fail (im != NULL);

    import->status = status;
    import->done = done;
    import->done_data = data;

    im->import (import, t, im);
}

void
e_import_cancel (EImport *import,
                 EImportTarget *t,
                 EImportImporter *im)
{
    if (im->cancel)
        im->cancel (import, t, im);
}

/**
 * e_import_get_widget:
 * @import: an #EImport
 * @target: Target of interest
 * @im: Importer to get widget of
 *
 * Gets a widget that the importer uses to configure its
 * destination.  This widget should be packed into a container
 * widget.  It should not be shown_all.
 *
 * Return value: NULL if the importer doesn't support/require
 * a destination.
 **/
GtkWidget *
e_import_get_widget (EImport *import,
                     EImportTarget *target,
                     EImportImporter *im)
{
    g_return_val_if_fail (im != NULL, NULL);
    g_return_val_if_fail (target != NULL, NULL);

    return im->get_widget (import, target, im);
}

/**
 * e_import_get_preview_widget:
 * @import: an #EImport
 * @target: Target of interest
 * @im: Importer to get a preview widget of
 *
 * Gets a widget that the importer uses to preview data to be
 * imported.  This widget should be packed into a container
 * widget.  It should not be shown_all.
 *
 * Return value: NULL if the importer doesn't support preview.
 **/
GtkWidget *
e_import_get_preview_widget (EImport *import,
                     EImportTarget *target,
                     EImportImporter *im)
{
    g_return_val_if_fail (im != NULL, NULL);
    g_return_val_if_fail (target != NULL, NULL);

    if (!im->get_preview)
        return NULL;

    return im->get_preview (import, target, im);
}

/**
 * e_import_complete:
 * @import: an #EImport
 * @target: Target just completed (unused currently)
 *
 * Signify that an import is complete.  This must be called by
 * importer implementations when they are done.
 **/
void
e_import_complete (EImport *import,
                   EImportTarget *target)
{
    if (import->done)
        import->done (import, import->done_data);
}

void
e_import_status (EImport *import,
                 EImportTarget *target,
                 const gchar *what,
                 gint pc)
{
    if (import->status)
        import->status (import, what, pc, import->done_data);
}

/**
 * e_import_get_importers:
 * @emp: an #EImport
 * @target: an #EImportTarget
 *
 * Get a list of importers.  If @target is supplied, then only
 * importers which support the type and location specified by the
 * target are listed.  If @target is NULL, then all importers are
 * listed.
 *
 * Return value: A list of importers.  The list should be freed when
 * no longer needed.
 **/
GSList *
e_import_get_importers (EImport *emp,
                        EImportTarget *target)
{
    GSList *importers = NULL;
    GList *link;

    link = E_IMPORT_GET_CLASS (emp)->importers;

    while (link != NULL) {
        EImportImporters *ei = link->data;

        if (target == NULL
            || (ei->importer->type == target->type
            && ei->importer->supported (emp, target, ei->importer))) {
            importers = g_slist_append (importers, ei->importer);
        }

        link = g_list_next (link);
    }

    return importers;
}

/* ********************************************************************** */

static gint
importer_compare (EImportImporters *node_a,
                  EImportImporters *node_b)
{
    gint pri_a = node_a->importer->pri;
    gint pri_b = node_b->importer->pri;

    return (pri_a == pri_b) ? 0 : (pri_a < pri_b) ? -1 : 1;
}

/**
 * e_import_class_add_importer:
 * @ec: An initialised implementing instance of EImport.
 * @importer: Importer to add.
 * @freefunc: If supplied, called to free the importer node
 * when it is no longer needed.
 * @data: Data for the callback.
 *
 **/
void
e_import_class_add_importer (EImportClass *class,
                             EImportImporter *importer,
                             EImportImporterFunc freefunc,
                             gpointer data)
{
    EImportImporters *node;

    node = g_malloc (sizeof (*node));
    node->importer = importer;
    node->free = freefunc;
    node->data = data;

    class->importers = g_list_sort (
        g_list_prepend (class->importers, node),
        (GCompareFunc) importer_compare);
}

/**
 * e_import_target_new:
 * @ep: Parent EImport object.
 * @type: type, up to implementor
 * @size: Size of object to allocate.
 *
 * Allocate a new import target suitable for this class.  Implementing
 * classes will define the actual content of the target.
 **/
gpointer
e_import_target_new (EImport *ep,
                     gint type,
                     gsize size)
{
    EImportTarget *t;

    if (size < sizeof (EImportTarget)) {
        g_warning ("Size less than size of EImportTarget\n");
        size = sizeof (EImportTarget);
    }

    t = g_malloc0 (size);
    t->import = ep;
    g_object_ref (ep);
    t->type = type;
    g_datalist_init (&t->data);

    return t;
}

/**
 * e_import_target_free:
 * @ep: Parent EImport object.
 * @o: The target to fre.
 *
 * Free a target.  The implementing class can override this method to
 * free custom targets.
 **/
void
e_import_target_free (EImport *ep,
                      gpointer o)
{
    EImportTarget *t = o;

    ((EImportClass *) G_OBJECT_GET_CLASS (ep))->target_free (ep, t);
}

EImportTargetURI *
e_import_target_new_uri (EImport *import,
                         const gchar *uri_src,
                         const gchar *uri_dst)
{
    EImportTargetURI *t;

    t = e_import_target_new (import, E_IMPORT_TARGET_URI, sizeof (*t));
    t->uri_src = g_strdup (uri_src);
    t->uri_dest = g_strdup (uri_dst);

    return t;
}

EImportTargetHome *
e_import_target_new_home (EImport *import)
{
    return e_import_target_new (
        import, E_IMPORT_TARGET_HOME, sizeof (EImportTargetHome));
}

/* ********************************************************************** */

/* Import menu plugin handler */

/*
 * <e-plugin
 *   class="org.gnome.mail.plugin.import:1.0"
 *   id="org.gnome.mail.plugin.import.item:1.0"
 *   type="shlib"
 *   location="/opt/gnome2/lib/camel/1.0/libcamelimap.so"
 *   name="imap"
 *   description="IMAP4 and IMAP4v1 mail store">
 *   <hook class="org.gnome.mail.importMenu:1.0"
 *         handler="HandleImport">
 *   <menu id="any" target="select">
 *    <item
 *     type="item|toggle|radio|image|submenu|bar"
 *     active
 *     path="foo/bar"
 *     label="label"
 *     icon="foo"
 *     activate="ep_view_emacs"/>
 *   </menu>
 * </e-plugin>
 */

#define emph ((EImportHook *)eph)

static const EImportHookTargetMask eih_no_masks[] = {
    { NULL }
};

static const EImportHookTargetMap eih_targets[] = {
    { "uri", E_IMPORT_TARGET_URI, eih_no_masks },
    { "home", E_IMPORT_TARGET_HOME, eih_no_masks },
    { NULL }
};

G_DEFINE_TYPE (
    EImportHook,
    e_import_hook,
    E_TYPE_PLUGIN_HOOK)

static gboolean
eih_supported (EImport *ei,
               EImportTarget *target,
               EImportImporter *im)
{
    struct _EImportHookImporter *ihook = (EImportHookImporter *) im;
    EImportHook *hook = im->user_data;

    return e_plugin_invoke (hook->hook.plugin, ihook->supported, target) != NULL;
}

static GtkWidget *
eih_get_widget (EImport *ei,
                EImportTarget *target,
                EImportImporter *im)
{
    struct _EImportHookImporter *ihook = (EImportHookImporter *) im;
    EImportHook *hook = im->user_data;

    return e_plugin_invoke (hook->hook.plugin, ihook->get_widget, target);
}

static void
eih_import (EImport *ei,
            EImportTarget *target,
            EImportImporter *im)
{
    struct _EImportHookImporter *ihook = (EImportHookImporter *) im;
    EImportHook *hook = im->user_data;

    e_plugin_invoke (hook->hook.plugin, ihook->import, target);
}

static void
eih_cancel (EImport *ei,
            EImportTarget *target,
            EImportImporter *im)
{
    struct _EImportHookImporter *ihook = (EImportHookImporter *) im;
    EImportHook *hook = im->user_data;

    e_plugin_invoke (hook->hook.plugin, ihook->cancel, target);
}

static void
eih_free_importer (EImportImporter *im,
                   gpointer data)
{
    EImportHookImporter *ihook = (EImportHookImporter *) im;

    g_free (ihook->supported);
    g_free (ihook->get_widget);
    g_free (ihook->import);
    g_free (ihook);
}

static struct _EImportHookImporter *
emph_construct_importer (EPluginHook *eph,
                         xmlNodePtr root)
{
    struct _EImportHookImporter *item;
    EImportHookTargetMap *map;
    EImportHookClass *class = (EImportHookClass *) G_OBJECT_GET_CLASS (eph);
    gchar *tmp;

    d (printf ("  loading import item\n"));
    item = g_malloc0 (sizeof (*item));

    tmp = (gchar *)xmlGetProp (root, (const guchar *)"target");
    if (tmp == NULL)
        goto error;
    map = g_hash_table_lookup (class->target_map, tmp);
    xmlFree (tmp);
    if (map == NULL)
        goto error;

    item->importer.type = map->id;
    item->supported = e_plugin_xml_prop (root, "supported");
    item->get_widget = e_plugin_xml_prop (root, "get-widget");
    item->import = e_plugin_xml_prop (root, "import");
    item->cancel = e_plugin_xml_prop (root, "cancel");

    item->importer.name = e_plugin_xml_prop (root, "name");
    item->importer.description = e_plugin_xml_prop (root, "description");

    item->importer.user_data = eph;

    if (item->import == NULL || item->supported == NULL)
        goto error;

    item->importer.supported = eih_supported;
    item->importer.import = eih_import;
    if (item->get_widget)
        item->importer.get_widget = eih_get_widget;
    if (item->cancel)
        item->importer.cancel = eih_cancel;

    return item;
error:
    d (printf ("error!\n"));
    eih_free_importer ((EImportImporter *) item, NULL);
    return NULL;
}

static gint
emph_construct (EPluginHook *eph,
                EPlugin *ep,
                xmlNodePtr root)
{
    xmlNodePtr node;
    EImportClass *class;

    d (printf ("loading import hook\n"));

    if (E_PLUGIN_HOOK_CLASS (e_import_hook_parent_class)->
        construct (eph, ep, root) == -1)
        return -1;

    class = E_IMPORT_HOOK_GET_CLASS (eph)->import_class;

    node = root->children;
    while (node) {
        if (strcmp ((gchar *)node->name, "importer") == 0) {
            struct _EImportHookImporter *ihook;

            ihook = emph_construct_importer (eph, node);
            if (ihook) {
                e_import_class_add_importer (
                    class, &ihook->importer,
                    eih_free_importer, eph);
                emph->importers = g_slist_append (
                    emph->importers, ihook);
            }
        }
        node = node->next;
    }

    eph->plugin = ep;

    return 0;
}

static void
e_import_hook_class_init (EImportHookClass *class)
{
    EPluginHookClass *plugin_hook_class;
    gint ii;

    plugin_hook_class = E_PLUGIN_HOOK_CLASS (class);
    plugin_hook_class->id = "org.gnome.evolution.import:1.0";
    plugin_hook_class->construct = emph_construct;

    /** @HookClass: Evolution Importers
     * @Id: org.gnome.evolution.import:1.0
     * @Target: EImportTarget
     *
     * A hook for data importers.
     **/

    class->target_map = g_hash_table_new (g_str_hash, g_str_equal);
    class->import_class = g_type_class_ref (E_TYPE_IMPORT);

    for (ii = 0; eih_targets[ii].type; ii++)
        e_import_hook_class_add_target_map (class, &eih_targets[ii]);
}

static void
e_import_hook_init (EImportHook *hook)
{
}

/**
 * e_import_hook_class_add_target_map:
 *
 * @class: The dervied EimportHook class.
 * @map: A map used to describe a single EImportTarget type for this
 * class.
 *
 * Add a targe tmap to a concrete derived class of EImport.  The
 * target map enumates the target types available for the implenting
 * class.
 **/
void
e_import_hook_class_add_target_map (EImportHookClass *class,
                                    const EImportHookTargetMap *map)
{
    g_hash_table_insert (
        class->target_map, (gpointer) map->type, (gpointer) map);
}