From 53b87a79ebbbd1d8df33f70e578be537877727c8 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Mon, 9 May 2011 02:58:33 +0300 Subject: [PATCH] * WIP: refactor mu-msg -- mu-msg-file --- src/Makefile.am | 6 +- src/mu-cmd-extract.c | 4 +- src/mu-cmd.c | 2 +- src/mu-index.c | 2 +- src/mu-msg-contact.c | 4 +- src/mu-msg-fields.c | 28 +- src/mu-msg-fields.h | 13 +- src/mu-msg-file.c | 863 +++++++++++++++++++++++++++++++++- src/mu-msg-file.h | 44 ++ src/mu-msg-iter.cc | 2 +- src/mu-msg-iter.h | 2 +- src/mu-msg-part.c | 9 +- src/mu-msg-prio.c | 5 + src/mu-msg-prio.h | 2 +- src/mu-msg-priv.h | 40 +- src/mu-msg.c | 947 ++++++-------------------------------- src/mu-msg.h | 21 +- src/mu-runtime.c | 7 +- src/tests/test-mu-cmd.c | 2 - src/tests/test-mu-msg.c | 20 +- src/tests/test-mu-query.c | 8 +- src/tests/test-mu-store.c | 17 +- toys/mug/mug-msg-view.c | 2 +- toys/mug2/mug-msg-view.c | 2 +- 24 files changed, 1138 insertions(+), 914 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index c7b811cc..415d4e9e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -72,6 +72,8 @@ libmu_la_SOURCES= \ mu-msg-data-cache.h \ mu-msg-fields.c \ mu-msg-fields.h \ + mu-msg-file.c \ + mu-msg-file.h \ mu-msg-flags.c \ mu-msg-flags.h \ mu-msg-iter-priv.hh \ @@ -101,10 +103,6 @@ libmu_la_SOURCES= \ mu-util.h -# mu-msg-file.h \ -# mu-msg-file.c \ -# - libmu_la_LIBADD= \ $(XAPIAN_LIBS) \ $(GMIME_LIBS) \ diff --git a/src/mu-cmd-extract.c b/src/mu-cmd-extract.c index bb35a542..48205b1c 100644 --- a/src/mu-cmd-extract.c +++ b/src/mu-cmd-extract.c @@ -190,7 +190,7 @@ save_parts (const char *path, MuConfig *opts) GError *err; err = NULL; - msg = mu_msg_new (path, NULL, &err); + msg = mu_msg_new_from_file (path, NULL, &err); if (!msg) { g_warning ("error: %s", err->message); g_error_free (err); @@ -239,7 +239,7 @@ show_parts (const char* path, MuConfig *opts) GError *err; err = NULL; - msg = mu_msg_new (path, NULL, &err); + msg = mu_msg_new_from_file (path, NULL, &err); if (!msg) { g_warning ("error: %s", err->message); g_error_free (err); diff --git a/src/mu-cmd.c b/src/mu-cmd.c index e9673792..4eb03f68 100644 --- a/src/mu-cmd.c +++ b/src/mu-cmd.c @@ -82,7 +82,7 @@ mu_cmd_view (MuConfig *opts) for (i = 1, rv = MU_EXITCODE_OK; opts->params[i] && rv == MU_EXITCODE_OK; ++i) { GError *err = NULL; - MuMsg *msg = mu_msg_new (opts->params[i], NULL, &err); + MuMsg *msg = mu_msg_new_from_file (opts->params[i], NULL, &err); if (!msg) { g_warning ("error: %s", err->message); g_error_free (err); diff --git a/src/mu-index.c b/src/mu-index.c index 850d7f02..5a324891 100644 --- a/src/mu-index.c +++ b/src/mu-index.c @@ -141,7 +141,7 @@ insert_or_update_maybe (const char* fullpath, const char* mdir, return MU_OK; /* nothing to do for this one */ err = NULL; - msg = mu_msg_new (fullpath, mdir, &err); + msg = mu_msg_new_from_file (fullpath, mdir, &err); if ((G_UNLIKELY(!msg))) { g_warning ("%s: failed to create mu_msg for %s", __FUNCTION__, fullpath); diff --git a/src/mu-msg-contact.c b/src/mu-msg-contact.c index 40ba8ed5..3f621bb1 100644 --- a/src/mu-msg-contact.c +++ b/src/mu-msg-contact.c @@ -127,7 +127,7 @@ get_contacts_from (MuMsg *msg, MuMsgContactForeachFunc func, * internet_address_parse_string has the nice side-effect of * splitting in names and addresses for us */ lst = internet_address_list_parse_string ( - g_mime_message_get_sender (msg->_mime_msg)); + g_mime_message_get_sender (msg->_file->_mime_msg)); if (lst) { address_list_foreach (lst, MU_MSG_CONTACT_TYPE_FROM, @@ -159,7 +159,7 @@ mu_msg_contact_foreach (MuMsg *msg, MuMsgContactForeachFunc func, /* get to, cc, bcc */ for (i = 0; i != G_N_ELEMENTS(ctypes); ++i) { InternetAddressList *addrlist; - addrlist = g_mime_message_get_recipients (msg->_mime_msg, + addrlist = g_mime_message_get_recipients (msg->_file->_mime_msg, ctypes[i]._gmime_type); address_list_foreach (addrlist, ctypes[i]._type, func, user_data); } diff --git a/src/mu-msg-fields.c b/src/mu-msg-fields.c index 5f7c678b..d0573674 100644 --- a/src/mu-msg-fields.c +++ b/src/mu-msg-fields.c @@ -29,13 +29,20 @@ * must be in the value (at least when using MuMsgIter) */ enum _FieldFlags { - FLAG_GMIME = 1 << 0, /* field retrieved through gmime */ - FLAG_XAPIAN_INDEX = 1 << 1, /* field is indexed in xapian */ - FLAG_XAPIAN_TERM = 1 << 2, /* field stored as term in xapian */ - FLAG_XAPIAN_VALUE = 1 << 3, /* field stored as value in xapian */ - FLAG_XAPIAN_CONTACT = 1 << 4, /* field contains an e-mail-addr */ - FLAG_XAPIAN_ESCAPE = 1 << 5, /* field needs escaping for xapian */ - FLAG_NORMALIZE = 1 << 6 /* field needs fix for case/accents */ + FLAG_GMIME = 1 << 0, /* field retrieved through + * gmime */ + FLAG_XAPIAN_INDEX = 1 << 1, /* field is indexed in + * xapian */ + FLAG_XAPIAN_TERM = 1 << 2, /* field stored as term in + * xapian */ + FLAG_XAPIAN_VALUE = 1 << 3, /* field stored as value in + * xapian */ + FLAG_XAPIAN_CONTACT = 1 << 4, /* field contains one or more + * e-mail-addresses */ + FLAG_XAPIAN_ESCAPE = 1 << 5, /* field needs escaping for + * xapian */ + FLAG_NORMALIZE = 1 << 6 /* field needs flattening for + * case/accents */ }; typedef enum _FieldFlags FieldFlags; @@ -173,6 +180,13 @@ static const MuMsgField FIELD_DATA[] = { MU_MSG_FIELD_TYPE_STRING, "refs", 'r', 'R', FLAG_GMIME | FLAG_XAPIAN_VALUE + }, + + { + MU_MSG_FIELD_ID_SUMMARY, + MU_MSG_FIELD_TYPE_STRING, + NULL, 0, 0, + FLAG_GMIME } }; diff --git a/src/mu-msg-fields.h b/src/mu-msg-fields.h index f5009f88..84fc4f5f 100644 --- a/src/mu-msg-fields.h +++ b/src/mu-msg-fields.h @@ -44,6 +44,7 @@ enum _MuMsgFieldId { MU_MSG_FIELD_ID_MSGID, MU_MSG_FIELD_ID_TIMESTAMP, MU_MSG_FIELD_ID_REFS, + MU_MSG_FIELD_ID_SUMMARY, MU_MSG_FIELD_ID_NUM, @@ -128,6 +129,16 @@ char mu_msg_field_xapian_prefix (MuMsgFieldId id) G_GNUC_PURE; MuMsgFieldType mu_msg_field_type (MuMsgFieldId id) G_GNUC_PURE; +/** + * is the field a string? + * + * @param id a MuMsgFieldId + * + * @return TRUE if the field a string, FALSE otherwise + */ +#define mu_msg_field_is_string(MFID)\ + (mu_msg_field_type((MFID))==MU_MSG_FIELD_TYPE_STRING?TRUE:FALSE) + /** * is the field numeric (has type MU_MSG_FIELD_TYPE_(BYTESIZE|TIME_T|INT))? * @@ -235,8 +246,6 @@ MuMsgFieldId mu_msg_field_id_from_name (const char* str, */ MuMsgFieldId mu_msg_field_id_from_shortcut (char kar, gboolean err) G_GNUC_PURE; - - G_END_DECLS #endif /*__MU_MSG_FIELDS_H__*/ diff --git a/src/mu-msg-file.c b/src/mu-msg-file.c index 7a14f708..4847974e 100644 --- a/src/mu-msg-file.c +++ b/src/mu-msg-file.c @@ -1,5 +1,5 @@ /* -** Copyright (C) 2010 Dirk-Jan C. Binnema +** 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 @@ -16,3 +16,864 @@ ** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mu-util.h" +#include "mu-str.h" +#include "mu-maildir.h" +#include "mu-msg-priv.h" + +static gboolean init_file_metadata (MuMsgFile *self, const char* path, const char *mdir, + GError **err); +static gboolean init_mime_msg (MuMsgFile *msg, GError **err); + + +#define CACHE(MFID) (self->_str_cache[(MFID)]) +#define SET_CACHE(MFID,V)(self->_str_cache[(MFID)]=(V)) + +MuMsgFile* +mu_msg_file_new (const char* filepath, const char *mdir, GError **err) +{ + int i; + MuMsgFile *self; + + g_return_val_if_fail (filepath, NULL); + self = g_slice_new0 (MuMsgFile); + + if (!init_file_metadata (self, filepath, mdir, err)) { + mu_msg_file_destroy (self); + return NULL; + } + + if (!init_mime_msg (self, err)) { + mu_msg_file_destroy (self); + return NULL; + } + + for (i = 0; i != MU_MSG_FIELD_ID_NUM; ++i) + SET_CACHE(i,NULL); + + return self; +} + + +void +mu_msg_file_destroy (MuMsgFile *self) +{ + int i; + + if (!self) + return; + + for (i = 0; i != MU_MSG_FIELD_ID_NUM; ++i) + g_free (self->_str_cache[i]); + + if (self->_mime_msg) + g_object_unref (self->_mime_msg); + + g_slice_free (MuMsgFile, self); +} + + +static gboolean +init_file_metadata (MuMsgFile *self, const char* path, const gchar* mdir, + GError **err) +{ + struct stat statbuf; + + if (access (path, R_OK) != 0) { + g_set_error (err, 0, MU_ERROR_FILE, + "cannot read file %s: %s", + path, strerror(errno)); + return FALSE; + } + + if (stat (path, &statbuf) < 0) { + g_set_error (err, 0, MU_ERROR_FILE, + "cannot stat %s: %s", + path, strerror(errno)); + return FALSE; + } + + if (!S_ISREG(statbuf.st_mode)) { + g_set_error (err, 0, MU_ERROR_FILE, + "not a regular file: %s", path); + return FALSE; + } + + self->_timestamp = statbuf.st_mtime; + /* size_t should be enough for message size... */ + + self->_size = (size_t)statbuf.st_size; + + SET_CACHE(MU_MSG_FIELD_ID_PATH, g_strdup(path)); + SET_CACHE(MU_MSG_FIELD_ID_MAILDIR, mdir ? g_strdup(mdir): NULL); + + return TRUE; +} + + + +static GMimeStream* +get_mime_stream (MuMsgFile *self, GError **err) +{ + FILE *file; + GMimeStream *stream; + + file = fopen (self->_str_cache [MU_MSG_FIELD_ID_PATH], "r"); + if (!file) { + g_set_error (err, 0, MU_ERROR_FILE, + "cannot open %s: %s", + self->_str_cache [MU_MSG_FIELD_ID_PATH], + strerror (errno)); + return NULL; + } + + stream = g_mime_stream_file_new (file); + if (!stream) { + g_set_error (err, 0, MU_ERROR_GMIME, + "cannot create mime stream for %s", + self->_str_cache [MU_MSG_FIELD_ID_PATH]); + fclose (file); + return NULL; + } + + return stream; +} + +static gboolean +init_mime_msg (MuMsgFile *self, GError **err) +{ + GMimeStream *stream; + GMimeParser *parser; + + stream = get_mime_stream (self, err); + if (!stream) + return FALSE; + + parser = g_mime_parser_new_with_stream (stream); + g_object_unref (stream); + if (!parser) { + g_set_error (err, 0, MU_ERROR_GMIME, + "cannot create mime parser for %s", + self->_str_cache [MU_MSG_FIELD_ID_PATH]); + return FALSE; + } + + self->_mime_msg = g_mime_parser_construct_message (parser); + g_object_unref (parser); + if (!self->_mime_msg) { + g_set_error (err, 0, MU_ERROR_GMIME, + "cannot construct mime message for %s", + self->_str_cache [MU_MSG_FIELD_ID_PATH]); + return FALSE; + } + + return TRUE; +} + + +static const char* +get_recipient (MuMsgFile *self, GMimeRecipientType rtype) +{ + const char *val; + char *recep; + InternetAddressList *receps; + + switch (rtype) { + case GMIME_RECIPIENT_TYPE_TO: + val = CACHE(MU_MSG_FIELD_ID_TO); + if (val) return val; else break; + case GMIME_RECIPIENT_TYPE_CC: + val = CACHE(MU_MSG_FIELD_ID_CC); + if (val) return val; else break; + case GMIME_RECIPIENT_TYPE_BCC: + val = CACHE(MU_MSG_FIELD_ID_BCC); + if (val) return val; else break; + default: g_return_val_if_reached (NULL); + } + + receps = g_mime_message_get_recipients (self->_mime_msg, rtype); + recep = (char*)internet_address_list_to_string (receps, TRUE); + + if (mu_str_is_empty(recep)) { + g_free (recep); + return NULL; + } + + switch (rtype) { + + case GMIME_RECIPIENT_TYPE_TO: + return SET_CACHE (MU_MSG_FIELD_ID_TO, recep); + + case GMIME_RECIPIENT_TYPE_CC: + return SET_CACHE (MU_MSG_FIELD_ID_CC, recep); + + case GMIME_RECIPIENT_TYPE_BCC: + return SET_CACHE (MU_MSG_FIELD_ID_BCC, recep); + + default: g_return_val_if_reached (NULL); + } +} + + + +static gboolean +part_looks_like_attachment (GMimeObject *part) +{ + GMimeContentDisposition *disp; + const char *str; + + disp = g_mime_object_get_content_disposition (part); + if (!GMIME_IS_CONTENT_DISPOSITION(disp)) + return FALSE; /* no content disp? prob not + * an attachment. */ + + str = g_mime_content_disposition_get_disposition (disp); + + /* ok, it says it's an attachment, so it probably is... */ + if (!str) + return TRUE; + if (strcmp (str, GMIME_DISPOSITION_ATTACHMENT) == 0) + return TRUE; + else if (strcmp (str, GMIME_DISPOSITION_INLINE) == 0) { + /* inline-images are also considered attachments... */ + GMimeContentType *ct; + ct = g_mime_object_get_content_type (part); + if (ct) + return g_mime_content_type_is_type + (ct, "image", "*"); + } + + return FALSE; +} + + +static void +msg_cflags_cb (GMimeObject *parent, GMimeObject *part, MuMsgFlags *flags) +{ + if (*flags & MU_MSG_FLAG_HAS_ATTACH) + return; + + if (!GMIME_IS_PART(part)) + return; + + if (part_looks_like_attachment(part)) + *flags |= MU_MSG_FLAG_HAS_ATTACH; +} + + + +static MuMsgFlags +get_content_flags (MuMsgFile *self) +{ + GMimeContentType *ctype; + MuMsgFlags flags; + GMimeObject *part; + + if (!GMIME_IS_MESSAGE(self->_mime_msg)) + return MU_MSG_FLAG_NONE; + + flags = 0; + g_mime_message_foreach (self->_mime_msg, + (GMimeObjectForeachFunc)msg_cflags_cb, + &flags); + + /* note: signed or encrypted status for a message is determined by + * the top-level mime-part + */ + if ((part = g_mime_message_get_mime_part(self->_mime_msg))) { + ctype = g_mime_object_get_content_type + (GMIME_OBJECT(part)); + if (!ctype) { + g_warning ("not a content type!"); + return 0; + } + + if (ctype) { + if (g_mime_content_type_is_type + (ctype,"*", "signed")) + flags |= MU_MSG_FLAG_SIGNED; + if (g_mime_content_type_is_type + (ctype,"*", "encrypted")) + flags |= MU_MSG_FLAG_ENCRYPTED; + } + } else + g_warning ("no top level mime part found"); + + return flags; +} + + +static MuMsgFlags +get_flags (MuMsgFile *self) +{ + g_return_val_if_fail (self, MU_MSG_FLAG_NONE); + + if (self->_flags == MU_MSG_FLAG_NONE) { + self->_flags = mu_maildir_get_flags_from_path + (CACHE(MU_MSG_FIELD_ID_PATH)); + self->_flags |= get_content_flags (self); + } + + return self->_flags; +} + + +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, "X-Priority"); + if (!str) + str = g_mime_object_get_header (obj, "X-MSMail-Priority"); + if (!str) + str = g_mime_object_get_header (obj, "Importance"); + if (!str) + str = g_mime_object_get_header (obj, "Precedence"); + if (str) + return (to_lower(g_strdup(str))); + else + return NULL; +} + + +static MuMsgPrio +parse_prio_str (const char* priostr) +{ + int i; + struct { + const char* _str; + MuMsgPrio _prio; + } str_prio[] = { + { "high", MU_MSG_PRIO_HIGH }, + { "1", MU_MSG_PRIO_HIGH }, + { "2", MU_MSG_PRIO_HIGH }, + + { "normal", MU_MSG_PRIO_NORMAL }, + { "3", MU_MSG_PRIO_NORMAL }, + + { "low", MU_MSG_PRIO_LOW }, + { "list", MU_MSG_PRIO_LOW }, + { "bulk", MU_MSG_PRIO_LOW }, + { "4", MU_MSG_PRIO_LOW }, + { "5", MU_MSG_PRIO_LOW } + }; + + for (i = 0; i != G_N_ELEMENTS(str_prio); ++i) + if (g_strstr_len (priostr, -1, str_prio[i]._str) != NULL) + return str_prio[i]._prio; + + /* e.g., last-fm uses 'fm-user'... as precedence */ + return MU_MSG_PRIO_NORMAL; +} + +static MuMsgPrio +get_prio (MuMsgFile *self) +{ + char* priostr; + + g_return_val_if_fail (self, 0); + + if (self->_prio != MU_MSG_PRIO_NONE) + return self->_prio; + + priostr = get_prio_header_field (self); + if (!priostr) + return MU_MSG_PRIO_NORMAL; + + self->_prio = parse_prio_str (priostr); + g_free (priostr); + + return self->_prio; +} + + +/* static const char* */ +/* get_header (MuMsgFile *self, const char* header) */ +/* { */ +/* g_return_val_if_fail (msg, NULL); */ +/* g_return_val_if_fail (header, NULL); */ + +/* return g_mime_object_get_header (GMIME_OBJECT(self->_mime_msg), */ +/* header); */ +/* } */ + + +struct _GetBodyData { + GMimeObject *_txt_part, *_html_part; + gboolean _want_html; +}; +typedef struct _GetBodyData GetBodyData; + + +static gboolean +looks_like_attachment (GMimeObject *part) +{ + const char *str; + GMimeContentDisposition *disp; + + disp = g_mime_object_get_content_disposition (GMIME_OBJECT(part)); + if (!GMIME_IS_CONTENT_DISPOSITION(disp)) + return FALSE; + + str = g_mime_content_disposition_get_disposition (disp); + if (!str) + return FALSE; + + if (strcmp(str,GMIME_DISPOSITION_INLINE) == 0) + return FALSE; /* inline, so it's not an attachment */ + + return TRUE; /* looks like an attachment */ +} + +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)) + return; + + ct = g_mime_object_get_content_type (part); + if (!GMIME_IS_CONTENT_TYPE(ct)) { + g_warning ("not a content type!"); + return; + } + + if (looks_like_attachment (part)) + return; /* not the body */ + + /* is it right content type? */ + if (g_mime_content_type_is_type (ct, "text", "plain")) + data->_txt_part = part; + else if (g_mime_content_type_is_type (ct, "text", "html")) + data->_html_part = part; + else + return; /* wrong type */ +} + + +/* turn \0-terminated buf into ascii (which is a utf8 subset); convert + * any non-ascii into '.' + */ +static void +asciify (char *buf) +{ + char *c; + for (c = buf; c && *c; ++c) + if (!isascii(*c)) + c[0] = '.'; +} + + + +static gchar* +text_to_utf8 (const char* buffer, const char *charset) +{ + GError *err; + gchar * utf8; + + err = NULL; + utf8 = g_convert_with_fallback (buffer, -1, "UTF-8", + charset, (gchar*)".", + NULL, NULL, &err); + if (!utf8) { + MU_WRITE_LOG ("%s: conversion failed from %s: %s", + __FUNCTION__, charset, + err ? err->message : ""); + if (err) + g_error_free (err); + } + + return utf8; +} + + +/* NOTE: buffer will be *freed* or returned unchanged */ +static char* +convert_to_utf8 (GMimePart *part, char *buffer) +{ + GMimeContentType *ctype; + const char* charset; + unsigned char *cur; + + /* optimization: if the buffer is plain ascii, no conversion + * is done... */ + for (cur = (unsigned char*)buffer; *cur && *cur < 0x80; ++cur); + if (*cur == '\0') + return buffer; + + ctype = g_mime_object_get_content_type (GMIME_OBJECT(part)); + g_return_val_if_fail (GMIME_IS_CONTENT_TYPE(ctype), NULL); + + charset = g_mime_content_type_get_parameter (ctype, "charset"); + if (charset) + charset = g_mime_charset_iconv_name (charset); + + /* of course, the charset specified may be incorrect... */ + if (charset) { + char *utf8 = text_to_utf8 (buffer, charset); + if (utf8) { + g_free (buffer); + return utf8; + } + } + + /* hmmm.... no charset at all, or conversion failed; ugly + * hack: replace all non-ascii chars with '.' + * instead... TODO: come up with something better */ + asciify (buffer); + return buffer; +} + + +static gchar* +stream_to_string (GMimeStream *stream, size_t buflen) +{ + char *buffer; + ssize_t bytes; + + buffer = g_new(char, buflen + 1); + g_mime_stream_reset (stream); + + /* we read everything in one go */ + bytes = g_mime_stream_read (stream, buffer, buflen); + if (bytes < 0) { + g_warning ("%s: failed to read from stream", __FUNCTION__); + g_free (buffer); + return NULL; + } + + buffer[bytes]='\0'; + + return buffer; +} + + +static gchar* +part_to_string (GMimePart *part, gboolean *err) +{ + GMimeDataWrapper *wrapper; + GMimeStream *stream = NULL; + ssize_t buflen; + char *buffer = NULL; + + *err = TRUE; + g_return_val_if_fail (GMIME_IS_PART(part), NULL); + + wrapper = g_mime_part_get_content_object (part); + if (!wrapper) { + /* this happens with invalid mails */ + g_debug ("failed to create data wrapper"); + goto cleanup; + } + + stream = g_mime_stream_mem_new (); + if (!stream) { + g_warning ("failed to create mem stream"); + goto cleanup; + } + + buflen = g_mime_data_wrapper_write_to_stream (wrapper, stream); + if (buflen <= 0) {/* empty buffer, not an error */ + *err = FALSE; + goto cleanup; + } + + buffer = stream_to_string (stream, (size_t)buflen); + + /* convert_to_utf8 will free the old 'buffer' if needed */ + buffer = convert_to_utf8 (part, buffer); + + *err = FALSE; + +cleanup: + if (stream) + g_object_unref (G_OBJECT(stream)); + + return buffer; +} + + +static char* +get_body (MuMsgFile *self, gboolean want_html) +{ + GetBodyData data; + char *str; + gboolean err; + + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (GMIME_IS_MESSAGE(self->_mime_msg), NULL); + + memset (&data, 0, sizeof(GetBodyData)); + data._want_html = want_html; + + err = FALSE; + g_mime_message_foreach (self->_mime_msg, + (GMimeObjectForeachFunc)get_body_cb, + &data); + if (want_html) + str = data._html_part ? + part_to_string (GMIME_PART(data._html_part), &err) : + NULL; + else + str = data._txt_part ? + part_to_string (GMIME_PART(data._txt_part), &err) : + NULL; + + /* note, str may be NULL (no body), but that's not necessarily + * an error; we only warn when an actual error occured */ + if (err) + g_warning ("error occured while retrieving %s body" + "for message %s", + want_html ? "html" : "text", + (CACHE(MU_MSG_FIELD_ID_PATH))); + return str; +} + +static const char* +get_body_html (MuMsgFile *self) +{ + g_return_val_if_fail (self, NULL); + + if (CACHE(MU_MSG_FIELD_ID_BODY_HTML)) + return CACHE(MU_MSG_FIELD_ID_BODY_HTML); + else + return SET_CACHE(MU_MSG_FIELD_ID_BODY_HTML, + get_body (self, TRUE)); +} + + +static const char* +get_body_text (MuMsgFile *self) +{ + g_return_val_if_fail (self, NULL); + + if (CACHE(MU_MSG_FIELD_ID_BODY_TEXT)) + return CACHE(MU_MSG_FIELD_ID_BODY_TEXT); + else + return SET_CACHE(MU_MSG_FIELD_ID_BODY_TEXT, + get_body (self, FALSE)); +} + +static const char* +get_summary (MuMsgFile *self, size_t max_lines) +{ + const char *body; + + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (max_lines > 0, NULL); + + if (CACHE(MU_MSG_FIELD_ID_SUMMARY)) + return CACHE(MU_MSG_FIELD_ID_SUMMARY); + + /* nope; calculate it */ + body = get_body_text (self); + if (!body) + return NULL; /* there was no text body */ + + return SET_CACHE(MU_MSG_FIELD_ID_SUMMARY, + mu_str_summarize (body, max_lines)); +} + + +static GSList* +get_msgids_from_header (MuMsgFile *self, const char* header) +{ + GSList *msgids; + const char *str; + + msgids = NULL; + str = g_mime_object_get_header (GMIME_OBJECT(self->_mime_msg), + header); + + /* get stuff from the 'references' header */ + if (str) { + const GMimeReferences *cur; + GMimeReferences *mime_refs; + mime_refs = g_mime_references_decode (str); + for (cur = mime_refs; cur; cur = g_mime_references_get_next(cur)) { + const char* msgid; + msgid = g_mime_references_get_message_id (cur); + if (msgid) + msgids = g_slist_prepend (msgids, g_strdup (msgid)); + } + g_mime_references_free (mime_refs); + } + + return g_slist_reverse (msgids); +} + + + +static const GSList* +get_references (MuMsgFile *self) +{ + GSList *refs, *inreply; + + g_return_val_if_fail (self, NULL); + + if (self->_refs) + return self->_refs; + + refs = get_msgids_from_header (self, "References"); + + /* now, add in-reply-to:, we only take the first one if there + * are more */ + inreply = get_msgids_from_header (self, "In-reply-to"); + if (inreply) { + refs = g_slist_prepend (refs, g_strdup ((gchar*)inreply->data)); + g_slist_foreach (inreply, (GFunc)g_free, NULL); + g_slist_free (inreply); + } + + /* put in proper order */ + self->_refs = g_slist_reverse (refs); + + return self->_refs; +} + +static const char* +get_references_str (MuMsgFile *self) +{ + const GSList *refs; + gchar *refsstr; + + g_return_val_if_fail (self, NULL); + + if (CACHE(MU_MSG_FIELD_ID_REFS)) + return CACHE(MU_MSG_FIELD_ID_REFS); + + refsstr = NULL; + refs = get_references (self); + if (refs) { + const GSList *cur; + for (cur = refs; cur; cur = g_slist_next(cur)) { + char *tmp; + tmp = g_strdup_printf ("%s%s%s", + refsstr ? refsstr : "", + refsstr ? "," : "", + g_strdup((gchar*)cur->data)); + g_free (refsstr); + refsstr = tmp; + } + } + + return SET_CACHE(MU_MSG_FIELD_ID_REFS, refsstr); +} + + + + +const char* +mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid) +{ + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (mu_msg_field_is_string(mfid), NULL); + + switch (mfid) { + + case MU_MSG_FIELD_ID_BCC: + return get_recipient (self, GMIME_RECIPIENT_TYPE_BCC); + + case MU_MSG_FIELD_ID_BODY_TEXT: return get_body_text (self); + case MU_MSG_FIELD_ID_BODY_HTML: return get_body_html (self); + + case MU_MSG_FIELD_ID_CC: + return get_recipient (self, GMIME_RECIPIENT_TYPE_CC); + + case MU_MSG_FIELD_ID_FROM: + return g_mime_message_get_sender (self->_mime_msg); + + case MU_MSG_FIELD_ID_PATH: + return CACHE(MU_MSG_FIELD_ID_PATH); + + case MU_MSG_FIELD_ID_SUBJECT: + return g_mime_message_get_subject (self->_mime_msg); + + case MU_MSG_FIELD_ID_TO: + return get_recipient (self, GMIME_RECIPIENT_TYPE_TO); + + case MU_MSG_FIELD_ID_MSGID: + return g_mime_message_get_message_id (self->_mime_msg); + + case MU_MSG_FIELD_ID_MAILDIR: + return CACHE(MU_MSG_FIELD_ID_MAILDIR); + + case MU_MSG_FIELD_ID_REFS: + return get_references_str (self); + + case MU_MSG_FIELD_ID_SUMMARY: + return get_summary (self, 5); + + default: + g_return_val_if_reached (NULL); + } +} + +gint64 +mu_msg_file_get_num_field (MuMsgFile *self, const MuMsgFieldId mfid) +{ + 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: { + time_t t; + g_mime_message_get_date (self->_mime_msg, &t, NULL); + return (time_t)t; + } + + case MU_MSG_FIELD_ID_FLAGS: + return (gint64)get_flags(self); + + case MU_MSG_FIELD_ID_PRIO: + return (gint64)get_prio(self); + + case MU_MSG_FIELD_ID_SIZE: + return (gint64)get_size(self); + + default: g_return_val_if_reached (-1); + } +} + + diff --git a/src/mu-msg-file.h b/src/mu-msg-file.h index fe5f73a1..624e41e8 100644 --- a/src/mu-msg-file.h +++ b/src/mu-msg-file.h @@ -20,5 +20,49 @@ #ifndef __MU_MSG_FILE_H__ #define __MU_MSG_FILE_H__ +struct _MuMsgFile; +typedef struct _MuMsgFile MuMsgFile; + +/** + * create a new message from a file + * + * @param path full path to the message + * @param mdir + * @param err error to receive (when function returns NULL), or NULL + * + * @return a new MuMsg, or NULL in case of error + */ +MuMsgFile *mu_msg_file_new (const char *path, const char* mdir, GError **err); + + +/** + * destroy a MuMsgFile object + * + * @param self object to destroy, or NULL + */ +void mu_msg_file_destroy (MuMsgFile *self); + + +/** + * get a string value for this message + * + * @param self a valid MuMsgFile + * @param msfid the message field id to get (must be string-based one) + * + * @return a const string, or NULL + */ +const char* mu_msg_file_get_str_field (MuMsgFile *self, + MuMsgFieldId msfid); + +/** + * get a numeric value for this message -- the return value should be + * cast into the actual type, e.g., time_t, MuMsgPrio etc. + * + * @param self a valid MuMsgFile + * @param msfid the message field id to get (must be string-based one) + * + * @return the numeric value, or -1 + */ +gint64 mu_msg_file_get_num_field (MuMsgFile *self, MuMsgFieldId msfid); #endif /*__MU_MSG_FILE_H__*/ diff --git a/src/mu-msg-iter.cc b/src/mu-msg-iter.cc index 095e3416..bfdd7618 100644 --- a/src/mu-msg-iter.cc +++ b/src/mu-msg-iter.cc @@ -95,7 +95,7 @@ mu_msg_iter_get_msg (MuMsgIter *iter, GError **err) return NULL; } - msg = mu_msg_new (path, NULL, err); + msg = mu_msg_new_from_file (path, NULL, err); if (!msg) return NULL; diff --git a/src/mu-msg-iter.h b/src/mu-msg-iter.h index 69c5415d..faa60fe4 100644 --- a/src/mu-msg-iter.h +++ b/src/mu-msg-iter.h @@ -1,5 +1,5 @@ /* -** Copyright (C) 2008-2010 Dirk-Jan C. Binnema +** Copyright (C) 2008-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 diff --git a/src/mu-msg-part.c b/src/mu-msg-part.c index 43baa209..24de9bdd 100644 --- a/src/mu-msg-part.c +++ b/src/mu-msg-part.c @@ -53,7 +53,7 @@ find_part (MuMsg* msg, guint partidx) fpdata.idx = 0; fpdata.part = NULL; - g_mime_message_foreach (msg->_mime_msg, + g_mime_message_foreach (msg->_file->_mime_msg, (GMimeObjectForeachFunc)find_part_cb, &fpdata); return fpdata.part; @@ -100,14 +100,14 @@ mu_msg_part_foreach (MuMsg *msg, MuMsgPartForeachFunc func, PartData pdata; g_return_if_fail (msg); - g_return_if_fail (GMIME_IS_OBJECT(msg->_mime_msg)); + g_return_if_fail (GMIME_IS_OBJECT(msg->_file->_mime_msg)); pdata._msg = msg; pdata._idx = 0; pdata._func = func; pdata._user_data = user_data; - g_mime_message_foreach (msg->_mime_msg, + g_mime_message_foreach (msg->_file->_mime_msg, (GMimeObjectForeachFunc)part_foreach_cb, &pdata); } @@ -321,7 +321,8 @@ mu_msg_part_find_cid (MuMsg *msg, const char* sought_cid) cid = g_str_has_prefix (sought_cid, "cid:") ? sought_cid + 4 : sought_cid; - return msg_part_find_idx (msg->_mime_msg, (MatchFunc)match_content_id, + return msg_part_find_idx (msg->_file->_mime_msg, + (MatchFunc)match_content_id, (gpointer)cid); } diff --git a/src/mu-msg-prio.c b/src/mu-msg-prio.c index 2b9f12d3..6ed203cd 100644 --- a/src/mu-msg-prio.c +++ b/src/mu-msg-prio.c @@ -42,6 +42,11 @@ mu_msg_prio_from_char (char k) char mu_msg_prio_char (MuMsgPrio prio) { + if (!(prio == 'l' || prio == 'n' || prio == 'h')) { + g_warning ("prio: %c", (char)prio); + } + + g_return_val_if_fail (prio == 'l' || prio == 'n' || prio == 'h', 0); return (char)prio; diff --git a/src/mu-msg-prio.h b/src/mu-msg-prio.h index 1712e80a..98506c53 100644 --- a/src/mu-msg-prio.h +++ b/src/mu-msg-prio.h @@ -31,7 +31,7 @@ enum _MuMsgPrio { }; typedef enum _MuMsgPrio MuMsgPrio; -static const MuMsgPrio MU_MSG_PRIO_NONE = (MuMsgPrio)-1; +static const MuMsgPrio MU_MSG_PRIO_NONE = (MuMsgPrio)0; /** diff --git a/src/mu-msg-priv.h b/src/mu-msg-priv.h index cd5255f8..f379afe2 100644 --- a/src/mu-msg-priv.h +++ b/src/mu-msg-priv.h @@ -24,46 +24,32 @@ #include #include "mu-msg.h" +#include "mu-msg-file.h" G_BEGIN_DECLS /* we put the the MuMsg definition in this separate -priv file, so we * can split the mu_msg implementations over separate files */ -enum _StringFields { +struct _MuMsgFile { + GMimeMessage *_mime_msg; - HTML_FIELD = 0, /* body as HTML */ - TEXT_FIELD, /* body as plain text */ - SUMMARY_FIELD, /* body summary */ + /* we waste a few bytes here for none-string fields... */ + gchar *_str_cache[MU_MSG_FIELD_ID_NUM]; - TO_FIELD, /* To: */ - CC_FIELD, /* Cc: */ - BCC_FIELD, /* Bcc: */ + GSList *_refs; - PATH_FIELD, /* full path */ - MDIR_FIELD, /* the maildir */ - - FLAGS_FIELD_STR, /* message flags */ + time_t _timestamp; + size_t _size; - REFS_FIELD, /* msg references, as a comma-sep'd string */ - - FIELD_NUM + MuMsgFlags _flags; + MuMsgPrio _prio; }; -typedef enum _StringFields StringFields; + struct _MuMsg { - guint _refcount; - - GMimeMessage *_mime_msg; - MuMsgFlags _flags; - - char* _fields[FIELD_NUM]; - - size_t _size; - time_t _timestamp; - MuMsgPrio _prio; - - GSList *_refs; /* msgids of message we refer to */ + guint _refcount; + MuMsgFile *_file; }; G_END_DECLS diff --git a/src/mu-msg.c b/src/mu-msg.c index 5dcf4b25..e0327b8f 100644 --- a/src/mu-msg.c +++ b/src/mu-msg.c @@ -32,16 +32,14 @@ #include "mu-util.h" #include "mu-str.h" -#include "mu-maildir.h" - /* note, we do the gmime initialization here rather than in * mu-runtime, because this way we don't need mu-runtime for simple * cases -- such as our unit tests */ static gboolean _gmime_initialized = FALSE; -void -mu_msg_gmime_init (void) +static void +gmime_init (void) { g_return_if_fail (!_gmime_initialized); @@ -54,9 +52,8 @@ mu_msg_gmime_init (void) _gmime_initialized = TRUE; } - -void -mu_msg_gmime_uninit (void) +static void +gmime_uninit (void) { g_return_if_fail (_gmime_initialized); @@ -64,894 +61,238 @@ mu_msg_gmime_uninit (void) _gmime_initialized = FALSE; } +MuMsg* +mu_msg_new_from_file (const char *path, const char *mdir, GError **err) +{ + MuMsg *self; + MuMsgFile *msgfile; + + g_return_val_if_fail (path, NULL); + + if (G_UNLIKELY(!_gmime_initialized)) { + gmime_init (); + g_atexit (gmime_uninit); + } + + msgfile = mu_msg_file_new (path, mdir, err); + if (!msgfile) + return NULL; + + self = g_slice_new0 (MuMsg); + + self->_file = msgfile; + self->_refcount = 1; + + return self; +} + static void -mu_msg_destroy (MuMsg *msg) +mu_msg_destroy (MuMsg *self) { - int i; - - if (!msg) + if (!self) return; - - if (G_IS_OBJECT(msg->_mime_msg)) { - g_object_unref (msg->_mime_msg); - msg->_mime_msg = NULL; - } - - for (i = 0; i != FIELD_NUM; ++i) - g_free (msg->_fields[i]); - g_slist_foreach (msg->_refs, (GFunc)g_free, NULL); - g_slist_free (msg->_refs); + mu_msg_file_destroy (self->_file); - g_slice_free (MuMsg, msg); + g_slice_free (MuMsg, self); } -static gboolean -init_file_metadata (MuMsg* msg, const char* path, const gchar* mdir, - GError **err) -{ - struct stat statbuf; - - if (access (path, R_OK) != 0) { - g_set_error (err, 0, MU_ERROR_FILE, - "cannot read file %s: %s", - path, strerror(errno)); - return FALSE; - } - - if (stat (path, &statbuf) < 0) { - g_set_error (err, 0, MU_ERROR_FILE, - "cannot stat %s: %s", - path, strerror(errno)); - return FALSE; - } - - if (!S_ISREG(statbuf.st_mode)) { - g_set_error (err, 0, MU_ERROR_FILE, - "not a regular file: %s", path); - return FALSE; - } - - msg->_timestamp = statbuf.st_mtime; - /* size_t should be enough for message size... */ - msg->_size = (size_t)statbuf.st_size; - msg->_fields[PATH_FIELD] = strdup (path); - - /* FIXME: maybe try to derive it from the path? */ - if (mdir) - msg->_fields[MDIR_FIELD] = strdup (mdir); - - return TRUE; -} - - - -static GMimeStream* -get_mime_stream (MuMsg *msg, GError **err) -{ - FILE *file; - GMimeStream *stream; - - file = fopen (mu_msg_get_path(msg), "r"); - if (!file) { - g_set_error (err, 0, MU_ERROR_FILE, - "cannot open %s: %s", mu_msg_get_path(msg), - strerror (errno)); - return NULL; - } - - stream = g_mime_stream_file_new (file); - if (!stream) { - g_set_error (err, 0, MU_ERROR_GMIME, - "cannot create mime stream for %s", - mu_msg_get_path(msg)); - fclose (file); - return NULL; - } - - return stream; -} - -static gboolean -init_mime_msg (MuMsg *msg, GError **err) -{ - GMimeStream *stream; - GMimeParser *parser; - - stream = get_mime_stream (msg, err); - if (!stream) - return FALSE; - - parser = g_mime_parser_new_with_stream (stream); - g_object_unref (stream); - if (!parser) { - g_set_error (err, 0, MU_ERROR_GMIME, - "cannot create mime parser for %s", - mu_msg_get_path(msg)); - return FALSE; - } - - msg->_mime_msg = g_mime_parser_construct_message (parser); - g_object_unref (parser); - if (!msg->_mime_msg) { - g_set_error (err, 0, MU_ERROR_GMIME, - "cannot construct mime message for %s", - mu_msg_get_path(msg)); - return FALSE; - } - - return TRUE; -} - MuMsg* -mu_msg_ref (MuMsg *msg) +mu_msg_ref (MuMsg *self) { - g_return_val_if_fail (msg, NULL); + g_return_val_if_fail (self, NULL); - ++msg->_refcount; - - return msg; + ++self->_refcount; + + return self; } void -mu_msg_unref (MuMsg *msg) +mu_msg_unref (MuMsg *self) { - g_return_if_fail (msg); - g_return_if_fail (msg->_refcount >= 1); + g_return_if_fail (self); + g_return_if_fail (self->_refcount >= 1); - if (--msg->_refcount == 0) - mu_msg_destroy (msg); -} - - -MuMsg* -mu_msg_new (const char* filepath, const gchar* mdir, GError **err) -{ - MuMsg *msg; - - g_return_val_if_fail (filepath, NULL); - g_return_val_if_fail (_gmime_initialized, NULL); - - msg = g_slice_new0 (MuMsg); - msg->_prio = MU_MSG_PRIO_NONE; - msg->_refcount = 1; - msg->_refs = NULL; - - if (!init_file_metadata(msg, filepath, mdir, err)) { - mu_msg_unref (msg); - return NULL; - } - - if (!init_mime_msg(msg, err)) { - mu_msg_unref (msg); - return NULL; - } - - return msg; + if (--self->_refcount == 0) + mu_msg_destroy (self); } const char* -mu_msg_get_path (MuMsg *msg) +mu_msg_get_path (MuMsg *self) { - g_return_val_if_fail (msg, NULL); - - return msg->_fields[PATH_FIELD]; + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_PATH); } -const char* -mu_msg_get_subject (MuMsg *msg) -{ - g_return_val_if_fail (msg, NULL); - - return g_mime_message_get_subject (msg->_mime_msg); -} - -const char* -mu_msg_get_msgid (MuMsg *msg) -{ - g_return_val_if_fail (msg, NULL); - - return g_mime_message_get_message_id (msg->_mime_msg); -} - - -const char* -mu_msg_get_maildir (MuMsg *msg) -{ - g_return_val_if_fail (msg, NULL); - - return msg->_fields[MDIR_FIELD]; -} - - - const char* -mu_msg_get_from (MuMsg *msg) +mu_msg_get_subject (MuMsg *self) { - g_return_val_if_fail (msg, NULL); - - return g_mime_message_get_sender (msg->_mime_msg); + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_SUBJECT); +} + +const char* +mu_msg_get_msgid (MuMsg *self) +{ + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_MSGID); +} + +const char* +mu_msg_get_maildir (MuMsg *self) +{ + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_MAILDIR); } -static const char* -get_recipient (MuMsg *msg, GMimeRecipientType rtype, StringFields field) +const char* +mu_msg_get_from (MuMsg *self) { - /* can only be set once */ - if (!msg->_fields[field]) { - - char *recep; - InternetAddressList *receps; - receps = g_mime_message_get_recipients (msg->_mime_msg, - rtype); - /* FIXME: is there an internal leak in - * internet_address_list_to_string? */ - recep = (char*)internet_address_list_to_string (receps, - TRUE); - if (mu_str_is_empty(recep)) - g_free (recep); - else - msg->_fields[field] = recep; - } - - return msg->_fields[field]; + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_FROM); } -const char* -mu_msg_get_to (MuMsg *msg) +const char* +mu_msg_get_to (MuMsg *self) { - g_return_val_if_fail (msg, NULL); - return get_recipient (msg, GMIME_RECIPIENT_TYPE_TO, TO_FIELD); + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_TO); } -const char* -mu_msg_get_cc (MuMsg *msg) +const char* +mu_msg_get_cc (MuMsg *self) { - g_return_val_if_fail (msg, NULL); - return get_recipient (msg, GMIME_RECIPIENT_TYPE_CC, CC_FIELD); + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_CC); } -const char* -mu_msg_get_bcc (MuMsg *msg) + +const char* +mu_msg_get_bcc (MuMsg *self) { - g_return_val_if_fail (msg, NULL); - return get_recipient (msg, GMIME_RECIPIENT_TYPE_BCC, BCC_FIELD); + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_BCC); } time_t -mu_msg_get_date (MuMsg *msg) +mu_msg_get_date (MuMsg *self) { - time_t t; - - g_return_val_if_fail (msg, 0); - - /* TODO: check: is the GMT-offset relevant? */ - g_mime_message_get_date(msg->_mime_msg, &t, NULL); - - return t; + g_return_val_if_fail (self, (time_t)-1); + return (time_t)mu_msg_file_get_num_field (self->_file, + MU_MSG_FIELD_ID_DATE); } -static gboolean -part_looks_like_attachment (GMimeObject *part) -{ - GMimeContentDisposition *disp; - const char *str; - - disp = g_mime_object_get_content_disposition (part); - if (!GMIME_IS_CONTENT_DISPOSITION(disp)) - return FALSE; /* no content disp? prob not - * an attachment. */ - - str = g_mime_content_disposition_get_disposition (disp); - - /* ok, it says it's an attachment, so it probably is... */ - if (!str) - return TRUE; - if (strcmp (str, GMIME_DISPOSITION_ATTACHMENT) == 0) - return TRUE; - else if (strcmp (str, GMIME_DISPOSITION_INLINE) == 0) { - /* inline-images are also considered attachments... */ - GMimeContentType *ct; - ct = g_mime_object_get_content_type (part); - if (ct) - return g_mime_content_type_is_type - (ct, "image", "*"); - } - - return FALSE; -} - - -static void -msg_cflags_cb (GMimeObject *parent, GMimeObject *part, MuMsgFlags *flags) -{ - if (*flags & MU_MSG_FLAG_HAS_ATTACH) - return; - - if (!GMIME_IS_PART(part)) - return; - - if (part_looks_like_attachment(part)) - *flags |= MU_MSG_FLAG_HAS_ATTACH; -} - - - -static MuMsgFlags -get_content_flags (MuMsg *msg) -{ - GMimeContentType *ctype; - MuMsgFlags flags; - GMimeObject *part; - - if (!GMIME_IS_MESSAGE(msg->_mime_msg)) - return MU_MSG_FLAG_NONE; - - flags = 0; - g_mime_message_foreach (msg->_mime_msg, - (GMimeObjectForeachFunc)msg_cflags_cb, - &flags); - - /* note: signed or encrypted status for a message is determined by - * the top-level mime-part - */ - if ((part = g_mime_message_get_mime_part(msg->_mime_msg))) { - ctype = g_mime_object_get_content_type - (GMIME_OBJECT(part)); - if (!ctype) { - g_warning ("not a content type!"); - return 0; - } - - if (ctype) { - if (g_mime_content_type_is_type - (ctype,"*", "signed")) - flags |= MU_MSG_FLAG_SIGNED; - if (g_mime_content_type_is_type - (ctype,"*", "encrypted")) - flags |= MU_MSG_FLAG_ENCRYPTED; - } - } else - g_warning ("no top level mime part found"); - - return flags; -} MuMsgFlags -mu_msg_get_flags (MuMsg *msg) +mu_msg_get_flags (MuMsg *self) { - g_return_val_if_fail (msg, MU_MSG_FLAG_NONE); - - if (msg->_flags == MU_MSG_FLAG_NONE) { - msg->_flags = mu_maildir_get_flags_from_path - (mu_msg_get_path(msg)); - msg->_flags |= get_content_flags (msg); - } - - return msg->_flags; + g_return_val_if_fail (self, MU_MSG_FLAG_NONE); + return (MuMsgFlags)mu_msg_file_get_num_field (self->_file, + MU_MSG_FIELD_ID_FLAGS); } - size_t -mu_msg_get_size (MuMsg *msg) +mu_msg_get_size (MuMsg *self) { - g_return_val_if_fail (msg, 0); - - return msg->_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 (MuMsg *msg) -{ - const char *str; - GMimeObject *obj; - - obj = GMIME_OBJECT(msg->_mime_msg); - - str = g_mime_object_get_header (obj, "X-Priority"); - if (!str) - str = g_mime_object_get_header (obj, "X-MSMail-Priority"); - if (!str) - str = g_mime_object_get_header (obj, "Importance"); - if (!str) - str = g_mime_object_get_header (obj, "Precedence"); - if (str) - return (to_lower(g_strdup(str))); - else - return NULL; -} - - -static MuMsgPrio -parse_prio_str (const char* priostr) -{ - int i; - struct { - const char* _str; - MuMsgPrio _prio; - } str_prio[] = { - { "high", MU_MSG_PRIO_HIGH }, - { "1", MU_MSG_PRIO_HIGH }, - { "2", MU_MSG_PRIO_HIGH }, - - { "normal", MU_MSG_PRIO_NORMAL }, - { "3", MU_MSG_PRIO_NORMAL }, - - { "low", MU_MSG_PRIO_LOW }, - { "list", MU_MSG_PRIO_LOW }, - { "bulk", MU_MSG_PRIO_LOW }, - { "4", MU_MSG_PRIO_LOW }, - { "5", MU_MSG_PRIO_LOW } - }; - - for (i = 0; i != G_N_ELEMENTS(str_prio); ++i) - if (g_strstr_len (priostr, -1, str_prio[i]._str) != NULL) - return str_prio[i]._prio; - - /* e.g., last-fm uses 'fm-user'... as precedence */ - return MU_MSG_PRIO_NORMAL; + g_return_val_if_fail (self, 0); + return (size_t)mu_msg_file_get_num_field (self->_file, + MU_MSG_FIELD_ID_SIZE); } MuMsgPrio -mu_msg_get_prio (MuMsg *msg) +mu_msg_get_prio (MuMsg *self) { - char* priostr; - - g_return_val_if_fail (msg, 0); - - if (msg->_prio != MU_MSG_PRIO_NONE) - return msg->_prio; - - priostr = get_prio_header_field (msg); - if (!priostr) - return MU_MSG_PRIO_NORMAL; - - msg->_prio = parse_prio_str (priostr); - g_free (priostr); - - return msg->_prio; + g_return_val_if_fail (self, (time_t)-1); + return (MuMsgPrio)mu_msg_file_get_num_field (self->_file, + MU_MSG_FIELD_ID_PRIO); } -const char* -mu_msg_get_header (MuMsg *msg, const char* header) -{ - g_return_val_if_fail (msg, NULL); - g_return_val_if_fail (header, NULL); +/* const char* */ +/* mu_msg_get_header (MuMsg *msg, const char* header) */ +/* { */ +/* g_return_val_if_fail (self, NULL); */ +/* g_return_val_if_fail (header, NULL); */ - return g_mime_object_get_header (GMIME_OBJECT(msg->_mime_msg), - header); -} +/* return g_mime_object_get_header (GMIME_OBJECT(self->_mime_msg), */ +/* header); */ +/* } */ time_t -mu_msg_get_timestamp (MuMsg *msg) +mu_msg_get_timestamp (MuMsg *self) { - g_return_val_if_fail (msg, 0); - - return msg->_timestamp; -} - -struct _GetBodyData { - GMimeObject *_txt_part, *_html_part; - gboolean _want_html; -}; -typedef struct _GetBodyData GetBodyData; - - -static gboolean -looks_like_attachment (GMimeObject *part) -{ - const char *str; - GMimeContentDisposition *disp; - - disp = g_mime_object_get_content_disposition (GMIME_OBJECT(part)); - if (!GMIME_IS_CONTENT_DISPOSITION(disp)) - return FALSE; - - str = g_mime_content_disposition_get_disposition (disp); - if (!str) - return FALSE; - - if (strcmp(str,GMIME_DISPOSITION_INLINE) == 0) - return FALSE; /* inline, so it's not an attachment */ - - return TRUE; /* looks like an attachment */ -} - -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)) - return; - - ct = g_mime_object_get_content_type (part); - if (!GMIME_IS_CONTENT_TYPE(ct)) { - g_warning ("not a content type!"); - return; - } - - if (looks_like_attachment (part)) - return; /* not the body */ - - /* is it right content type? */ - if (g_mime_content_type_is_type (ct, "text", "plain")) - data->_txt_part = part; - else if (g_mime_content_type_is_type (ct, "text", "html")) - data->_html_part = part; - else - return; /* wrong type */ -} - - -/* turn \0-terminated buf into ascii (which is a utf8 subset); convert - * any non-ascii into '.' - */ -static void -asciify (char *buf) -{ - char *c; - for (c = buf; c && *c; ++c) - if (!isascii(*c)) - c[0] = '.'; -} - - - -static gchar* -text_to_utf8 (const char* buffer, const char *charset) -{ - GError *err; - gchar * utf8; - - err = NULL; - utf8 = g_convert_with_fallback (buffer, -1, "UTF-8", - charset, (gchar*)".", - NULL, NULL, &err); - if (!utf8) { - MU_WRITE_LOG ("%s: conversion failed from %s: %s", - __FUNCTION__, charset, - err ? err ->message : ""); - if (err) - g_error_free (err); - } - - return utf8; -} - - -/* NOTE: buffer will be *freed* or returned unchanged */ -static char* -convert_to_utf8 (GMimePart *part, char *buffer) -{ - GMimeContentType *ctype; - const char* charset; - unsigned char *cur; - - /* optimization: if the buffer is plain ascii, no conversion - * is done... */ - for (cur = (unsigned char*)buffer; *cur && *cur < 0x80; ++cur); - if (*cur == '\0') - return buffer; - - ctype = g_mime_object_get_content_type (GMIME_OBJECT(part)); - g_return_val_if_fail (GMIME_IS_CONTENT_TYPE(ctype), NULL); - - charset = g_mime_content_type_get_parameter (ctype, "charset"); - if (charset) - charset = g_mime_charset_iconv_name (charset); - - /* of course, the charset specified may be incorrect... */ - if (charset) { - char *utf8 = text_to_utf8 (buffer, charset); - if (utf8) { - g_free (buffer); - return utf8; - } - } - - /* hmmm.... no charset at all, or conversion failed; ugly - * hack: replace all non-ascii chars with '.' - * instead... TODO: come up with something better */ - asciify (buffer); - return buffer; -} - - -static gchar* -stream_to_string (GMimeStream *stream, size_t buflen) -{ - char *buffer; - ssize_t bytes; - - buffer = g_new(char, buflen + 1); - g_mime_stream_reset (stream); - - /* we read everything in one go */ - bytes = g_mime_stream_read (stream, buffer, buflen); - if (bytes < 0) { - g_warning ("%s: failed to read from stream", __FUNCTION__); - g_free (buffer); - return NULL; - } - - buffer[bytes]='\0'; - - return buffer; -} - - -static gchar* -part_to_string (GMimePart *part, gboolean *err) -{ - GMimeDataWrapper *wrapper; - GMimeStream *stream = NULL; - ssize_t buflen; - char *buffer = NULL; - - *err = TRUE; - g_return_val_if_fail (GMIME_IS_PART(part), NULL); - - wrapper = g_mime_part_get_content_object (part); - if (!wrapper) { - /* this happens with invalid mails */ - g_debug ("failed to create data wrapper"); - goto cleanup; - } - - stream = g_mime_stream_mem_new (); - if (!stream) { - g_warning ("failed to create mem stream"); - goto cleanup; - } - - buflen = g_mime_data_wrapper_write_to_stream (wrapper, stream); - if (buflen <= 0) {/* empty buffer, not an error */ - *err = FALSE; - goto cleanup; - } - - buffer = stream_to_string (stream, (size_t)buflen); - - /* convert_to_utf8 will free the old 'buffer' if needed */ - buffer = convert_to_utf8 (part, buffer); - - *err = FALSE; - -cleanup: - if (stream) - g_object_unref (G_OBJECT(stream)); - - return buffer; -} - - -static char* -get_body (MuMsg *msg, gboolean want_html) -{ - GetBodyData data; - char *str; - gboolean err; - - g_return_val_if_fail (msg, NULL); - g_return_val_if_fail (GMIME_IS_MESSAGE(msg->_mime_msg), NULL); - - memset (&data, 0, sizeof(GetBodyData)); - data._want_html = want_html; - - err = FALSE; - g_mime_message_foreach (msg->_mime_msg, - (GMimeObjectForeachFunc)get_body_cb, - &data); - if (want_html) - str = data._html_part ? - part_to_string (GMIME_PART(data._html_part), &err) : - NULL; - else - str = data._txt_part ? - part_to_string (GMIME_PART(data._txt_part), &err) : - NULL; - - /* note, str may be NULL (no body), but that's not necessarily - * an error; we only warn when an actual error occured */ - if (err) - g_warning ("error occured while retrieving %s body" - "for message %s", - want_html ? "html" : "text", - mu_msg_get_path(msg)); - - return str; -} - -const char* -mu_msg_get_body_html (MuMsg *msg) -{ - g_return_val_if_fail (msg, NULL); - - if (msg->_fields[HTML_FIELD]) - return msg->_fields[HTML_FIELD]; - else - return msg->_fields[HTML_FIELD] = get_body (msg, TRUE); + g_return_val_if_fail (self, (time_t)-1); + return (MuMsgPrio)mu_msg_file_get_num_field (self->_file, + MU_MSG_FIELD_ID_TIMESTAMP); } const char* -mu_msg_get_body_text (MuMsg *msg) +mu_msg_get_body_html (MuMsg *self) { - g_return_val_if_fail (msg, NULL); - - if (msg->_fields[TEXT_FIELD]) - return msg->_fields[TEXT_FIELD]; - else - return msg->_fields[TEXT_FIELD] = get_body (msg, FALSE); + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_BODY_HTML); } + const char* -mu_msg_get_summary (MuMsg *msg, size_t max_lines) +mu_msg_get_body_text (MuMsg *self) { - const char *body; - - g_return_val_if_fail (msg, NULL); + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_BODY_TEXT); +} + + +const char* +mu_msg_get_summary (MuMsg *self, size_t max_lines) +{ + g_return_val_if_fail (self, NULL); g_return_val_if_fail (max_lines > 0, NULL); - /* do we have a summary cached already? */ - if (msg->_fields[SUMMARY_FIELD]) - return msg->_fields[SUMMARY_FIELD]; - - /* nope; calculate it */ - body = mu_msg_get_body_text (msg); - if (!body) - return NULL; /* there was no text body */ - - return msg->_fields[SUMMARY_FIELD] = - mu_str_summarize (body, max_lines); -} - - -static GSList* -get_msgids_from_header (MuMsg *msg, const char* header) -{ - GSList *msgids; - const char *str; - - msgids = NULL; - str = g_mime_object_get_header (GMIME_OBJECT(msg->_mime_msg), - header); - - /* get stuff from the 'references' header */ - if (str) { - const GMimeReferences *cur; - GMimeReferences *mime_refs; - mime_refs = g_mime_references_decode (str); - for (cur = mime_refs; cur; cur = g_mime_references_get_next(cur)) { - const char* msgid; - msgid = g_mime_references_get_message_id (cur); - if (msgid) - msgids = g_slist_prepend (msgids, g_strdup (msgid)); - } - g_mime_references_free (mime_refs); - } - - return g_slist_reverse (msgids); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_SUMMARY); } const char* -mu_msg_get_references_str (MuMsg *msg) +mu_msg_get_references_str (MuMsg *self) { - const GSList *refs; - gchar *refsstr; - - g_return_val_if_fail (msg, NULL); - - if (msg->_fields[REFS_FIELD]) - return msg->_fields[REFS_FIELD]; - - refsstr = NULL; - refs = mu_msg_get_references (msg); - if (refs) { - const GSList *cur; - for (cur = refs; cur; cur = g_slist_next(cur)) { - char *tmp; - tmp = g_strdup_printf ("%s%s%s", - refsstr ? refsstr : "", - refsstr ? "," : "", - g_strdup((gchar*)cur->data)); - g_free (refsstr); - refsstr = tmp; - } - } - - return msg->_fields[REFS_FIELD] = refsstr; + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, + MU_MSG_FIELD_ID_REFS); } -const GSList* -mu_msg_get_references (MuMsg *msg) -{ - GSList *refs, *inreply; - - g_return_val_if_fail (msg, NULL); - - if (msg->_refs) - return msg->_refs; - - refs = get_msgids_from_header (msg, "References"); - - /* now, add in-reply-to:, we only take the first one if there - * are more */ - inreply = get_msgids_from_header (msg, "In-reply-to"); - if (inreply) { - refs = g_slist_prepend (refs, g_strdup ((gchar*)inreply->data)); - g_slist_foreach (inreply, (GFunc)g_free, NULL); - g_slist_free (inreply); - } - - /* put in proper order */ - msg->_refs = g_slist_reverse (refs); - - return msg->_refs; -} - - - const char* -mu_msg_get_field_string (MuMsg *msg, MuMsgFieldId mfid) +mu_msg_get_field_string (MuMsg *self, MuMsgFieldId mfid) { - g_return_val_if_fail (msg, NULL); - - switch (mfid) { - case MU_MSG_FIELD_ID_BCC: return mu_msg_get_bcc (msg); - case MU_MSG_FIELD_ID_BODY_TEXT: return mu_msg_get_body_text (msg); - case MU_MSG_FIELD_ID_BODY_HTML: return mu_msg_get_body_html (msg); - case MU_MSG_FIELD_ID_CC: return mu_msg_get_cc (msg); - case MU_MSG_FIELD_ID_FROM: return mu_msg_get_from (msg); - case MU_MSG_FIELD_ID_PATH: return mu_msg_get_path (msg); - case MU_MSG_FIELD_ID_SUBJECT: return mu_msg_get_subject (msg); - case MU_MSG_FIELD_ID_TO: return mu_msg_get_to (msg); - case MU_MSG_FIELD_ID_MSGID: return mu_msg_get_msgid (msg); - case MU_MSG_FIELD_ID_MAILDIR: return mu_msg_get_maildir (msg); - case MU_MSG_FIELD_ID_REFS: return mu_msg_get_references_str (msg); - default: - g_return_val_if_reached (NULL); - } + g_return_val_if_fail (self, NULL); + return mu_msg_file_get_str_field (self->_file, mfid); } gint64 -mu_msg_get_field_numeric (MuMsg *msg, const MuMsgFieldId mfid) +mu_msg_get_field_numeric (MuMsg *self, MuMsgFieldId mfid) { - g_return_val_if_fail (msg, 0); - - switch (mfid) { - case MU_MSG_FIELD_ID_DATE: return mu_msg_get_date(msg); - case MU_MSG_FIELD_ID_FLAGS: return mu_msg_get_flags(msg); - case MU_MSG_FIELD_ID_PRIO: return mu_msg_get_prio(msg); - case MU_MSG_FIELD_ID_SIZE: return mu_msg_get_size(msg); - default: g_return_val_if_reached (-1); - } + g_return_val_if_fail (self, -1); + return mu_msg_file_get_num_field (self->_file, mfid); } diff --git a/src/mu-msg.h b/src/mu-msg.h index 5c414ce8..cdd5d59d 100644 --- a/src/mu-msg.h +++ b/src/mu-msg.h @@ -30,23 +30,6 @@ G_BEGIN_DECLS struct _MuMsg; typedef struct _MuMsg MuMsg; - -/** - * initialize the GMime-system; this function needs to be called - * before doing anything else with MuMsg. mu_runtime_init will call - * this function, so if you use that, you should not call this - * function. - */ -void mu_msg_gmime_init (void); - -/** - * uninitialize the GMime-system; this function needs to be called - * after you're done with MuMsg. mu_runtime_uninit will call this - * function, so if you use that, you should not call this function. - */ -void mu_msg_gmime_uninit (void); - - /** * create a new MuMsg* instance which parses a message and provides * read access to its properties; call mu_msg_destroy when done with it. @@ -62,8 +45,8 @@ void mu_msg_gmime_uninit (void); * @return a new MuMsg instance or NULL in case of error; call * mu_msg_unref when done with this message */ -MuMsg *mu_msg_new (const char* filepath, const char *maildir, - GError **err) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; +MuMsg *mu_msg_new_from_file (const char* filepath, const char *maildir, + GError **err) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; /** diff --git a/src/mu-runtime.c b/src/mu-runtime.c index 14c0c3d3..5abd24b1 100644 --- a/src/mu-runtime.c +++ b/src/mu-runtime.c @@ -93,9 +93,7 @@ mu_runtime_init (const char* muhome_arg) _data = g_new0 (MuRuntimeData, 1); _data->_str[MU_RUNTIME_PATH_MUHOME] = muhome; init_paths (muhome, _data); - - mu_msg_gmime_init (); - + return _initialized = TRUE; } @@ -140,8 +138,6 @@ mu_runtime_init_from_cmdline (int *pargc, char ***pargv) g_strdup (_data->_config->muhome); init_paths (_data->_str[MU_RUNTIME_PATH_MUHOME], _data); - mu_msg_gmime_init (); - return _initialized = TRUE; } @@ -166,7 +162,6 @@ mu_runtime_uninit (void) { g_return_if_fail (_initialized); - mu_msg_gmime_uninit (); runtime_free (); _initialized = FALSE; diff --git a/src/tests/test-mu-cmd.c b/src/tests/test-mu-cmd.c index 0e8d2f5e..bbad45e2 100644 --- a/src/tests/test-mu-cmd.c +++ b/src/tests/test-mu-cmd.c @@ -472,9 +472,7 @@ main (int argc, char *argv[]) G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION, (GLogFunc)black_hole, NULL); - mu_msg_gmime_init (); rv = g_test_run (); - mu_msg_gmime_uninit(); return rv; } diff --git a/src/tests/test-mu-msg.c b/src/tests/test-mu-msg.c index dabc9d7a..d5d46cad 100644 --- a/src/tests/test-mu-msg.c +++ b/src/tests/test-mu-msg.c @@ -65,7 +65,7 @@ test_mu_msg_01 (void) MuMsg *msg; gint i; - msg = mu_msg_new (MU_TESTMAILDIR + msg = mu_msg_new_from_file (MU_TESTMAILDIR "cur/1220863042.12663_1.mindcrime!2,S", NULL, NULL); @@ -78,8 +78,8 @@ test_mu_msg_01 (void) g_assert_cmpstr (mu_msg_get_msgid(msg), ==, "3BE9E6535E3029448670913581E7A1A20D852173@" "emss35m06.us.lmco.com"); - g_assert_cmpstr (mu_msg_get_header(msg, "Mailing-List"), - ==, "contact gcc-help-help@gcc.gnu.org; run by ezmlm"); + /* g_assert_cmpstr (mu_msg_get_header(msg, "Mailing-List"), */ + /* ==, "contact gcc-help-help@gcc.gnu.org; run by ezmlm"); */ g_assert_cmpuint (mu_msg_get_prio(msg), /* 'klub' */ ==, MU_MSG_PRIO_NORMAL); g_assert_cmpuint (mu_msg_get_date(msg), @@ -127,7 +127,7 @@ test_mu_msg_02 (void) MuMsg *msg; int i; - msg = mu_msg_new (MU_TESTMAILDIR + msg = mu_msg_new_from_file (MU_TESTMAILDIR "cur/1220863087.12663_19.mindcrime!2,S", NULL, NULL); @@ -139,8 +139,8 @@ test_mu_msg_02 (void) ==, "anon@example.com"); g_assert_cmpstr (mu_msg_get_msgid(msg), ==, "r6bpm5-6n6.ln1@news.ducksburg.com"); - g_assert_cmpstr (mu_msg_get_header(msg, "Errors-To"), - ==, "help-gnu-emacs-bounces+xxxx.klub=gmail.com@gnu.org"); + /* g_assert_cmpstr (mu_msg_get_header(msg, "Errors-To"), */ + /* ==, "help-gnu-emacs-bounces+xxxx.klub=gmail.com@gnu.org"); */ g_assert_cmpuint (mu_msg_get_prio(msg), /* 'low' */ ==, MU_MSG_PRIO_LOW); g_assert_cmpuint (mu_msg_get_date(msg), @@ -163,7 +163,7 @@ test_mu_msg_03 (void) { MuMsg *msg; - msg = mu_msg_new (MU_TESTMAILDIR + msg = mu_msg_new_from_file (MU_TESTMAILDIR "cur/1283599333.1840_11.cthulhu!2,", NULL, NULL); @@ -194,7 +194,7 @@ test_mu_msg_04 (void) { MuMsg *msg; - msg = mu_msg_new (MU_TESTMAILDIR2 + msg = mu_msg_new_from_file (MU_TESTMAILDIR2 "Foo/cur/mail5", NULL, NULL); g_assert_cmpstr (mu_msg_get_to(msg), @@ -245,10 +245,8 @@ main (int argc, char *argv[]) G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION, (GLogFunc)black_hole, NULL); - mu_msg_gmime_init (); rv = g_test_run (); - mu_msg_gmime_uninit (); - + return rv; } diff --git a/src/tests/test-mu-query.c b/src/tests/test-mu-query.c index 077c975e..75e46823 100644 --- a/src/tests/test-mu-query.c +++ b/src/tests/test-mu-query.c @@ -250,13 +250,11 @@ main (int argc, char *argv[]) g_test_add_func ("/mu-query/test-mu-query-04", test_mu_query_04); g_test_add_func ("/mu-query/test-mu-query-05", test_mu_query_05); - g_log_set_handler (NULL, - G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION, - (GLogFunc)black_hole, NULL); + /* g_log_set_handler (NULL, */ + /* G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION, */ + /* (GLogFunc)black_hole, NULL); */ - mu_msg_gmime_init (); rv = g_test_run (); - mu_msg_gmime_uninit (); return rv; } diff --git a/src/tests/test-mu-store.c b/src/tests/test-mu-store.c index e97b17d1..07e1a4f7 100644 --- a/src/tests/test-mu-store.c +++ b/src/tests/test-mu-store.c @@ -49,7 +49,6 @@ test_mu_store_new_destroy (void) g_assert_cmpuint (0,==,mu_store_count (store)); mu_store_flush (store); - mu_store_destroy (store); g_free (tmpdir); @@ -94,11 +93,9 @@ test_mu_store_store_and_count (void) g_assert (store); g_assert_cmpuint (0,==,mu_store_count (store)); - - mu_msg_gmime_init (); /* add one */ - msg = mu_msg_new (MU_TESTMAILDIR "cur/1283599333.1840_11.cthulhu!2,", NULL, NULL); + msg = mu_msg_new_from_file (MU_TESTMAILDIR "cur/1283599333.1840_11.cthulhu!2,", NULL, NULL); g_assert (msg); g_assert_cmpuint (mu_store_store (store, msg, TRUE), ==, MU_OK); g_assert_cmpuint (1,==,mu_store_count (store)); @@ -107,7 +104,7 @@ test_mu_store_store_and_count (void) mu_msg_unref (msg); /* add another one */ - msg = mu_msg_new (MU_TESTMAILDIR2 "bar/cur/mail3", NULL, NULL); + msg = mu_msg_new_from_file (MU_TESTMAILDIR2 "bar/cur/mail3", NULL, NULL); g_assert (msg); g_assert_cmpuint (mu_store_store (store, msg, TRUE), ==, MU_OK); g_assert_cmpuint (2,==,mu_store_count (store)); @@ -115,13 +112,12 @@ test_mu_store_store_and_count (void) mu_msg_unref (msg); /* try to add the first one again. count should be 2 still */ - msg = mu_msg_new (MU_TESTMAILDIR "cur/1283599333.1840_11.cthulhu!2,", NULL, NULL); + msg = mu_msg_new_from_file (MU_TESTMAILDIR "cur/1283599333.1840_11.cthulhu!2,", NULL, NULL); g_assert (msg); g_assert_cmpuint (mu_store_store (store, msg, TRUE), ==, MU_OK); g_assert_cmpuint (2,==,mu_store_count (store)); mu_msg_unref (msg); - mu_msg_gmime_uninit (); mu_store_destroy (store); } @@ -142,12 +138,10 @@ test_mu_store_store_remove_and_count (void) g_assert (store); g_assert_cmpuint (0,==,mu_store_count (store)); - - mu_msg_gmime_init (); /* add one */ err = NULL; - msg = mu_msg_new (MU_TESTMAILDIR "cur/1283599333.1840_11.cthulhu!2,", + msg = mu_msg_new_from_file (MU_TESTMAILDIR "cur/1283599333.1840_11.cthulhu!2,", NULL, &err); g_assert (msg); g_assert_cmpuint (mu_store_store (store, msg, TRUE), ==, MU_OK); @@ -159,8 +153,7 @@ test_mu_store_store_remove_and_count (void) g_assert_cmpuint (0,==,mu_store_count (store)); g_assert_cmpuint (FALSE,==,mu_store_contains_message (store, MU_TESTMAILDIR "cur/1283599333.1840_11.cthulhu!2,")); - - mu_msg_gmime_uninit (); + mu_store_destroy (store); } diff --git a/toys/mug/mug-msg-view.c b/toys/mug/mug-msg-view.c index a3163318..ce401a8d 100644 --- a/toys/mug/mug-msg-view.c +++ b/toys/mug/mug-msg-view.c @@ -292,7 +292,7 @@ mug_msg_view_set_msg (MugMsgView * self, const char *msgpath) return TRUE; } - msg = mu_msg_new (msgpath, NULL, NULL); + msg = mu_msg_new_from_file (msgpath, NULL, NULL); if (!msg) { empty_message (self); set_text (self, "Message not found; " "please run 'mu index'"); diff --git a/toys/mug2/mug-msg-view.c b/toys/mug2/mug-msg-view.c index 36e3b897..bc494375 100644 --- a/toys/mug2/mug-msg-view.c +++ b/toys/mug2/mug-msg-view.c @@ -121,7 +121,7 @@ mug_msg_view_set_msg (MugMsgView * self, const char *msgpath) MuMsg *msg; if (access (msgpath, R_OK) == 0) { - msg = mu_msg_new (msgpath, NULL, NULL); + msg = mu_msg_new_from_file (msgpath, NULL, NULL); mu_msg_view_set_message (MU_MSG_VIEW(priv->_view), msg); if (msg) mu_msg_unref (msg);