* 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 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

View File

@ -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;
} }

View File

@ -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}

View File

@ -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

View File

@ -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;
}

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

View File

@ -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;

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 * 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