/sysutils/utcount/

title='gsoc2013-evolution Git repository'/>
aboutsummaryrefslogblamecommitdiffstats
path: root/mail/em-format-html.c
blob: 4a4b51a10c23af3a1a7db82ccc2e3af548930b3c (plain) (tree)
































                                                                           
                 
                    







                                                                  
                                   
                                                                                                         
                                        
                                  
                                  



                                     
 
                       






                                             

                                          
                                       
                                  







                                     
                                     

                           
                        





                           
            


                                





                               
                             
                                                                                    



                                                              
                                                                                       









                                                                                                        

                                                                                                                     
                                                                                                                              
                                                                                  

                                                                                                                     
                                                                                                                   














                                                                                    






                                                  
                                                                                 

                                              
                                                
                                     







                                                                                               
                                    
                             

                                       

                                                                                                            
                              





















                                                              












                                                                              
           
                                               
 




                                                 












                                              
                                                                                 

















                                                                  

                                                                            
                                                                    
                                                  
        
















                                                           
                                                                                                         





                                                                                              

                                                          
                                                                      



                                                                                     
















                                                         
                                                       




                                                                                                
                                           


    
                                                           
 

                                        
                                                   








                                                                                         
                                                   



               
                                                                                        



                             
                       
 
                                                                      











                                                                 


                                                     





                                           

                                                                                                                                  


                                  

                                                      
                               
                    
                                                  

                                                                                                   






                                                                       
                    



































                                                                                                      

                                       






























































                                                                                                                     



                                                                              
                                                                                                                                           


                                                                                                                              





















                                                                                                                 
                                                                         











































                                                                                                                 

                                                                                                  















                                                                                          
                                                                                                                         

                                                                             


                                                                                                             

                                                            
                                 






                                                                                                  
                              


























                                                                                  
                                                                                           








                                                                            
                                                                                                   
                     
                                     
                         
                                                  

                                                           
                                                                              


                     
                                     
                            

                                                   

                                                     

  



                                                                                  


                                                         
                                                                                                      
 
                                                            
 




                                                                      

                                                                            

                                         
                                        



                                                                                                                  
                                                                                                       
                                                                                                                                    





                                                                                      
                                                                                                



                                                                                                                
                                  












                                                                                                                       

           




                                                                                                  
                             

                               
                      
                          

                                        

                                     

                                                                  
                                             

                                                                           













                                                                           

                                                                                                  

                                              








                                                                                                      



                                                                            
                                                                                             
                                                                                           
                                                                                       

                                                                   
 
                                                                   



                                                                                      
                                                  
                                             
         
 
                                                                      
                                                                                




                                                                                          
                                              




                                                                         
                                                                                                                    


                                                                                                                             
                                                                    
                                                                                                                            
                                                                           
                                                                     
                                                                      
                        
                                                                                            
                                                                         
                                                                           



























                                                                                                     
                                    
                                                                                                                  

                                                                                           
                                                                                                         
        
                                            
                                                    




                                                                           












                                                                  
                                                                           




                                                                                                 
                             
                                                     
                           
                         
 
                                    
                                                                                                  

                                                                                           
 
                                                                                              



                                                                      

                                                              




                                                                              
                                                                                       

                                      
                                                                                         


                                                          
                                                 




                                                                                                         
                                   
                                                                                                       
                                       

                                      











                                                                                                        
                                                                     










                                                                                



                                                                   



















                                                                                    

                                                               


                                  
                                                           









                                                                                                                 
                                                                  



























                                                                                                      







                                                                                                              
                                                                                                                  







                                                                                           
                                                                                                         


                                                           
                                                    


           










                                                                          
                        




                                                             
                                                                      






                                                                                                                    

                                                                                                   
                                                                                                                
                         




                                                                                       


                                                                             








                                                                                                           
                          
                                                
                                        









                                                              
                                                                 













                                                                                     
                                              











                                                                        

                                  

                                      



                                                            
                                                                              
                                                                                                                  
                                                                   



                                                                                                
                                                                      
                                                  
                                                   








                                                                                              

 
           



                                                                                          
                                                     







                                                                                             

                                                                                                      

                                                                                       





















                                                                
                                                   
                                                                        
                                                                                







                                                                      



                                                                          



















                                                                                           


                                  




















                                                                                                               

                                                                                                      



                                                               
                                                                
                                                                                                                       
                







                                                                                                                               
         
 
                                                      



                                                                




























                                                                                                            

                                                      








                                                                                                   
 

                                                                      
 

                                         








                                                                
                                         













                                                              


                                              



































                                                                                           
                                                                                                   

                                                




                                                                     

         



                                                                   
                                    
                
                               


                                                                                    


                                                                                                                

                                                                      
                                                                                         
                                                                   
                                                                                         

                                                  











                                                         
                                                                                                                             























                                                                            






                                         






















                                                                                                                      
                                                                                                                     


                               
        

                          
        

                             
        


                                               
                                                                                    
 
                                   






                                                                        

                                                                                                                              
                        

                                                           
                                                                                                                            
                            
                                                                                                                            






                                                      




                                                          
 




                                                                                                  
 

                                                                                                   


                                                                










                                                                                                                








                                                                      

                                                      
                                
                                                                              
                                                                                       
                                                                                                     






                                                                                               


                                                                               









                                                                                                   
                                                                           







                                                           

                    


                                                    






                                                                                    
                                                                                                                                   




                                                                                    
                                                                                                                                   




                                                                                     
                                                                                                                                    






                                           
                                     


                                                    
                                                                                                                            

                                                         
                                                                                                                            

                                                         
                                                                                                                             
                 
         


                   


           
                                                                                                                                              
 
                                                
                                      
                                
                            
                               
        

                                              
                            

                                            
                                                      






                                                    
                              
                          
                
                                                                                                                              














                                                                       
                                        
                                                                          







                                                                                                                                                 
                                                  
                                        
                                           

                                                                            
                                              
                                                                                  

                                               
                                                         
                                   
                                    
                                                                                 
                                               
                                                                           


                                         
                



                                    
                                                                                            

                                                                      






                                                                             
                                             



                                                                                                                             
                                                                                                    
                                
                                                                                                                                
                                                                                                
                         
                        


                                                                                
                                                            
                 
                
                                          




                                               










                                                                   
                                                                                                                     
                                          

                                                                   






                                                                          
                
                                                                                 
                                     
         
        
                                                               
        
                      
                           

 

                                                                             
 
                                         


                             
                                         
                                   


                                         
                                                                     
                                                           



                                                        
                                                              
                                                                                                                   




                                                                   

                                                          
                                                                                                               


                                              

                                         
                                 
                                   
 
                                                                  

                                                                                     
                                        



                                                                                                                 
                                                                                                                 

                                                                                                     



                                                                            
                                                            

                                                                                                           
                                                                               
                                                                 
                                                                                         
                                                                                                        
                                 

                                                      


                                    
        


                                                             






















                                                                                                            

                                                  
                                      
                                                       

                                                                                                              
                                                                                                                                            
 








                                                                                
 







                                                                                                                  

 
                                                                                                                    
 

                                      
                                                     
                                                 
                                                                                 
 

                                 
 
                                                     

                                                              
                               
                                                                     



                                                                                
        
                                                         
                                          
 
                                                     
                                                               
 
                                               
 

                                        






























                                                                                                                                    
                                                                                        


                                                                                   
                                                                                         









                                                                                                                           
                                                                                







                                                              
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 *  Authors: Michael Zucchi <notzed@ximian.com>
 *
 *  Copyright 2003 Ximian, Inc. (www.ximian.com)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
 *
 */

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

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>

