aboutsummaryrefslogblamecommitdiffstats
path: root/executive-summary/test-service/rdf-summary.c
blob: 48b4b8ece0f2afc14f16c12d283f35700de4c292 (plain) (tree)





















                                                                           
                                                           








                                                                             
                                                                                   
 




















                                       













































































                                                                                    
                               

                         
                       





                                  
                                   
















































                                                                                 
 







                                                                               



                                                                               
      

                                                









                                                                                  





















































                                                                                                                     





                                                  






                                 
                              
 
                                       












                                        
                                        


                                                             



                                                                             

                                                                  













                                                                              

                                                                                            
























                                                        

                                                               
                                   

                                        



                     






































































































































                                                                                                    

                           
                            
                                                                       

                                                                   











                                                                              





                                                                                         
















                                                                                 


                                                                                        






                                                                        
                        
                                                  

                         





                                           
                                                            
 

                                                                                        































                                                                                
 

                                                              
 
                 

        
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* RDF viewer Evolution Executive Summary Component.
 * Bonoboised by Iain Holmes  <iain@helixcode.com>
 * Copyright (C) 2000 Helix Code, Inc.
 *
 * Based on code from Portaloo
 * Channel retrieval tool
 *
 * (C) 1998 Alan Cox.
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <glib.h>
#include <gnome.h>
#include <bonobo.h>
#include <gnome-xml/parser.h>

#include <evolution-services/executive-summary-component.h>
#include <evolution-services/executive-summary-html-view.h>
#include <liboaf/liboaf.h>
#include <libgnomevfs/gnome-vfs.h>

int xmlSubstituteEntitiesDefaultValue = 1;  /* DV thinks of everything */

static int wipe_trackers = FALSE;
static int running_views = 0;

static BonoboGenericFactory *factory = NULL;
#define RDF_SUMMARY_ID "OAFIID:GNOME_Evolution_Summary_rdf_SummaryComponentFactory"

enum {
    PROPERTY_TITLE,
    PROPERTY_ICON
};

struct _RdfSummary {
    BonoboObject *component;
    BonoboObject *view;
    BonoboObject *bag;
    BonoboObject *property_control;

    GtkWidget *rdf;
    GtkWidget *g_limit;

    char *title;
    char *icon;
    char *location;
    int limit;
};
typedef struct _RdfSummary RdfSummary;

/************ RDF Parser *******************/

static char *
layer_find (xmlNodePtr node, 
        char *match, 
        char *fail)
{
    while (node!=NULL) {
#ifdef RDF_DEBUG
        xmlDebugDumpNode (stdout, node, 32);
        printf("%s.\n", node->name);
#endif
        if (strcasecmp (node->name, match)==0) {
            if (node->childs != NULL && node->childs->content != NULL) {
                return node->childs->content;
            } else {
                return fail;
            }
        }
        node = node->next;
    }
    return fail;
}

static char *
layer_find_url (xmlNodePtr node, 
        char *match, 
        char *fail)
{
    char *p = layer_find (node, match, fail);
    char *r = p;
    static char *wb = NULL;
    char *w;
    
    if (wb) {
        free (wb);
    }
    
    wb = w = malloc (3 * strlen (p));
    
    if (w == NULL) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    
    if (*r == ' ') r++; /* Fix UF bug */

    while (*r) {
        if (memcmp (r, "&amp;", 5) == 0) {
            *w++ = '&';
            r += 5;
            continue;
        }
        if (memcmp (r, "&lt;", 4) == 0) {
            *w++ = '<';
            r += 4;
            continue;
        }
        if (memcmp (r, "&gt;", 4) == 0) {
            *w++ = '>';
            r += 4;
            continue;
        }
        if (*r == '"' || *r == ' '){
            *w++ = '%';
            *w++ = "0123456789ABCDEF"[*r/16];
            *w++ = "0123456789ABCDEF"[*r&15];
            r++;
            continue;
        }
        *w++ = *r++;
    }
    *w = 0;
    return wb;
}

