aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-movemail.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-movemail.c')
-rw-r--r--camel/camel-movemail.c250
1 files changed, 249 insertions, 1 deletions
diff --git a/camel/camel-movemail.c b/camel/camel-movemail.c
index e15e26e7ae..3ba3ee9efb 100644
--- a/camel/camel-movemail.c
+++ b/camel/camel-movemail.c
@@ -26,16 +26,28 @@
#include <config.h>
#include <sys/stat.h>
+#include <sys/uio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
+#include <string.h>
#include "camel-movemail.h"
#include "camel-exception.h"
+#include "camel-mime-parser.h"
+#include "camel-mime-filter.h"
+#include "camel-mime-filter-from.h"
+
+#define d(x)
+
+/* 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);
+
/**
* camel_movemail: Copy an mbox file from a shared spool directory to a
* new folder in a Camel store
@@ -91,7 +103,7 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
return -1;
}
- dfd = open (dest, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ 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 "
@@ -199,6 +211,8 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
if (nread == 0)
break;
else if (nread == -1) {
+ if (errno == EINTR)
+ continue;
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Error reading mail file: %s",
g_strerror (errno));
@@ -209,6 +223,8 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
while (nread) {
nwrote = write (dfd, buf + written, nread);
if (nwrote == -1) {
+ if (errno == EINTR)
+ continue; /* continues inner loop */
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
"Error writing "
"mail temp file: %s",
@@ -250,3 +266,235 @@ camel_movemail (const char *source, const char *dest, CamelException *ex)
return error ? -1 : 1;
}
+
+static int
+camel_movemail_copy(int fromfd, int tofd, off_t start, size_t bytes)
+{
+ char buffer[4096];
+ int written = 0;
+
+ d(printf("writing %d bytes ... ", bytes));
+
+ if (lseek(fromfd, start, SEEK_SET) != start)
+ return -1;
+
+ while (bytes>0) {
+ int toread, towrite;
+
+ toread = bytes;
+ if (bytes>4096)
+ toread = 4096;
+ else
+ toread = bytes;
+ do {
+ towrite = read(fromfd, buffer, toread);
+ } while (towrite == -1 && errno == EINTR);
+
+ if (towrite == -1)
+ return -1;
+
+ /* check for 'end of file' */
+ if (towrite == 0) {
+ d(printf("end of file?\n"));
+ break;
+ }
+
+ do {
+ toread = write(tofd, buffer, towrite);
+ } while (toread == -1 && errno == EINTR);
+
+ if (toread == -1)
+ return -1;
+
+ written += toread;
+ bytes -= toread;
+ }
+
+ d(printf("written %d bytes\n", written));
+
+ return written;
+}
+
+#define PRE_SIZE (32)
+
+static int
+camel_movemail_copy_filter(int fromfd, int tofd, off_t start, size_t bytes, CamelMimeFilter *filter)
+{
+ char buffer[4096+PRE_SIZE];
+ int written = 0;
+ char *filterbuffer;
+ int filterlen, filterpre;
+
+ d(printf("writing %d bytes ... ", bytes));
+
+ camel_mime_filter_reset(filter);
+
+ if (lseek(fromfd, start, SEEK_SET) != start)
+ return -1;
+
+ while (bytes>0) {
+ int toread, towrite;
+
+ toread = bytes;
+ if (bytes>4096)
+ toread = 4096;
+ else
+ toread = bytes;
+ do {
+ towrite = read(fromfd, buffer+PRE_SIZE, toread);
+ } while (towrite == -1 && errno == EINTR);
+
+ if (towrite == -1)
+ return -1;
+
+ /* check for 'end of file' */
+ if (towrite == 0) {
+ d(printf("end of file?\n"));
+ camel_mime_filter_complete(filter, buffer+PRE_SIZE, towrite, PRE_SIZE,
+ &filterbuffer, &filterlen, &filterpre);
+ towrite = filterlen;
+ if (towrite == 0)
+ break;
+ } else {
+ camel_mime_filter_filter(filter, buffer+PRE_SIZE, towrite, PRE_SIZE,
+ &filterbuffer, &filterlen, &filterpre);
+ towrite = filterlen;
+ }
+
+ do {
+ toread = write(tofd, filterbuffer, towrite);
+ } while (toread == -1 && errno == EINTR);
+
+ if (toread == -1)
+ return -1;
+
+ written += toread;
+ bytes -= toread;
+ }
+
+ d(printf("written %d bytes\n", written));
+
+ return written;
+}
+
+/* write the headers back out again, but not he Content-Length header, because we dont
+ want to maintain it! */
+static int
+solaris_header_write(int fd, struct _header_raw *header)
+{
+ struct iovec iv[4];
+ int outlen = 0, len;
+
+ iv[1].iov_base = ":";
+ iv[1].iov_len = 1;
+ iv[3].iov_base = "\n";
+ iv[3].iov_len = 1;
+
+ while (header) {
+ if (strcasecmp(header->name, "Content-Length")) {
+ iv[0].iov_base = header->name;
+ iv[0].iov_len = strlen(header->name);
+ iv[2].iov_base = header->value;
+ iv[2].iov_len = strlen(header->value);
+
+ do {
+ len = writev(fd, iv, 4);
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1)
+ return -1;
+ outlen += len;
+ }
+ header = header->next;
+ }
+
+ do {
+ len = write(fd, "\n", 1);
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1)
+ return -1;
+
+ outlen += 1;
+
+ d(printf("Wrote %d bytes of headers\n", outlen));
+
+ return outlen;
+}
+
+/* Well, since Solaris is a tad broken wrt its 'mbox' folder format,
+ we must convert it to a real mbox format. Thankfully this is
+ mostly pretty easy */
+static int
+camel_movemail_solaris (int sfd, int dfd, CamelException *ex)
+{
+ CamelMimeParser *mp;
+ char *buffer;
+ int len;
+ CamelMimeFilterFrom *ffrom;
+ int ret = 1;
+
+ mp = camel_mime_parser_new();
+ camel_mime_parser_scan_from(mp, TRUE);
+ camel_mime_parser_init_with_fd(mp, sfd);
+
+ ffrom = camel_mime_filter_from_new();
+
+ while (camel_mime_parser_step(mp, &buffer, &len) == HSCAN_FROM) {
+ if (camel_mime_parser_step(mp, &buffer, &len) != HSCAN_FROM_END) {
+ const char *cl;
+ int length;
+ int start, body;
+ off_t newpos;
+
+ ret = 0;
+
+ start = camel_mime_parser_tell_start_from(mp);
+ body = camel_mime_parser_tell(mp);
+
+ /* write out headers, but NOT content-length header */
+ solaris_header_write(dfd, camel_mime_parser_headers_raw(mp));
+
+ cl = camel_mime_parser_header(mp, "content-length", NULL);
+ if (cl == NULL) {
+ g_warning("Required Content-Length header is missing from solaris mail box @ %d", (int)camel_mime_parser_tell(mp));
+ camel_mime_parser_drop_step(mp);
+ camel_mime_parser_drop_step(mp);
+ camel_mime_parser_step(mp, &buffer, &len);
+ camel_mime_parser_unstep(mp);
+ length = camel_mime_parser_tell_start_from(mp) - body;
+ newpos = -1;
+ } else {
+ length = atoi(cl);
+ camel_mime_parser_drop_step(mp);
+ camel_mime_parser_drop_step(mp);
+ newpos = length+body;
+ }
+ /* copy body->length converting From lines */
+ if (camel_movemail_copy_filter(sfd, dfd, body, length, (CamelMimeFilter *)ffrom) == -1)
+ goto fail;
+ if (newpos != -1)
+ camel_mime_parser_seek(mp, newpos, SEEK_SET);
+ } else {
+ g_error("Inalid parser state: %d", camel_mime_parser_state(mp));
+ }
+ }
+
+ gtk_object_unref((GtkObject *)mp);
+ gtk_object_unref((GtkObject *)ffrom);
+
+ return ret;
+
+fail:
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ "Error copying "
+ "mail temp file: %s",
+ g_strerror (errno));
+
+
+ gtk_object_unref((GtkObject *)mp);
+ gtk_object_unref((GtkObject *)ffrom);
+
+ return -1;
+}
+