mirror of https://github.com/djcb/mu.git
* added the mu mv command for moving, removing messages (WIP)
This commit is contained in:
parent
8ee5427975
commit
47073006d2
|
@ -26,5 +26,6 @@ dist_man_MANS = \
|
|||
mu-index.1 \
|
||||
mu-mkdir.1 \
|
||||
mu-view.1 \
|
||||
mu-mv.1 \
|
||||
mu.1 \
|
||||
mug.1
|
||||
|
|
|
@ -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)
|
38
src/mu-cmd.c
38
src/mu-cmd.c
|
@ -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;
|
||||
}
|
||||
|
|
13
src/mu-cmd.h
13
src/mu-cmd.h
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
94
src/mu-msg.c
94
src/mu-msg.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
10
src/mu-msg.h
10
src/mu-msg.h
|
@ -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:? */
|
||||
|
|
Loading…
Reference in New Issue