* added the mu mv command for moving, removing messages (WIP)

This commit is contained in:
Dirk-Jan C. Binnema 2011-08-01 22:42:23 +03:00
parent 8ee5427975
commit 47073006d2
8 changed files with 218 additions and 34 deletions

View File

@ -26,5 +26,6 @@ dist_man_MANS = \
mu-index.1 \
mu-mkdir.1 \
mu-view.1 \
mu-mv.1 \
mu.1 \
mug.1

75
man/mu-mv.1 Normal file
View File

@ -0,0 +1,75 @@
.TH MU MV 1 "August 2011" "User Manuals"
.SH NAME
mu mv\- move a message file to a Maildir
.SH SYNOPSIS
.B mu mv <source-path> <target-maildir>
.SH DESCRIPTION
\fBmu mv\fR is the \fBmu\fR sub-command for moving mail files to new
directories. It does \fBnot\fR use the mu database. The command is
deliberately limited and tries hard to maintain the Maildir-integrity and to
minimize chance of accidents
The \fIsource-path\fR must be a full, absolute path to the message you want to
move, while the \fItarget-maildir\fR is the path to the maildir, but
\fBwithout\fR the 'cur' or 'new' part - that part will be constructed from the
source message, so that message that live in 'new' will also be in 'new' in
the target, and the same for 'cur'. If needed, consult the \fBmaildir(5)\fR
documentation for details about 'cur' and 'new'.
As a special case, when \fI/dev/null\fR is specified as the target directory,
the mail file will be unlinked (deleted).
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 EXAMPLE
To move a message \fI/home/jimbo/Maildir/scuba/cur/123123123:2,S\fR to
\fI/home/jimbo/Maildir/archive\fR, you can use:
.nf
mu mv /home/jimbo/Maildir/scuba/cur/123123123:2,S /home/jimbo/Maildir/archive
.fi
This will move the message to the new path:
\fI/home/jimbo/Maildir/archive/cur/123123123:2,S\fR.
To remove a message \fI/home/fred/Maildir/trash/cur/123123123:2,S\fR, you
could do:
.nf
mu mv /home/fred/Maildir/trash/cur/123123123:2,S /dev/null
.fi
Obviously, you could also simply use \fBrm\fR in this case.
.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 BUGS
Please report bugs if you find them:
.BR http://code.google.com/p/mu0/issues/list
.SH AUTHOR
Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
.SH "SEE ALSO"
.BR maildir(5)
.BR mu(1)
.BR chmod(1)

View File

