routine to call an external movemail program. (camel_movemail): Nuke

* camel-movemail.c (movemail_external): routine to call an
	external movemail program.
	(camel_movemail): Nuke return value, use movemail_external when
	available and useful, and don't delete "dest" on errors, since
	it might have started non-empty.

svn path=/trunk/; revision=4355
This commit is contained in:
Dan Winship
2000-07-26 18:32:10 +00:00
parent 06415e37e2
commit c9e2825702
3 changed files with 142 additions and 49 deletions

View File

@ -1,3 +1,11 @@
2000-07-26 Dan Winship <danw@helixcode.com>
* camel-movemail.c (movemail_external): routine to call an
external movemail program.
(camel_movemail): Nuke return value, use movemail_external when
available and useful, and don't delete "dest" on errors, since
it might have started non-empty.
2000-07-26 Jeffrey Stedfast <fejj@helixcode.com>
* camel-url.c (camel_url_to_string): Should now always prepend a '/'

View File

@ -34,6 +34,7 @@
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include "camel-movemail.h"
#include "camel-exception.h"
@ -44,6 +45,13 @@
#define d(x)
#ifdef MOVEMAIL_PATH
#include <sys/wait.h>
static void movemail_external (const char *source, const char *dest,
CamelException *ex);
#endif
/* these could probably be exposed as a utility? (but only mbox needs it) */
static int camel_movemail_copy_filter(int fromfd, int tofd, off_t start, size_t bytes, CamelMimeFilter *filter);
static int camel_movemail_copy(int fromfd, int tofd, off_t start, size_t bytes);
@ -59,14 +67,11 @@ static int camel_movemail_copy(int fromfd, int tofd, off_t start, size_t bytes);
* readers and writers into a private (presumably Camel-controlled)
* directory. Dot locking is used on the source file (but not the
* destination).
*
* Return value: 1 if mail was copied, 0 if the source file contained
* no mail, -1 if an error occurred.
**/
int
void
camel_movemail (const char *source, const char *dest, CamelException *ex)
{
gboolean locked, error;
gboolean locked;
int sfd, dfd, tmpfd;
char *locktmpfile, *lockfile;
struct stat st;
@ -84,33 +89,16 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
* called a fraction earlier.)
*/
if (stat (source, &st) == -1) {
if (errno == ENOENT)
return 0;
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not check mail file %s: %s",
source, g_strerror (errno));
return -1;
if (errno != ENOENT) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not check mail file "
"%s: %s", source,
g_strerror (errno));
}
return;
}
if (st.st_size == 0)
return 0;
sfd = open (source, O_RDWR);
if (sfd == -1) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not open mail file %s: %s",
source, g_strerror (errno));
return -1;
}
dfd = open (dest, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
if (dfd == -1) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not open temporary mail "
"file %s: %s", dest, g_strerror (errno));
close (sfd);
return -1;
}
return;
/* Create the unique lock file. */
locktmpfile = g_strdup_printf ("%s.lock.XXXXXX", source);
@ -124,16 +112,49 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
tmpfd = -1;
#endif
if (tmpfd == -1) {
g_free (locktmpfile);
#ifdef MOVEMAIL_PATH
if (errno == EACCES) {
/* movemail_external will fail if the dest file
* already exists, so if it does, return now,
* let the fetch code process the mail that's
* already there, and then the user can try again.
*/
if (stat (dest, &st) == 0)
return;
movemail_external (source, dest, ex);
return;
}
#endif
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not create lock file "
"for %s: %s", source, g_strerror (errno));
close (sfd);
close (dfd);
unlink (dest);
return -1;
return;
}
close (tmpfd);
sfd = open (source, O_RDWR);
if (sfd == -1) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not open mail file %s: %s",
source, g_strerror (errno));
unlink (locktmpfile);
g_free (locktmpfile);
return;
}
dfd = open (dest, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
if (dfd == -1) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not open temporary mail "
"file %s: %s", dest, g_strerror (errno));
close (sfd);
unlink (locktmpfile);
g_free (locktmpfile);
return;
}
lockfile = g_strdup_printf ("%s.lock", source);
locked = FALSE;
time (&timeout);
@ -195,15 +216,13 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
g_free (locktmpfile);
close (sfd);
close (dfd);
unlink (dest);
return -1;
return;
}
/* OK. We have the file locked now. */
/* FIXME: Set a timer to keep the file locked. */
error = FALSE;
while (1) {
int written = 0;
@ -216,7 +235,6 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Error reading mail file: %s",
g_strerror (errno));
error = TRUE;
break;
}
@ -229,7 +247,6 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
"Error writing "
"mail temp file: %s",
g_strerror (errno));
error = TRUE;
break;
}
written += nwrote;
@ -239,9 +256,8 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
/* If no errors occurred copying the data, and we successfully
* close the destination file, then truncate the source file.
* If there is some sort of error, delete the destination file.
*/
if (!error) {
if (!camel_exception_is_set (ex)) {
if (close (dfd) == 0)
ftruncate (sfd, 0);
else {
@ -249,13 +265,9 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
"Failed to store mail in "
"temp file %s: %s", dest,
g_strerror (errno));
unlink (dest);
error = TRUE;
}
} else {
} else
close (dfd);
unlink (dest);
}
close (sfd);
/* Clean up lock files. */
@ -263,10 +275,83 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
g_free (lockfile);
unlink (locktmpfile);
g_free (locktmpfile);
return error ? -1 : 1;
}
#ifdef MOVEMAIL_PATH
static void
movemail_external (const char *source, const char *dest, CamelException *ex)
{
sigset_t mask, omask;
pid_t pid;
int fd[2], len = 0, nread, status;
char buf[BUFSIZ], *output = NULL;
/* Block SIGCHLD so the app can't mess us up. */
sigemptyset (&mask);
sigaddset (&mask, SIGCHLD);
sigprocmask (SIG_BLOCK, &mask, &omask);
if (pipe (fd) == -1) {
sigprocmask (SIG_SETMASK, &omask, NULL);
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not create pipe: %s",
g_strerror (errno));
return;
}
pid = fork ();
switch (pid) {
case -1:
close (fd[0]);
close (fd[1]);
sigprocmask (SIG_SETMASK, &omask, NULL);
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Could not fork: %s",
g_strerror (errno));
return;
case 0:
/* Child */
close (fd[0]);
close (STDIN_FILENO);
dup2 (fd[1], STDOUT_FILENO);
dup2 (fd[1], STDERR_FILENO);
execl (MOVEMAIL_PATH, MOVEMAIL_PATH, source, dest, NULL);
_exit (255);
break;
default:
break;
}
/* Parent */
close (fd[1]);
/* Read movemail's output. */
while ((nread = read (fd[0], buf, sizeof (buf))) > 0) {
output = g_realloc (output, len + nread + 1);
memcpy (output + len, buf, nread);
len += nread;
output[len] = '\0';
}
close (fd[0]);
/* Now get the exit status. */
while (waitpid (pid, &status, 0) == -1 && errno == EINTR)
;
sigprocmask (SIG_SETMASK, &omask, NULL);
if (!WIFEXITED (status) || WEXITSTATUS (status) != 0) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Movemail program failed: %s",
output ? output : "(Unknown error)");
}
g_free (output);
}
#endif
static int
camel_movemail_copy(int fromfd, int tofd, off_t start, size_t bytes)
{

View File

@ -35,7 +35,7 @@ extern "C" {
#include <camel/camel-exception.h>
int camel_movemail (const char *source, const char *dest, CamelException *ex);
void camel_movemail (const char *source, const char *dest, CamelException *ex);
#ifdef __cplusplus