* 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:
Dirk-Jan C. Binnema 2011-08-16 23:42:47 +03:00
parent 536280e1b6
commit 557a5e291c
8 changed files with 127 additions and 32 deletions

View File

@ -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
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
\fB\-\-printtarget\fR
\fB\-\-print-target\fR
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
@ -76,23 +86,30 @@ 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 /home/roger/Maildir/inbox/
mu mv /home/roger/Maildir/inbox/new/123123123 /home/roger/Maildir/inbox/ --flags=S
.fi
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:
.nf
mu --flags=S mv /home/roger/Maildir/inbox/new/123123123
mu mv /home/roger/Maildir/inbox/new/123123123 --flags=S
.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
Both source-path and target-directory must be on the same disk partition,
except when the target-directory is \fI/dev/null\fR.
.SH RETURN VALUE
\fBmu mv\fR returns 0 upon success, and some other value when an error

View File

@ -285,19 +285,31 @@ mu_cmd_mkdir (MuConfig *opts)
static gboolean
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> "
"<maildir>");
"[<maildir>]");
return FALSE;
}
/* FIXME: check for invalid flags */
if (!opts->flagstr)
*flags = MU_FLAG_INVALID; /* ie., ignore flags */
else
*flags = mu_flags_from_str (opts->flagstr,
MU_FLAG_TYPE_MAILDIR |
MU_FLAG_TYPE_MAILFILE);
else {
/* if there's a '+' or '-' sign in the string, it must
* be a flag-delta */
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;
}
@ -310,7 +322,7 @@ cmd_mv_dev_null (MuConfig *opts)
return MU_ERROR_FILE;
}
if (opts->printtarget)
if (opts->print_target)
g_print ("/dev/null\n"); /* /dev/null */
return MU_OK;
@ -334,7 +346,8 @@ mu_cmd_mv (MuConfig *opts)
err = NULL;
fullpath = mu_maildir_move_message (opts->params[1],
opts->params[2],
flags, &err);
flags, opts->ignore_dups,
&err);
if (!fullpath) {
if (err) {
MuError code;
@ -346,7 +359,7 @@ mu_cmd_mv (MuConfig *opts)
return MU_ERROR_FILE;
} else {
if (opts->printtarget)
if (opts->print_target)
g_print ("%s\n", fullpath);
return MU_OK;
}

View File

@ -322,7 +322,10 @@ 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},
{"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",
NULL},
{NULL, 0, 0, 0, NULL, NULL, NULL}

View File

@ -128,10 +128,11 @@ struct _MuConfig {
/* options for mv */
char *flagstr; /* message flags to set for
* the target */
gboolean printtarget; /* should be print the
* target file path on
* stdout */
gboolean print_target; /* should be print the
* target file path on
* stdout */
gboolean ignore_dups; /* silently ignore the
* src=target case */
/* options for view */
gboolean terminator; /* add separator \f between
* multiple messages in mu

View File

@ -60,7 +60,6 @@ mu_flag_type (MuFlags flag)
if (flag >= MU_FLAG_SIGNED && flag <= MU_FLAG_HAS_ATTACH)
return MU_FLAG_TYPE_CONTENT;
g_return_val_if_reached (MU_FLAG_TYPE_INVALID);
return MU_FLAG_TYPE_INVALID;
}
@ -87,7 +86,6 @@ mu_flag_char (MuFlags flag)
case MU_FLAG_UNREAD: return 'u';
default:
g_return_val_if_reached (0);
return 0;
}
}
@ -115,13 +113,11 @@ mu_flag_from_char (char kar)
case 'u': return MU_FLAG_UNREAD;
default:
g_return_val_if_reached (MU_FLAG_INVALID);
return MU_FLAG_INVALID;
}
}
/* does not use FLAG_INFO, optimized */
const char*
mu_flag_name (MuFlags flag)
@ -143,7 +139,6 @@ mu_flag_name (MuFlags flag)
case MU_FLAG_UNREAD: return "unread";
default:
g_return_val_if_reached (NULL);
return NULL;
}
}
@ -160,7 +155,7 @@ mu_flags_to_str_s (MuFlags flags, MuFlagType types)
types & FLAG_INFO[u].flag_type)
str[v++] = FLAG_INFO[u].kar;
str[v] = '\0';
return str;
}
@ -199,3 +194,39 @@ mu_flags_foreach (MuFlagsForeachFunc func, gpointer 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;
}

View File

@ -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);
/**
* 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);
/**

View File

@ -812,10 +812,12 @@ msg_move (const char* src, const char *dst, GError **err)
gchar*
mu_maildir_move_message (const char* oldpath, const char* targetmdir,
MuFlags newflags, GError **err)
MuFlags newflags, gboolean ignore_dups,
GError **err)
{
char *newfullpath;
gboolean rv;
gboolean src_is_target;
g_return_val_if_fail (oldpath, FALSE);
@ -827,16 +829,21 @@ mu_maildir_move_message (const char* oldpath, const char* targetmdir,
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,
"target equals source");
return FALSE;
}
rv = msg_move (oldpath, newfullpath, err);
if (!rv) {
g_free (newfullpath);
return NULL;
if (!src_is_target) {
rv = msg_move (oldpath, newfullpath, err);
if (!rv) {
g_free (newfullpath);
return NULL;
}
}
return newfullpath;

View File

@ -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
* moved to another directory (say, from new/ to cur/)
* @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
* function return FALSE, err is not set for all error condition
* (ie. not for parameter errors)
*
* @return return the full path name of the target file (g_free) if
* the move succeeded, NULL otherwise
*/
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