#include <glib.h>
#include <gtk/gtk.h>
#ifdef G_OS_WIN32
/* Work around 'DATADIR' and 'interface' lossage in <windows.h> */
#define DATADIR crap_DATADIR
#include <windows.h>
#undef DATADIR
#undef interface
#endif

#include <libedataserver/e-iconv.h>
#include <libedataserver/e-data-server-util.h>  /* for e_utf8_strftime, what about e_time_format_time? */
#include <libedataserver/e-time-utils.h>
#include "e-util/e-icon-factory.h"
#include "e-util/e-util-private.h"

#include <gtkhtml/gtkhtml.h>
#include <gtkhtml/gtkhtml-embedded.h>
#include <gtkhtml/gtkhtml-stream.h>

#include <glib/gi18n.h>

#include <camel/camel-mime-message.h>
#include <camel/camel-stream.h>
#include <camel/camel-stream-filter.h>
#include <camel/camel-mime-filter.h>
#include <camel/camel-mime-filter-tohtml.h>
#include <camel/camel-mime-filter-enriched.h>
#include <camel/camel-mime-filter-basic.h>
#include <camel/camel-gpg-context.h>
#include <camel/camel-cipher-context.h>
#include <camel/camel-multipart.h>
#include <camel/camel-stream-mem.h>
#include <camel/camel-url.h>
#include <camel/camel-stream-fs.h>
#include <camel/camel-string-utils.h>
#include <camel/camel-http-stream.h>
#include <camel/camel-data-cache.h>
#include <camel/camel-file-utils.h>

