Index: python/deskbar-handler/tracker-module.py =================================================================== --- python/deskbar-handler/tracker-module.py (revision 1250) +++ python/deskbar-handler/tracker-module.py (working copy) @@ -112,6 +112,7 @@ 'action': { # more actions for different MUAs 'key': 'mua', # see TrackerLiveSearchAction.action for a demo 'Evolution/Email': 'evolution %(uri)s', + 'Modest/Email': 'modest-open %(uri)s', 'Thunderbird/Email': 'thunderbird -viewtracker %(uri)s', 'KMail/Email': 'kmail --view %(uri)s', }, Index: python/deskbar-handler/tracker-handler.py =================================================================== --- python/deskbar-handler/tracker-handler.py (revision 1250) +++ python/deskbar-handler/tracker-handler.py (working copy) @@ -49,6 +49,7 @@ 'action': { # more actions for different MUAs 'key': 'mua', # see TrackerLiveSearchMatch.action for a demo 'Evolution/Email': 'evolution %(uri)s', + 'Modest/Email': 'modest-open %(uri)s', 'Thunderbird/Email': 'thunderbird -viewtracker %(uri)s', 'KMail/Email': 'kmail --view %(uri)s', }, Index: src/trackerd/tracker-db-email.c =================================================================== --- src/trackerd/tracker-db-email.c (revision 1250) +++ src/trackerd/tracker-db-email.c (working copy) @@ -65,7 +65,7 @@ const gchar *filename, const gchar *uri_prefix) { - gchar *types[5] = {"MBOX", "IMAP", "IMAP4", "MAIL_TYPE_MAILDIR", "MAIL_TYPE_MH"}; + gchar *types[6] = {"MBOX", "IMAP", "IMAP4", "MAIL_TYPE_MAILDIR", "MAIL_TYPE_MH", "MAIL_TYPE_POP"}; gchar *str_mail_app = tracker_int_to_str (mail_app); gchar *str_mail_type = tracker_int_to_str (mail_type); @@ -393,6 +393,8 @@ { if (app == MAIL_APP_EVOLUTION) { return g_strdup ("EvolutionEmails"); + } else if (app == MAIL_APP_MODEST) { + return g_strdup ("ModestEmails"); } else if (app == MAIL_APP_KMAIL) { return g_strdup ("KMailEmails"); } else if (app == MAIL_APP_THUNDERBIRD) { @@ -410,6 +412,8 @@ { if (app == MAIL_APP_EVOLUTION) { return g_strdup ("Evolution/Email"); + } else if (app == MAIL_APP_MODEST) { + return g_strdup ("Modest/Email"); } else if (app == MAIL_APP_KMAIL) { return g_strdup ("KMail/Email"); } else if (app == MAIL_APP_THUNDERBIRD) { @@ -427,6 +431,8 @@ { if (app == MAIL_APP_EVOLUTION) { return g_strdup ("EvolutionAttachments"); + } else if (app == MAIL_APP_MODEST) { + return g_strdup ("ModestAttachments"); } else if (app == MAIL_APP_KMAIL) { return g_strdup ("KMailAttachments"); } else if (app == MAIL_APP_THUNDERBIRD) { @@ -458,7 +464,7 @@ gboolean -tracker_db_email_save_email (DBConnection *db_con, MailMessage *mm) +tracker_db_email_save_email (DBConnection *db_con, MailMessage *mm, MailApplication mail_app) { gint mbox_id, type_id, id, len; gchar *service, *attachment_service, *mime; @@ -523,10 +529,9 @@ } else { mbox_id = 0; mm->offset =0; - service = g_strdup ("EvolutionEmails"); - mime = g_strdup ("Evolution/Email"); - attachment_service = g_strdup ("EvolutionAttachments"); - + service = get_service_name (mail_app); + mime = get_mime (mail_app); + attachment_service = get_attachment_service_name (mail_app); } type_id = tracker_get_id_for_service (service); Index: src/trackerd/tracker-db-email.h =================================================================== --- src/trackerd/tracker-db-email.h (revision 1250) +++ src/trackerd/tracker-db-email.h (working copy) @@ -28,7 +28,7 @@ off_t tracker_db_email_get_last_mbox_offset (DBConnection *db_con, const gchar *mail_file_path); void tracker_db_email_update_mbox_offset (DBConnection *db_con, MailFile *mf); gboolean tracker_db_email_is_up_to_date (DBConnection *db_con, const gchar *uri, guint32 *id); -gboolean tracker_db_email_save_email (DBConnection *db_con, MailMessage *mm); +gboolean tracker_db_email_save_email (DBConnection *db_con, MailMessage *mm, MailApplication mail_app); gboolean tracker_db_email_is_saved_email_file (DBConnection *db_con, const gchar *uri); void tracker_db_email_update_email (DBConnection *db_con, MailMessage *mm); gboolean tracker_db_email_delete_email_file (DBConnection *db_con, const gchar *uri); Index: src/trackerd/tracker-email-utils.c =================================================================== --- src/trackerd/tracker-email-utils.c (revision 1250) +++ src/trackerd/tracker-email-utils.c (working copy) @@ -92,7 +92,7 @@ return FALSE; } - tracker_db_email_save_email (db_con, mail_msg); + tracker_db_email_save_email (db_con, mail_msg, mail_app); email_free_mail_message (mail_msg); @@ -154,7 +154,7 @@ deleted++; } - tracker_db_email_save_email (db_con, mail_msg); + tracker_db_email_save_email (db_con, mail_msg, mail_app); tracker_db_email_update_mbox_offset (db_con, mf); email_free_mail_message (mail_msg); Index: src/trackerd/tracker-email.c =================================================================== --- src/trackerd/tracker-email.c (revision 1250) +++ src/trackerd/tracker-email.c (working copy) @@ -77,7 +77,7 @@ if (!g_module_symbol (module, "tracker_email_index_file", (gpointer *) &func)) return FALSE; - return (func) (db_con, info); + return (func) (db_con->emails, info); } gboolean Index: src/trackerd/tracker-email-utils.h =================================================================== --- src/trackerd/tracker-email-utils.h (revision 1250) +++ src/trackerd/tracker-email-utils.h (working copy) @@ -31,6 +31,7 @@ MAIL_APP_KMAIL, MAIL_APP_THUNDERBIRD, MAIL_APP_THUNDERBIRD_FEED, + MAIL_APP_MODEST, MAIL_APP_UNKNOWN } MailApplication; @@ -41,7 +42,8 @@ MAIL_TYPE_IMAP, MAIL_TYPE_IMAP4, MAIL_TYPE_MAILDIR, - MAIL_TYPE_MH + MAIL_TYPE_MH, + MAIL_TYPE_POP, } MailType; Index: src/trackerd/tracker-email-thunderbird.c =================================================================== --- src/trackerd/tracker-email-thunderbird.c (revision 1250) +++ src/trackerd/tracker-email-thunderbird.c (working copy) @@ -178,7 +178,7 @@ if (mail_msg->parent_mail_file->mail_app == MAIL_APP_THUNDERBIRD ) { // || mail_msg->parent_mail_file->mail_app == MAIL_APP_THUNDERBIRD_FEED) { - tracker_db_email_save_email (db_con, mail_msg); + tracker_db_email_save_email (db_con, mail_msg, mail_app); email_free_mail_file(mail_msg->parent_mail_file); email_free_mail_message (mail_msg); return TRUE; Index: src/trackerd/tracker-dbus-search.c =================================================================== --- src/trackerd/tracker-dbus-search.c (revision 1250) +++ src/trackerd/tracker-dbus-search.c (working copy) @@ -103,7 +103,8 @@ service_array[1] = tracker_get_id_for_service ("EvolutionEmails"); service_array[2] = tracker_get_id_for_service ("KMailEmails"); service_array[3] = tracker_get_id_for_service ("ThunderbirdEmails"); - service_count = 4; + service_array[4] = tracker_get_id_for_service ("ModestEmails"); + service_count = 5; } else if (strcmp (service, "Conversations") == 0) { service_array[1] = tracker_get_id_for_service ("GaimConversations"); Index: src/trackerd/tracker-email-evolution.c =================================================================== --- src/trackerd/tracker-email-evolution.c (revision 1250) +++ src/trackerd/tracker-email-evolution.c (working copy) @@ -1401,7 +1401,7 @@ if (!(*save_ondisk_mail) (db_con, mail_msg)) { tracker_log ("WARNING: Message, or message parts, could not be found locally - if you are using IMAP make sure you have selected the \"copy folder content locally for offline operation\" option in Evolution"); /* we do not have all infos but we still save them */ - if (!tracker_db_email_save_email (db_con, mail_msg)) { + if (!tracker_db_email_save_email (db_con, mail_msg, MAIL_APP_EVOLUTION)) { tracker_log ("Failed to save email"); } } @@ -2308,7 +2308,7 @@ tracker_log ("... Treatment of mail parts of \"%s\" finished", mail_msg->uri); if (ret) { - tracker_db_email_save_email (db_con, mail_msg); + tracker_db_email_save_email (db_con, mail_msg, MAIL_APP_EVOLUTION); } } else { tracker_log ("...Indexing of mail parts failed"); @@ -2337,7 +2337,7 @@ MailMessage *mail_msg_on_disk = NULL; mail_msg_on_disk = email_parse_mail_message_by_path (MAIL_APP_EVOLUTION, - mail_msg->path, NULL, NULL); + mail_msg->path, NULL, NULL); if (mail_msg_on_disk && mail_msg_on_disk->parent_mail_file) { @@ -2345,9 +2345,9 @@ mail_msg_on_disk->uri = g_strdup (mail_msg->uri); mail_msg_on_disk->store = mail_msg->store; - tracker_db_email_save_email (db_con, mail_msg_on_disk); + tracker_db_email_save_email (db_con, mail_msg_on_disk, MAIL_APP_EVOLUTION); - email_free_mail_file (mail_msg_on_disk->parent_mail_file); + email_free_mail_file (mail_msg_on_disk->parent_mail_file); email_free_mail_message (mail_msg_on_disk); return TRUE; @@ -2652,7 +2652,7 @@ gint i = sizeof (type) - 1; \ gint v = EOF; \ \ - while (i >= 0 && (v = fgetc (in)) != EOF) { \ + while (i >= 0 && (v = fgetc (in)) != EOF) { \ save |= ((type)v) << (i * 8); \ i--; \ } \ Index: src/trackerd/tracker-email-modest.c =================================================================== --- src/trackerd/tracker-email-modest.c (revision 0) +++ src/trackerd/tracker-email-modest.c (revision 0) @@ -0,0 +1,1714 @@ +/* Tracker + * routines for emails with Modest + * Copyright (C) 2008, Philip Van Hoof (pvanhoof gnome org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tracker-email-modest.h" +#include "tracker-email-utils.h" +#include "tracker-db-email.h" +#include "tracker-cache.h" +#include "tracker-dbus.h" +#include "tracker-watch.h" + + +#define MODEST_MAIL_DIR_S ".modest/cache/mail" +#define MODEST_LOCAL_MAIL_DIR_S ".modest/local_folders" + + +typedef struct { + gchar *mail_dir; /* something like "/home/laurent.modest/mail" */ + GSList *imap_dirs; /* list of IMAP directories */ + GSList *pop_dirs; /* list of POP directories */ + GSList *maildir_dirs; /* list of maildir directories */ +} ModestConfig; + + +enum { + MODEST_MESSAGE_ANSWERED = 1 << 0, + MODEST_MESSAGE_DELETED = 1 << 1, + MODEST_MESSAGE_DRAFT = 1 << 2, + MODEST_MESSAGE_FLAGGED = 1 << 3, + MODEST_MESSAGE_SEEN = 1 << 4, + MODEST_MESSAGE_ATTACHMENTS = 1 << 5, + MODEST_MESSAGE_CACHED = 1 << 6, + MODEST_MESSAGE_PARTIAL = 1 << 7, + MODEST_MESSAGE_EXPUNGED = 1 << 8, + MODEST_MESSAGE_HIGH_PRIORITY = 0<<9|1<<10, + MODEST_MESSAGE_NORMAL_PRIORITY = 0<<9|0<<10, + MODEST_MESSAGE_LOW_PRIORITY = 1<<9|0<<10, + MODEST_MESSAGE_SUSPENDED = 1<<11 +}; + +typedef struct { + gchar *path; /* path the summary file */ + FILE *f; /* opened file descriptor for the file */ +} SummaryFile; + +typedef struct { + gint32 version; + gboolean legacy; + gint32 flags; + gint32 nextuid; + time_t time; + gint32 saved_count; + gint32 unread_count; + gint32 deleted_count; + gint32 junk_count; + gchar *uri_prefix; +} SummaryFileHeader; + +/* Some infos are only accessible throw a deep code path but we need to retreive them. */ +typedef struct { + gchar *mail_uid; +} ModestAdHocInfos; + + +extern Tracker *tracker; + +static ModestConfig *modest_config = NULL; + + +static gboolean load_modest_config (ModestConfig **conf); +static void free_modest_config (ModestConfig *conf); + + +static gboolean is_in_dir_pop (const gchar *dir); +static gboolean is_in_dir_imap (const gchar *dir); +static gboolean is_in_dir_maildir (const gchar *dir); + +typedef gboolean (* LoadSummaryFileMetaHeaderFct) (SummaryFile *summary, SummaryFileHeader *header); +typedef gboolean (* LoadMailMessageFct) (SummaryFile *summary, MailMessage **mail_msg); +typedef gboolean (* SkipMailMessageFct) (SummaryFile *summary); +typedef gboolean (* SaveOnDiskMailMessageFct) (DBConnection *db_con, MailMessage *msg); + +static void index_mail_messages_by_summary_file (DBConnection *db_con, MailType mail_type, + const gchar *summary_file_path, + LoadSummaryFileMetaHeaderFct load_meta_header, + LoadMailMessageFct load_mail, + SkipMailMessageFct skip_mail, + SaveOnDiskMailMessageFct save_ondisk_mail); + +static gboolean open_summary_file (const gchar *path, SummaryFile **summary); +static void free_summary_file (SummaryFile *summary); + +static gboolean load_summary_file_header (SummaryFile *summary, SummaryFileHeader **header); +static void free_summary_file_header (SummaryFileHeader *header); +static gboolean load_summary_file_meta_header_for_pop (SummaryFile *summary, SummaryFileHeader *header); +static gboolean load_summary_file_meta_header_for_maildir (SummaryFile *summary, SummaryFileHeader *header); +static gboolean load_summary_file_meta_header_for_imap (SummaryFile *summary, SummaryFileHeader *header); + +static gboolean load_mail_message_for_imap (SummaryFile *summary, MailMessage **mail_msg); +static gboolean load_mail_message_for_pop (SummaryFile *summary, MailMessage **mail_msg); +static gboolean load_mail_message_for_maildir (SummaryFile *summary, MailMessage **mail_msg); +static gboolean do_load_mail_message_for_imap (SummaryFile *summary, MailMessage **mail_msg, gboolean do_skipping_of_content_info); +static gboolean do_load_mail_message_for_pop (SummaryFile *summary, MailMessage **mail_msg, gboolean do_skipping_of_content_info); +static gboolean do_load_mail_message_for_maildir (SummaryFile *summary, MailMessage **mail_msg, gboolean do_skipping_of_content_info); + +static gboolean load_mail_message (SummaryFile *summary, MailMessage *mail_msg); + +static gboolean skip_mail_message_for_imap (SummaryFile *summary); +static gboolean skip_mail_message_for_pop (SummaryFile *summary); +static gboolean skip_mail_message_for_maildir (SummaryFile *summary); + +static gboolean do_skip_mail_message_for_maildir (SummaryFile *summary, gboolean do_skipping_of_content_info); +static gboolean do_skip_mail_message_for_pop (SummaryFile *summary, gboolean do_skipping_of_content_info); +static gboolean do_skip_mail_message_for_imap (SummaryFile *summary, gboolean do_skipping_of_content_info); + +static gboolean skip_mail_message (SummaryFile *summary); + +static gboolean skip_loading_content_info (SummaryFile *summary); +static gboolean do_skip_loading_content_info (SummaryFile *summary); + +static gboolean save_ondisk_email_message_for_imap (DBConnection *db_con, MailMessage *mail_msg); +static gboolean save_ondisk_email_message_for_pop (DBConnection *db_con, MailMessage *mail_msg); +static gboolean save_ondisk_email_message_for_maildir (DBConnection *db_con, MailMessage *mail_msg); +static gboolean do_save_ondisk_email_message_generic (DBConnection *db_con, MailMessage *mail_msg); +static gboolean do_save_ondisk_email_message (DBConnection *db_con, MailMessage *mail_msg); + +static GSList * add_persons_from_internet_address_list_string_parsing (GSList *list, const gchar *s); + +static inline gboolean decode_gint32 (FILE *f, gint32 *n); +static inline gboolean skip_gint32_decoding (FILE *f); +static inline gboolean decode_guint32 (FILE *f, guint32 *n); +static inline gboolean skip_guint32_decoding (FILE *f); +static inline gboolean decode_time_t (FILE *f, time_t *t); +static inline gboolean skip_time_t_decoding (FILE *f); +static inline gboolean decode_off_t (FILE *f, off_t *t); +static inline gboolean skip_off_t_decoding (FILE *f); +static inline gboolean decode_string (FILE *f, gchar **str); +static inline gboolean skip_string_decoding (FILE *f); +static inline gboolean skip_token_decoding (FILE *f); + +static void check_summary_file (DBConnection *db_con, const gchar *filename, MailStore *store); + + +static gboolean +modest_module_is_running (void) +{ + return modest_config != NULL; +} + + +/******************************************************************************************** + Public functions +*********************************************************************************************/ + +gboolean +tracker_email_init (void) +{ + ModestConfig *conf; + + if (modest_config) { + return TRUE; + } + + conf = NULL; + + if (load_modest_config (&conf)) { + modest_config = conf; + } + + return modest_module_is_running (); +} + + + +gboolean +tracker_email_finalize (void) +{ + if (!modest_config) { + return TRUE; + } + + free_modest_config (modest_config); + modest_config = NULL; + + return !modest_module_is_running (); +} + +static void +free_modest_config (ModestConfig *conf) +{ + if (!conf) { + return; + } + + if (conf->mail_dir) { + g_free (conf->mail_dir); + } + + #define FREE_MY_LIST(list, free_fct) \ + g_slist_foreach (list, (GFunc) free_fct, NULL); \ + g_slist_free (list); + + FREE_MY_LIST (conf->imap_dirs, g_free); + FREE_MY_LIST (conf->pop_dirs, g_free); + FREE_MY_LIST (conf->maildir_dirs, g_free); + + #undef FREE_MY_LIST + + g_slice_free (ModestConfig, conf); +} + +void +tracker_email_watch_emails (DBConnection *db_con) +{ + gchar ***res, **row; + gint j; + + /* if initial indexing has not finished reset mtime on all email stuff so they are rechecked */ + if (tracker_db_get_option_int (db_con->common, "InitialIndex") == 1) { + char *sql = g_strdup_printf ("update Services set mtime = 0 where path like '%s/.modest/%s'", g_get_home_dir (), "%"); + + tracker_exec_sql (db_con, sql); + g_free (sql); + } + + /* check all registered mbox/paths for deletions */ + res = tracker_db_email_get_mboxes (db_con); + + for (j = 0; (row = tracker_db_get_row (res, j)); j++) { + + if (row[2] && row[3]) { + MailStore *store = tracker_db_email_get_mbox_details (db_con, row[3]); + + if (store) { + check_summary_file (db_con, row[2], store); + tracker_db_email_free_mail_store (store); + } + } + } + + if (res) { + tracker_db_free_result (res); + } + + g_slist_foreach (modest_config->imap_dirs, (GFunc) email_watch_directory, "ModestEmails"); + g_slist_foreach (modest_config->pop_dirs, (GFunc) email_watch_directory, "ModestEmails"); + g_slist_foreach (modest_config->maildir_dirs, (GFunc) email_watch_directory, "ModestEmails"); +} + +static gboolean +modest_file_is_interesting (FileInfo *info) +{ + g_return_val_if_fail (info, FALSE); + g_return_val_if_fail (info->uri, FALSE); + g_return_val_if_fail (modest_config, FALSE); + g_return_val_if_fail (modest_config->mail_dir, FALSE); + + /* maildir/pop/imap all have summary files (*.ev-summary.mmap or "summary.mmap") */ + if ((strcmp (info->uri, "summary.mmap") == 0) || g_str_has_suffix (info->uri, "summary.mmap")) { + return TRUE; + } else { + return FALSE; + } + + return FALSE; +} + + +gboolean +tracker_email_index_file (DBConnection *db_con, FileInfo *info) +{ + gchar *file_name; + + g_return_val_if_fail (db_con, FALSE); + g_return_val_if_fail (info, FALSE); + + if (!modest_file_is_interesting (info)) + return FALSE; + + file_name = g_path_get_basename (info->uri); + + tracker_debug ("indexing email summary %s", info->uri); + + if (is_in_dir_imap (info->uri)) { + if (strcmp (file_name, "summary.mmap") == 0) { + index_mail_messages_by_summary_file (db_con, MAIL_TYPE_IMAP, info->uri, + load_summary_file_meta_header_for_imap, + load_mail_message_for_imap, + skip_mail_message_for_imap, + save_ondisk_email_message_for_imap); + } + } + + if (is_in_dir_pop (info->uri)) { + if (strcmp (file_name, "summary.mmap") == 0) { + index_mail_messages_by_summary_file (db_con, MAIL_TYPE_POP, info->uri, + load_summary_file_meta_header_for_pop, + load_mail_message_for_pop, + skip_mail_message_for_pop, + save_ondisk_email_message_for_pop); + } + } + + if (is_in_dir_maildir (info->uri)) { + if (strcmp (file_name, "summary.mmap") || g_str_has_suffix (info->uri, "summary.mmap")) { + index_mail_messages_by_summary_file (db_con, MAIL_TYPE_MAILDIR, info->uri, + load_summary_file_meta_header_for_maildir, + load_mail_message_for_maildir, + skip_mail_message_for_maildir, + save_ondisk_email_message_for_maildir); + } + } + + g_free (file_name); + + return TRUE; +} + +const gchar * +tracker_email_get_name (void) +{ + return "ModestEmails"; +} + + +/******************************************************************************************** + Private functions +*********************************************************************************************/ + + +static void +check_summary_file (DBConnection *db_con, const gchar *filename, MailStore *store) +{ + SummaryFile *summary = NULL; + + g_return_if_fail (store); + + if (open_summary_file (filename, &summary)) { + SummaryFileHeader *header; + gchar *path; + + header = NULL; + + tracker_log ("Scanning summary file %s for junk", filename); + + if (!load_summary_file_header (summary, &header)) { + free_summary_file (summary); + tracker_error ("ERROR: failed to open summary file %s", filename); + return; + } + + if (store->type == MAIL_TYPE_IMAP) { + if (!load_summary_file_meta_header_for_imap (summary, header)) { + free_summary_file_header (header); + free_summary_file (summary); + tracker_error ("ERROR: failed to open summary header file %s", filename); + return; + } + + } else if (store->type == MAIL_TYPE_POP) { + if (!load_summary_file_meta_header_for_pop (summary, header)) { + free_summary_file_header (header); + free_summary_file (summary); + tracker_error ("ERROR: failed to open summary header file %s", filename); + return; + } + } else if (store->type == MAIL_TYPE_MAILDIR) { + if (!load_summary_file_meta_header_for_pop (summary, header)) { + free_summary_file_header (header); + free_summary_file (summary); + tracker_error ("ERROR: failed to open summary header file %s", filename); + return; + } + + } else { + tracker_error ("ERROR: summary file not supported"); + free_summary_file_header (header); + free_summary_file (summary); + return; + + } + + path = tracker_db_email_get_mbox_path (db_con, filename); + tracker_db_email_set_message_counts (db_con, path, store->mail_count, header->junk_count, header->deleted_count); + g_free (path); + + free_summary_file_header (header); + free_summary_file (summary); + } +} + + + + +static GSList* +moredir (char *name, char *lastname, GSList *list) { + DIR *dir = opendir (name); + struct dirent *d; + + if (dir) { + while ( (d = readdir(dir)) ) { + struct stat st; + if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) { + char *tmp = g_build_filename (name, d->d_name, NULL); + if (stat(tmp, &st) == 0 && S_ISDIR(st.st_mode)) + list = moredir (tmp, name, list); + g_free (tmp); + + if ((strcmp (d->d_name, "summary.mmap") == 0) || g_str_has_suffix (d->d_name, "summary.mmap")) { + tracker_log ("Adding mail_dir: %s\n", name); + list = g_slist_prepend (list, g_strdup (name)); + + /* Question from Philip Van Hoof: + * I think we can return here, if a maildir's root + * has two summary files, for two subdirs, only + * monitoring the root once should suffice, I think + * + * Example FS structure: + * + * MyMailDirRoot <- Added to maildir_dirs twice (two summary files) + * +- MyFolder1 + * | +- cur <- Actual settled E-mails + * | +- new <- Recently created E-mails + * | `- tmp <- Being created E-mails + * | + * +- MyFolder2 <- Added to maildir_dirs once (one summary file) + * | +- MyFolder3.ev-summary.mmap <- to monitor + * | +- MyFolder3 + * | | +- cur + * | | +- new + * | | `- tmp + * | | + * | +- cur + * | +- new + * | `- tmp + * +- MyFolder1.ev-summary.mmap <- to monitor + * `- MyFolder2.ev-summary.mmap <- to monitor + */ + } + } + } + closedir(dir); + } + return list; +} + +static gboolean +load_modest_config (ModestConfig **conf) +{ + char *dir_imap, *dir_pop, *dir_maildir; + ModestConfig *m_conf; + + if (*conf) { + free_modest_config (*conf); + } + + *conf = g_slice_new0 (ModestConfig); + m_conf = *conf; + + m_conf->mail_dir = g_build_filename (g_get_home_dir (), MODEST_MAIL_DIR_S, NULL); + + + dir_imap = g_build_filename (m_conf->mail_dir, "imap", NULL); + dir_pop = g_build_filename (m_conf->mail_dir, "pop", NULL); + dir_maildir = g_strdup (MODEST_LOCAL_MAIL_DIR_S); + + tracker_log ("Checking for Modest email accounts..."); + + m_conf->imap_dirs = moredir (dir_imap, m_conf->mail_dir, m_conf->imap_dirs); + m_conf->pop_dirs = moredir (dir_pop, m_conf->mail_dir, m_conf->pop_dirs); + + /* TODO: Future support + * m_conf->maildir_dirs must be updated whenever an MMC card gets inserted */ + + m_conf->maildir_dirs = moredir (dir_maildir, dir_maildir, m_conf->maildir_dirs); + + g_free (dir_imap); + g_free (dir_pop); + g_free (dir_maildir); + + return TRUE; +} + + + +static gboolean +is_in_dir_imap (const gchar *path) +{ + g_return_val_if_fail (path, FALSE); + return strstr (path, G_DIR_SEPARATOR_S "imap") != NULL; +} + + +static gboolean +is_in_dir_maildir (const gchar *path) +{ + g_return_val_if_fail (path, FALSE); + return strstr (path, G_DIR_SEPARATOR_S "maildir") != NULL; +} + + +static gboolean +is_in_dir_pop (const gchar *path) +{ + g_return_val_if_fail (path, FALSE); + return strstr (path, G_DIR_SEPARATOR_S "pop" G_DIR_SEPARATOR_S) != NULL; +} + + +static void +index_mail_messages_by_summary_file (DBConnection *db_con, + MailType mail_type, + const gchar *summary_file_path, + LoadSummaryFileMetaHeaderFct load_meta_header, + LoadMailMessageFct load_mail, + SkipMailMessageFct skip_mail, + SaveOnDiskMailMessageFct save_ondisk_mail) +{ + SummaryFile *summary = NULL; + + if (!tracker->is_running) + return; + + if (open_summary_file (summary_file_path, &summary)) { + SummaryFileHeader *header; + gint32 mail_count, junk_count, delete_count; + gchar *dir; + char *piece; + + header = NULL; + + if (!load_summary_file_header (summary, &header)) { + free_summary_file (summary); + return; + } + + if (!(*load_meta_header) (summary, header)) { + free_summary_file_header (header); + free_summary_file (summary); + return; + } + + dir = g_path_get_dirname (summary->path); + + /* check summary file is registered */ + if (tracker_db_email_get_mbox_id (db_con, dir) == -1) { + const gchar *pos_folders = strstr (dir, G_DIR_SEPARATOR_S "folders" G_DIR_SEPARATOR_S); + + if (pos_folders) { + size_t len_pos_folders = strlen (pos_folders); + + if (len_pos_folders > 9) { /* strlen ("/folders/") == 9 */ + gchar *uri_dir, *clean_uri_dir, *uri_prefix; + + pos_folders += 9; + + uri_dir = NULL; + + /* we find relative summary file path from directory INBOX (or Sent, etc.). + It can be INBOX/, INBOX/sent-mail ,etc. */ + if (pos_folders) { + uri_dir = g_strdup (pos_folders); + } + + clean_uri_dir = NULL; + + if (uri_dir) { + gchar *tmp_str = tracker_string_replace (uri_dir, "subfolders/", NULL); + clean_uri_dir = tracker_string_replace (tmp_str, "folders/", NULL); + g_free (tmp_str); + } + + if (mail_type == MAIL_TYPE_IMAP || mail_type == MAIL_TYPE_POP) { + char *tdir = g_strdup (dir); + char *loc = strstr (tdir, MODEST_MAIL_DIR_S); + loc += strlen (MODEST_MAIL_DIR_S) + 1; + loc = strchr (loc, '/'); loc++; // imap + loc = strchr (loc, '/'); // acc name + loc++; + *loc = '\0'; + char *tmp = g_build_filename (tdir, "url_string", NULL); + FILE *f = fopen (tmp, "r"); + if (f) { + char str[4000]; + memset (str, 0, 4000); + fgets (str, 4000, f); + piece = g_strndup (str, strlen (str)); + } else + piece = g_strdup ("unknown://location/"); + g_free (tmp); + g_free (tdir); + } else if (mail_type == MAIL_TYPE_MAILDIR) + piece = g_strdup_printf ("maildir://%s/", dir); + + if (clean_uri_dir) { + uri_prefix = g_strdup_printf ("%s/%s/", piece, clean_uri_dir); + g_free (clean_uri_dir); + } else { + uri_prefix = g_strdup (piece); + } + + g_free (piece); + g_free (uri_dir); + + tracker_db_email_register_mbox (db_con, MAIL_APP_MODEST, mail_type, dir, summary_file_path, uri_prefix); + + //g_free (uri_prefix); + } + } + } + + + MailStore *store = tracker_db_email_get_mbox_details (db_con, dir); + + if (!store) { + tracker_error ("ERROR: could not retrieve store for file %s", dir); + free_summary_file (summary); + free_summary_file_header (header); + + g_free (dir); + return; + } + + tracker_debug ("Number of existing messages in %s are %d, %d junk, %d deleted and header totals are %d, %d, %d", dir, + store->mail_count, store->junk_count, store->delete_count, header->saved_count, header->junk_count, header->deleted_count); + + tracker->mbox_count++; + tracker_dbus_send_index_progress_signal ("Emails", dir); + + if (header->saved_count > store->mail_count) { + /* assume new emails received */ + + gint i; + + /* skip already indexed emails */ + for (i = 0; i < store->mail_count; i++) { + if (!(*skip_mail) (summary)) { + tracker_error ("ERROR: skipping email no. %d in summary file", i+1); + tracker_db_email_free_mail_store (store); + free_summary_file (summary); + free_summary_file_header (header); + tracker->mbox_processed++; + g_free (dir); + return; + } + } + + mail_count = 0; + junk_count = 0; + delete_count = 0; + + /* now we will read the new emails */ + for (i = store->mail_count; i < header->saved_count; i++) { + MailMessage *mail_msg = NULL; + + mail_count++; + tracker_debug ("processing email no. %d / %" G_GINT32_FORMAT, store->mail_count + 1, header->saved_count); + + if (!(*load_mail) (summary, &mail_msg)) { + tracker_error ("ERROR: loading email no. %d in summary file", mail_count); + tracker_db_email_free_mail_store (store); + free_summary_file (summary); + free_summary_file_header (header); + tracker->mbox_processed++; + g_free (dir); + return; + } + + gchar *sum_file_dir = g_path_get_dirname (summary->path); + mail_msg->path = g_strdup_printf ("%s%s%d.", sum_file_dir, G_DIR_SEPARATOR_S, mail_msg->id); + g_free (sum_file_dir); + + gchar *str_id = tracker_int_to_str (mail_msg->id); + mail_msg->uri = g_strconcat (store->uri_prefix, str_id, NULL); + g_free (str_id); + + mail_msg->store = store; + + if (!(*save_ondisk_mail) (db_con, mail_msg)) { + tracker_log ("WARNING: Message, or message parts, could not be found locally - if you are using IMAP make sure you have selected the \"copy folder content locally for offline operation\" option in Modest"); + /* we do not have all infos but we still save them */ + if (!tracker_db_email_save_email (db_con, mail_msg, MAIL_APP_MODEST)) { + tracker_log ("Failed to save email"); + } + } + + if (mail_msg->junk) { + junk_count++; + } + + if (mail_msg->deleted) { + delete_count++; + } + + email_free_mail_file (mail_msg->parent_mail_file); + email_free_mail_message (mail_msg); + + if (!tracker_cache_process_events (db_con->data, TRUE)) { + tracker->status = STATUS_SHUTDOWN; + tracker->shutdown = TRUE; + tracker_dbus_send_index_status_change_signal (); + return; + } + + if (tracker_db_regulate_transactions (db_con->data, 500)) { + + if (tracker->index_count % 1000 == 0) { + tracker_db_end_index_transaction (db_con->data); + tracker_db_refresh_all (db_con->data); + tracker_db_start_index_transaction (db_con->data); + } + + tracker_dbus_send_index_progress_signal ("Emails", dir); + + } + + + } + + tracker_log ("No. of new emails indexed in summary file %s is %d, %d junk, %d deleted", dir, mail_count, junk_count, delete_count); + + tracker_db_email_set_message_counts (db_con, dir, store->mail_count, store->junk_count, store->delete_count); + + } else { + /* schedule check for junk */ + tracker_db_email_flag_mbox_junk (db_con, dir); + } + + tracker->mbox_processed++; + tracker_dbus_send_index_progress_signal ("Emails", dir); + + tracker_db_email_free_mail_store (store); + free_summary_file (summary); + free_summary_file_header (header); + + g_free (dir); + } +} + + + + +static gboolean +open_summary_file (const gchar *path, SummaryFile **summary) +{ + gint fd; + FILE *f; + + g_return_val_if_fail (path, FALSE); + + if (!tracker_file_is_indexable (path)) { + return FALSE; + } + + if (*summary) { + free_summary_file (*summary); + *summary = NULL; + } + + fd = tracker_file_open (path, TRUE); + + if (fd == -1) { + return FALSE; + } + + f = fdopen (fd, "r"); + if (!f) { + tracker_file_close (fd, TRUE); + return FALSE; + } + + *summary = g_slice_new0 (SummaryFile); + (*summary)->f = f; + (*summary)->path = g_strdup (path); + + return TRUE; +} + + +static void +free_summary_file (SummaryFile *summary) +{ + if (!summary) { + return; + } + + fclose (summary->f); + + g_free (summary->path); + g_slice_free (SummaryFile, summary); +} + + +static gboolean +load_summary_file_header (SummaryFile *summary, SummaryFileHeader **header) +{ + SummaryFileHeader *h; + FILE *f; + + g_return_val_if_fail (summary, FALSE); + + if (*header) { + free_summary_file_header (*header); + } + + *header = g_slice_new0 (SummaryFileHeader); + + h = *header; + + h->uri_prefix = NULL; + + f = summary->f; + + + if (!decode_gint32 (f, &h->version)) { + goto error; + } + + tracker_debug ("summary.version = %d", h->version); + + if (h->version > 0xff && (h->version & 0xff) < 12) { + tracker_error ("ERROR: summary file header version too low"); + goto error; + } + + h->legacy = !(h->version < 0x100 && h->version >= 13); + + if (h->legacy) { + tracker_debug ("WARNING: summary file is a legacy version"); + } + + + if (!decode_gint32 (f, &h->flags) || + !decode_gint32 (f, &h->nextuid) || + !decode_time_t (f, &h->time) || + !decode_gint32 (f, &h->saved_count)) { + goto error; + } + + tracker_debug ("summary.flags = %d", h->flags); + tracker_debug ("summary.nextuid = %d", h->nextuid); + tracker_debug ("summary.time = %d", h->time); + tracker_debug ("summary.count = %" G_GINT32_FORMAT, h->saved_count); + + if (!h->legacy) { + if (!decode_gint32 (f, &h->unread_count) || + !decode_gint32 (f, &h->deleted_count) || + !decode_gint32 (f, &h->junk_count)) { + goto error; + } + } + + tracker_debug ("summary.Unread = %d", h->unread_count); + tracker_debug ("summary.deleted = %d", h->deleted_count); + tracker_debug ("summary.junk = %d", h->junk_count); + + return TRUE; + + error: + free_summary_file_header (*header); + *header = NULL; + + return FALSE; +} + + +static void +free_summary_file_header (SummaryFileHeader *header) +{ + if (!header) { + return; + } + + if (header->uri_prefix) { + g_free (header->uri_prefix); + } + + g_slice_free (SummaryFileHeader, header); +} + + +static gboolean +load_summary_file_meta_header_generic (SummaryFile *summary, SummaryFileHeader *header) +{ + FILE *f; + + g_return_val_if_fail (summary, FALSE); + g_return_val_if_fail (header, FALSE); + + f = summary->f; + + /* check for legacy version */ + if (header->version != 0x30c) { + gint32 version; + + if (!decode_gint32 (f, &version)) { + return FALSE; + } + + if (version < 0) { + tracker_error ("ERROR: summary file version too low"); + return FALSE; + } + + /* Right now we only support summary versions 1 through 3 */ + if (version > 3) { + tracker_error ("ERROR: reported summary version (%" G_GINT32_FORMAT ") is too new", version); + return FALSE; + } + + if (version == 2) { + if (!skip_gint32_decoding (f)) { + return FALSE; + } + } + + } + + return TRUE; +} + +static gboolean +load_summary_file_meta_header_for_imap (SummaryFile *summary, SummaryFileHeader *header) +{ + FILE *f; + guint32 dummy0; + + g_return_val_if_fail (summary, FALSE); + g_return_val_if_fail (header, FALSE); + + f = summary->f; + + /* check for legacy version */ + if (header->version != 0x30c) { + gint32 version, dummy1; + + if (!decode_gint32 (f, &version)) { + return FALSE; + } + + if (version < 0) { + tracker_error ("ERROR: summary file version too low"); + return FALSE; + } + + /* Right now we only support summary versions 1 through 3 */ + if (version > 3) { + tracker_error ("ERROR: reported summary version (%" G_GINT32_FORMAT ") is too new", version); + return FALSE; + } + + if (version == 2) { + if (!skip_gint32_decoding (f)) { + return FALSE; + } + } + + /* validity */ + if (!decode_gint32 (f, &dummy1)) { + return FALSE; + } + } else { + /* validity */ + if (!decode_guint32 (f, &dummy0)) { + return FALSE; + } + } + + return TRUE; +} + + +static gboolean +load_summary_file_meta_header_for_pop (SummaryFile *summary, SummaryFileHeader *header) +{ + return load_summary_file_meta_header_generic (summary, header); +} + +static gboolean +load_summary_file_meta_header_for_maildir (SummaryFile *summary, SummaryFileHeader *header) +{ + return load_summary_file_meta_header_generic (summary, header); +} + + +static gboolean +load_mail_message_for_imap (SummaryFile *summary, MailMessage **mail_msg) +{ + return do_load_mail_message_for_imap (summary, mail_msg, TRUE); +} + +static gboolean +load_mail_message_for_maildir (SummaryFile *summary, MailMessage **mail_msg) +{ + return do_load_mail_message_for_maildir (summary, mail_msg, TRUE); +} + +static gboolean +load_mail_message_for_pop (SummaryFile *summary, MailMessage **mail_msg) +{ + return do_load_mail_message_for_pop (summary, mail_msg, TRUE); +} + + +static gboolean +do_load_mail_message_for_imap (SummaryFile *summary, MailMessage **mail_msg, gboolean do_skipping_of_content_info) +{ + guint32 server_flags; + + g_return_val_if_fail (summary, FALSE); + + if (*mail_msg) { + email_free_mail_message (*mail_msg); + } + + *mail_msg = email_allocate_mail_message (); + + if (!load_mail_message (summary, *mail_msg)) { + goto error; + } + + if (!decode_guint32 (summary->f, &server_flags)) { + goto error; + } + + if (do_skipping_of_content_info) { + if (!skip_loading_content_info (summary)) { + goto error; + } + } + + return TRUE; + + error: + email_free_mail_message (*mail_msg); + *mail_msg = NULL; + return FALSE; +} + + + +static gboolean +do_load_mail_message_generic (SummaryFile *summary, MailMessage **mail_msg, gboolean do_skipping_of_content_info) +{ + g_return_val_if_fail (summary, FALSE); + + if (*mail_msg) { + email_free_mail_message (*mail_msg); + } + + *mail_msg = email_allocate_mail_message (); + + if (!load_mail_message (summary, *mail_msg)) { + goto error; + } + + if (do_skipping_of_content_info) { + if (!skip_loading_content_info (summary)) { + goto error; + } + } + + return TRUE; + + error: + email_free_mail_message (*mail_msg); + *mail_msg = NULL; + return FALSE; +} + + + +static gboolean +do_load_mail_message_for_pop (SummaryFile *summary, MailMessage **mail_msg, gboolean do_skipping_of_content_info) +{ + + return do_load_mail_message_generic (summary, mail_msg, do_skipping_of_content_info); +} + + + +static gboolean +do_load_mail_message_for_maildir (SummaryFile *summary, MailMessage **mail_msg, gboolean do_skipping_of_content_info) +{ + return do_load_mail_message_generic (summary, mail_msg, do_skipping_of_content_info); +} + +static gboolean +load_mail_message (SummaryFile *summary, MailMessage *mail_msg) +{ + FILE *f; + guint32 flags, size, count; + time_t date_sent, date_received; + gchar *uid, *to, *cc, *mlist; + + g_return_val_if_fail (summary, FALSE); + g_return_val_if_fail (mail_msg, FALSE); + + f = summary->f; + + if (!decode_string (f, &uid) || + !decode_guint32 (f, &size) || /* Size and flags are reversed in tny */ + !decode_guint32 (f, &flags) || /* Size and flags are reversed in tny */ + !decode_time_t (f, &date_sent) || + !decode_time_t (f, &date_received) || + !decode_string (f, &mail_msg->subject) || + !decode_string (f, &mail_msg->from) || + !decode_string (f, &to) || + !decode_string (f, &cc) || + !decode_string (f, &mlist)) /* mlist will be an empty string in tny */ + { + + return FALSE; + } + + g_free (mlist); + + + mail_msg->id = strtoul (uid, NULL, 10); + + g_free (uid); + + if ((flags & MODEST_MESSAGE_DELETED) == MODEST_MESSAGE_DELETED) { + mail_msg->deleted = TRUE; + } + + if ((flags & MODEST_MESSAGE_EXPUNGED) == MODEST_MESSAGE_EXPUNGED) { + mail_msg->deleted = TRUE; + } + + mail_msg->junk = FALSE; + + mail_msg->date = (long) date_received; + + mail_msg->to = add_persons_from_internet_address_list_string_parsing (NULL, to); + mail_msg->cc = add_persons_from_internet_address_list_string_parsing (NULL, cc); + + g_free (to); + g_free (cc); + + skip_gint32_decoding (f); /* mi->message_id.id.part.hi */ + skip_gint32_decoding (f); /* mi->message_id.id.part.lo */ + + /* references */ + if (decode_guint32 (f, &count) && count <= 500) { + guint32 i; + for (i = 0; i < count; i++) { + skip_gint32_decoding (f); /* mi->references->references[i].id.part.hi */ + skip_gint32_decoding (f); /* mi->references->references[i].id.part.lo */ + } + } else { + return FALSE; + } + + /* user flags */ + if (decode_guint32 (f, &count) && count <= 500) { + guint32 i; + for (i = 0; i < count; i++) { + skip_string_decoding (f); /* a flag */ + } + } else { + return FALSE; + } + + /* user tags */ + if (decode_guint32 (f, &count) && count <= 500) { + guint32 i; + for (i = 0; i < count; i++) { + skip_string_decoding (f); /* tag name */ + skip_string_decoding (f); /* tag value */ + } + } else { + return FALSE; + } + + return TRUE; +} + + +static gboolean +skip_mail_message_for_imap (SummaryFile *summary) +{ + return do_skip_mail_message_for_imap (summary, TRUE); +} + + +static gboolean +skip_mail_message_for_pop (SummaryFile *summary) +{ + return do_skip_mail_message_for_pop (summary, TRUE); +} + +static gboolean +skip_mail_message_for_maildir (SummaryFile *summary) +{ + return do_skip_mail_message_for_maildir (summary, TRUE); +} + + +static gboolean +do_skip_mail_message_for_imap (SummaryFile *summary, gboolean do_skipping_of_content_info) +{ + g_return_val_if_fail (summary, FALSE); + + if (!skip_mail_message (summary)) { + return FALSE; + } + + if (!skip_guint32_decoding (summary->f)) { + return FALSE; + } + + if (do_skipping_of_content_info) { + if (!skip_loading_content_info (summary)) { + return FALSE; + } + } + + return TRUE; +} + + + +static gboolean +do_skip_mail_message_for_pop (SummaryFile *summary, gboolean do_skipping_of_content_info) +{ + g_return_val_if_fail (summary, FALSE); + + if (!skip_mail_message (summary)) { + return FALSE; + } + + if (!skip_guint32_decoding (summary->f)) { + return FALSE; + } + + if (do_skipping_of_content_info) { + if (!skip_loading_content_info (summary)) { + return FALSE; + } + } + + return TRUE; +} + + + +static gboolean +do_skip_mail_message_for_maildir (SummaryFile *summary, gboolean do_skipping_of_content_info) +{ + g_return_val_if_fail (summary, FALSE); + + if (!skip_mail_message (summary)) { + return FALSE; + } + + if (!skip_guint32_decoding (summary->f)) { + return FALSE; + } + + if (do_skipping_of_content_info) { + if (!skip_loading_content_info (summary)) { + return FALSE; + } + } + + return TRUE; +} + + + + +static gboolean +skip_mail_message (SummaryFile *summary) +{ + FILE *f; + guint32 count; + time_t tt; + guint n; + + g_return_val_if_fail (summary, FALSE); + + f = summary->f; + + if (!skip_string_decoding (f)) + return FALSE; + + if (!decode_guint32 (f, &n)) + return FALSE; + + if (!decode_guint32 (f, &n)) + return FALSE; + + if (!decode_time_t (f, &tt)) + return FALSE; + + if (!decode_time_t (f, &tt)) + return FALSE; + + if (!skip_string_decoding (f)) + return FALSE; + + if (!skip_string_decoding (f)) + return FALSE; + + if (!skip_string_decoding (f)) + return FALSE; + + if (!skip_string_decoding (f)) + return FALSE; + + if (!skip_string_decoding (f)) + return FALSE; + + + skip_gint32_decoding (f); /* mi->message_id.id.part.hi */ + skip_gint32_decoding (f); /* mi->message_id.id.part.lo */ + + /* references , always 0 items in tny */ + if (decode_guint32 (f, &count) && count <= 500) { + guint32 i; + for (i = 0; i < count; i++) { + skip_gint32_decoding (f); /* mi->references->references[i].id.part.hi */ + skip_gint32_decoding (f); /* mi->references->references[i].id.part.lo */ + } + } else { + return FALSE; + } + + /* user flags , always 0 items in tny */ + if (decode_guint32 (f, &count) && count <= 500) { + guint32 i; + for (i = 0; i < count; i++) { + skip_string_decoding (f); /* a flag */ + } + } else { + return FALSE; + } + + /* user tags , always 0 items in tny */ + if (decode_guint32 (f, &count) && count <= 500) { + guint32 i; + for (i = 0; i < count; i++) { + skip_string_decoding (f); /* tag name */ + skip_string_decoding (f); /* tag value */ + } + } else { + return FALSE; + } + + return TRUE; +} + + +static inline gboolean +skip_over_mail (FILE *f) +{ + return (skip_string_decoding (f) && /* uid */ + skip_guint32_decoding (f) && /* size switched with flags in tny */ + skip_guint32_decoding (f) && /* flags switched with size in tny */ + skip_time_t_decoding (f) && /* date_sent */ + skip_time_t_decoding (f) && /* date_received */ + skip_string_decoding (f) && /* subject */ + skip_string_decoding (f) && /* from */ + skip_string_decoding (f) && /* to */ + skip_string_decoding (f) && /* cc */ + skip_string_decoding (f)); /* mlist? */ +} + + +static gboolean +skip_loading_content_info (SummaryFile *summary) +{ + guint32 count, i; + + g_return_val_if_fail (summary, FALSE); + + if (!do_skip_loading_content_info (summary)) { + return FALSE; + } + + if (!decode_guint32 (summary->f, &count)) { + return FALSE; + } + + if (count > 500) { + return FALSE; + } + + for (i = 0; i < count; i++) { + if (!skip_loading_content_info (summary)) { + return FALSE; + } + } + + return TRUE; +} + + +static gboolean +do_skip_loading_content_info (SummaryFile *summary) +{ + FILE *f; + guint32 count; + guint32 doit = 0; + + g_return_val_if_fail (summary, FALSE); + + f = summary->f; + + if (!decode_guint32 (f, &doit)) + return FALSE; + + if (!doit) + return TRUE; + + skip_token_decoding (f); /* type */ + skip_token_decoding (f); /* subtype */ + + if (decode_guint32 (f, &count) && count <= 500) { + guint32 i; + for (i = 0; i < count; i++) { + skip_token_decoding (f); /* name */ + skip_token_decoding (f); /* value */ + } + } else { + return FALSE; + } + + if (!skip_token_decoding (f) || /* id */ + !skip_token_decoding (f) || /* description */ + !skip_token_decoding (f) || /* encoding */ + !decode_guint32 (f, &count)) { /* size */ + return FALSE; + } + + return TRUE; +} + + +static gboolean +save_ondisk_email_message_for_imap (DBConnection *db_con, MailMessage *mail_msg) +{ + return do_save_ondisk_email_message_generic (db_con, mail_msg); +} + + +static gboolean +save_ondisk_email_message_for_pop (DBConnection *db_con, MailMessage *mail_msg) +{ + return do_save_ondisk_email_message_generic (db_con, mail_msg); +} + +static gboolean +save_ondisk_email_message_for_maildir (DBConnection *db_con, MailMessage *mail_msg) +{ + return do_save_ondisk_email_message_generic (db_con, mail_msg); +} + +static gboolean +do_save_ondisk_email_message_generic (DBConnection *db_con, MailMessage *mail_msg) +{ + g_return_val_if_fail (db_con, FALSE); + g_return_val_if_fail (mail_msg, FALSE); + + tracker_log ("Trying to index mail \"%s\"", mail_msg->uri); + + if (!do_save_ondisk_email_message (db_con, mail_msg)) { + tracker_log ("Indexing mail without body nor attachment parsing \"%s\"", mail_msg->uri); + tracker_db_email_save_email (db_con, mail_msg, MAIL_APP_MODEST); + } else { + tracker_log ("Simple index of mail \"%s\" finished", mail_msg->uri); + } + + + return TRUE; + +} + +static gboolean +do_save_ondisk_email_message (DBConnection *db_con, MailMessage *mail_msg) +{ + g_return_val_if_fail (db_con, FALSE); + g_return_val_if_fail (mail_msg, FALSE); + g_return_val_if_fail (mail_msg->path, FALSE); + + if (g_file_test (mail_msg->path, G_FILE_TEST_EXISTS) && tracker_file_is_indexable (mail_msg->path)) { + /* we have downloaded the mail message on disk so we can fully index it. */ + MailMessage *mail_msg_on_disk = NULL; + + mail_msg_on_disk = email_parse_mail_message_by_path (MAIL_APP_MODEST, + mail_msg->path, NULL, NULL); + + if (mail_msg_on_disk && mail_msg_on_disk->parent_mail_file) { + + mail_msg_on_disk->parent_mail_file->next_email_offset = 0; + mail_msg_on_disk->uri = g_strdup (mail_msg->uri); + mail_msg_on_disk->store = mail_msg->store; + + tracker_db_email_save_email (db_con, mail_msg_on_disk, MAIL_APP_MODEST); + + email_free_mail_file (mail_msg_on_disk->parent_mail_file); + email_free_mail_message (mail_msg_on_disk); + + return TRUE; + } + } + + return FALSE; +} + + +static GSList * +add_persons_from_internet_address_list_string_parsing (GSList *list, const gchar *s) +{ + InternetAddressList *addrs_list, *tmp; + + g_return_val_if_fail (s, NULL); + + addrs_list = internet_address_parse_string (s); + + for (tmp = addrs_list; tmp; tmp = tmp->next) { + MailPerson *mp; + + mp = email_allocate_mail_person (); + + mp->addr = g_strdup (tmp->address->value.addr); + if(tmp->address->name) + mp->name = g_strdup (tmp->address->name); + else + mp->name = g_strdup (tmp->address->value.addr); + + list = g_slist_prepend (list, mp); + } + + internet_address_list_destroy (addrs_list); + + return list; +} + + + +/*** + Functions to decode summary (or ev-summary) files. +***/ + + +static inline gboolean +decode_string (FILE *in, gchar **str) +{ + guint32 len; + register gchar *ret; + + if (!decode_guint32 (in, &len)) { + *str = NULL; + return FALSE; + } + + /* I think I need to remove this for tinymail vs. evolution, + * because Tinymail's format cares about a last \0 character */ + + /* len--; */ + + if (len > 65536) { + *str = NULL; + return FALSE; + } + + ret = g_malloc (len+1); + if (len > 0 && fread (ret, len, 1, in) != 1) { + g_free (ret); + *str = NULL; + return FALSE; + } + + ret[len] = 0; + *str = ret; + return TRUE; +} + + +static inline gboolean +decode_gint32 (FILE *f, gint32 *dest) +{ + guint32 save; + + if (!f) return FALSE; + + if (fread (&save, sizeof (save), 1, f) == 1) { + *dest = g_ntohl (save); + return TRUE; + } else { + return FALSE; + } +} + +/* This is completely different in Tinymail (we just reuse the impl for signed) */ +static inline gboolean +decode_guint32 (FILE *f, guint32 *n) +{ + return decode_gint32 (f, (gint32*)n); +} + +/* These are all aliases for signed ints in tinymail's format */ + +#define CFU_DECODE_T(type) \ +static inline gboolean \ +decode_##type (FILE *in, type *dest) \ +{ \ + return decode_gint32 (in, (gint32*) dest); \ +} + +CFU_DECODE_T(time_t) +CFU_DECODE_T(off_t) +CFU_DECODE_T(size_t) + +static inline gboolean +skip_gint32_decoding (FILE *f) +{ + return fseek (f, 4, SEEK_CUR) > 0; +} + + +/* Same, we just reuse the impl. for signed numbers */ +static inline gboolean +skip_guint32_decoding (FILE *f) +{ + return skip_gint32_decoding (f); +} + +/* Same, we just reuse the impl. for signed numbers */ +static inline gboolean +skip_time_t_decoding (FILE *f) +{ + return skip_gint32_decoding (f); +} + +/* Same, we just reuse the impl. for signed numbers */ +static inline gboolean +skip_off_t_decoding (FILE *f) +{ + return skip_gint32_decoding (f); +} + + +static inline gboolean +skip_string_decoding (FILE *f) +{ + guint32 len; + + if (!decode_guint32 (f, &len)) { + return FALSE; + } + + /* Same as decode_string, Tinymail cares about the last \0 character + * whereas this character is not present in Evolution's format */ + + if (fseek (f, len /*- 1*/, SEEK_CUR) != 0) { + tracker_error ("ERROR: seek failed for string with length %d with error code %d", len - 1, errno); + return FALSE; + } + + return TRUE; +} + + +static inline gboolean +skip_token_decoding (FILE *f) +{ + guint32 len; + + if (!decode_guint32 (f, &len)) { + return FALSE; + } + + if (len < 32) { + return TRUE; + } + + len -= 32; + return fseek (f, len, SEEK_CUR) == 0; +} Index: src/trackerd/tracker-email-kmail.c =================================================================== --- src/trackerd/tracker-email-kmail.c (revision 1250) +++ src/trackerd/tracker-email-kmail.c (working copy) @@ -736,7 +736,7 @@ mail_msg->uri = g_strdup (mail_msg->path); mail_msg->store = store; mail_msg->mtime = tracker_get_file_mtime (mail_msg->path); - tracker_db_email_save_email (db_con, mail_msg); + tracker_db_email_save_email (db_con, mail_msg, MAIL_APP_KMAIL); email_free_mail_file (mail_msg->parent_mail_file); email_free_mail_message (mail_msg); Index: src/trackerd/tracker-email-modest.h =================================================================== --- src/trackerd/tracker-email-modest.h (revision 0) +++ src/trackerd/tracker-email-modest.h (revision 0) @@ -0,0 +1 @@ + Index: src/trackerd/Makefile.am =================================================================== --- src/trackerd/Makefile.am (revision 1250) +++ src/trackerd/Makefile.am (working copy) @@ -122,8 +122,13 @@ mail_modules_LTLIBRARIES = \ libemail-evolution.la \ libemail-thunderbird.la \ - libemail-kmail.la + libemail-kmail.la \ + libemail-modest.la +libemail_modest_la_SOURCES = tracker-email-modest.c +libemail_modest_la_LDFLAGS = $(module_flags) +libemail_modest_la_LIBADD = $(GLIB2_LIBS) + libemail_evolution_la_SOURCES = tracker-email-evolution.c libemail_evolution_la_LDFLAGS = $(module_flags) libemail_evolution_la_LIBADD = $(GLIB2_LIBS) Index: src/libtracker-common/tracker-configuration.c =================================================================== --- src/libtracker-common/tracker-configuration.c (revision 1250) +++ src/libtracker-common/tracker-configuration.c (working copy) @@ -140,6 +140,8 @@ "[Emails]\n", "# Index email messages from Evolution\n", "IndexEvolutionEmails = true\n", + "# Index email messages from Modest\n", + "IndexModestEmails = false\n", "# Index email messages from Thunderbird\n", "IndexThunderbirdEmails = true\n\n", "[Performance]\n", Index: src/tracker-search-tool/tracker-search-tool-callbacks.c =================================================================== --- src/tracker-search-tool/tracker-search-tool-callbacks.c (revision 1250) +++ src/tracker-search-tool/tracker-search-tool-callbacks.c (working copy) @@ -603,6 +603,8 @@ if (gsearch->type == SERVICE_EMAILS) { if (strstr (mime, "Evolution")) { exec = g_strdup_printf ("evolution \"%s\"", uri); + } else if (strstr (mime, "Modest")) { + exec = g_strdup_printf ("modest-open \"%s\"", uri); } else if (strstr (mime, "KMail")) { exec = g_strdup_printf ("kmail --view \"%s\"", uri); } else if (strstr (mime, "Thunderbird")) { Index: src/tracker-preferences/tracker-preferences.glade =================================================================== --- src/tracker-preferences/tracker-preferences.glade (revision 1250) +++ src/tracker-preferences/tracker-preferences.glade (working copy) @@ -878,6 +878,19 @@ + + True + Enable _Modest email indexing + True + 0 + True + True + + + False + + + True False Index: src/tracker-preferences/tracker-preferences.c =================================================================== --- src/tracker-preferences/tracker-preferences.c (revision 1250) +++ src/tracker-preferences/tracker-preferences.c (working copy) @@ -468,6 +468,13 @@ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value); widget = glade_xml_get_widget (priv->gxml, + "chkEnableModestIndexing"); + value = tracker_configuration_get_boolean ("/Emails/IndexModestEmails", + NULL); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value); + + + widget = glade_xml_get_widget (priv->gxml, "chkEnableThunderbirdIndexing"); value = tracker_configuration_get_boolean ("/Emails/IndexThunderbirdEmails", NULL); @@ -750,6 +757,16 @@ tracker_configuration_set_boolean ("/Emails/IndexEvolutionEmails", bvalue); } + + widget = glade_xml_get_widget (priv->gxml, "chkEnableModestIndexing"); + bvalue = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + bvalue_old = tracker_configuration_get_boolean ("/Emails/IndexModestEmails", + NULL); + if (bvalue != bvalue_old) { + set_bool_option (priv, "EnableModest", bvalue); + tracker_configuration_set_boolean ("/Emails/IndexModestEmails", bvalue); + } + widget = glade_xml_get_widget (priv->gxml, "chkEnableThunderbirdIndexing"); bvalue = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); bvalue_old = tracker_configuration_get_boolean ("/Emails/IndexThunderbirdEmails", Index: docs/tracker.cfg.5 =================================================================== --- docs/tracker.cfg.5 (revision 1250) +++ docs/tracker.cfg.5 (working copy) @@ -163,6 +163,9 @@ IndexEvolutionEmails=BOOLEAN Enable or disable indexing for Evolution emails. .TP +IndexModestEmails=BOOLEAN +Enable or disable indexing for Modest emails. +.TP IndexThunderbirdEmails=BOOLEAN Enable or disable indexing for Thunderbird emails. Index: data/services/default.service =================================================================== --- data/services/default.service (revision 1250) +++ data/services/default.service (working copy) @@ -170,6 +170,18 @@ TileMetadata=Email:Sender;Email:Subject;Email:Date;Email:SentTo;Email:CC;Email:Attachments ContentMetadata=Email:Body +[ModestEmails] +DisplayName=Modest Emails +Description=Modest based emails +Parent=Emails +ViewerExec=modest-open "%1" +KeyMetadata1=Email:Subject +KeyMetadata2=Email:Sender +KeyMetadata3=Email:Date +TabularMetadata=Email:Sender;Email:Subject;Email:Date; +TileMetadata=Email:Sender;Email:Subject;Email:Date;Email:SentTo;Email:CC;Email:Attachments +ContentMetadata=Email:Body + [ThunderbirdEmails] DisplayName=Thunderbird Emails Description=Thunderbird based emails @@ -206,6 +218,12 @@ Parent=EmailAttachments Icon=stock_attach +[ModestAttachments] +DisplayName=Modest Email Attachments +Description=All files that are attached to an Modest Email +Parent=EmailAttachments +Icon=stock_attach + [KMailAttachments] DisplayName=KMail Email Attachments Description=All files that are attached to an KMail Email