static void 
tree_walk (xmlNodePtr root,
       RdfSummary *summary,
       GString *html)
{
    BonoboArg *arg;
    xmlNodePtr walk;
    xmlNodePtr rewalk = root;
    xmlNodePtr channel = NULL;
    xmlNodePtr image = NULL;
    xmlNodePtr item[16];
    int items = 0;
    int limit = summary->limit;
    int i;
    char *t;
    char n[512];
    char *tmp;
    
    do {
        walk = rewalk;
        rewalk = NULL;
        
        while (walk!=NULL){
#ifdef RDF_DEBUG
            printf ("%p, %s\n", walk, walk->name);
#endif
            if (strcasecmp (walk->name, "rdf") == 0) {
                rewalk = walk->childs;
                walk = walk->next;
                continue;
            }
            if (strcasecmp (walk->name, "rss") == 0){
                rewalk = walk->childs;
                walk = walk->next;
                continue;
            }
            /* This is the channel top level */
#ifdef RDF_DEBUG
            printf ("Top level '%s'.\n", walk->name);
#endif
            if (strcasecmp (walk->name, "channel") == 0) {
                channel = walk;
                rewalk = channel->childs;
            }
            if (strcasecmp (walk->name, "image") == 0) {
                image = walk;
                g_print ("Image\n");
            }
            if (strcasecmp (walk->name, "item") == 0 && items < 16) {
                item[items++] = walk;
            }
            walk = walk->next;
        }
    }
    while (rewalk);
    
    if (channel == NULL) {
        fprintf(stderr, "No channel definition.\n");
        exit(1);
    }

    t = layer_find(channel->childs, "title", "No title");

    arg = bonobo_arg_new (BONOBO_ARG_STRING);
    BONOBO_ARG_SET_STRING (arg, t);
    bonobo_property_bag_set_value (BONOBO_PROPERTY_BAG (summary->bag),
                       "window_title", (const BonoboArg *) arg,
                       NULL);
    bonobo_arg_release (arg);

#if 0
    tmp = g_strdup_printf ("%s",
                   layer_find(channel->childs, "description", ""));
    g_string_append (html, tmp);
    g_free (tmp);
#endif

    if (image && !wipe_trackers) {      
        char *icon;

        icon = layer_find_url (image->childs, "url", "apple-red.png");
        arg = bonobo_arg_new (BONOBO_ARG_STRING);
        BONOBO_ARG_SET_STRING (arg, icon);
        bonobo_property_bag_set_value (BONOBO_PROPERTY_BAG (summary->bag),
                           "window_icon", 
                           (const BonoboArg *) arg, NULL);
        bonobo_arg_release (arg);
            
    }

    g_string_append (html, "<br clear=all><FONT size=\"-1\" face=\"helvetica\"><P><UL>\n");

    for (i = 0; i < items; i++) {
        char *p = layer_find (item[i]->childs, "title", "No information");
        
        if(i == limit)
            g_string_append (html, "--\n");
        if (wipe_trackers) {
            char *p = layer_find_url (item[i]->childs, "link", "");
            char *x = strchr (p, '?');
            unsigned char *r, *w;
            int n;
            if (x == NULL)
                continue;
            x++;
            r = x;
            w = x;
            while (*r) {
                if (*r == '+') {
                    *w++ = ' ';
                } else if (*r == '%') {
                    sscanf (r+1, "%02x", &n);
                    *w++ = n;
                    r += 2;
                } else {
                    *w++ = *r;
                }
                r++;
            }
            *w = 0;
            tmp = g_strdup_printf ("<LI><A href=\"%s\">\n", x+4);
            g_string_append (html, tmp);
            g_free (tmp);
        }
        else {
            tmp = g_strdup_printf ("<LI><A href=\"%s\">\n", layer_find_url(item[i]->childs, "link", ""));
            g_string_append (html, tmp);
            g_free (tmp);
        }

        tmp = g_strdup_printf ("%s\n</A>\n", p);
        g_string_append (html, tmp);
        g_free (tmp);
    }
    g_string_append (html, "</UL></FONT>\n");
}

/********* ExecutiveSummaryComponent section **************/
static void 
view_destroyed (GtkObject *object,
        gpointer data)
{
    RdfSummary *summary = (RdfSummary *) data;

    g_free (summary->title);
    g_free (summary->icon);
    g_free (summary);

    running_views--;
    if (running_views <= 0) {
        gtk_main_quit ();
    }
}

