diff --git a/lib/Makefile.am b/lib/Makefile.am index c7d32830..7d60a5f8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -58,8 +58,6 @@ libmu_la_SOURCES= \ mu-log.h \ mu-maildir.c \ mu-maildir.h \ - mu-msg-cache.c \ - mu-msg-cache.h \ ${crypto} \ mu-msg-crypto.h \ mu-msg-doc.cc \ @@ -96,7 +94,6 @@ libmu_la_SOURCES= \ mu-util.c \ mu-util.h - libmu_la_LIBADD= \ $(XAPIAN_LIBS) \ $(GMIME_LIBS) \ diff --git a/lib/mu-msg-cache.c b/lib/mu-msg-cache.c deleted file mode 100644 index 34a287f5..00000000 --- a/lib/mu-msg-cache.c +++ /dev/null @@ -1,262 +0,0 @@ -/* -** Copyright (C) 2011 Dirk-Jan C. Binnema -** -** 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -** -*/ - -#include "mu-flags.h" -#include "mu-msg-prio.h" -#include "mu-msg-cache.h" -#include "mu-str.h" - -struct _MuMsgCache { - - /* all string properties */ - char *_str[MU_MSG_STRING_FIELD_ID_NUM]; - - GSList *_refs, *_tags; - - time_t _timestamp, _date; - size_t _size; - MuFlags _flags; - MuMsgPrio _prio; - - /* */ - unsigned _cached, _allocated; -}; - -/* _cached and _allocated have a bit for each MuMsgFieldId to remember - * which ones have been cached, and which ones have been allocated. */ - -#define is_allocated(C,MFID) ((C)->_allocated & (1 << (MFID))) -#define is_cached(C,MFID) ((C)->_cached & (1 << (MFID))) - -#define set_allocated(C,MFID) ((C)->_allocated |= (1 << (MFID))) -#define set_cached(C,MFID) ((C)->_cached |= (1 << (MFID))) - -#define reset_allocated(C,MFID) ((C)->_allocated &= ~(1 << (MFID))) -#define reset_cached(C,MFID) ((C)->_cached &= ~(1 << (MFID))) - - -static void -cache_clear (MuMsgCache *self) -{ - int i; - - for (i = 0; i != MU_MSG_STRING_FIELD_ID_NUM; ++i) - self->_str[i] = NULL; - - self->_timestamp = (time_t)-1; - self->_size = (size_t)-1; - self->_flags = MU_FLAG_NONE; - self->_prio = MU_MSG_PRIO_NONE; - self->_date = (time_t)-1; - - self->_refs = self->_tags = NULL; - - self->_cached = 0; - self->_allocated = 0; -} - - -MuMsgCache* -mu_msg_cache_new (void) -{ - MuMsgCache *self; - - self = g_slice_new0 (MuMsgCache); - cache_clear (self); - - return self; -} - - -void -mu_msg_cache_destroy (MuMsgCache *self) -{ - int i; - - if (!self) - return; - - g_return_if_fail (self); - - for (i = 0; i != MU_MSG_STRING_FIELD_ID_NUM; ++i) - if (is_allocated(self, i)) - g_free (self->_str[i]); - - mu_str_free_list (self->_tags); - mu_str_free_list (self->_refs); - - g_slice_free (MuMsgCache, self); -} - - - -const char* -mu_msg_cache_set_str (MuMsgCache *self, MuMsgFieldId mfid, char *str, - gboolean do_free) -{ - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (mu_msg_field_is_string(mfid), NULL); - - /* maybe there was an old, allocated value there already? */ - if (is_allocated(self, mfid)) - g_free (self->_str[mfid]); - - self->_str[mfid] = str; - set_cached (self, mfid); - - if (do_free) - set_allocated (self, mfid); - else - reset_allocated (self, mfid); - - return str; -} - - -const char* -mu_msg_cache_str (MuMsgCache *cache, MuMsgFieldId mfid) -{ - g_return_val_if_fail (mu_msg_field_is_string(mfid), NULL); - return cache->_str[mfid]; -} - - - -const GSList* -mu_msg_cache_set_str_list (MuMsgCache *self, MuMsgFieldId mfid, - GSList *lst, gboolean do_free) -{ - g_return_val_if_fail(self, NULL); - g_return_val_if_fail(mu_msg_field_is_string_list(mfid), NULL); - - switch (mfid) { - case MU_MSG_FIELD_ID_REFS: - if (is_allocated(self, mfid)) - mu_str_free_list (self->_refs); - self->_refs = lst; - break; - - case MU_MSG_FIELD_ID_TAGS: - if (is_allocated(self, mfid)) - mu_str_free_list (self->_tags); - self->_tags = lst; - break; - default: - g_return_val_if_reached(NULL); - return NULL; - } - - set_cached (self, mfid); - - if (do_free) - set_allocated (self, mfid); - else - reset_allocated (self, mfid); - - return lst; -} - - -const GSList* -mu_msg_cache_str_list (MuMsgCache *self, MuMsgFieldId mfid) -{ - g_return_val_if_fail (mu_msg_field_is_string_list(mfid), NULL); - - switch (mfid) { - case MU_MSG_FIELD_ID_REFS: - return self->_refs; - default: - g_return_val_if_reached(NULL); - return NULL; - } -} - - -gint64 -mu_msg_cache_set_num (MuMsgCache *self, MuMsgFieldId mfid, gint64 val) -{ - g_return_val_if_fail(self, -1); - g_return_val_if_fail(mu_msg_field_is_numeric(mfid), -1); - - switch (mfid) { - case MU_MSG_FIELD_ID_DATE: - self->_date = (time_t)val; - break; - case MU_MSG_FIELD_ID_PRIO: - self->_prio = (MuMsgPrio)val; - break; - case MU_MSG_FIELD_ID_FLAGS: - self->_flags = (MuFlags)val; - break; - case MU_MSG_FIELD_ID_SIZE: - self->_size = (size_t)val; - break; - default: - g_return_val_if_reached(-1); - return -1; - } - - set_cached (self, mfid); - return val; -} - - -gint64 -mu_msg_cache_num (MuMsgCache *self, MuMsgFieldId mfid) -{ - g_return_val_if_fail(mu_msg_field_is_numeric(mfid), -1); - - switch (mfid) { - case MU_MSG_FIELD_ID_DATE: - return (gint64)self->_date; - case MU_MSG_FIELD_ID_PRIO: - return (gint64)self->_prio; - case MU_MSG_FIELD_ID_FLAGS: - return (gint64)self->_flags; - case MU_MSG_FIELD_ID_SIZE: - return (gint64)self->_size; - default: g_return_val_if_reached(-1); - } - - set_cached (self, mfid); -} - - -gboolean -mu_msg_cache_cached (MuMsgCache *self, MuMsgFieldId mfid) -{ - g_return_val_if_fail (mfid < MU_MSG_FIELD_ID_NUM, FALSE); - return is_cached(self, mfid) ? TRUE : FALSE; -} - - -void -mu_msg_cache_allocate_all (MuMsgCache *self) -{ - int mfid; - - g_return_if_fail (self); - - for (mfid = 0; mfid != MU_MSG_STRING_FIELD_ID_NUM; ++mfid) { - if (self->_str[mfid] && !is_allocated(self, mfid)) { - self->_str[mfid] = g_strdup (self->_str[mfid]); - set_allocated(self, mfid); - } - } -} diff --git a/lib/mu-msg-cache.h b/lib/mu-msg-cache.h deleted file mode 100644 index ea0ecbb3..00000000 --- a/lib/mu-msg-cache.h +++ /dev/null @@ -1,159 +0,0 @@ -/* -** Copyright (C) 2011 Dirk-Jan C. Binnema -** -** 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -** -*/ - -#ifndef __MU_MSG_CACHE_H__ -#define __MU_MSG_CACHE_H__ - -#include -#include - -/* MuMsgCache caches all values for one specific MuMsg, whether its - * backend is a MuMsgFile or MuMsgDb. The idea is to take all the - * values from the MuMsg so we can release the backend (file or db). - * - * It is specifically designed minimize memory allocations; you can - * either store dynamically-allocated strings, of which the cache will - * take ownership (and g_free in the end), *or* use strings, either - * static or owned elsewhere. In the later case, no copy will be made - * until mu_msg_cache_allocate_all is called - * - * Minimizing allocations in esp. necessary when storing - * search-results as a list of MuMsg instances - */ - -G_BEGIN_DECLS - -struct _MuMsgCache; -typedef struct _MuMsgCache MuMsgCache; - -/** - * initialize the cache - * - * @param self ptr to a cache struct - */ -MuMsgCache *mu_msg_cache_new (void); - -/** - * free the strings in the cache - * - * @param self ptr to a cache struct - */ -void mu_msg_cache_destroy (MuMsgCache *self); - - - -/** - * add a string value to the cache; it will *not* be freed - * - * @param self a cache struc - * @param mfid the MessageFieldId - * @param str the string value to set - * @param do_free whether the cache should free this value (i.e, take ownership) - * - * @return the cached value (this is for nesting function calls) - */ -const char* mu_msg_cache_set_str (MuMsgCache *self, MuMsgFieldId mfid, - char *str, gboolean do_free); - - -/** - * get a string value from the cache - * - * @param self ptr to a MuMsgCache - * @param mfid the MessageFieldId for a string value - * - * @return the string, or NULL. Don't modify. - */ -const char* mu_msg_cache_str (MuMsgCache *cache, MuMsgFieldId mfid); - - - -/** - * cache a string-list value - * - * @param self a mumsgcache - * @param mfid the MessageFieldId for a string-list value - * @param lst the list - * @param do_free whether the cache should free this value (i.e, take ownership) - * - * @return - */ -const GSList* mu_msg_cache_set_str_list (MuMsgCache *self, MuMsgFieldId mfid, - GSList *lst, gboolean do_free); - -/** - * get a string-list value from the cache - * - * @param cache a MuMsgCache - * @param mfid the MessageFieldId for string-list value - * - * @return a list, which should not be modified - */ -const GSList* mu_msg_cache_str_list (MuMsgCache *cache, MuMsgFieldId mfid); - - -/** - * add a numeric value to the cache - * - * @param self a MuMsgCache ptr - * @param mfid the MessageFieldId for a numeric value - * @param val the value - * - * @return the cached value (this is for nesting function calls) - * - */ -gint64 mu_msg_cache_set_num (MuMsgCache *self, MuMsgFieldId mfid, gint64 val); - - -/** - * get a numeric value from the cache - * - * @param self a MuMsgCache ptr - * @param mfid the MessageFieldId for a numeric value - * - * @return a numeric value - */ -gint64 mu_msg_cache_num (MuMsgCache *self, MuMsgFieldId mfid); - - - -/** - * is the value cached already? - * - * @param self a MuMsgCache ptr - * @param mfid the MessageFieldId for a numeric value - * - * @return TRUE if the value is cached, FALSE otherwise - */ -gboolean mu_msg_cache_cached (MuMsgCache *self, MuMsgFieldId mfid); - - - -/** - * copy all data that was not already owned by the cache - * - * @param self a MuMsgCache ptr - */ -void mu_msg_cache_allocate_all (MuMsgCache *self); - - -G_END_DECLS - -#endif /*__MU_MSG_CACHE_H__*/ - diff --git a/lib/mu-msg-doc.cc b/lib/mu-msg-doc.cc index 8ffdc5fb..421e739f 100644 --- a/lib/mu-msg-doc.cc +++ b/lib/mu-msg-doc.cc @@ -63,15 +63,12 @@ mu_msg_doc_destroy (MuMsgDoc *self) gchar* -mu_msg_doc_get_str_field (MuMsgDoc *self, MuMsgFieldId mfid, - gboolean *do_free) +mu_msg_doc_get_str_field (MuMsgDoc *self, MuMsgFieldId mfid) { g_return_val_if_fail (self, NULL); g_return_val_if_fail (mu_msg_field_id_is_valid(mfid), NULL); g_return_val_if_fail (mu_msg_field_is_string(mfid), NULL); - *do_free = TRUE; - try { const std::string s (self->doc().get_value(mfid)); return s.empty() ? NULL : g_strdup (s.c_str()); @@ -81,15 +78,12 @@ mu_msg_doc_get_str_field (MuMsgDoc *self, MuMsgFieldId mfid, GSList* -mu_msg_doc_get_str_list_field (MuMsgDoc *self, MuMsgFieldId mfid, - gboolean *do_free) +mu_msg_doc_get_str_list_field (MuMsgDoc *self, MuMsgFieldId mfid) { g_return_val_if_fail (self, NULL); g_return_val_if_fail (mu_msg_field_id_is_valid(mfid), NULL); g_return_val_if_fail (mu_msg_field_is_string_list(mfid), NULL); - *do_free = TRUE; - try { /* return a comma-separated string as a GSList */ const std::string s (self->doc().get_value(mfid)); @@ -122,5 +116,3 @@ mu_msg_doc_get_num_field (MuMsgDoc *self, MuMsgFieldId mfid) } MU_XAPIAN_CATCH_BLOCK_RETURN(-1); } - - diff --git a/lib/mu-msg-doc.h b/lib/mu-msg-doc.h index 4630662d..d4ced0ba 100644 --- a/lib/mu-msg-doc.h +++ b/lib/mu-msg-doc.h @@ -29,14 +29,14 @@ struct _MuMsgDoc; typedef struct _MuMsgDoc MuMsgDoc; /** - * create a new MuMsgDoc instance - * + * create a new MuMsgDoc instance + * * @param doc a Xapian::Document* (you'll need to cast the * Xapian::Document* to XapianDocument*, because only C (not C++) is * allowed in this header file. MuMsgDoc takes _ownership_ of this pointer; * don't touch it afterwards * @param err receives error info, or NULL - * + * * @return a new MuMsgDoc instance (free with mu_msg_doc_destroy), or * NULL in case of error. */ @@ -47,7 +47,7 @@ MuMsgDoc* mu_msg_doc_new (XapianDocument *doc, GError **err) * destroy a MuMsgDoc instance -- free all the resources. Note, after * destroying, any strings returned from mu_msg_doc_get_str_field with * do_free==FALSE are no longer valid - * + * * @param self a MuMsgDoc instance */ void mu_msg_doc_destroy (MuMsgDoc *self); @@ -55,45 +55,36 @@ void mu_msg_doc_destroy (MuMsgDoc *self); /** * get a string parameter from the msgdoc - * + * * @param self a MuMsgDoc instance * @param mfid a MuMsgFieldId for a string field - * @param do_free receives either TRUE or FALSE, where TRUE means that - * the caller owns the string, and has to free it (g_free) when done - * with it; FALSE means that the MuMsgDoc owns the string, and it is - * only valid as long as the MuMsgDoc is valid (ie., before - * mu_msg_doc_destroy). - * - * @return a string for the given field (see do_free), or NULL in case of error + * + * @return a string for the given field (see do_free), or NULL in case of error. + * free with g_free */ -gchar* mu_msg_doc_get_str_field (MuMsgDoc *self, MuMsgFieldId mfid, - gboolean *do_free) +gchar* mu_msg_doc_get_str_field (MuMsgDoc *self, MuMsgFieldId mfid) G_GNUC_WARN_UNUSED_RESULT; /** * get a string-list parameter from the msgdoc - * + * * @param self a MuMsgDoc instance * @param mfid a MuMsgFieldId for a string-list field - * @param do_free receives either TRUE or FALSE, where TRUE means that - * the caller owns the string, and has to free it (mu_str_free_list) when done - * with it; FALSE means that the MuMsgDoc owns the list, and it is - * only valid as long as the MuMsgDoc is valid (ie., before - * mu_msg_doc_destroy). - * - * @return a list for the given field (see do_free), or NULL in case of error + * + * @return a list for the given field (see do_free), or NULL in case + * of error. free with mu_str_free_list */ -GSList* mu_msg_doc_get_str_list_field (MuMsgDoc *self, MuMsgFieldId mfid, - gboolean *do_free) G_GNUC_WARN_UNUSED_RESULT; +GSList* mu_msg_doc_get_str_list_field (MuMsgDoc *self, MuMsgFieldId mfid) + G_GNUC_WARN_UNUSED_RESULT; /** - * + * * get a numeric parameter from the msgdoc - * + * * @param self a MuMsgDoc instance * @param mfid a MuMsgFieldId for a numeric field - * + * * @return the numerical value, or -1 in case of error. You'll need to * cast this value to the actual type (e.g. time_t for MU_MSG_FIELD_ID_DATE) */ diff --git a/lib/mu-msg-file.c b/lib/mu-msg-file.c index c42e2d59..061c4284 100644 --- a/lib/mu-msg-file.c +++ b/lib/mu-msg-file.c @@ -74,18 +74,9 @@ mu_msg_file_destroy (MuMsgFile *self) if (self->_mime_msg) g_object_unref (self->_mime_msg); - mu_str_free_list (self->_free_later); - g_slice_free (MuMsgFile, self); } -static const gchar* -free_string_later (MuMsgFile *self, gchar *str) -{ - self->_free_later = g_slist_prepend (self->_free_later, str); - return str; -} - static gboolean init_file_metadata (MuMsgFile *self, const char* path, const gchar* mdir, @@ -316,46 +307,10 @@ static size_t get_size (MuMsgFile *self) { g_return_val_if_fail (self, 0); - return self->_size; } -static char* -to_lower (char *s) -{ - char *t = s; - while (t&&*t) { - t[0] = g_ascii_tolower(t[0]); - ++t; - } - return s; -} - - -static char* -get_prio_header_field (MuMsgFile *self) -{ - const char *str; - GMimeObject *obj; - - obj = GMIME_OBJECT(self->_mime_msg); - - str = g_mime_object_get_header (obj, "Precedence"); - if (!str) - str = g_mime_object_get_header (obj, "X-Priority"); - if (!str) - str = g_mime_object_get_header (obj, "Importance"); - /* NOTE: "X-MSMail-Priority" is never seen without "X-Priority" */ - /* if (!str) */ - /* str = g_mime_object_get_header (obj, "X-MSMail-Priority"); */ - if (str) - return (to_lower(g_strdup(str))); - else - return NULL; -} - - static MuMsgPrio parse_prio_str (const char* priostr) { @@ -379,7 +334,7 @@ parse_prio_str (const char* priostr) }; for (i = 0; i != G_N_ELEMENTS(str_prio); ++i) - if (g_strstr_len (priostr, -1, str_prio[i]._str) != NULL) + if (g_ascii_strcasecmp (priostr, str_prio[i]._str) == 0) return str_prio[i]._prio; /* e.g., last-fm uses 'fm-user'... as precedence */ @@ -389,38 +344,33 @@ parse_prio_str (const char* priostr) static MuMsgPrio get_prio (MuMsgFile *self) { - MuMsgPrio prio; - char* priostr; + GMimeObject *obj; + const char* priostr; g_return_val_if_fail (self, MU_MSG_PRIO_NONE); - priostr = get_prio_header_field (self); + obj = GMIME_OBJECT(self->_mime_msg); + + priostr = g_mime_object_get_header (obj, "Precedence"); if (!priostr) - return MU_MSG_PRIO_NORMAL; + priostr = g_mime_object_get_header (obj, "X-Priority"); + if (!priostr) + priostr = g_mime_object_get_header (obj, "Importance"); - prio = parse_prio_str (priostr); - g_free (priostr); - - return prio; + return priostr ? parse_prio_str (priostr) : MU_MSG_PRIO_NORMAL; } -struct _GetBodyData { - GMimeObject *_txt_part, *_html_part; - gboolean _want_html; -}; +struct _GetBodyData { GMimeObject *_txt_part, *_html_part;}; typedef struct _GetBodyData GetBodyData; - - static void get_body_cb (GMimeObject *parent, GMimeObject *part, GetBodyData *data) { GMimeContentType *ct; /* already found what we're looking for? */ - if ((data->_want_html && data->_html_part != NULL) || - (!data->_want_html && data->_txt_part != NULL)) + if (data->_html_part && data->_txt_part) return; ct = g_mime_object_get_content_type (part); @@ -433,12 +383,12 @@ get_body_cb (GMimeObject *parent, GMimeObject *part, GetBodyData *data) return; /* not the body */ /* is it right content type? */ - if (g_mime_content_type_is_type (ct, "text", "plain")) + if (!data->_txt_part && + g_mime_content_type_is_type (ct, "text", "plain")) data->_txt_part = part; - else if (g_mime_content_type_is_type (ct, "text", "html")) + else if (!data->_html_part && + g_mime_content_type_is_type (ct, "text", "html")) data->_html_part = part; - else - return; /* wrong type */ } @@ -566,10 +516,7 @@ mu_msg_mime_get_body_part (GMimeMessage *msg, gboolean decrypt, g_return_val_if_fail (GMIME_IS_MESSAGE(msg), NULL); memset (&data, 0, sizeof(GetBodyData)); - data._want_html = want_html; - - mu_mime_message_foreach (msg, - decrypt, + mu_mime_message_foreach (msg, decrypt, (GMimeObjectForeachFunc)get_body_cb, &data); if (want_html) @@ -667,8 +614,6 @@ get_concatenated_text (MuMsgFile *self, gboolean decrypt) } - - static gboolean contains (GSList *lst, const char *str) { @@ -683,12 +628,12 @@ static GSList* get_references (MuMsgFile *self) { GSList *msgids; - const char *str; unsigned u; const char *headers[] = { "References", "In-reply-to", NULL }; for (msgids = NULL, u = 0; headers[u]; ++u) { + char *str; const GMimeReferences *cur; GMimeReferences *mime_refs; @@ -697,6 +642,8 @@ get_references (MuMsgFile *self) continue; mime_refs = g_mime_references_decode (str); + g_free (str); + for (cur = mime_refs; cur; cur = g_mime_references_get_next(cur)) { const char* msgid; msgid = g_mime_references_get_message_id (cur); @@ -716,13 +663,17 @@ get_references (MuMsgFile *self) static GSList* get_tags (MuMsgFile *self) { - const char *hdr; + GSList *lst; + char *hdr; hdr = mu_msg_file_get_header (self, "X-Label"); if (!hdr) return NULL; - return mu_str_to_list (hdr, ',', TRUE); + lst = mu_str_to_list (hdr, ',', TRUE); + g_free (hdr); + + return lst; } @@ -761,7 +712,8 @@ recipient_type (MuMsgFieldId mfid) char* -mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid, gboolean *do_free) +mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid, + gboolean *do_free) { g_return_val_if_fail (self, NULL); g_return_val_if_fail (mu_msg_field_is_string(mfid), NULL); @@ -806,22 +758,15 @@ mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid, gboolean *do_free GSList* -mu_msg_file_get_str_list_field (MuMsgFile *self, MuMsgFieldId mfid, - gboolean *do_free) +mu_msg_file_get_str_list_field (MuMsgFile *self, MuMsgFieldId mfid) { g_return_val_if_fail (self, NULL); g_return_val_if_fail (mu_msg_field_is_string_list(mfid), NULL); switch (mfid) { - - case MU_MSG_FIELD_ID_REFS: - *do_free = TRUE; - return get_references (self); - case MU_MSG_FIELD_ID_TAGS: - *do_free = TRUE; - return get_tags (self); - default: - g_return_val_if_reached (NULL); + case MU_MSG_FIELD_ID_REFS: return get_references (self); + case MU_MSG_FIELD_ID_TAGS: return get_tags (self); + default: g_return_val_if_reached (NULL); } } @@ -854,7 +799,7 @@ mu_msg_file_get_num_field (MuMsgFile *self, const MuMsgFieldId mfid) } -const char* +char* mu_msg_file_get_header (MuMsgFile *self, const char *header) { const gchar *hdr; @@ -868,7 +813,7 @@ mu_msg_file_get_header (MuMsgFile *self, const char *header) hdr = g_mime_object_get_header (GMIME_OBJECT(self->_mime_msg), header); - return hdr ? free_string_later (self, mu_str_utf8ify(hdr)) : NULL; + return hdr ? mu_str_utf8ify(hdr) : NULL; } diff --git a/lib/mu-msg-file.h b/lib/mu-msg-file.h index 512ed530..ec844336 100644 --- a/lib/mu-msg-file.h +++ b/lib/mu-msg-file.h @@ -53,11 +53,9 @@ void mu_msg_file_destroy (MuMsgFile *self); * @param self a MuMsgFile instance * @param header a header (e.g. 'X-Mailer' or 'List-Id') * - * @return the value of the header or NULL if not found. Note, only - * valid as long as this MuMsgFile is valid -- before - * mu_msg_file_destroy + * @return the value of the header or NULL if not found; free with g_free */ -const char* mu_msg_file_get_header (MuMsgFile *self, const char *header); +char* mu_msg_file_get_header (MuMsgFile *self, const char *header); /** @@ -84,17 +82,10 @@ char* mu_msg_file_get_str_field (MuMsgFile *self, * * @param self a valid MuMsgFile * @param msfid the message field id to get (must be of type string-list) - * @param do_free receives TRUE or FALSE, conveying if this string - * should be owned & freed (TRUE) or not by caller. In case 'FALSE', - * this function should be treated as if it were returning a const - * GSList*, and note that in that case the string is only valid as long - * as the MuMsgFile is alive, ie. before mu_msg_file_destroy * - * @return a GSList*, or NULL + * @return a GSList*, or NULL; free with mu_str_free_list */ -GSList* mu_msg_file_get_str_list_field (MuMsgFile *self, - MuMsgFieldId msfid, - gboolean *do_free) +GSList* mu_msg_file_get_str_list_field (MuMsgFile *self, MuMsgFieldId msfid) G_GNUC_WARN_UNUSED_RESULT; diff --git a/lib/mu-msg-part.c b/lib/mu-msg-part.c index 73b22118..47426cf6 100644 --- a/lib/mu-msg-part.c +++ b/lib/mu-msg-part.c @@ -386,25 +386,27 @@ handle_encrypted_part (MuMsg *msg, return TRUE; } -static gboolean -looks_like_body (MuMsg *msg, GMimeObject *parent, MuMsgPart *msgpart) +/* check if the current part might be a body part, and, if so, update + * the msgpart struct */ +static void +check_if_body_part (MuMsg *msg, GMimeObject *mobj, MuMsgPart *msgpart) { - /* if we've already seen a body for this one, don't consider - * more */ - if (msg->_file->_body_seen) - return FALSE; + /* is it an attachment? if so, this one is not the body */ + if (msgpart->part_type & MU_MSG_PART_TYPE_ATTACHMENT) + return; - if (parent && - !GMIME_IS_MESSAGE_PART(parent) && - !GMIME_IS_MULTIPART(parent)) - return FALSE; /* probably not a body */ + /* is it a text part? */ + if (g_ascii_strcasecmp (msgpart->type, "text") != 0) + return; - if (g_strcmp0 (msgpart->type, "text") != 0) - return FALSE; /* probably not a body */ - - return TRUE; /* maybe a body part */ + /* we consider it a body part if it's an inline text/plain or + * text/html */ + if ((g_ascii_strcasecmp (msgpart->subtype, "plain") == 0) || + (g_ascii_strcasecmp (msgpart->subtype, "html") == 0)) + msgpart->part_type |= MU_MSG_PART_TYPE_BODY; } + /* call 'func' with information about this MIME-part */ static gboolean handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, @@ -423,19 +425,13 @@ handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, } msgpart.size = get_part_size (part); - msgpart.part_type = MU_MSG_PART_TYPE_LEAF; msgpart.part_type |= get_disposition ((GMimeObject*)part); - /* a top-level non-attachment text part is probably a body */ - if (looks_like_body (msg, parent, &msgpart)) { - msgpart.part_type |= MU_MSG_PART_TYPE_BODY; - /* remember that we (probably) saw the body */ - msg->_file->_body_seen = TRUE; - } + check_if_body_part (msg, (GMimeObject*)part, &msgpart); - msgpart.data = (gpointer)part; - msgpart.index = index; + msgpart.data = (gpointer)part; + msgpart.index = index; func (msg, &msgpart, user_data); diff --git a/lib/mu-msg-priv.h b/lib/mu-msg-priv.h index f55cea2a..579844f1 100644 --- a/lib/mu-msg-priv.h +++ b/lib/mu-msg-priv.h @@ -32,7 +32,6 @@ #include #include #include -#include #include "mu-msg-part.h" G_BEGIN_DECLS @@ -43,15 +42,6 @@ struct _MuMsgFile { size_t _size; char _path [PATH_MAX + 1]; char _maildir [PATH_MAX + 1]; - - /* when we iterate over the parts, remember whether - * the body has been seen already */ - gboolean _body_seen; - - /* list where we push allocated strings so we can - * free them when the struct gets destroyed - */ - GSList *_free_later; }; @@ -65,7 +55,12 @@ struct _MuMsg { MuMsgFile *_file; /* based on GMime, ie. a file on disc */ MuMsgDoc *_doc; /* based on Xapian::Document */ - MuMsgCache *_cache; + /* lists where we push allocated strings / GSLists of string + * so we can free them when the struct gets destroyed (and we + * can return them as 'const to callers) + */ + GSList *_free_later_str; + GSList *_free_later_lst; }; diff --git a/lib/mu-msg.c b/lib/mu-msg.c index bbb9cdfb..4e59a600 100644 --- a/lib/mu-msg.c +++ b/lib/mu-msg.c @@ -73,12 +73,7 @@ msg_new (void) MuMsg *self; self = g_slice_new0 (MuMsg); - self->_refcount = 1; - self->_cache = mu_msg_cache_new (); - - self->_file = NULL; - self->_doc = NULL; return self; } @@ -108,8 +103,6 @@ mu_msg_new_from_file (const char *path, const char *mdir, } - - MuMsg* mu_msg_new_from_doc (XapianDocument *doc, GError **err) { @@ -143,7 +136,13 @@ mu_msg_destroy (MuMsg *self) mu_msg_file_destroy (self->_file); mu_msg_doc_destroy (self->_doc); - mu_msg_cache_destroy (self->_cache); + + { /* cleanup the strings / lists we stored */ + mu_str_free_list (self->_free_later_str); + g_slist_foreach (self->_free_later_lst, + (GFunc)mu_str_free_list, NULL); + g_slist_free (self->_free_later_lst); + } g_slice_free (MuMsg, self); } @@ -169,46 +168,51 @@ mu_msg_unref (MuMsg *self) mu_msg_destroy (self); } +static const gchar* +free_later_str (MuMsg *self, gchar *str) +{ + if (str) + self->_free_later_str = + g_slist_prepend (self->_free_later_str, str); + return str; +} + +static const GSList* +free_later_lst (MuMsg *self, GSList *lst) +{ + if (lst) + self->_free_later_lst = + g_slist_prepend (self->_free_later_lst, lst); + return lst; +} + /* use this instead of mu_msg_get_path so we don't get into infinite * regress...*/ static const char* get_path (MuMsg *self) { - const char *path; char *val; gboolean do_free; - /* try to get the path from the cache */ - path = mu_msg_cache_str (self->_cache, MU_MSG_FIELD_ID_PATH); - if (path) - return path; + do_free = TRUE; + val = NULL; - /* nothing found yet? try the doc in case we are using that - * backend */ - val = NULL; if (self->_doc) - val = mu_msg_doc_get_str_field (self->_doc, - MU_MSG_FIELD_ID_PATH, - &do_free); + val = mu_msg_doc_get_str_field + (self->_doc, MU_MSG_FIELD_ID_PATH); /* not in the cache yet? try to get it from the file backend, * in case we are using that */ if (!val && self->_file) - val = mu_msg_file_get_str_field (self->_file, - MU_MSG_FIELD_ID_PATH, - &do_free); + val = mu_msg_file_get_str_field + (self->_file, MU_MSG_FIELD_ID_PATH, &do_free); - /* this cannot happen unless there are bugs in mu */ - if (!val) { + /* shouldn't happen */ + if (!val) g_warning ("%s: cannot find path", __FUNCTION__); - return NULL; - } - /* we found something */ - return mu_msg_cache_set_str (self->_cache, - MU_MSG_FIELD_ID_PATH, val, - do_free); + return free_later_str (self, val); } @@ -245,57 +249,39 @@ mu_msg_unload_msg_file (MuMsg *msg) } - static const GSList* get_str_list_field (MuMsg *self, MuMsgFieldId mfid) { - gboolean do_free; GSList *val; - /* first we try the cache */ - if (mu_msg_cache_cached (self->_cache, mfid)) - return mu_msg_cache_str_list (self->_cache, mfid); - - /* if it's not in the cache but it is a value retrievable from - * the doc backend, use that */ val = NULL; + if (self->_doc && mu_msg_field_xapian_value (mfid)) - val = mu_msg_doc_get_str_list_field (self->_doc, - mfid, &do_free); - else { + val = mu_msg_doc_get_str_list_field (self->_doc, mfid); + if (!val) { /* if we don't have a file object yet, we need to * create it from the file on disk */ if (!mu_msg_load_msg_file (self, NULL)) return NULL; - val = mu_msg_file_get_str_list_field (self->_file, mfid, - &do_free); + val = mu_msg_file_get_str_list_field (self->_file, mfid); } - /* if we get a string that needs freeing, we tell the cache to - * mark the string as such, so it will be freed when the cache - * is freed (or when the value is overwritten) */ - return mu_msg_cache_set_str_list (self->_cache, mfid, val, - do_free); + return free_later_lst (self, val); } - - static const char* get_str_field (MuMsg *self, MuMsgFieldId mfid) { - gboolean do_free; char *val; + gboolean do_free; - /* first we try the cache */ - if (mu_msg_cache_cached (self->_cache, mfid)) - return mu_msg_cache_str (self->_cache, mfid); - - /* if it's not in the cache but it is a value retrievable from - * the doc backend, use that */ + do_free = FALSE; val = NULL; + if (self->_doc && mu_msg_field_xapian_value (mfid)) - val = mu_msg_doc_get_str_field (self->_doc, mfid, &do_free); + val = mu_msg_doc_get_str_field (self->_doc, mfid); + else if (mu_msg_field_gmime (mfid)) { /* if we don't have a file object yet, we need to * create it from the file on disk */ @@ -304,13 +290,10 @@ get_str_field (MuMsg *self, MuMsgFieldId mfid) val = mu_msg_file_get_str_field (self->_file, mfid, &do_free); } else { g_warning ("%s: cannot retrieve field", __FUNCTION__); - return NULL; + val = NULL; } - /* if we get a string that needs freeing, we tell the cache to - * mark the string as such, so it will be freed when the cache - * is freed (or when the value is overwritten) */ - return mu_msg_cache_set_str (self->_cache, mfid, val, do_free); + return do_free ? free_later_str (self, val) : val; } @@ -319,12 +302,6 @@ get_num_field (MuMsg *self, MuMsgFieldId mfid) { guint64 val; - /* first try the cache */ - if (mu_msg_cache_cached (self->_cache, mfid)) - return mu_msg_cache_num (self->_cache, mfid); - - /* if it's not in the cache but it is a value retrievable from - * the doc backend, use that */ val = -1; if (self->_doc && mu_msg_field_xapian_value (mfid)) val = mu_msg_doc_get_num_field (self->_doc, mfid); @@ -336,7 +313,7 @@ get_num_field (MuMsg *self, MuMsgFieldId mfid) val = mu_msg_file_get_num_field (self->_file, mfid); } - return mu_msg_cache_set_num (self->_cache, mfid, val); + return val; } @@ -833,8 +810,6 @@ get_target_mdir (MuMsg *msg, const char *target_maildir, GError **err) } - - /* * move a msg to another maildir, trying to maintain 'integrity', * ie. msg in 'new/' will go to new/, one in cur/ goes to cur/. be @@ -861,24 +836,14 @@ mu_msg_move_to_maildir (MuMsg *self, const char *maildir, /* update the message path and the flags; they may have * changed */ - if (newfullpath) { - mu_msg_cache_set_str (self->_cache, MU_MSG_FIELD_ID_PATH, newfullpath, - TRUE); /* the cache will free the string */ - mu_msg_cache_set_str (self->_cache, MU_MSG_FIELD_ID_MAILDIR, - g_strdup(maildir), TRUE); - /* the cache will free the string */ + if (!newfullpath) + return FALSE; - /* the contentflags haven't changed, so make sure they persist */ - flags |= mu_msg_get_flags (self) & - (MU_FLAG_HAS_ATTACH|MU_FLAG_ENCRYPTED|MU_FLAG_SIGNED); - /* update the pseudo-flag as well */ - if (!(flags & MU_FLAG_NEW) && (flags & MU_FLAG_SEEN)) - flags &= ~MU_FLAG_UNREAD; - else - flags |= MU_FLAG_UNREAD; + /* clear the old backends */ + mu_msg_doc_destroy (self->_doc); + mu_msg_file_destroy (self->_file); - mu_msg_cache_set_num (self->_cache, MU_MSG_FIELD_ID_FLAGS, flags); - } - - return newfullpath ? TRUE : FALSE; + /* and create a new one */ + self->_file = mu_msg_file_new (newfullpath, targetmdir, err); + return self->_file ? TRUE : FALSE; }