From 27f894733e551067737a21bc21259ccbda60c777 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Sat, 10 Jul 2004 01:31:04 +0000 Subject: only call expunge if the folder is set. (emfb_enable_map[]): only enable 2004-07-09 Not Zed * em-folder-browser.c (emfb_folder_expunge): only call expunge if the folder is set. (emfb_enable_map[]): only enable expunge menu item if we have a valid folder set. ** See bug #60900. * em-format-html.c: convert the text_inline_parts hash to be keyed off the partid. (efh_free_inline_parts): -> efh_free_cache and fix to do it. * em-format.c (emf_free_cache): make the inline table cache other info too based on partid, this frees the structure. (emf_clone_inlines): copy all of the cache data. (em_format_is_inline): use the new data structure to determine state. (em_format_set_inline): same for setting. (emf_multipart_signed): cache/lookup the cached part. (emf_insert_cache): helper to add a cache entry. (emf_multipart_encrypted): cache decrypted part. (emf_application_xpkcs7mime): same. 2004-07-08 Not Zed ** See bug #60900 (related only). * em-format-html-display.c (efhd_attachment_show): let set_inline do the redraw itself if required. kill some dead code. * em-format.c (em_format_set_inline): trigger a redraw here like the other em_format_set methods, if the state changed. * em-format.c (emf_format_clone): free inline table keys & setup string hash table. * em-format-quote.c (emfq_format_attachment): * em-format-html-display.c (efhd_format_attachment): * em-format-html.c (efh_format_attachment): is_inline api changes. * em-format-html-display.c (efhd_attachment_show): set_inline api changes. * em-format.c (em_format_is_inline): make this use the partid rather than the part address as a key, which may change. (emf_init): make the inline talbe a string hashtable. (emf_finalise): free inline keys. (emf_clone_inlines): copy the key string. svn path=/trunk/; revision=26614 --- mail/ChangeLog | 50 ++++++++++++++++ mail/em-folder-browser.c | 6 +- mail/em-format-html-display.c | 35 +----------- mail/em-format-html.c | 52 +++++++++++++---- mail/em-format-quote.c | 2 +- mail/em-format.c | 130 ++++++++++++++++++++++++++++++++++++++---- mail/em-format.h | 7 ++- 7 files changed, 219 insertions(+), 63 deletions(-) diff --git a/mail/ChangeLog b/mail/ChangeLog index 6b0eafccfc..fd86443c71 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,53 @@ +2004-07-09 Not Zed + + * em-folder-browser.c (emfb_folder_expunge): only call expunge if + the folder is set. + (emfb_enable_map[]): only enable expunge menu item if we have a + valid folder set. + + ** See bug #60900. + + * em-format-html.c: convert the text_inline_parts hash to be keyed + off the partid. + (efh_free_inline_parts): -> efh_free_cache and fix to do it. + + * em-format.c (emf_free_cache): make the inline table cache other + info too based on partid, this frees the structure. + (emf_clone_inlines): copy all of the cache data. + (em_format_is_inline): use the new data structure to determine + state. + (em_format_set_inline): same for setting. + (emf_multipart_signed): cache/lookup the cached part. + (emf_insert_cache): helper to add a cache entry. + (emf_multipart_encrypted): cache decrypted part. + (emf_application_xpkcs7mime): same. + +2004-07-08 Not Zed + + ** See bug #60900 (related only). + + * em-format-html-display.c (efhd_attachment_show): let set_inline + do the redraw itself if required. kill some dead code. + + * em-format.c (em_format_set_inline): trigger a redraw here like + the other em_format_set methods, if the state changed. + + * em-format.c (emf_format_clone): free inline table keys & setup + string hash table. + + * em-format-quote.c (emfq_format_attachment): + * em-format-html-display.c (efhd_format_attachment): + * em-format-html.c (efh_format_attachment): is_inline api changes. + + * em-format-html-display.c (efhd_attachment_show): set_inline api + changes. + + * em-format.c (em_format_is_inline): make this use the partid + rather than the part address as a key, which may change. + (emf_init): make the inline talbe a string hashtable. + (emf_finalise): free inline keys. + (emf_clone_inlines): copy the key string. + 2004-07-07 Jeffrey Stedfast Fix for bug #61199. diff --git a/mail/em-folder-browser.c b/mail/em-folder-browser.c index e61453e8ce..e9c14ea600 100644 --- a/mail/em-folder-browser.c +++ b/mail/em-folder-browser.c @@ -556,8 +556,9 @@ static void emfb_folder_expunge(BonoboUIComponent *uid, void *data, const char *path) { EMFolderBrowser *emfb = data; - - em_utils_expunge_folder(gtk_widget_get_toplevel((GtkWidget *)emfb), emfb->view.folder); + + if (emfb->view.folder) + em_utils_expunge_folder(gtk_widget_get_toplevel((GtkWidget *)emfb), emfb->view.folder); } static void @@ -722,6 +723,7 @@ static const EMFolderViewEnable emfb_enable_map[] = { { "EditInvertSelection", EM_POPUP_SELECT_FOLDER }, { "EditSelectAll", EM_POPUP_SELECT_FOLDER }, { "EditSelectThread", EM_FOLDER_VIEW_SELECT_THREADED }, + { "FolderExpunge", EM_POPUP_SELECT_FOLDER }, { "MailPost", EM_POPUP_SELECT_FOLDER }, { "MessageMarkAllAsRead", EM_POPUP_SELECT_FOLDER }, { "ViewHideSelected", EM_POPUP_SELECT_MANY }, diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index a55189d644..fd5e653625 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -1046,38 +1046,7 @@ efhd_attachment_show(GtkWidget *w, struct _attach_puri *info) d(printf("show attachment button called\n")); info->shown = ~info->shown; - em_format_set_inline(info->puri.format, info->puri.part, info->shown); - /* FIXME: do this in an idle handler */ - em_format_redraw(info->puri.format); -#if 0 - /* FIXME: track shown state in parent */ - - if (info->shown) { - d(printf("hiding\n")); - info->shown = FALSE; - if (info->frame) - gtk_widget_hide((GtkWidget *)info->frame); - gtk_widget_show(info->forward); - gtk_widget_hide(info->down); - } else { - d(printf("showing\n")); - info->shown = TRUE; - if (info->frame) - gtk_widget_show((GtkWidget *)info->frame); - gtk_widget_hide(info->forward); - gtk_widget_show(info->down); - - /* have we decoded it yet? */ - if (info->output) { - info->handle->handler(info->puri.format, info->output, info->puri.part, info->handle); - camel_stream_close(info->output); - camel_object_unref(info->output); - info->output = NULL; - } - } - - em_format_set_inline(info->puri.format, info->puri.part, info->shown); -#endif + em_format_set_inline(info->puri.format, info->puri.part_id, info->shown); } static EMPopupItem efhd_menu_items[] = { @@ -1498,7 +1467,7 @@ efhd_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, info = (struct _attach_puri *)em_format_add_puri(emf, sizeof(*info), classid, part, efhd_attachment_frame); em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_attachment_button); info->handle = handle; - info->shown = em_format_is_inline(emf, info->puri.part, handle); + info->shown = em_format_is_inline(emf, info->puri.part_id, info->puri.part, handle); info->snoop_mime_type = emf->snoop_mime_type; camel_stream_write_string(stream, diff --git a/mail/em-format-html.c b/mail/em-format-html.c index 0cb3e15cb2..d84238fda0 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -75,13 +75,19 @@ #define EFH_TABLE_OPEN "" +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 */ + /* Table that re-maps text parts into a mutlipart/mixed, EMFormatHTMLCache * */ GHashTable *text_inline_parts; EDList pending_jobs; @@ -120,7 +126,7 @@ efh_init(GObject *o) 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(NULL, NULL); + 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); @@ -163,10 +169,27 @@ efh_gtkhtml_destroy(GtkHTML *html, EMFormatHTML *efh) } } +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_inline_parts(void *key, void *data, void *user) +efh_free_cache(void *key, void *val, void *dat) { - camel_object_unref(data); + struct _EMFormatHTMLCache *efhc = val; + + if (efhc->textmp) + camel_object_unref(efhc->textmp); + g_free(efhc); } static void @@ -180,7 +203,7 @@ efh_finalise(GObject *o) efh_gtkhtml_destroy(efh->html, efh); - g_hash_table_foreach(efh->priv->text_inline_parts, efh_free_inline_parts, NULL); + 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); @@ -635,7 +658,8 @@ efh_text_plain(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFo const char *format; guint32 flags; int i, count, len; - + struct _EMFormatHTMLCache *efhc; + camel_stream_printf (stream, "
\n" "
\n" @@ -663,8 +687,8 @@ efh_text_plain(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFo filters a bit. Perhaps the superclass should just deal with html anyway and be done with it ... */ - mp = g_hash_table_lookup(efh->priv->text_inline_parts, part); - if (mp == NULL) { + efhc = g_hash_table_lookup(efh->priv->text_inline_parts, ((EMFormat *)efh)->part_id->str); + if (efhc == NULL || (mp = efhc->textmp) == NULL) { EMInlineFilter *inline_filter; CamelStream *null; CamelContentType *ct; @@ -685,8 +709,12 @@ efh_text_plain(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFo camel_data_wrapper_write_to_stream(dw, (CamelStream *)filtered_stream); camel_stream_close((CamelStream *)filtered_stream); camel_object_unref(filtered_stream); + mp = em_inline_filter_get_multipart(inline_filter); - g_hash_table_insert(efh->priv->text_inline_parts, part, mp); + if (efhc == NULL) + efhc = efh_insert_cache(efh, ((EMFormat *)efh)->part_id->str); + efhc->textmp = mp; + camel_object_unref(inline_filter); camel_content_type_unref(ct); } @@ -1292,9 +1320,9 @@ efh_format_timeout(struct _format_msg *m) | GTK_HTML_BEGIN_BLOCK_UPDATES | GTK_HTML_BEGIN_BLOCK_IMAGES); } else { /* clear cache of inline-scanned text parts */ - g_hash_table_foreach(p->text_inline_parts, efh_free_inline_parts, NULL); + g_hash_table_foreach(p->text_inline_parts, efh_free_cache, NULL); g_hash_table_destroy(p->text_inline_parts); - p->text_inline_parts = g_hash_table_new(NULL, NULL); + p->text_inline_parts = g_hash_table_new(g_str_hash, g_str_equal); p->last_part = m->message; } @@ -1747,7 +1775,7 @@ efh_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, c camel_stream_write_string(stream, "
"); - if (handle && em_format_is_inline(emf, part, handle)) + if (handle && em_format_is_inline(emf, emf->part_id->str, part, handle)) handle->handler(emf, stream, part, handle); } diff --git a/mail/em-format-quote.c b/mail/em-format-quote.c index dc5695cfc2..16d6bbc4e6 100644 --- a/mail/em-format-quote.c +++ b/mail/em-format-quote.c @@ -397,7 +397,7 @@ emfq_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart *part) static void emfq_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle) { - if (handle && em_format_is_inline(emf, part, handle)) { + if (handle && em_format_is_inline(emf, emf->part_id->str, part, handle)) { char *text, *html; camel_stream_write_string(stream, diff --git a/mail/em-format.c b/mail/em-format.c index 35fed724ca..b7598f97c8 100644 --- a/mail/em-format.c +++ b/mail/em-format.c @@ -54,6 +54,24 @@ #define d(x) +/* Used to cache various data/info for redraws + The validity stuff could be cached at a higher level but this is easier + This absolutely relies on the partid being _globally unique_ + This is still kind of yucky, we should maintian a full tree of all this data, + along with/as part of the puri tree */ +struct _EMFormatCache { + struct _CamelCipherValidity *valid; /* validity copy */ + struct _CamelMimePart *secured; /* encrypted subpart */ + + unsigned int state:2; /* inline state */ + + char partid[1]; +}; + +#define INLINE_UNSET (0) +#define INLINE_ON (1) +#define INLINE_OFF (2) + static void emf_builtin_init(EMFormatClass *); static const EMFormatHandler *emf_find_handler(EMFormat *emf, const char *mime_type); @@ -70,12 +88,36 @@ enum { static guint emf_signals[EMF_LAST_SIGNAL]; static GObjectClass *emf_parent; +static void +emf_free_cache(void *key, void *val, void *dat) +{ + struct _EMFormatCache *efc = val; + + if (efc->valid) + camel_cipher_validity_free(efc->valid); + if (efc->secured) + camel_object_unref(efc->secured); + g_free(efc); +} + +static struct _EMFormatCache * +emf_insert_cache(EMFormat *emf, const char *partid) +{ + struct _EMFormatCache *new; + + new = g_malloc0(sizeof(*new)+strlen(partid)); + strcpy(new->partid, partid); + g_hash_table_insert(emf->inline_table, new->partid, new); + + return new; +} + static void emf_init(GObject *o) { EMFormat *emf = (EMFormat *)o; - emf->inline_table = g_hash_table_new(NULL, NULL); + emf->inline_table = g_hash_table_new(g_str_hash, g_str_equal); e_dlist_init(&emf->header_list); em_format_default_headers(emf); emf->part_id = g_string_new(""); @@ -89,8 +131,8 @@ emf_finalise(GObject *o) if (emf->session) camel_object_unref(emf->session); - if (emf->inline_table) - g_hash_table_destroy(emf->inline_table); + g_hash_table_foreach(emf->inline_table, emf_free_cache, NULL); + g_hash_table_destroy(emf->inline_table); em_format_clear_headers(emf); camel_cipher_validity_free(emf->valid); @@ -526,7 +568,14 @@ em_format_part(EMFormat *emf, CamelStream *stream, CamelMimePart *part) static void emf_clone_inlines(void *key, void *val, void *data) { - g_hash_table_insert(((EMFormat *)data)->inline_table, key, val); + struct _EMFormatCache *emfc = val, *new; + + new = emf_insert_cache((EMFormat *)data, emfc->partid); + new->state = emfc->state; + if (emfc->valid) + new->valid = camel_cipher_validity_clone(emfc->valid); + if (emfc->secured) + camel_object_ref((new->secured = emfc->secured)); } static void @@ -535,8 +584,9 @@ emf_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeM em_format_clear_puri_tree(emf); if (emf != emfsource) { + g_hash_table_foreach(emf->inline_table, emf_free_cache, NULL); g_hash_table_destroy(emf->inline_table); - emf->inline_table = g_hash_table_new(NULL, NULL); + emf->inline_table = g_hash_table_new(g_str_hash, g_str_equal); if (emfsource) { struct _EMFormatHeader *h; @@ -829,6 +879,7 @@ int em_format_is_attachment(EMFormat *emf, CamelMimePart *part) * em_format_is_inline: * @emf: * @part: + * @partid: format->part_id part id of this part. * @handle: handler for this part * * Returns true if the part should be displayed inline. Any part with @@ -840,16 +891,17 @@ int em_format_is_attachment(EMFormat *emf, CamelMimePart *part) * * Return value: **/ -int em_format_is_inline(EMFormat *emf, CamelMimePart *part, const EMFormatHandler *handle) +int em_format_is_inline(EMFormat *emf, const char *partid, CamelMimePart *part, const EMFormatHandler *handle) { - void *dummy, *override; + struct _EMFormatCache *emfc; const char *tmp; if (handle == NULL) return FALSE; - if (g_hash_table_lookup_extended(emf->inline_table, part, &dummy, &override)) - return GPOINTER_TO_INT(override); + emfc = g_hash_table_lookup(emf->inline_table, partid); + if (emfc && emfc->state != INLINE_UNSET) + return emfc->state & 1; /* some types need to override the disposition, e.g. application/x-pkcs7-mime */ if (handle->flags & EM_FORMAT_HANDLER_INLINE_DISPOSITION) @@ -866,16 +918,27 @@ int em_format_is_inline(EMFormat *emf, CamelMimePart *part, const EMFormatHandle /** * em_format_set_inline: * @emf: - * @part: + * @partid: id of part * @state: * * Force the attachment @part to be expanded or hidden explictly to match * @state. This is used only to record the change for a redraw or * cloned layout render and does not force a redraw. **/ -void em_format_set_inline(EMFormat *emf, CamelMimePart *part, int state) +void em_format_set_inline(EMFormat *emf, const char *partid, int state) { - g_hash_table_insert(emf->inline_table, part, GINT_TO_POINTER(state)); + struct _EMFormatCache *emfc; + + emfc = g_hash_table_lookup(emf->inline_table, partid); + if (emfc == NULL) { + emfc = emf_insert_cache(emf, partid); + } else if (emfc->state != INLINE_UNSET && (emfc->state & 1) == state) + return; + + emfc->state = state?INLINE_ON:INLINE_OFF; + + if (emf->message) + em_format_redraw(emf); } void em_format_format_error(EMFormat *emf, CamelStream *stream, const char *fmt, ...) @@ -1013,6 +1076,14 @@ emf_application_xpkcs7mime(EMFormat *emf, CamelStream *stream, CamelMimePart *pa extern CamelSession *session; CamelMimePart *opart; CamelCipherValidity *valid; + struct _EMFormatCache *emfc; + + /* should this perhaps run off a key of ".secured" ? */ + emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str); + if (emfc && emfc->valid) { + em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid)); + return; + } ex = camel_exception_new(); @@ -1024,6 +1095,12 @@ emf_application_xpkcs7mime(EMFormat *emf, CamelStream *stream, CamelMimePart *pa em_format_format_error(emf, stream, ex->desc?ex->desc:_("Could not parse S/MIME message: Unknown error")); em_format_part_as(emf, stream, part, NULL); } else { + if (emfc == NULL) + emfc = emf_insert_cache(emf, emf->part_id->str); + + emfc->valid = camel_cipher_validity_clone(valid); + camel_object_ref((emfc->secured = opart)); + em_format_format_secure(emf, stream, opart, valid); } @@ -1126,6 +1203,14 @@ emf_multipart_encrypted(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *protocol; CamelMimePart *opart; CamelCipherValidity *valid; + struct _EMFormatCache *emfc; + + /* should this perhaps run off a key of ".secured" ? */ + emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str); + if (emfc && emfc->valid) { + em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid)); + return; + } /* Currently we only handle RFC2015-style PGP encryption. */ protocol = camel_content_type_param (((CamelDataWrapper *) part)->mime_type, "protocol"); @@ -1145,9 +1230,16 @@ emf_multipart_encrypted(EMFormat *emf, CamelStream *stream, CamelMimePart *part, em_format_format_error(emf, stream, ex->desc); em_format_part_as(emf, stream, part, "multipart/mixed"); } else { + if (emfc == NULL) + emfc = emf_insert_cache(emf, emf->part_id->str); + + emfc->valid = camel_cipher_validity_clone(valid); + camel_object_ref((emfc->secured = opart)); + em_format_format_secure(emf, stream, opart, valid); } + /* TODO: Make sure when we finalise this part, it is zero'd out */ camel_object_unref(opart); camel_object_unref(context); camel_exception_free(ex); @@ -1272,6 +1364,14 @@ emf_multipart_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, co CamelMimePart *cpart; CamelMultipartSigned *mps; CamelCipherContext *cipher = NULL; + struct _EMFormatCache *emfc; + + /* should this perhaps run off a key of ".secured" ? */ + emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str); + if (emfc && emfc->valid) { + em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid)); + return; + } mps = (CamelMultipartSigned *)camel_medium_get_content_object((CamelMedium *)part); if (!CAMEL_IS_MULTIPART_SIGNED(mps) @@ -1308,6 +1408,12 @@ emf_multipart_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, co em_format_format_error(emf, stream, ex->desc); em_format_part_as(emf, stream, part, "multipart/mixed"); } else { + if (emfc == NULL) + emfc = emf_insert_cache(emf, emf->part_id->str); + + emfc->valid = camel_cipher_validity_clone(valid); + camel_object_ref((emfc->secured = cpart)); + em_format_format_secure(emf, stream, cpart, valid); } diff --git a/mail/em-format.h b/mail/em-format.h index 14db358e58..8cbdc69a1a 100644 --- a/mail/em-format.h +++ b/mail/em-format.h @@ -190,9 +190,10 @@ void em_format_add_header(EMFormat *emf, const char *name, guint32 flags); Or maybe it should live with sub-classes? */ int em_format_is_attachment(EMFormat *emf, struct _CamelMimePart *part); -int em_format_is_inline(EMFormat *emf, struct _CamelMimePart *part, const EMFormatHandler *handle); -/* FIXME: not sure about this api */ -void em_format_set_inline(EMFormat *emf, struct _CamelMimePart *part, int state); + +int em_format_is_inline(EMFormat *emf, const char *partid, struct _CamelMimePart *part, const EMFormatHandler *handle); +void em_format_set_inline(EMFormat *emf, const char *partid, int state); + char *em_format_describe_part(struct _CamelMimePart *part, const char *mimetype); /* for implementers */ -- cgit v1.2.3