static int
download (RdfSummary *summary)
{
    ExecutiveSummaryHtmlView *view;
    GString *rdf;
    GString *html;
    char *xml;
    GnomeVFSHandle *handle = NULL;
    GnomeVFSResult result;
    xmlDocPtr doc;
    char *location;
    int len = 0;

    /* Download the RDF file here */
    /* Then parse it */
    /* The update it */

    g_print ("Starting download\n");
    view = EXECUTIVE_SUMMARY_HTML_VIEW (summary->view);
    result = gnome_vfs_open (&handle, summary->location, 
                 GNOME_VFS_OPEN_READ);
    if (result != GNOME_VFS_OK) {
        char *emsg;

        emsg = g_strdup_printf ("<b>Cannot open location:<br>%s</b>",
                    summary->location);
        executive_summary_html_view_set_html (view, emsg);
        g_free (emsg);
        return FALSE;
    }

    rdf = g_string_new ("");

    while (1) {
        char buffer[4096];
        GnomeVFSFileSize size;

        memset (buffer, 0x00, 4096);

        result = gnome_vfs_read (handle, buffer, 4096, &size);
        if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) {
            executive_summary_html_view_set_html (view,
                                  "<b>Error reading data.</b>");
            g_string_free (rdf, TRUE);
            return FALSE;
        }

        if (size == 0) {
            break;
        }

        rdf = g_string_append (rdf, buffer);
        len += size;
    }

    gnome_vfs_close (handle);
    xml = rdf->str;
    g_string_free (rdf, FALSE);

    doc = xmlParseMemory (xml, len);
    if (doc == NULL) {
        g_warning ("Unable to parse document.");
        return FALSE;
    }
    
    g_free (xml);
    html = g_string_new ("");

    tree_walk (doc->root, summary, html);
    executive_summary_html_view_set_html (view, html->str);
    g_string_free (html, TRUE);

    g_print ("Finished Download\n");
    return FALSE;
}

static void
get_prop (BonoboPropertyBag *bag,
      BonoboArg *arg,
      guint arg_id,
      gpointer user_data)
{
    RdfSummary *summary = (RdfSummary *) user_data;

    switch (arg_id) {
    case PROPERTY_TITLE:
        BONOBO_ARG_SET_STRING (arg, summary->title);
        break;

    case PROPERTY_ICON:
        BONOBO_ARG_SET_STRING (arg, summary->icon);
        break;
        
    default:
        break;
    }
}

static void
set_prop (BonoboPropertyBag *bag,
      const BonoboArg *arg,
      guint arg_id,
      gpointer user_data)
{
    RdfSummary *summary = (RdfSummary *) user_data;

    switch (arg_id) {
    case PROPERTY_TITLE:
        if (summary->title)
            g_free (summary->title);

        summary->title = g_strdup (BONOBO_ARG_GET_STRING (arg));
        bonobo_property_bag_notify_listeners (bag, "window_title",
                              arg, NULL);
        break;

    case PROPERTY_ICON:
        if (summary->icon)
            g_free (summary->icon);

        summary->icon = g_strdup (BONOBO_ARG_GET_STRING (arg));
        bonobo_property_bag_notify_listeners (bag, "window_icon",
                              arg, NULL);
        break;

    default:
        break;
    }
}

static void
entry_changed (GtkEntry *entry,
          RdfSummary *summary)
{
    bonobo_property_control_changed (BONOBO_PROPERTY_CONTROL (summary->property_control), NULL);
}

static BonoboControl *
property_control (BonoboPropertyControl *property_control,
          int page_num,
          gpointer user_data)
{
    BonoboControl *control;
    RdfSummary *summary = (RdfSummary *) user_data;
    GtkWidget *container, *label, *hbox;
    char *climit;

    container = gtk_vbox_new (FALSE, 2);
    gtk_container_set_border_width (GTK_CONTAINER (container), 2);
    hbox = gtk_hbox_new (FALSE, 2);

    label = gtk_label_new ("Location:");
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

    summary->rdf = gtk_entry_new ();
    if (summary->location)
        gtk_entry_set_text (GTK_ENTRY (summary->rdf), summary->location);

    gtk_signal_connect (GTK_OBJECT (summary->rdf), "changed",
                GTK_SIGNAL_FUNC (entry_changed), summary);

    gtk_box_pack_start (GTK_BOX (hbox), summary->rdf, TRUE, TRUE, 0);

    gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0);

    hbox = gtk_hbox_new (FALSE, 2);

    label = gtk_label_new ("Maximum number of entries:");
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

    summary->g_limit = gtk_entry_new ();
    climit = g_strdup_printf ("%d", summary->limit);
    gtk_entry_set_text (GTK_ENTRY (summary->g_limit), climit);
    g_free (climit);

    gtk_signal_connect (GTK_OBJECT (summary->g_limit), "changed",
                GTK_SIGNAL_FUNC (entry_changed), summary);

    gtk_box_pack_start (GTK_BOX (hbox), summary->g_limit, TRUE, TRUE, 0);

    gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0);
    gtk_widget_show_all (container);

    control = bonobo_control_new (container);
    return control;
}

