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-index.1 \
|
||||||
mu-mkdir.1 \
|
mu-mkdir.1 \
|
||||||
mu-view.1 \
|
mu-view.1 \
|
||||||
|
mu-mv.1 \
|
||||||
mu.1 \
|
mu.1 \
|
||||||
mug.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;
|
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);
|
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
|
* execute the cfind command
|
||||||
*
|
*
|
||||||
|
|
|
@ -355,13 +355,14 @@ parse_cmd (MuConfig *opts, int *argcp, char ***argvp)
|
||||||
} Cmd;
|
} Cmd;
|
||||||
|
|
||||||
Cmd cmd_map[] = {
|
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 },
|
{ "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;
|
opts->cmd = MU_CONFIG_CMD_NONE;
|
||||||
|
@ -406,6 +407,9 @@ add_context_group (GOptionContext *context, MuConfig *opts)
|
||||||
case MU_CONFIG_CMD_EXTRACT:
|
case MU_CONFIG_CMD_EXTRACT:
|
||||||
group = config_options_group_extract (opts);
|
group = config_options_group_extract (opts);
|
||||||
break;
|
break;
|
||||||
|
case MU_CONFIG_CMD_MV: /* no options for this one yet */
|
||||||
|
/* group = config_options_group_mv (opts); */
|
||||||
|
break;
|
||||||
case MU_CONFIG_CMD_CFIND:
|
case MU_CONFIG_CMD_CFIND:
|
||||||
group = config_options_group_cfind (opts);
|
group = config_options_group_cfind (opts);
|
||||||
break;
|
break;
|
||||||
|
@ -527,13 +531,14 @@ mu_config_execute (MuConfig *opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (opts->cmd) {
|
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_CLEANUP: return mu_cmd_cleanup (opts);
|
||||||
case MU_CONFIG_CMD_EXTRACT: return mu_cmd_extract (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_FIND: return mu_cmd_find (opts);
|
||||||
case MU_CONFIG_CMD_INDEX: return mu_cmd_index (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_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_VIEW: return mu_cmd_view (opts);
|
||||||
case MU_CONFIG_CMD_CFIND: return mu_cmd_cfind (opts);
|
|
||||||
case MU_CONFIG_CMD_UNKNOWN:
|
case MU_CONFIG_CMD_UNKNOWN:
|
||||||
g_printerr ("mu: unknown command '%s'\n\n", opts->cmdstr);
|
g_printerr ("mu: unknown command '%s'\n\n", opts->cmdstr);
|
||||||
show_usage (FALSE);
|
show_usage (FALSE);
|
||||||
|
|
|
@ -69,6 +69,8 @@ enum _MuConfigCmd {
|
||||||
MU_CONFIG_CMD_VIEW,
|
MU_CONFIG_CMD_VIEW,
|
||||||
MU_CONFIG_CMD_EXTRACT,
|
MU_CONFIG_CMD_EXTRACT,
|
||||||
MU_CONFIG_CMD_CFIND,
|
MU_CONFIG_CMD_CFIND,
|
||||||
|
MU_CONFIG_CMD_MV,
|
||||||
|
|
||||||
MU_CONFIG_CMD_NONE,
|
MU_CONFIG_CMD_NONE,
|
||||||
};
|
};
|
||||||
typedef enum _MuConfigCmd MuConfigCmd;
|
typedef enum _MuConfigCmd MuConfigCmd;
|
||||||
|
|
92
src/mu-msg.c
92
src/mu-msg.c
|
@ -774,6 +774,67 @@ msg_move (const char* oldpath, const char *newfullpath, GError **err)
|
||||||
return TRUE;
|
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',
|
* 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
|
* 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
|
gboolean
|
||||||
mu_msg_move_to_maildir (MuMsg *self, const char* targetmdir, GError **err)
|
mu_msg_move_to_maildir (MuMsg *self, const char* targetmdir, GError **err)
|
||||||
{
|
{
|
||||||
const char *oldpath;
|
|
||||||
MaildirType mtype;
|
|
||||||
char *newfullpath;
|
char *newfullpath;
|
||||||
|
|
||||||
g_return_val_if_fail (self, FALSE);
|
g_return_val_if_fail (self, FALSE);
|
||||||
g_return_val_if_fail (targetmdir, 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);
|
newfullpath = mu_msg_file_move_to_maildir (mu_msg_get_path (self),
|
||||||
|
targetmdir, err);
|
||||||
mtype = get_maildir_type (oldpath);
|
if (newfullpath) /* update our path to new one... */
|
||||||
g_return_val_if_fail (mtype==MAILDIR_TYPE_CUR||mtype==MAILDIR_TYPE_NEW,
|
mu_msg_cache_set_str (self->_cache, MU_MSG_FIELD_ID_PATH, newfullpath,
|
||||||
FALSE);
|
TRUE); /* the cache will free the string */
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
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
|
* 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
|
* 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
|
* @param msg a message with an existing file system path in an actual
|
||||||
* maildir
|
* 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
|
* @param targetmdir the target maildir; note that this the base-level
|
||||||
* Maildir, ie. /home/user/Maildir/archive, and must _not_ include the
|
* 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
|
* '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
|
* @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 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,
|
gboolean mu_msg_move_to_maildir (MuMsg *msg, const char* targetmdir,
|
||||||
GError **err);
|
GError **err);
|
||||||
|
char* mu_msg_file_move_to_maildir (const char *msgpath, const char* targetmdir,
|
||||||
|
GError **err);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum _MuMsgContactType { /* Reply-To:? */
|
enum _MuMsgContactType { /* Reply-To:? */
|
||||||
|
|
Loading…
Reference in New Issue