#include <libedataserver/e-msgport.h>

#include "mail-component.h"
#include "mail-config.h"
#include "mail-mt.h"

#include "em-format-html.h"
#include "em-html-stream.h"
#include "em-utils.h"

#define d(x)

#define EFH_TABLE_OPEN "<table>"

struct _EMFormatHTMLCache {
    CamelMultipart *textmp;

    char partid[1];
};

struct _EMFormatHTMLPrivate {
    struct _CamelMimeMessage *last_part;    /* not reffed, DO NOT dereference */
    volatile int format_id;     /* format thread id */
    guint format_timeout_id;
    struct _format_msg *format_timeout_msg;

    /* Table that re-maps text parts into a mutlipart/mixed, EMFormatHTMLCache * */
    GHashTable *text_inline_parts;

    EDList pending_jobs;
    GMutex *lock;
};

static void efh_url_requested(GtkHTML *html, const char *url, GtkHTMLStream *handle, EMFormatHTML *efh);
static gboolean efh_object_requested(GtkHTML *html, GtkHTMLEmbedded *eb, EMFormatHTML *efh);
static void efh_gtkhtml_destroy(GtkHTML *html, EMFormatHTML *efh);

static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);

static void efh_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource);
static void efh_format_error(EMFormat *emf, CamelStream *stream, const char *txt);
static void efh_format_source(EMFormat *, CamelStream *, CamelMimePart *);
static void efh_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *);
static void efh_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid);
static gboolean efh_busy(EMFormat *);

static void efh_builtin_init(EMFormatHTMLClass *efhc);

static void efh_write_image(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri);

static EMFormatClass *efh_parent;
static CamelDataCache *emfh_http_cache;

#define EMFH_HTTP_CACHE_PATH "http"

