* mu-mv: optionally, let it update the database (--updatedb) and print the
target file on stdout (--printtarget)
This commit is contained in:
52
man/mu-mv.1
52
man/mu-mv.1
@ -6,7 +6,7 @@ mu mv\- move a message file to a Maildir
|
|||||||
|
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
|
||||||
.B mu mv <source-path> <target-maildir>
|
.B mu mv [--flags=<flags>] [--updatedb] [--printtarget] <source-path> <target-maildir>
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.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
|
parameters. It's recommended not to use wildcards on the shell, the result may
|
||||||
be unexpected.
|
be unexpected.
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-flags\fR=\fI<flags>\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
|
.SH EXAMPLE
|
||||||
|
|
||||||
To move a message \fI/home/jimbo/Maildir/scuba/cur/123123123:2,S\fR to
|
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.
|
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
|
.SH LIMITATIONS
|
||||||
|
|
||||||
Both source-path and target-directory must be on the same disk partition,
|
Both source-path and target-directory must be on the same disk partition,
|
||||||
except when the target-directory is \fI/dev/null\fR.
|
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
|
.SH BUGS
|
||||||
|
|
||||||
|
|||||||
78
src/mu-cmd.c
78
src/mu-cmd.c
@ -38,6 +38,7 @@
|
|||||||
#include "mu-contacts.h"
|
#include "mu-contacts.h"
|
||||||
#include "mu-runtime.h"
|
#include "mu-runtime.h"
|
||||||
#include "mu-msg-flags.h"
|
#include "mu-msg-flags.h"
|
||||||
|
#include "mu-store.h"
|
||||||
|
|
||||||
#define VIEW_TERMINATOR '\f' /* form-feed */
|
#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
|
MuExitCode
|
||||||
mu_cmd_mv (MuConfig *opts)
|
mu_cmd_mv (MuConfig *opts)
|
||||||
@ -308,21 +355,17 @@ mu_cmd_mv (MuConfig *opts)
|
|||||||
GError *err;
|
GError *err;
|
||||||
gchar *fullpath;
|
gchar *fullpath;
|
||||||
MuMsgFlags flags;
|
MuMsgFlags flags;
|
||||||
|
MuExitCode rv;
|
||||||
|
|
||||||
if (!mv_check_params (opts, &flags))
|
if (!mv_check_params (opts, &flags))
|
||||||
return MU_EXITCODE_ERROR;
|
return MU_EXITCODE_ERROR;
|
||||||
|
|
||||||
err = NULL;
|
err = NULL;
|
||||||
|
|
||||||
/* special case: /dev/null */
|
/* special case: /dev/null */
|
||||||
if (g_strcmp0 (opts->params[2], "/dev/null") == 0) {
|
if (g_strcmp0 (opts->params[2], "/dev/null") == 0)
|
||||||
if (unlink (opts->params[1]) != 0) {
|
return mv_remove (opts->params[1], opts);
|
||||||
g_warning ("unlink failed: %s", strerror (errno));
|
|
||||||
return MU_EXITCODE_ERROR;
|
|
||||||
} else
|
|
||||||
return MU_EXITCODE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
fullpath = mu_msg_file_move_to_maildir (opts->params[1], opts->params[2],
|
fullpath = mu_msg_file_move_to_maildir (opts->params[1], opts->params[2],
|
||||||
flags, &err);
|
flags, &err);
|
||||||
if (!fullpath) {
|
if (!fullpath) {
|
||||||
@ -330,8 +373,19 @@ mu_cmd_mv (MuConfig *opts)
|
|||||||
g_warning ("move failed: %s", err->message);
|
g_warning ("move failed: %s", err->message);
|
||||||
g_error_free (err);
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -319,6 +319,11 @@ config_options_group_mv (MuConfig *opts)
|
|||||||
GOptionEntry entries[] = {
|
GOptionEntry entries[] = {
|
||||||
{"flags", 0, 0, G_OPTION_ARG_STRING, &opts->flagstr,
|
{"flags", 0, 0, G_OPTION_ARG_STRING, &opts->flagstr,
|
||||||
"flags to set for the target (DFNPRST)", NULL},
|
"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}
|
{NULL, 0, 0, 0, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -126,6 +126,11 @@ struct _MuConfig {
|
|||||||
/* options for mv */
|
/* options for mv */
|
||||||
char *flagstr; /* message flags to set for
|
char *flagstr; /* message flags to set for
|
||||||
* the target */
|
* 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 */
|
/* options for view */
|
||||||
gboolean terminator; /* add separator \f between
|
gboolean terminator; /* add separator \f between
|
||||||
|
|||||||
@ -622,11 +622,11 @@ get_message_uid (MuMsg *msg)
|
|||||||
return get_message_uid (mu_msg_get_path(msg));
|
return get_message_uid (mu_msg_get_path(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
MuResult
|
gboolean
|
||||||
mu_store_store (MuStore *store, MuMsg *msg, gboolean replace)
|
mu_store_store (MuStore *store, MuMsg *msg, gboolean replace)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (store, MU_ERROR);
|
g_return_val_if_fail (store, FALSE);
|
||||||
g_return_val_if_fail (msg, MU_ERROR);
|
g_return_val_if_fail (msg, FALSE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Xapian::Document newdoc;
|
Xapian::Document newdoc;
|
||||||
@ -654,21 +654,52 @@ mu_store_store (MuStore *store, MuMsg *msg, gboolean replace)
|
|||||||
id = store->_db.replace_document (uid, newdoc);
|
id = store->_db.replace_document (uid, newdoc);
|
||||||
else
|
else
|
||||||
id = store->_db.add_document (newdoc);
|
id = store->_db.add_document (newdoc);
|
||||||
|
|
||||||
/* DEBUG */
|
|
||||||
//g_print ("\n[%s]\n", newdoc.serialise().c_str());
|
|
||||||
|
|
||||||
++store->_processed;
|
++store->_processed;
|
||||||
commit_trx_if (store,
|
commit_trx_if (store,
|
||||||
store->_processed % store->_trx_size == 0);
|
store->_processed % store->_trx_size == 0);
|
||||||
|
|
||||||
return MU_OK;
|
return TRUE;
|
||||||
|
|
||||||
} MU_XAPIAN_CATCH_BLOCK;
|
} MU_XAPIAN_CATCH_BLOCK;
|
||||||
|
|
||||||
rollback_trx_if (store, store->_in_transaction);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -109,9 +109,19 @@ void mu_store_flush (MuStore *store);
|
|||||||
*
|
*
|
||||||
* @return TRUE if it succeeded, FALSE otherwise
|
* @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
|
* remove a message from the database
|
||||||
*
|
*
|
||||||
|
|||||||
@ -399,11 +399,12 @@ enum _MuResult {
|
|||||||
typedef enum _MuResult MuResult;
|
typedef enum _MuResult MuResult;
|
||||||
|
|
||||||
enum _MuExitCode {
|
enum _MuExitCode {
|
||||||
MU_EXITCODE_OK = 0,
|
MU_EXITCODE_OK = 0,
|
||||||
MU_EXITCODE_ERROR = 1,
|
MU_EXITCODE_ERROR = 1,
|
||||||
MU_EXITCODE_NO_MATCHES = 2,
|
MU_EXITCODE_NO_MATCHES = 2,
|
||||||
MU_EXITCODE_DB_LOCKED = 3,
|
MU_EXITCODE_DB_LOCKED = 3,
|
||||||
MU_EXITCODE_DB_CORRUPTED = 4
|
MU_EXITCODE_DB_CORRUPTED = 4,
|
||||||
|
MU_EXITCODE_DB_UPDATE_ERROR = 5
|
||||||
};
|
};
|
||||||
typedef enum _MuExitCode MuExitCode;
|
typedef enum _MuExitCode MuExitCode;
|
||||||
|
|
||||||
@ -411,7 +412,7 @@ enum _MuError {
|
|||||||
MU_ERROR_XAPIAN, /* general xapian related error */
|
MU_ERROR_XAPIAN, /* general xapian related error */
|
||||||
MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK, /* can't get write lock */
|
MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK, /* can't get write lock */
|
||||||
MU_ERROR_XAPIAN_CORRUPTION, /* database corruption */
|
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_NOT_UPTODATE, /* database version is not uptodate */
|
||||||
MU_ERROR_XAPIAN_MISSING_DATA, /* missing data for a document */
|
MU_ERROR_XAPIAN_MISSING_DATA, /* missing data for a document */
|
||||||
MU_ERROR_QUERY, /* (parsing) error in the query */
|
MU_ERROR_QUERY, /* (parsing) error in the query */
|
||||||
|
|||||||
Reference in New Issue
Block a user