@ -273,3 +273,41 @@ mu_cmd_mkdir (MuConfig *opts)
return MU_EXITCODE_OK;
}
MuExitCode
mu_cmd_mv (MuConfig *opts)
{
GError *err;
gchar *fullpath;
if (!opts->params[1] || !opts->params[2]) {
g_warning ("usage: mu mv <sourcefile> <targetmaildir>");
return MU_EXITCODE_ERROR;
}
err = NULL;
/* special case: /dev/null */
if (strcmp (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;
}
fullpath = mu_msg_file_move_to_maildir (opts->params[1], opts->params[2],
&err);
if (!fullpath) {
if (err) {
g_warning ("move failed: %s", err->message);
g_error_free (err);
}
return MU_EXITCODE_ERROR;
}
return MU_EXITCODE_OK;
}

View File

@ -94,6 +94,19 @@ MuExitCode mu_cmd_find (MuConfig *opts);
MuExitCode mu_cmd_extract (MuConfig *opts);
/**
* execute the 'mv' command
*
* @param opts configuration options
*
* @return MU_EXITCODE_OK (0) if the command succeeds,
* MU_EXITCODE_ERROR otherwise
*/
MuExitCode mu_cmd_mv (MuConfig *opts);
/**
* execute the cfind command
*

View File

@ -355,13 +355,14 @@ parse_cmd (MuConfig *opts, int *argcp, char ***argvp)
} Cmd;
Cmd cmd_map[] = {
{ "index", MU_CONFIG_CMD_INDEX },
{ "find", MU_CONFIG_CMD_FIND },
{ "cleanup", MU_CONFIG_CMD_CLEANUP },
{ "mkdir", MU_CONFIG_CMD_MKDIR },
{ "view", MU_CONFIG_CMD_VIEW },
{ "extract", MU_CONFIG_CMD_EXTRACT },
{ "cfind", MU_CONFIG_CMD_CFIND },
{ "cleanup", MU_CONFIG_CMD_CLEANUP },
{ "extract", MU_CONFIG_CMD_EXTRACT },
{ "find", MU_CONFIG_CMD_FIND },
{ "index", MU_CONFIG_CMD_INDEX },
{ "mkdir", MU_CONFIG_CMD_MKDIR },
{ "mv", MU_CONFIG_CMD_MV },
{ "view", MU_CONFIG_CMD_VIEW },
};
opts->cmd = MU_CONFIG_CMD_NONE;
@ -406,6 +407,9 @@ add_context_group (GOptionContext *context, MuConfig *opts)
case MU_CONFIG_CMD_EXTRACT:
group = config_options_group_extract (opts);
break;
case MU_CONFIG_CMD_MV: /* no options for this one yet */
/* group = config_options_group_mv (opts); */
break;
case MU_CONFIG_CMD_CFIND:
group = config_options_group_cfind (opts);
break;
@ -527,13 +531,14 @@ mu_config_execute (MuConfig *opts)
}
switch (opts->cmd) {
case MU_CONFIG_CMD_CFIND: return mu_cmd_cfind (opts);
case MU_CONFIG_CMD_CLEANUP: return mu_cmd_cleanup (opts);
case MU_CONFIG_CMD_EXTRACT: return mu_cmd_extract (opts);
case MU_CONFIG_CMD_FIND: return mu_cmd_find (opts);
case MU_CONFIG_CMD_INDEX: return mu_cmd_index (opts);
case MU_CONFIG_CMD_MKDIR: return mu_cmd_mkdir (opts);
case MU_CONFIG_CMD_MV: return mu_cmd_mv (opts);
case MU_CONFIG_CMD_VIEW: return mu_cmd_view (opts);
case MU_CONFIG_CMD_CFIND: return mu_cmd_cfind (opts);
case MU_CONFIG_CMD_UNKNOWN:
g_printerr ("mu: unknown command '%s'\n\n", opts->cmdstr);
show_usage (FALSE);

View File

@ -69,6 +69,8 @@ enum _MuConfigCmd {
MU_CONFIG_CMD_VIEW,
MU_CONFIG_CMD_EXTRACT,
MU_CONFIG_CMD_CFIND,
MU_CONFIG_CMD_MV,
MU_CONFIG_CMD_NONE,
};
typedef enum _MuConfigCmd MuConfigCmd;

View File

@ -774,6 +774,67 @@ msg_move (const char* oldpath, const char *newfullpath, GError **err)
return TRUE;
}
/*
* move a msg to another maildir, trying to maintain 'integrity',
* ie. msg in 'new/' will go to new/, one in cur/ goes to cur/. be
* super-paranoid here...
*/
gchar*
mu_msg_file_move_to_maildir (const char* oldpath, const char* targetmdir,
GError **err)
{
MaildirType mtype;
char *newfullpath;
gboolean rv;
g_return_val_if_fail (oldpath, FALSE);
g_return_val_if_fail (targetmdir, FALSE);
if (!g_path_is_absolute(oldpath)) {
g_set_error (err, 0, MU_ERROR_FILE,
"source is not an absolute path: '%s'", oldpath);
return FALSE;
}
mtype = get_maildir_type (oldpath);
if (mtype != MAILDIR_TYPE_CUR && mtype != MAILDIR_TYPE_NEW) {
g_set_error (err, 0, MU_ERROR_FILE,
"source is not in a 'cur' or 'new' maildir: '%s'",
oldpath);
return FALSE;
}
if (!g_path_is_absolute(targetmdir)) {
g_set_error (err, 0, MU_ERROR_FILE,
"target is not an absolute path: '%s'", targetmdir);
return FALSE;
}
if (!mu_util_check_dir (targetmdir, TRUE, TRUE)) {
g_set_error (err, 0, MU_ERROR_FILE,
"target is not a read-writable dir: '%s'", targetmdir);
return FALSE;
}
newfullpath = get_new_fullpath (oldpath, targetmdir, mtype);
if (!newfullpath) {
g_set_error (err, 0, MU_ERROR_FILE,
"failed to determine target full path");
return FALSE;
}
rv = msg_move (oldpath, newfullpath, err);
if (!rv) {
g_free (newfullpath);
return NULL;
}
return newfullpath;
}
/*
* move a msg to another maildir, trying to maintain 'integrity',
* ie. msg in 'new/' will go to new/, one in cur/ goes to cur/. be
@ -782,36 +843,19 @@ msg_move (const char* oldpath, const char *newfullpath, GError **err)
gboolean
mu_msg_move_to_maildir (MuMsg *self, const char* targetmdir, GError **err)
{
const char *oldpath;
MaildirType mtype;
char *newfullpath;
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (targetmdir, FALSE);
g_return_val_if_fail (g_path_is_absolute(targetmdir), FALSE);
g_return_val_if_fail (mu_util_check_dir (targetmdir, TRUE, TRUE), FALSE);
oldpath = mu_msg_get_path (self);
mtype = get_maildir_type (oldpath);
g_return_val_if_fail (mtype==MAILDIR_TYPE_CUR||mtype==MAILDIR_TYPE_NEW,
FALSE);
newfullpath = get_new_fullpath (oldpath, targetmdir, mtype);
g_return_val_if_fail (newfullpath, FALSE);
if (!msg_move (oldpath, newfullpath, err))
goto error;
/* update our path to new one... */
mu_msg_cache_set_str (self->_cache, MU_MSG_FIELD_ID_PATH, newfullpath,
TRUE);
return TRUE;
error:
g_free (newfullpath);
return FALSE;
newfullpath = mu_msg_file_move_to_maildir (mu_msg_get_path (self),
targetmdir, err);
if (newfullpath) /* update our path to new one... */
mu_msg_cache_set_str (self->_cache, MU_MSG_FIELD_ID_PATH, newfullpath,
TRUE); /* the cache will free the string */
return newfullpath ? TRUE : FALSE;
}

