* mu mv updates:
- rename --printtarget into --print-target - support 'delta' flags - add --ignore-dups to silently ignore the src = target case
This commit is contained in:
27
man/mu-mv.1
27
man/mu-mv.1
@ -46,10 +46,20 @@ The flags is a sequence of characters from the set D (draft), F (flagged), N
|
|||||||
flags-parameter is case-sensitive. Any other characters will be silently
|
flags-parameter is case-sensitive. Any other characters will be silently
|
||||||
ignored.
|
ignored.
|
||||||
|
|
||||||
|
The \fB\-\-flags\fR also has a second, 'delta', syntax. In this syntax, each
|
||||||
|
of the flag characters is prefixed with either '+' or '-', which means that
|
||||||
|
the corresponding flag will be added or removed. Using this syntax, you can
|
||||||
|
change individual flags, without changing all of them.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-printtarget\fR
|
\fB\-\-print-target\fR
|
||||||
return the target path on standard output upon succesful completion of the
|
return the target path on standard output upon succesful completion of the
|
||||||
move (with or without a succesful database update)
|
move (with or without a succesful database update).
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-ignore-dups\fR
|
||||||
|
silently ignore the case where the source file is the same as the target.
|
||||||
|
|
||||||
|
|
||||||
.SH EXAMPLE
|
.SH EXAMPLE
|
||||||
|
|
||||||
@ -76,23 +86,30 @@ To mark a message as no longer new and 'Seen', and update the database
|
|||||||
afterwards, you could do:
|
afterwards, you could do:
|
||||||
|
|
||||||
.nf
|
.nf
|
||||||
mu --flags=S mv /home/roger/Maildir/inbox/new/123123123 /home/roger/Maildir/inbox/
|
mu mv /home/roger/Maildir/inbox/new/123123123 /home/roger/Maildir/inbox/ --flags=S
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
In this case, as we are not moving the message to a diffent maildir, we can
|
In this case, as we are not moving the message to a diffent maildir, we can
|
||||||
leave off the maildir-argument; so the following is equivalent:
|
leave off the maildir-argument; so the following is equivalent:
|
||||||
|
|
||||||
.nf
|
.nf
|
||||||
mu --flags=S mv /home/roger/Maildir/inbox/new/123123123
|
mu mv /home/roger/Maildir/inbox/new/123123123 --flags=S
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
|
Finally, using the 'delta'-syntax, you can set the 'seen'-flag
|
||||||
|
and 'replied'-flag while removing the 'new' flag with:
|
||||||
|
|
||||||
|
.nf
|
||||||
|
mu mv /home/billy/Maildir/inbox/new/12aa34343 --flags=+S+R-N
|
||||||
|
.fi
|
||||||
|
which would give us a new file:
|
||||||
|
\fI/home/billy/Maildir/inbox/cur/12aa34343:2,SR\fR
|
||||||
|
|
||||||
.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 RETURN VALUE
|
.SH RETURN VALUE
|
||||||
|
|
||||||
\fBmu mv\fR returns 0 upon success, and some other value when an error
|
\fBmu mv\fR returns 0 upon success, and some other value when an error
|
||||||
|
|||||||
31
src/mu-cmd.c
31
src/mu-cmd.c
@ -285,19 +285,31 @@ mu_cmd_mkdir (MuConfig *opts)
|
|||||||
static gboolean
|
static gboolean
|
||||||
mv_check_params (MuConfig *opts, MuFlags *flags)
|
mv_check_params (MuConfig *opts, MuFlags *flags)
|
||||||
{
|
{
|
||||||
if (!opts->params[1] || !opts->params[2]) {
|
if (!opts->params[1]) {
|
||||||
g_warning ("usage: mu mv [--flags=<flags>] <mailfile> "
|
g_warning ("usage: mu mv [--flags=<flags>] <mailfile> "
|
||||||
"<maildir>");
|
"[<maildir>]");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: check for invalid flags */
|
/* FIXME: check for invalid flags */
|
||||||
if (!opts->flagstr)
|
if (!opts->flagstr)
|
||||||
*flags = MU_FLAG_INVALID; /* ie., ignore flags */
|
*flags = MU_FLAG_INVALID; /* ie., ignore flags */
|
||||||
else
|
else {
|
||||||
*flags = mu_flags_from_str (opts->flagstr,
|
/* if there's a '+' or '-' sign in the string, it must
|
||||||
MU_FLAG_TYPE_MAILDIR |
|
* be a flag-delta */
|
||||||
MU_FLAG_TYPE_MAILFILE);
|
if (strstr (opts->flagstr, "+") || strstr (opts->flagstr, "-")) {
|
||||||
|
MuFlags oldflags;
|
||||||
|
oldflags = mu_maildir_get_flags_from_path (opts->params[1]);
|
||||||
|
*flags = mu_flags_from_str_delta (opts->flagstr,
|
||||||
|
oldflags,
|
||||||
|
MU_FLAG_TYPE_MAILDIR|
|
||||||
|
MU_FLAG_TYPE_MAILFILE);
|
||||||
|
} else
|
||||||
|
*flags = mu_flags_from_str (opts->flagstr,
|
||||||
|
MU_FLAG_TYPE_MAILDIR |
|
||||||
|
MU_FLAG_TYPE_MAILFILE);
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +322,7 @@ cmd_mv_dev_null (MuConfig *opts)
|
|||||||
return MU_ERROR_FILE;
|
return MU_ERROR_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->printtarget)
|
if (opts->print_target)
|
||||||
g_print ("/dev/null\n"); /* /dev/null */
|
g_print ("/dev/null\n"); /* /dev/null */
|
||||||
|
|
||||||
return MU_OK;
|
return MU_OK;
|
||||||
@ -334,7 +346,8 @@ mu_cmd_mv (MuConfig *opts)
|
|||||||
err = NULL;
|
err = NULL;
|
||||||
fullpath = mu_maildir_move_message (opts->params[1],
|
fullpath = mu_maildir_move_message (opts->params[1],
|
||||||
opts->params[2],
|
opts->params[2],
|
||||||
flags, &err);
|
flags, opts->ignore_dups,
|
||||||
|
&err);
|
||||||
if (!fullpath) {
|
if (!fullpath) {
|
||||||
if (err) {
|
if (err) {
|
||||||
MuError code;
|
MuError code;
|
||||||
@ -346,7 +359,7 @@ mu_cmd_mv (MuConfig *opts)
|
|||||||
return MU_ERROR_FILE;
|
return MU_ERROR_FILE;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (opts->printtarget)
|
if (opts->print_target)
|
||||||
g_print ("%s\n", fullpath);
|
g_print ("%s\n", fullpath);
|
||||||
return MU_OK;
|
return MU_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -322,7 +322,10 @@ 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},
|
||||||
{"printtarget", 0, 0, G_OPTION_ARG_NONE, &opts->printtarget,
|
{"ignore-dups", 0, 0, G_OPTION_ARG_NONE, &opts->ignore_dups,
|
||||||
|
"whether to silently ignore the source = target case",
|
||||||
|
NULL},
|
||||||
|
{"print-target", 0, 0, G_OPTION_ARG_NONE, &opts->print_target,
|
||||||
"whether to print the target path upon succesful completion",
|
"whether to print the target path upon succesful completion",
|
||||||
NULL},
|
NULL},
|
||||||
{NULL, 0, 0, 0, NULL, NULL, NULL}
|
{NULL, 0, 0, 0, NULL, NULL, NULL}
|
||||||
|
|||||||
@ -128,10 +128,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 printtarget; /* should be print the
|
gboolean print_target; /* should be print the
|
||||||
* target file path on
|
* target file path on
|
||||||
* stdout */
|
* stdout */
|
||||||
|
gboolean ignore_dups; /* silently ignore the
|
||||||
|
* src=target case */
|
||||||
/* options for view */
|
/* options for view */
|
||||||
gboolean terminator; /* add separator \f between
|
gboolean terminator; /* add separator \f between
|
||||||
* multiple messages in mu
|
* multiple messages in mu
|
||||||
|
|||||||
@ -60,7 +60,6 @@ mu_flag_type (MuFlags flag)
|
|||||||
if (flag >= MU_FLAG_SIGNED && flag <= MU_FLAG_HAS_ATTACH)
|
if (flag >= MU_FLAG_SIGNED && flag <= MU_FLAG_HAS_ATTACH)
|
||||||
return MU_FLAG_TYPE_CONTENT;
|
return MU_FLAG_TYPE_CONTENT;
|
||||||
|
|
||||||
g_return_val_if_reached (MU_FLAG_TYPE_INVALID);
|
|
||||||
return MU_FLAG_TYPE_INVALID;
|
return MU_FLAG_TYPE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +86,6 @@ mu_flag_char (MuFlags flag)
|
|||||||
case MU_FLAG_UNREAD: return 'u';
|
case MU_FLAG_UNREAD: return 'u';
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_return_val_if_reached (0);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,13 +113,11 @@ mu_flag_from_char (char kar)
|
|||||||
case 'u': return MU_FLAG_UNREAD;
|
case 'u': return MU_FLAG_UNREAD;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_return_val_if_reached (MU_FLAG_INVALID);
|
|
||||||
return MU_FLAG_INVALID;
|
return MU_FLAG_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* does not use FLAG_INFO, optimized */
|
/* does not use FLAG_INFO, optimized */
|
||||||
const char*
|
const char*
|
||||||
mu_flag_name (MuFlags flag)
|
mu_flag_name (MuFlags flag)
|
||||||
@ -143,7 +139,6 @@ mu_flag_name (MuFlags flag)
|
|||||||
case MU_FLAG_UNREAD: return "unread";
|
case MU_FLAG_UNREAD: return "unread";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_return_val_if_reached (NULL);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +155,7 @@ mu_flags_to_str_s (MuFlags flags, MuFlagType types)
|
|||||||
types & FLAG_INFO[u].flag_type)
|
types & FLAG_INFO[u].flag_type)
|
||||||
str[v++] = FLAG_INFO[u].kar;
|
str[v++] = FLAG_INFO[u].kar;
|
||||||
str[v] = '\0';
|
str[v] = '\0';
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,3 +194,39 @@ mu_flags_foreach (MuFlagsForeachFunc func, gpointer user_data)
|
|||||||
func (FLAG_INFO[u].flag, user_data);
|
func (FLAG_INFO[u].flag, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MuFlags
|
||||||
|
mu_flags_from_str_delta (const char *str, MuFlags oldflags,
|
||||||
|
MuFlagType types)
|
||||||
|
{
|
||||||
|
const char *cur;
|
||||||
|
MuFlags newflags;
|
||||||
|
|
||||||
|
g_return_val_if_fail (str, MU_FLAG_INVALID);
|
||||||
|
|
||||||
|
for (cur = str, newflags = oldflags; *cur; ++cur) {
|
||||||
|
|
||||||
|
MuFlags f;
|
||||||
|
if (*cur == '+' || *cur == '-') {
|
||||||
|
f = mu_flag_from_char (cur[1]);
|
||||||
|
if (f == 0)
|
||||||
|
goto error;
|
||||||
|
if (*cur == '+')
|
||||||
|
newflags |= f;
|
||||||
|
else
|
||||||
|
newflags &= ~f;
|
||||||
|
++cur;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newflags;
|
||||||
|
error:
|
||||||
|
g_warning ("invalid flag string");
|
||||||
|
return MU_FLAG_INVALID;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -122,6 +122,26 @@ const char* mu_flags_to_str_s (MuFlags flags, MuFlagType types);
|
|||||||
MuFlags mu_flags_from_str (const char *str, MuFlagType types);
|
MuFlags mu_flags_from_str (const char *str, MuFlagType types);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update #oldflags with the flags in #str, where #str consists of the
|
||||||
|
* the normal flag characters, but prefixed with either '+' or '-',
|
||||||
|
* which means resp. "add this flag" or "remove this flag" from
|
||||||
|
* oldflags. So, e.g. "-N+S" would unset the NEW flag and set the
|
||||||
|
* SEEN flag, without affecting other flags.
|
||||||
|
*
|
||||||
|
* @param str the string representation
|
||||||
|
* @param old flags to update
|
||||||
|
* @param types the flag types to accept (other will be ignored)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
MuFlags mu_flags_from_str_delta (const char *str, MuFlags oldflags,
|
||||||
|
MuFlagType types);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef void (*MuFlagsForeachFunc) (MuFlags flag, gpointer user_data);
|
typedef void (*MuFlagsForeachFunc) (MuFlags flag, gpointer user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -812,10 +812,12 @@ msg_move (const char* src, const char *dst, GError **err)
|
|||||||
|
|
||||||
gchar*
|
gchar*
|
||||||
mu_maildir_move_message (const char* oldpath, const char* targetmdir,
|
mu_maildir_move_message (const char* oldpath, const char* targetmdir,
|
||||||
MuFlags newflags, GError **err)
|
MuFlags newflags, gboolean ignore_dups,
|
||||||
|
GError **err)
|
||||||
{
|
{
|
||||||
char *newfullpath;
|
char *newfullpath;
|
||||||
gboolean rv;
|
gboolean rv;
|
||||||
|
gboolean src_is_target;
|
||||||
|
|
||||||
g_return_val_if_fail (oldpath, FALSE);
|
g_return_val_if_fail (oldpath, FALSE);
|
||||||
|
|
||||||
@ -827,16 +829,21 @@ mu_maildir_move_message (const char* oldpath, const char* targetmdir,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_strcmp0 (oldpath, newfullpath) == 0) {
|
|
||||||
|
src_is_target = (g_strcmp0 (oldpath, newfullpath) == 0);
|
||||||
|
|
||||||
|
if (!ignore_dups && src_is_target) {
|
||||||
g_set_error (err, 0, MU_ERROR_FILE_TARGET_EQUALS_SOURCE,
|
g_set_error (err, 0, MU_ERROR_FILE_TARGET_EQUALS_SOURCE,
|
||||||
"target equals source");
|
"target equals source");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = msg_move (oldpath, newfullpath, err);
|
if (!src_is_target) {
|
||||||
if (!rv) {
|
rv = msg_move (oldpath, newfullpath, err);
|
||||||
g_free (newfullpath);
|
if (!rv) {
|
||||||
return NULL;
|
g_free (newfullpath);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newfullpath;
|
return newfullpath;
|
||||||
|
|||||||
@ -171,14 +171,17 @@ char* mu_maildir_get_new_path (const char *oldpath, const char *new_mdir,
|
|||||||
* of the message are affected; note that this may still involve a
|
* of the message are affected; note that this may still involve a
|
||||||
* moved to another directory (say, from new/ to cur/)
|
* moved to another directory (say, from new/ to cur/)
|
||||||
* @param flags to set for the target (influences the filename, path)
|
* @param flags to set for the target (influences the filename, path)
|
||||||
|
* @param ignore_dups whether to silent ignore the src=target case (and return TRUE)
|
||||||
* @param err (may be NULL) may contain error information; note if the
|
* @param err (may be NULL) may contain error information; note if the
|
||||||
* function return FALSE, err is not set for all error condition
|
* function return FALSE, err is not set for all error condition
|
||||||
* (ie. not for parameter errors)
|
* (ie. not for parameter errors)
|
||||||
|
*
|
||||||
* @return return the full path name of the target file (g_free) if
|
* @return return the full path name of the target file (g_free) if
|
||||||
* the move succeeded, NULL otherwise
|
* the move succeeded, NULL otherwise
|
||||||
*/
|
*/
|
||||||
gchar* mu_maildir_move_message (const char* oldpath, const char* targetmdir,
|
gchar* mu_maildir_move_message (const char* oldpath, const char* targetmdir,
|
||||||
MuFlags newflags, GError **err);
|
MuFlags newflags, gboolean ignore_dups,
|
||||||
|
GError **err);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user