static void
efh_init(GObject *o)
{
    EMFormatHTML *efh = (EMFormatHTML *)o;

    efh->priv = g_malloc0(sizeof(*efh->priv));

    e_dlist_init(&efh->pending_object_list);
    e_dlist_init(&efh->priv->pending_jobs);
    efh->priv->lock = g_mutex_new();
    efh->priv->format_id = -1;
    efh->priv->text_inline_parts = g_hash_table_new(g_str_hash, g_str_equal);

    efh->html = (GtkHTML *)gtk_html_new();
    gtk_html_set_blocking(efh->html, FALSE);
    g_object_ref_sink(efh->html);

    gtk_html_set_default_content_type(efh->html, "text/html; charset=utf-8");
    gtk_html_set_editable(efh->html, FALSE);
    
    g_signal_connect(efh->html, "destroy", G_CALLBACK(efh_gtkhtml_destroy), efh);
    g_signal_connect(efh->html, "url_requested", G_CALLBACK(efh_url_requested), efh);
    g_signal_connect(efh->html, "object_requested", G_CALLBACK(efh_object_requested), efh);

    efh->body_colour = 0xeeeeee;
    efh->text_colour = 0;
    efh->frame_colour = 0x3f3f3f;
    efh->content_colour = 0xffffff;
    efh->text_html_flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES
        | CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
    efh->show_icon = TRUE;
}

static void
efh_gtkhtml_destroy(GtkHTML *html, EMFormatHTML *efh)
{
    if (efh->priv->format_timeout_id != 0) {
        g_source_remove(efh->priv->format_timeout_id);
        efh->priv->format_timeout_id = 0;
        mail_msg_free(efh->priv->format_timeout_msg);
        efh->priv->format_timeout_msg = NULL;
    }

    /* This probably works ... */
    if (efh->priv->format_id != -1)
        mail_msg_cancel(efh->priv->format_id);

    if (efh->html) {
        g_object_unref(efh->html);
        efh->html = NULL;
    }
}

static struct _EMFormatHTMLCache *
efh_insert_cache(EMFormatHTML *efh, const char *partid)
{
    struct _EMFormatHTMLCache *efhc;

    efhc = g_malloc0(sizeof(*efh) + strlen(partid));
    strcpy(efhc->partid, partid);
    g_hash_table_insert(efh->priv->text_inline_parts, efhc->partid, efhc);

    return efhc;
}


static void
efh_free_cache(void *key, void *val, void *dat)
{
    struct _EMFormatHTMLCache *efhc = val;

    if (efhc->textmp)
        camel_object_unref(efhc->textmp);
    g_free(efhc);
}