View File

@ -376,10 +376,13 @@ char* mu_msg_to_sexp (MuMsg *msg, gboolean dbonly);
/**
* move a message to another maildir; the function returns the full
* path to the new message, and changes the msg to now point to the
* new maildir
* new maildir. mu_msg_file_move_to_maildir, but takes a msgpath as it
* argument
*
* @param msg a message with an existing file system path in an actual
* maildir
* @param msgpath an absolute file system path to an existing message in an
* actual maildir
* @param targetmdir the target maildir; note that this the base-level
* Maildir, ie. /home/user/Maildir/archive, and must _not_ include the
* 'cur' or 'new' part. mu_msg_move_to_maildir will make sure that the
@ -388,10 +391,13 @@ char* mu_msg_to_sexp (MuMsg *msg, gboolean dbonly);
* @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 TRUE if it worked, FALSE otherwise
* @return TRUE if it worked, FALSE otherwise (mu_msg_move_to_maildir) or the full path name of the target file (g_free) for mu_msg_file_move_to_maildir
*/
gboolean mu_msg_move_to_maildir (MuMsg *msg, const char* targetmdir,
GError **err);
char* mu_msg_file_move_to_maildir (const char *msgpath, const char* targetmdir,
GError **err);
enum _MuMsgContactType { /* Reply-To:? */