/* find a container for the given msgid; if it does not exist yet, * create a new one, and register it */ static MuContainer* find_or_create (GHashTable *id_table, MuMsg *msg, guint docid) { MuContainer *c; const char* msgid; g_return_val_if_fail (msg, NULL); g_return_val_if_fail (docid != 0, NULL); msgid = mu_msg_get_msgid (msg); if (!msgid) msgid = mu_msg_get_path (msg); /* fake it */ c = g_hash_table_lookup (id_table, msgid); /* If id_table contains an empty MuContainer for this ID: * * * Store this message in the MuContainer's message slot. */ if (c) { if (!c->msg) { c->msg = mu_msg_ref (msg); c->docid = docid; return c; } else { /* special case, not in the JWZ algorithm: the * container exists already and has a message; this * means that we are seeing *another message* with a * message-id we already saw... create this message, * and mark it as a duplicate, and a child of the one * we saw before; use its path as a fake message-id * */ MuContainer *c2; const char* fake_msgid; fake_msgid = mu_msg_get_path (msg); c2 = mu_container_new (msg, docid, fake_msgid); c2->flags = MU_CONTAINER_FLAG_DUP; c = mu_container_append_children (c, c2); g_hash_table_insert (id_table, (gpointer)fake_msgid, c2); return NULL; /* don't process this message further */ } } else { /* Else: Create a new MuContainer object holding this message; Index the MuContainer by Message-ID in id_table. */ c = mu_container_new (msg, docid, msgid); g_hash_table_insert (id_table, (gpointer)msgid, c); /* assert_no_duplicates (id_table); */ return c; } }
/* we need do to determine the * /home/foo/Maildir/bar * from the /bar * that we got */ char* get_target_mdir (MuMsg *msg, const char *target_maildir, GError **err) { char *rootmaildir, *rv; const char *maildir; gboolean not_top_level; /* maildir is the maildir stored in the message, e.g. '/foo' */ maildir = mu_msg_get_maildir(msg); if (!maildir) { mu_util_g_set_error (err, MU_ERROR_GMIME, "message without maildir"); return NULL; } /* the 'rootmaildir' is the filesystem path from root to * maildir, ie. /home/user/Maildir/foo */ rootmaildir = mu_maildir_get_maildir_from_path (mu_msg_get_path(msg)); if (!rootmaildir) { mu_util_g_set_error (err, MU_ERROR_GMIME, "cannot determine maildir"); return NULL; } /* we do a sanity check: verify that that maildir is a suffix of * rootmaildir;*/ not_top_level = TRUE; if (!g_str_has_suffix (rootmaildir, maildir) && /* special case for the top-level '/' maildir, and * remember not_top_level */ (not_top_level = (g_strcmp0 (maildir, "/") != 0))) { g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_FILE, "path is '%s', but maildir is '%s' ('%s')", rootmaildir, mu_msg_get_maildir(msg), mu_msg_get_path (msg)); g_free (rootmaildir); return NULL; } /* if we're not at the top-level, remove the final '/' from * the rootmaildir */ if (not_top_level) rootmaildir[strlen(rootmaildir) - strlen (mu_msg_get_maildir(msg))] = '\0'; rv = g_strconcat (rootmaildir, target_maildir, NULL); g_free (rootmaildir); return rv; }
gboolean mu_msg_is_readable (MuMsg *self) { g_return_val_if_fail (self, FALSE); return access (mu_msg_get_path (self), R_OK) == 0 ? TRUE : FALSE; }
static MuError move_msgid (MuStore *store, unsigned docid, const char* flagstr, GError **err) { MuMsg *msg; MuError rv; MuFlags flags; rv = MU_ERROR; msg = mu_store_get_msg (store, docid, err); if (!msg) goto leave; flags = flagstr ? get_flags (mu_msg_get_path(msg), flagstr) : mu_msg_get_flags (msg); if (flags == MU_FLAG_INVALID) { mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, "invalid flags"); goto leave; } rv = do_move (store, docid, msg, NULL, flags, err); leave: if (msg) mu_msg_unref (msg); if (rv != MU_OK) print_and_clear_g_error (err); return rv; }
/* NOTE: this assumes there is only _one_ docid (message) for the * particular message id */ static unsigned get_docid_from_msgid (MuQuery *query, const char *str, GError **err) { gchar *querystr; unsigned docid; MuMsgIter *iter; querystr = g_strdup_printf ("msgid:%s", str); iter = mu_query_run (query, querystr, FALSE, MU_MSG_FIELD_ID_NONE, FALSE, 1, err); g_free (querystr); docid = MU_STORE_INVALID_DOCID; if (!iter || mu_msg_iter_is_done (iter)) mu_util_g_set_error (err, MU_ERROR_NO_MATCHES, "could not find message %s", str); else { MuMsg *msg; msg = mu_msg_iter_get_msg_floating (iter); if (!mu_msg_is_readable(msg)) { mu_util_g_set_error (err, MU_ERROR_FILE_CANNOT_READ, "'%s' is not readable", mu_msg_get_path(msg)); } else docid = mu_msg_iter_get_docid (iter); mu_msg_iter_destroy (iter); } return docid; }
gchar* mu_msg_part_get_cache_path (MuMsg *msg, MuMsgOptions opts, guint partid, GError **err) { char *dirname, *filepath; const char* path; g_return_val_if_fail (msg, NULL); if (!mu_msg_load_msg_file (msg, NULL)) return NULL; path = mu_msg_get_path (msg); /* g_compute_checksum_for_string may be better, but requires * rel. new glib (2.16) */ dirname = g_strdup_printf ("%s%c%x%c%u", mu_util_cache_dir(), G_DIR_SEPARATOR, g_str_hash (path), G_DIR_SEPARATOR, partid); if (!mu_util_create_dir_maybe (dirname, 0700, FALSE)) { mu_util_g_set_error (err, MU_ERROR_FILE, "failed to create dir %s", dirname); g_free (dirname); return NULL; } filepath = mu_msg_part_get_path (msg, opts, dirname, partid, err); g_free (dirname); return filepath; }
static JsonBuilder* get_message_json (MuMsg *msg) { JsonBuilder *builder = json_builder_new (); json_builder_begin_object (builder); json_add_recipients(builder, msg); json_add_subject(builder, msg); json_builder_set_member_name (builder, "msgid"); json_builder_add_string_value (builder, mu_msg_get_msgid (msg)); json_builder_set_member_name (builder, "date"); json_builder_add_int_value (builder, (unsigned)mu_msg_get_date (msg)); json_add_flags(builder, msg); json_builder_set_member_name (builder, "path"); json_builder_add_string_value (builder, mu_msg_get_path (msg)); json_builder_set_member_name (builder, "folder"); json_builder_add_string_value (builder, mu_msg_get_maildir (msg)); json_builder_set_member_name (builder, "size"); json_builder_add_int_value (builder, (unsigned)mu_msg_get_size (msg)); json_builder_end_object (builder); return builder; }
static void add_row (GtkListStore * store, MuMsg *msg) { GtkTreeIter treeiter; const gchar *datestr, *flagstr; gchar *from, *to; time_t timeval; timeval = mu_msg_get_date (msg); datestr = timeval == 0 ? "-" : mu_date_display_s (timeval); from = empty_or_display_contact (mu_msg_get_from (msg)); to = empty_or_display_contact (mu_msg_get_to (msg)); flagstr = mu_flags_to_str_s (mu_msg_get_flags (msg), MU_FLAG_TYPE_ANY); gtk_list_store_append (store, &treeiter); gtk_list_store_set (store, &treeiter, MUG_COL_DATESTR, datestr, MUG_COL_MAILDIR, mu_msg_get_maildir (msg), MUG_COL_FLAGSSTR, flagstr, MUG_COL_FROM, from, MUG_COL_TO, to, MUG_COL_SUBJECT, mu_msg_get_subject (msg), MUG_COL_PATH, mu_msg_get_path (msg), MUG_COL_PRIO, mu_msg_get_prio (msg), MUG_COL_FLAGS, mu_msg_get_flags (msg), MUG_COL_TIME, timeval, -1); g_free (from); g_free (to); }
static void add_row (GtkTreeStore * store, MuMsg *msg, GtkTreeIter *treeiter) { const gchar *datestr, *flagstr; gchar *from, *to; time_t timeval; timeval = mu_msg_get_date (msg); datestr = timeval == 0 ? "-" : mu_date_display_s (timeval); from = empty_or_display_contact (mu_msg_get_from (msg)); to = empty_or_display_contact (mu_msg_get_to (msg)); flagstr = mu_flags_to_str_s (mu_msg_get_flags (msg), MU_FLAG_TYPE_ANY); /* if (0) { */ /* GtkTreeIter myiter; */ /* if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL(store), */ /* &myiter, path)) */ /* g_warning ("%s: cannot get iter for %s", * __FUNCTION__, path); */ /* } */ gtk_tree_store_set (store, treeiter, MUG_COL_DATESTR, datestr, MUG_COL_MAILDIR, mu_msg_get_maildir (msg), MUG_COL_FLAGSSTR, flagstr, MUG_COL_FROM, from, MUG_COL_TO, to, MUG_COL_SUBJECT, mu_msg_get_subject (msg), MUG_COL_PATH, mu_msg_get_path (msg), MUG_COL_PRIO, mu_msg_get_prio (msg), MUG_COL_FLAGS, mu_msg_get_flags (msg), MUG_COL_TIME, timeval, -1); g_free (from); g_free (to); }
struct _JsonNode* mu_msg_to_json (MuMsg *msg, unsigned docid, const MuMsgIterThreadInfo *ti, MuMsgOptions opts) { JsonNode *node; JsonBuilder *bob; time_t t; size_t s; g_return_val_if_fail (msg, NULL); g_return_val_if_fail (!((opts & MU_MSG_OPTION_HEADERS_ONLY) && (opts & MU_MSG_OPTION_EXTRACT_IMAGES)),NULL); bob = json_builder_new (); bob = json_builder_begin_object (bob); if (ti) add_thread_info (bob, ti); add_string_member (bob, "subject", mu_msg_get_subject (msg)); /* in the no-headers-only case (see below) we get a more complete list * of contacts, so no need to get them here if that's the case */ if (opts & MU_MSG_OPTION_HEADERS_ONLY) add_contacts (bob, msg); t = mu_msg_get_date (msg); if (t != (time_t)-1) add_int_member (bob, "date", t); s = mu_msg_get_size (msg); if (s != (size_t)-1) add_int_member (bob, "size", s); add_string_member (bob, "message-id", mu_msg_get_msgid (msg)); add_string_member (bob, "mailing-list", mu_msg_get_mailing_list (msg)); add_string_member (bob, "path", mu_msg_get_path (msg)); add_string_member (bob, "maildir", mu_msg_get_maildir (msg)); add_string_member (bob, "priority", mu_msg_prio_name(mu_msg_get_prio(msg))); add_flags (bob, msg); add_list_member (bob, "tags", mu_msg_get_tags(msg)); add_list_member (bob, "references", mu_msg_get_references (msg)); add_string_member (bob, "in-reply-to", mu_msg_get_header (msg, "In-Reply-To")); /* headers are retrieved from the database, views from the * message file file attr things can only be gotten from the * file (ie., mu view), not from the database (mu find). */ if (!(opts & MU_MSG_OPTION_HEADERS_ONLY)) add_file_parts (bob, msg, opts); bob = json_builder_end_object (bob); node = json_builder_get_root (bob); g_clear_object (&bob); return node; }
/* * 'move' moves a message to a different maildir and/or changes its * flags. parameters are *either* a 'docid:' or 'msgid:' pointing to * the message, a 'maildir:' for the target maildir, and a 'flags:' * parameter for the new flags. * * returns an (:update <new-msg-sexp>) * */ static MuError cmd_move (ServerContext *ctx, GHashTable *args, GError **err) { unsigned docid; MuMsg *msg; MuFlags flags; const char *maildir, *flagstr; gboolean new_name; /* check if the move is based on the message id; if so, handle * it in move_msgid_maybe */ if (move_msgid_maybe (ctx, args, err)) return MU_OK; maildir = get_string_from_args (args, "maildir", TRUE, err); flagstr = get_string_from_args (args, "flags", TRUE, err); new_name = get_bool_from_args (args, "newname", TRUE, err); docid = determine_docid (ctx->query, args, err); if (docid == MU_STORE_INVALID_DOCID || !(msg = mu_store_get_msg (ctx->store, docid, err))) { print_and_clear_g_error (err); return MU_OK; } /* if maildir was not specified, take the current one */ if (!maildir) maildir = mu_msg_get_maildir (msg); /* determine the real target flags, which come from the * flags-parameter we received (ie., flagstr), if any, plus * the existing message flags. */ if (flagstr) flags = get_flags (mu_msg_get_path(msg), flagstr); else flags = mu_msg_get_flags (msg); if (flags == MU_FLAG_INVALID) { print_error (MU_ERROR_IN_PARAMETERS, "invalid flags"); goto leave; } if ((do_move (ctx->store, docid, msg, maildir, flags, new_name, err) != MU_OK)) print_and_clear_g_error (err); leave: mu_msg_unref (msg); return MU_OK; }
time_t mu_msg_get_timestamp (MuMsg *self) { const char *path; struct stat statbuf; g_return_val_if_fail (self, 0); if (self->_file) return self->_file->_timestamp; path = mu_msg_get_path (self); if (!path || stat (path, &statbuf) < 0) return 0; return statbuf.st_mtime; }
static gboolean exec_cmd (MuMsg *msg, MuMsgIter *iter, MuConfig *opts, GError **err) { gint status; char *cmdline, *escpath; gboolean rv; escpath = g_shell_quote (mu_msg_get_path (msg)); cmdline = g_strdup_printf ("%s %s", opts->exec, escpath); rv = g_spawn_command_line_sync (cmdline, NULL, NULL, &status, err); g_free (cmdline); g_free (escpath); return rv; }
static gboolean output_xml (MuMsg *msg, MuMsgIter *iter, MuConfig *opts, GError **err) { g_print ("\t<message>\n"); print_attr_xml ("from", mu_msg_get_from (msg)); print_attr_xml ("to", mu_msg_get_to (msg)); print_attr_xml ("cc", mu_msg_get_cc (msg)); print_attr_xml ("subject", mu_msg_get_subject (msg)); g_print ("\t\t<date>%u</date>\n", (unsigned)mu_msg_get_date (msg)); g_print ("\t\t<size>%u</size>\n", (unsigned)mu_msg_get_size (msg)); print_attr_xml ("msgid", mu_msg_get_msgid (msg)); print_attr_xml ("path", mu_msg_get_path (msg)); print_attr_xml ("maildir", mu_msg_get_maildir (msg)); g_print ("\t</message>\n"); return TRUE; }
static gboolean dump_container (MuContainer *c) { const gchar* subject; if (!c) { g_print ("<empty>\n"); return TRUE; } subject = (c->msg) ? mu_msg_get_subject (c->msg) : "<none>"; g_print ("[%s][%s m:%p p:%p docid:%u %s]\n",c->msgid, subject, (void*)c, (void*)c->parent, c->docid, c->msg ? mu_msg_get_path (c->msg) : ""); return TRUE; }
/* * move a msg to another maildir, trying to maintain 'integrity', * ie. msg in 'new/' will go to new/, one in cur/ goes to cur/. be * super-paranoid here... */ gboolean mu_msg_move_to_maildir (MuMsg *self, const char *maildir, MuFlags flags, gboolean ignore_dups, GError **err) { char *newfullpath; char *targetmdir; g_return_val_if_fail (self, FALSE); g_return_val_if_fail (maildir, FALSE); /* i.e. "/inbox" */ targetmdir = get_target_mdir (self, maildir, err); if (!targetmdir) return FALSE; newfullpath = mu_maildir_move_message (mu_msg_get_path (self), targetmdir, flags, ignore_dups, err); g_free (targetmdir); /* update the message path and the flags; they may have * changed */ if (newfullpath) { mu_msg_cache_set_str (self->_cache, MU_MSG_FIELD_ID_PATH, newfullpath, TRUE); /* the cache will free the string */ mu_msg_cache_set_str (self->_cache, MU_MSG_FIELD_ID_MAILDIR, g_strdup(maildir), TRUE); /* the cache will free the string */ /* the contentflags haven't changed, so make sure they persist */ flags |= mu_msg_get_flags (self) & (MU_FLAG_HAS_ATTACH|MU_FLAG_ENCRYPTED|MU_FLAG_SIGNED); /* update the pseudo-flag as well */ if (!(flags & MU_FLAG_NEW) && (flags & MU_FLAG_SEEN)) flags &= ~MU_FLAG_UNREAD; else flags |= MU_FLAG_UNREAD; mu_msg_cache_set_num (self->_cache, MU_MSG_FIELD_ID_FLAGS, flags); } return newfullpath ? TRUE : FALSE; }
void mu_msg_body_view_set_message_source (MuMsgBodyView *self, MuMsg *msg) { const gchar *path; gchar *data; g_return_if_fail (MU_IS_MSG_BODY_VIEW(self)); g_return_if_fail (msg); set_message (self, NULL); path = msg ? mu_msg_get_path (msg) : NULL; if (path && g_file_get_contents (path, &data, NULL, NULL)) { set_text (self, data); g_free (data); } else set_text (self, ""); self->_priv->_view_mode = VIEW_MODE_SOURCE; }
/* * move a msg to another maildir, trying to maintain 'integrity', * ie. msg in 'new/' will go to new/, one in cur/ goes to cur/. be * super-paranoid here... */ gboolean mu_msg_move_to_maildir (MuMsg *self, const char *maildir, MuFlags flags, gboolean ignore_dups, gboolean new_name, GError **err) { char *newfullpath; char *targetmdir; g_return_val_if_fail (self, FALSE); g_return_val_if_fail (maildir, FALSE); /* i.e. "/inbox" */ /* targetmdir is the full path to maildir, i.e., * /home/foo/Maildir/inbox */ targetmdir = get_target_mdir (self, maildir, err); if (!targetmdir) return FALSE; newfullpath = mu_maildir_move_message (mu_msg_get_path (self), targetmdir, flags, ignore_dups, new_name, err); /* update the message path and the flags; they may have * changed */ if (!newfullpath) { g_free (targetmdir); return FALSE; } /* clear the old backends */ mu_msg_doc_destroy (self->_doc); self->_doc = NULL; mu_msg_file_destroy (self->_file); /* and create a new one */ self->_file = mu_msg_file_new (newfullpath, maildir, err); g_free (targetmdir); return self->_file ? TRUE : FALSE; }
/* * creating a message object just to get a path seems a bit excessive * maybe mu_store_get_path could be added if this turns out to be a * problem * * NOTE: not re-entrant. */ static const char* get_path_from_docid (MuStore *store, unsigned docid, GError **err) { MuMsg *msg; const char* msgpath; static char path[PATH_MAX + 1]; msg = mu_store_get_msg (store, docid, err); if (!msg) return NULL; msgpath = mu_msg_get_path (msg); if (!msgpath) { mu_msg_unref (msg); return NULL; } strncpy (path, msgpath, sizeof(path)); mu_msg_unref (msg); return path; }
static gboolean output_link (MuMsg *msg, MuMsgIter *iter, MuConfig *opts, GError **err) { return mu_maildir_link (mu_msg_get_path (msg), opts->linksdir, err); }