static void
efh_finalise(GObject *o)
{
    EMFormatHTML *efh = (EMFormatHTML *)o;

    /* FIXME: check for leaked stuff */

    em_format_html_clear_pobject(efh);

    efh_gtkhtml_destroy(efh->html, efh);

    g_hash_table_foreach(efh->priv->text_inline_parts, efh_free_cache, NULL);
    g_hash_table_destroy(efh->priv->text_inline_parts);

    g_free(efh->priv);

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

static void
efh_base_init(EMFormatHTMLClass *efhklass)
{
    efh_builtin_init(efhklass);
}

static void
efh_class_init(GObjectClass *klass)
{
    ((EMFormatClass *)klass)->format_clone = efh_format_clone;
    ((EMFormatClass *)klass)->format_error = efh_format_error;
    ((EMFormatClass *)klass)->format_source = efh_format_source;
    ((EMFormatClass *)klass)->format_attachment = efh_format_attachment;
    ((EMFormatClass *)klass)->format_secure = efh_format_secure;
    ((EMFormatClass *)klass)->busy = efh_busy;
    
    klass->finalize = efh_finalise;
}

GType
em_format_html_get_type(void)
{
    static GType type = 0;

    if (type == 0) {
        static const GTypeInfo info = {
            sizeof(EMFormatHTMLClass),
            (GBaseInitFunc)efh_base_init, NULL,
            (GClassInitFunc)efh_class_init,
            NULL, NULL,
            sizeof(EMFormatHTML), 0,
            (GInstanceInitFunc)efh_init
        };
        const char *base_directory = mail_component_peek_base_directory (mail_component_peek ());
        char *path;

        efh_parent = g_type_class_ref(em_format_get_type());
        type = g_type_register_static(em_format_get_type(), "EMFormatHTML", &info, 0);

        /* cache expiry - 2 hour access, 1 day max */
        path = alloca(strlen(base_directory)+16);
        sprintf(path, "%s/cache", base_directory);
        emfh_http_cache = camel_data_cache_new(path, 0, NULL);
        if (emfh_http_cache) {
            camel_data_cache_set_expire_age(emfh_http_cache, 24*60*60);
            camel_data_cache_set_expire_access(emfh_http_cache, 2*60*60);
        }
    }

    return type;
}

EMFormatHTML *em_format_html_new(void)
{
    EMFormatHTML *efh;

    efh = g_object_new(em_format_html_get_type(), 0);

    return efh;
}

/* force loading of http images */
void em_format_html_load_http(EMFormatHTML *emfh)
{
    if (emfh->load_http == MAIL_CONFIG_HTTP_ALWAYS)
        return;

    /* This will remain set while we're still rendering the same message, then it wont be */
    emfh->load_http_now = TRUE;
    d(printf("redrawing with images forced on\n"));
    em_format_redraw((EMFormat *)emfh);
}

void
em_format_html_set_load_http(EMFormatHTML *emfh, int style)
{
    if (emfh->load_http != style) {
        emfh->load_http = style;
        em_format_redraw((EMFormat *)emfh);
    }
}

void
em_format_html_set_mark_citations(EMFormatHTML *emfh, int state, guint32 citation_colour)
{
    if (emfh->mark_citations ^ state || emfh->citation_colour != citation_colour) {
        emfh->mark_citations = state;
        emfh->citation_colour = citation_colour;
        em_format_redraw((EMFormat *)emfh);
    }
}

CamelMimePart *
em_format_html_file_part(EMFormatHTML *efh, const char *mime_type, const char *filename)
{
    CamelMimePart *part;
    CamelStream *stream;
    CamelDataWrapper *dw;
    char *basename;

    stream = camel_stream_fs_new_with_name(filename, O_RDONLY, 0);
    if (stream == NULL)
        return NULL;

    part = camel_mime_part_new();
    dw = camel_data_wrapper_new();
    camel_data_wrapper_construct_from_stream(dw, stream);
    camel_object_unref(stream);
    if (mime_type)
        camel_data_wrapper_set_mime_type(dw, mime_type);
    part = camel_mime_part_new();
    camel_medium_set_content_object((CamelMedium *)part, dw);
    camel_object_unref(dw);
    basename = g_path_get_basename (filename);
    camel_mime_part_set_filename(part, basename);
    g_free (basename);

    return part;
}

/* all this api is a pain in the bum ... */

EMFormatHTMLPObject *
em_format_html_add_pobject(EMFormatHTML *efh, size_t size, const char *classid, CamelMimePart *part, EMFormatHTMLPObjectFunc func)
{
    EMFormatHTMLPObject *pobj;

    g_assert(size >= sizeof(EMFormatHTMLPObject));

    pobj = g_malloc0(size);
    if (classid)
        pobj->classid = g_strdup(classid);
    else
        pobj->classid = g_strdup_printf("e-object:///%s", ((EMFormat *)efh)->part_id->str);

    pobj->format = efh;
    pobj->func = func;
    pobj->part = part;

    e_dlist_addtail(&efh->pending_object_list, (EDListNode *)pobj);

    return pobj;
}

EMFormatHTMLPObject *
em_format_html_find_pobject(EMFormatHTML *emf, const char *classid)
{
    EMFormatHTMLPObject *pw;

    pw = (EMFormatHTMLPObject *)emf->pending_object_list.head;
    while (pw->next) {
        if (!strcmp(pw->classid, classid))
            return pw;
        pw = pw->next;
    }

    return NULL;
}

EMFormatHTMLPObject *
em_format_html_find_pobject_func(EMFormatHTML *emf, CamelMimePart *part, EMFormatHTMLPObjectFunc func)
{
    EMFormatHTMLPObject *pw;

    pw = (EMFormatHTMLPObject *)emf->pending_object_list.head;
    while (pw->next) {
        if (pw->func == func && pw->part == part)
            return pw;
        pw = pw->next;
    }

    return NULL;
}

void
em_format_html_remove_pobject(EMFormatHTML *emf, EMFormatHTMLPObject *pobject)
{
    e_dlist_remove((EDListNode *)pobject);
    if (pobject->free)
        pobject->free(pobject);
    g_free(pobject->classid);
    g_free(pobject);
}

void
em_format_html_clear_pobject(EMFormatHTML *emf)
{
    d(printf("clearing pending objects\n"));
    while (!e_dlist_empty(&emf->pending_object_list))
        em_format_html_remove_pobject(emf, (EMFormatHTMLPObject *)emf->pending_object_list.head);
}

struct _EMFormatHTMLJob *
em_format_html_job_new(EMFormatHTML *emfh, void (*callback)(struct _EMFormatHTMLJob *job, int cancelled), void *data)
{
    struct _EMFormatHTMLJob *job = g_malloc0(sizeof(*job));

    job->format = emfh;
    job->puri_level = ((EMFormat *)emfh)->pending_uri_level;
    job->callback = callback;
    job->u.data = data;
    if (((EMFormat *)emfh)->base)
        job->base = camel_url_copy(((EMFormat *)emfh)->base);

    return job;
}

void
em_format_html_job_queue(EMFormatHTML *emfh, struct _EMFormatHTMLJob *job)
{
    g_mutex_lock(emfh->priv->lock);
    e_dlist_addtail(&emfh->priv->pending_jobs, (EDListNode *)job);
    g_mutex_unlock(emfh->priv->lock);
}

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

static void emfh_getpuri(struct _EMFormatHTMLJob *job, int cancelled)
{
    d(printf(" running getpuri task\n"));
    if (!cancelled)
        job->u.puri->func((EMFormat *)job->format, job->stream, job->u.puri);
}

static void emfh_gethttp(struct _EMFormatHTMLJob *job, int cancelled)
{
    CamelStream *cistream = NULL, *costream = NULL, *instream = NULL;
    CamelURL *url;
    ssize_t n, total = 0;
    char buffer[1500];

    if (cancelled
        || (url = camel_url_new(job->u.uri, NULL)) == NULL)
        goto badurl;

    d(printf(" running load uri task: %s\n", job->u.uri));

    if (emfh_http_cache)
        instream = cistream = camel_data_cache_get(emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);

    if (instream == NULL) {
        char *proxy;


        if (!(job->format->load_http_now
              || job->format->load_http == MAIL_CONFIG_HTTP_ALWAYS
              || (job->format->load_http == MAIL_CONFIG_HTTP_SOMETIMES
              && em_utils_in_addressbook((CamelInternetAddress *)camel_mime_message_get_from(job->format->format.message))))) {
            /* TODO: Ideally we would put the http requests into another queue and only send them out
               if the user selects 'load images', when they do.  The problem is how to maintain this
               state with multiple renderings, and how to adjust the thread dispatch/setup routine to handle it */
            camel_url_free(url);
            goto done;
        }

        instream = camel_http_stream_new(CAMEL_HTTP_METHOD_GET, ((EMFormat *)job->format)->session, url);
        proxy = em_utils_get_proxy_uri();
        camel_http_stream_set_proxy((CamelHttpStream *)instream, proxy);
        g_free(proxy);
        camel_operation_start(NULL, _("Retrieving `%s'"), job->u.uri);
    } else
        camel_operation_start_transient(NULL, _("Retrieving `%s'"), job->u.uri);

    camel_url_free(url);

    if (instream == NULL)
        goto done;

    if (emfh_http_cache != NULL && cistream == NULL)
        costream = camel_data_cache_add(emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);

    do {
        /* FIXME: progress reporting in percentage, can we get the length always?  do we care? */
        n = camel_stream_read(instream, buffer, sizeof (buffer));
        if (n > 0) {
            camel_operation_progress_count(NULL, total);
            total += n;
            d(printf("  read %d bytes\n", n));
            if (costream && camel_stream_write(costream, buffer, n) == -1) {
                camel_data_cache_remove(emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
                camel_object_unref(costream);
                costream = NULL;
            }

            camel_stream_write(job->stream, buffer, n);
        } else if (n < 0 && costream) {
            camel_data_cache_remove(emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
            camel_object_unref(costream);
            costream = NULL;            
        }
    } while (n>0);

    /* indicates success */
    if (n == 0)
        camel_stream_close(job->stream);

    if (costream)
        camel_object_unref(costream);

    camel_object_unref(instream);
done:
    camel_operation_end(NULL);
badurl:
    g_free(job->u.uri);
}

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

static void
efh_url_requested(GtkHTML *html, const char *url, GtkHTMLStream *handle, EMFormatHTML *efh)
{
    EMFormatPURI *puri;
    struct _EMFormatHTMLJob *job = NULL;

    d(printf("url requested, html = %p, url '%s'\n", html, url));

    puri = em_format_find_visible_puri((EMFormat *)efh, url);
    if (puri) {
        CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)puri->part);
        CamelContentType *ct = dw?dw->mime_type:NULL;

        /* GtkHTML only handles text and images.
           application/octet-stream parts are the only ones
           which are snooped for other content.  So only try
           to pass these to it - any other types are badly
           formed or intentionally malicious emails.  They
           will still show as attachments anyway */

        if (ct && (camel_content_type_is(ct, "text", "*")
               || camel_content_type_is(ct, "image", "*")
               || camel_content_type_is(ct, "application", "octet-stream"))) {
            puri->use_count++;

            d(printf(" adding puri job\n"));
            job = em_format_html_job_new(efh, emfh_getpuri, puri);
        } else {
            d(printf(" part is unknown type '%s', not using\n", ct?camel_content_type_format(ct):"<unset>"));
            gtk_html_stream_close(handle, GTK_HTML_STREAM_ERROR);
        }
    } else if (g_ascii_strncasecmp(url, "http:", 5) == 0 || g_ascii_strncasecmp(url, "https:", 6) == 0) {
        d(printf(" adding job, get %s\n", url));
        job = em_format_html_job_new(efh, emfh_gethttp, g_strdup(url));
    } else if  (g_ascii_strncasecmp(url, "/", 1) == 0) {
        char *data = NULL;
        guint length = 0;
        gboolean status;
        
        status = g_file_get_contents (url, &data, &length, NULL);
        if (status)
            gtk_html_stream_write (handle, data, length);

        gtk_html_stream_close(handle, status? GTK_HTML_STREAM_OK : GTK_HTML_STREAM_ERROR);
        g_free (data);
    } else {
        d(printf("HTML Includes reference to unknown uri '%s'\n", url));
        gtk_html_stream_close(handle, GTK_HTML_STREAM_ERROR);
    }

    if (job) {
        job->stream = em_html_stream_new(html, handle);
        em_format_html_job_queue(efh, job);
    }
}

static gboolean
efh_object_requested(GtkHTML *html, GtkHTMLEmbedded *eb, EMFormatHTML *efh)
{
    EMFormatHTMLPObject *pobject;
    int res = FALSE;

    if (eb->classid == NULL)
        return FALSE;

    pobject = em_format_html_find_pobject(efh, eb->classid);
    if (pobject) {
        /* This stops recursion of the part */
        e_dlist_remove((EDListNode *)pobject);
        res = pobject->func(efh, eb, pobject);
        e_dlist_addhead(&efh->pending_object_list, (EDListNode *)pobject);
    } else {
        d(printf("HTML Includes reference to unknown object '%s'\n", eb->classid));
    }

    return res;
}

/* ********************************************************************** */
#include "em-inline-filter.h"
#include <camel/camel-stream-null.h>

/* FIXME: This is duplicated in em-format-html-display, should be exported or in security module */
static const struct {
    const char *icon, *shortdesc;
} smime_sign_table[4] = {
    { "stock_signature-bad", N_("Unsigned") },
    { "stock_signature-ok", N_("Valid signature") },
    { "stock_signature-bad", N_("Invalid signature") },
    { "stock_signature", N_("Valid signature but cannot verify sender") },
};

static const struct {
    const char *icon, *shortdesc;
} smime_encrypt_table[4] = {
    { "stock_lock-broken", N_("Unencrypted") },
    { "stock_lock", N_("Encrypted, weak"),},
    { "stock_lock-ok", N_("Encrypted") },
    { "stock_lock-ok", N_("Encrypted, strong") },
};

static const char *smime_sign_colour[4] = {
    "", " bgcolor=\"#88bb88\"", " bgcolor=\"#bb8888\"", " bgcolor=\"#e8d122\""
};

/* TODO: this could probably be virtual on em-format-html
   then we only need one version of each type handler */
static void
efh_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid)
{
    efh_parent->format_secure(emf, stream, part, valid);

    /* To explain, if the validity is the same, then we are the
       base validity and now have a combined sign/encrypt validity
       we can display.  Primarily a new verification context is
       created when we have an embeded message. */
    if (emf->valid == valid
        && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
        || valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) {
        char *classid, *iconpath;
        const char *icon;
        CamelMimePart *iconpart;
        
        camel_stream_printf (stream, "<table border=0 width=\"100%%\" cellpadding=3 cellspacing=0%s><tr>",
                     smime_sign_colour[valid->sign.status]);
        
        classid = g_strdup_printf("smime:///em-format-html/%s/icon/signed", emf->part_id->str);
        camel_stream_printf(stream, "<td valign=\"top\"><img src=\"%s\"></td><td valign=\"top\" width=\"100%%\">", classid);
        
        if (valid->sign.status != 0)
            icon = smime_sign_table[valid->sign.status].icon;
        else
            icon = smime_encrypt_table[valid->encrypt.status].icon;
        iconpath = e_icon_factory_get_icon_filename(icon, E_ICON_SIZE_DIALOG);
        iconpart = em_format_html_file_part((EMFormatHTML *)emf, "image/png", iconpath);
        if (iconpart) {
            (void)em_format_add_puri(emf, sizeof(EMFormatPURI), classid, iconpart, efh_write_image);
            camel_object_unref(iconpart);
        }
        g_free (iconpath);
        g_free(classid);

        if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
            camel_stream_printf(stream, "%s<br>", _(smime_sign_table[valid->sign.status].shortdesc));
        }

        if (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
            camel_stream_printf(stream, "%s<br>", _(smime_encrypt_table[valid->encrypt.status].shortdesc));
        }

        camel_stream_printf(stream, "</td></tr></table>");
    }
}
    
static void
efh_text_plain(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
{
    CamelStreamFilter *filtered_stream;
    CamelMimeFilter *html_filter;
    CamelMultipart *mp;
    CamelDataWrapper *dw;
    CamelContentType *type;
    const char *format;
    guint32 flags;
    int i, count, len;
    struct _EMFormatHTMLCache *efhc;

    flags = efh->text_html_flags;
    
    dw = camel_medium_get_content_object((CamelMedium *)part);

    /* Check for RFC 2646 flowed text. */
    if (camel_content_type_is(dw->mime_type, "text", "plain")
        && (format = camel_content_type_param(dw->mime_type, "format"))
        && !g_ascii_strcasecmp(format, "flowed"))
        flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;

    /* This scans the text part for inline-encoded data, creates
       a multipart of all the parts inside it. */

    /* FIXME: We should discard this multipart if it only contains