From bdf1237c3456ffa383c5d4d1f0fe317ec4854a07 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Tue, 2 Aug 2011 21:27:32 +0300 Subject: [PATCH] * mu-mv: optionally, let it update the database (--updatedb) and print the target file on stdout (--printtarget) --- man/mu-mv.1 | 52 +++++++++++++++++++++++++++++++-- src/mu-cmd.c | 78 +++++++++++++++++++++++++++++++++++++++++-------- src/mu-config.c | 5 ++++ src/mu-config.h | 5 ++++ src/mu-store.cc | 47 ++++++++++++++++++++++++----- src/mu-store.h | 12 +++++++- src/mu-util.h | 13 +++++---- 7 files changed, 182 insertions(+), 30 deletions(-) diff --git a/man/mu-mv.1 b/man/mu-mv.1 index 619c9f13..52003ef2 100644 --- a/man/mu-mv.1 +++ b/man/mu-mv.1 @@ -6,7 +6,7 @@ mu mv\- move a message file to a Maildir .SH SYNOPSIS -.B mu mv +.B mu mv [--flags=] [--updatedb] [--printtarget] .SH DESCRIPTION @@ -29,6 +29,29 @@ Note, unlike the UNIX \fImv\fR command, \fImu mv\fR takes precisely two parameters. It's recommended not to use wildcards on the shell, the result may be unexpected. +.SH OPTIONS + +.TP +\fB\-\-flags\fR=\fI\fR +using the this option, you can change the file flags of the target file. If +you change the 'N' (new) flag, this will also change the exact target +directory ('new' vs 'cur'). + +The flags is a sequence of characters from the set D (draft), F (flagged) ,N +(new), P (passed), R (replied), S (seen) and T (trashed). Note, the +flags-parameter is case-sensitive. + +.TP +\fB\-\-updatedb\fR +update the Xapian database after the move. You can use the general +\fB\-\-muhome=\fR option to specify the database if it does not live at the +default place. + +.TP +\fB\-\-printtarget\fR +return the target path on standard output upon succesful completion of the +move (with or without a succesful database update) + .SH EXAMPLE To move a message \fI/home/jimbo/Maildir/scuba/cur/123123123:2,S\fR to @@ -50,14 +73,37 @@ could do: Obviously, you could also simply use \fBrm\fR in this case. +To mark a message as no longer new and 'Seen', and update the database +afterwards, you could do: + +.nf + mu --flags=S mv /home/roger/Maildir/inbox/new/123123123:2, /home/roger/Maildir/inbox/ +.fi + + + .SH LIMITATIONS Both source-path and target-directory must be on the same disk partition, except when the target-directory is \fI/dev/null\fR. -.SH OPTIONS -\fBmu mv\fR takes no options. +.SH RETURN VALUE + +\fBmu mv\fR returns 0 upon success; in general, the following error codes are +returned: + +.nf +| code | meaning | +|------+-----------------------------------| +| 0 | ok | +| 1 | general error | +| 4 | database is corrupted | +| 5 | some other database update error | +.fi + +Note that if you get a database error rather than a general error, this means +that moving the file succeeded, but that the database update afterwards failed. .SH BUGS diff --git a/src/mu-cmd.c b/src/mu-cmd.c index cb530905..0f14c55a 100644 --- a/src/mu-cmd.c +++ b/src/mu-cmd.c @@ -38,6 +38,7 @@ #include "mu-contacts.h" #include "mu-runtime.h" #include "mu-msg-flags.h" +#include "mu-store.h" #define VIEW_TERMINATOR '\f' /* form-feed */ @@ -301,6 +302,52 @@ mv_check_params (MuConfig *opts, MuMsgFlags *flags) } +static gboolean +update_db_after_mv (MuConfig *opts, const char *src, const char* target) +{ + MuStore *store; + GError *err; + gboolean rv1, rv2; + + err = NULL; + store = mu_store_new (mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), + mu_runtime_path(MU_RUNTIME_PATH_CONTACTS), &err); + + if (!store) { + if (err) { + g_warning ("store error: %s", err->message); + g_error_free (err); + } else + g_warning ("failed to create store object"); + + return FALSE; + } + + if (!(rv1 = mu_store_remove (store, src))) + g_warning ("failed to remove message from store"); + + if (!(rv2 = mu_store_store_path (store, target))) + g_warning ("failed to store target message"); + + mu_store_destroy (store); + + return rv1 && rv2; +} + +static MuExitCode +mv_remove (const char *path, MuConfig *opts) +{ + if (unlink (path) != 0) { + g_warning ("unlink failed: %s", strerror (errno)); + return MU_EXITCODE_ERROR; + } + + if (!opts->updatedb || update_db_after_mv (opts, path, NULL)) + return MU_EXITCODE_OK; + else + return MU_EXITCODE_DB_UPDATE_ERROR; +} + MuExitCode mu_cmd_mv (MuConfig *opts) @@ -308,21 +355,17 @@ mu_cmd_mv (MuConfig *opts) GError *err; gchar *fullpath; MuMsgFlags flags; - + MuExitCode rv; + if (!mv_check_params (opts, &flags)) return MU_EXITCODE_ERROR; err = NULL; /* special case: /dev/null */ - if (g_strcmp0 (opts->params[2], "/dev/null") == 0) { - if (unlink (opts->params[1]) != 0) { - g_warning ("unlink failed: %s", strerror (errno)); - return MU_EXITCODE_ERROR; - } else - return MU_EXITCODE_OK; - } - + if (g_strcmp0 (opts->params[2], "/dev/null") == 0) + return mv_remove (opts->params[1], opts); + fullpath = mu_msg_file_move_to_maildir (opts->params[1], opts->params[2], flags, &err); if (!fullpath) { @@ -330,8 +373,19 @@ mu_cmd_mv (MuConfig *opts) g_warning ("move failed: %s", err->message); g_error_free (err); } - return MU_EXITCODE_ERROR; - } + return MU_EXITCODE_ERROR; + + } else if (opts->printtarget) /* if the move worked, print the */ + g_print ("%s\n", fullpath); /* target (if user set + * --printtarget) */ + + /* now, when --updatedb db was given, try to update it */ + if (!opts->updatedb || update_db_after_mv (opts, opts->params[1], fullpath)) + rv = MU_EXITCODE_OK; + else + rv = MU_EXITCODE_DB_UPDATE_ERROR; - return MU_EXITCODE_OK; + g_free (fullpath); + + return rv; } diff --git a/src/mu-config.c b/src/mu-config.c index f88c1446..0c9efafe 100644 --- a/src/mu-config.c +++ b/src/mu-config.c @@ -319,6 +319,11 @@ config_options_group_mv (MuConfig *opts) GOptionEntry entries[] = { {"flags", 0, 0, G_OPTION_ARG_STRING, &opts->flagstr, "flags to set for the target (DFNPRST)", NULL}, + {"updatedb", 0, 0, G_OPTION_ARG_NONE, &opts->updatedb, + "whether to update the database after the move", NULL}, + {"printtarget", 0, 0, G_OPTION_ARG_NONE, &opts->updatedb, + "whether to print the target path upon succesful completion", + NULL}, {NULL, 0, 0, 0, NULL, NULL, NULL} }; diff --git a/src/mu-config.h b/src/mu-config.h index a013a4f5..a342bb2b 100644 --- a/src/mu-config.h +++ b/src/mu-config.h @@ -126,6 +126,11 @@ struct _MuConfig { /* options for mv */ char *flagstr; /* message flags to set for * the target */ + gboolean updatedb; /* should the database be updated after + * moving? */ + gboolean printtarget; /* should be print the + * target file path on + * stdout */ /* options for view */ gboolean terminator; /* add separator \f between diff --git a/src/mu-store.cc b/src/mu-store.cc index 6574b1c5..1ae004d2 100644 --- a/src/mu-store.cc +++ b/src/mu-store.cc @@ -622,11 +622,11 @@ get_message_uid (MuMsg *msg) return get_message_uid (mu_msg_get_path(msg)); } -MuResult +gboolean mu_store_store (MuStore *store, MuMsg *msg, gboolean replace) { - g_return_val_if_fail (store, MU_ERROR); - g_return_val_if_fail (msg, MU_ERROR); + g_return_val_if_fail (store, FALSE); + g_return_val_if_fail (msg, FALSE); try { Xapian::Document newdoc; @@ -654,21 +654,52 @@ mu_store_store (MuStore *store, MuMsg *msg, gboolean replace) id = store->_db.replace_document (uid, newdoc); else id = store->_db.add_document (newdoc); - - /* DEBUG */ - //g_print ("\n[%s]\n", newdoc.serialise().c_str()); ++store->_processed; commit_trx_if (store, store->_processed % store->_trx_size == 0); - return MU_OK; + return TRUE; } MU_XAPIAN_CATCH_BLOCK; rollback_trx_if (store, store->_in_transaction); - return MU_ERROR; + return FALSE; +} + + +gboolean +mu_store_store_path (MuStore *store, const char *path) +{ + MuMsg *msg; + GError *err; + gboolean rv; + + g_return_val_if_fail (store, FALSE); + g_return_val_if_fail (path, FALSE); + + err = NULL; + msg = mu_msg_new_from_file (path, NULL, &err); + + if (!msg) { + if (err) { + g_warning ("failed to create message %s to store: %s", + path, err->message); + g_error_free (err); + } else + g_warning ("failed to create message %s to store", path); + + return FALSE; + } + + rv = mu_store_store (store, msg, TRUE); + if (!rv) + g_warning ("failed to store %s", path); + + mu_msg_unref (msg); + + return rv; } diff --git a/src/mu-store.h b/src/mu-store.h index e875f1b8..610ccb18 100644 --- a/src/mu-store.h +++ b/src/mu-store.h @@ -109,9 +109,19 @@ void mu_store_flush (MuStore *store); * * @return TRUE if it succeeded, FALSE otherwise */ -MuResult mu_store_store (MuStore *store, MuMsg *msg, gboolean replace); +gboolean mu_store_store (MuStore *store, MuMsg *msg, gboolean replace); +/** + * store an email message in the XapianStore; similar to mu_store_store, but instead takes a path as parameter instead of a MuMsg* + * + * @param store a valid store + * @param path full filesystem path to a valid message + * + * @return TRUE if it succeeded, FALSE otherwise + */ +gboolean mu_store_store_path (MuStore *store, const char *path); + /** * remove a message from the database * diff --git a/src/mu-util.h b/src/mu-util.h index 85faadc2..f40e4800 100644 --- a/src/mu-util.h +++ b/src/mu-util.h @@ -399,11 +399,12 @@ enum _MuResult { typedef enum _MuResult MuResult; enum _MuExitCode { - MU_EXITCODE_OK = 0, - MU_EXITCODE_ERROR = 1, - MU_EXITCODE_NO_MATCHES = 2, - MU_EXITCODE_DB_LOCKED = 3, - MU_EXITCODE_DB_CORRUPTED = 4 + MU_EXITCODE_OK = 0, + MU_EXITCODE_ERROR = 1, + MU_EXITCODE_NO_MATCHES = 2, + MU_EXITCODE_DB_LOCKED = 3, + MU_EXITCODE_DB_CORRUPTED = 4, + MU_EXITCODE_DB_UPDATE_ERROR = 5 }; typedef enum _MuExitCode MuExitCode; @@ -411,7 +412,7 @@ enum _MuError { MU_ERROR_XAPIAN, /* general xapian related error */ MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK, /* can't get write lock */ MU_ERROR_XAPIAN_CORRUPTION, /* database corruption */ - MU_ERROR_XAPIAN_DIR, /* xapian dir is not accessible */ + MU_ERROR_XAPIAN_DIR, /* xapian dir is not accessible */ MU_ERROR_XAPIAN_NOT_UPTODATE, /* database version is not uptodate */ MU_ERROR_XAPIAN_MISSING_DATA, /* missing data for a document */ MU_ERROR_QUERY, /* (parsing) error in the query */