static void
property_action (GtkObject *property_control,
         int page_num,
         Bonobo_PropertyControl_Action action,
         RdfSummary *summary)
{
    switch (action) {
    case Bonobo_PropertyControl_APPLY:
        g_free (summary->location);
        summary->location = g_strdup (gtk_entry_get_text (GTK_ENTRY (summary->rdf)));
        summary->limit = atoi (gtk_entry_get_text (GTK_ENTRY (summary->g_limit)));
        g_idle_add (download, summary);
        break;
 
    case Bonobo_PropertyControl_HELP:
        g_print ("HELP: Page %d!\n", page_num);
        break;

    default:
        break;
    }
}

static BonoboObject *
create_view (ExecutiveSummaryComponentFactory *_factory,
         void *closure)
{
    RdfSummary *summary;
    BonoboObject *component, *view, *bag, *property, *event_source;
    char *html = "<b>Loading RDF file. . .<br>Please wait</b>";
    
    summary = g_new (RdfSummary, 1);
    summary->icon = g_strdup ("apple-green.png");
    summary->title = g_strdup ("Downloading...");
    summary->location = g_strdup ("http://news.gnome.org/gnome-news/rdf");
    summary->limit = 10;

    component = executive_summary_component_new ();
    gtk_signal_connect (GTK_OBJECT (component), "destroy",
                GTK_SIGNAL_FUNC (view_destroyed), summary);

    summary->component = component;

    /* Share the event source between the ExecutiveSummaryHtmlView and the
       BonoboPropertyControl as we can only have one Bonobo::EventSource
       interface aggregated */
    event_source = bonobo_event_source_new ();

    view = executive_summary_html_view_new_full (BONOBO_EVENT_SOURCE (event_source));
    summary->view = view;
    executive_summary_html_view_set_html (EXECUTIVE_SUMMARY_HTML_VIEW (view),
                          html);
    bonobo_object_add_interface (component, view);

    bag = bonobo_property_bag_new (get_prop, set_prop, summary);
    summary->bag = bag;
    bonobo_property_bag_add (BONOBO_PROPERTY_BAG (bag),
                 "window_title", PROPERTY_TITLE,
                 BONOBO_ARG_STRING, NULL,
                 "The title of this component's window", 0);
    bonobo_property_bag_add (BONOBO_PROPERTY_BAG (bag),
                 "window_icon", PROPERTY_ICON,
                 BONOBO_ARG_STRING, NULL,
                 "The icon for this component's window", 0);
    bonobo_object_add_interface (component, bag);
                 
    property = bonobo_property_control_new_full (property_control, 1,
                             BONOBO_EVENT_SOURCE (event_source),
                             summary);
    summary->property_control = property;

    gtk_signal_connect (GTK_OBJECT (property), "action",
                GTK_SIGNAL_FUNC (property_action), summary);

    bonobo_object_add_interface (component, property);

    running_views++;
    gtk_timeout_add (5000, download, summary);

    return component;
}

static BonoboObject *
factory_fn (BonoboGenericFactory *_factory,
        void *closure)
{
    ExecutiveSummaryComponentFactory *component_factory;

    component_factory = executive_summary_component_factory_new (create_view, NULL);
    return BONOBO_OBJECT (component_factory);
}

static void
factory_init (void)
{
    if (factory != NULL) {
        return;
    }

    factory = bonobo_generic_factory_new (RDF_SUMMARY_ID, factory_fn, NULL);
    if (factory == NULL) {
        g_error ("Cannot initialize factory");
    }
}

int 
main (int argc, 
      char *argv[])
{
    CORBA_ORB orb;

    gnome_init_with_popt_table ("RDF-Summary", VERSION,
                    argc, argv, oaf_popt_options, 0, NULL);
    orb = oaf_init (argc, argv);
    gnome_vfs_init ();

    if (bonobo_init (orb, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL) == FALSE) {
        g_error ("Could not initialize Bonobo");
    }

    factory_init ();
    bonobo_main ();

    if (factory != NULL)
        bonobo_object_unref (BONOBO_OBJECT (factory));

    return 0;
}