aboutsummaryrefslogtreecommitdiff
path: root/libsylph
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2010-07-12 09:33:27 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2010-07-12 09:33:27 +0000
commitec14e81935047bd2b2182595b76650b5f2fef893 (patch)
treed87f0c546859b5ef9a8f49a4f9abcdbd75ac63e7 /libsylph
parentaf81f08052caa5dd3bf88b31d9eed3cf6158e9df (diff)
implemented concatenation of partial messages (RFC 2046).
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@2608 ee746299-78ed-0310-b773-934348b2243d
Diffstat (limited to 'libsylph')
-rw-r--r--libsylph/procmime.c43
-rw-r--r--libsylph/procmime.h6
-rw-r--r--libsylph/procmsg.c145
-rw-r--r--libsylph/procmsg.h5
-rw-r--r--libsylph/utils.c99
-rw-r--r--libsylph/utils.h7
6 files changed, 281 insertions, 24 deletions
diff --git a/libsylph/procmime.c b/libsylph/procmime.c
index f4f55ede..2789563f 100644
--- a/libsylph/procmime.c
+++ b/libsylph/procmime.c
@@ -736,6 +736,49 @@ void procmime_scan_content_type_str(const gchar *content_type,
procmime_mime_params_free(mparams);
}
+void procmime_scan_content_type_partial(const gchar *content_type,
+ gint *total, gchar **part_id,
+ gint *number)
+{
+ MimeParams *mparams;
+ GSList *cur;
+ gchar *id_str = NULL;
+ gint t = 0, n = 0;
+
+ *total = 0;
+ *part_id = NULL;
+ *number = 0;
+
+ mparams = procmime_parse_mime_parameter(content_type);
+
+ if (!mparams->hvalue ||
+ g_ascii_strcasecmp(mparams->hvalue, "message/partial") != 0) {
+ procmime_mime_params_free(mparams);
+ return;
+ }
+
+ for (cur = mparams->plist; cur != NULL; cur = cur->next) {
+ MimeParam *param = (MimeParam *)cur->data;
+ if (!g_ascii_strcasecmp(param->name, "total")) {
+ t = atoi(param->value);
+ } else if (!id_str && !g_ascii_strcasecmp(param->name, "id")) {
+ id_str = g_strdup(param->value);
+ } else if (!g_ascii_strcasecmp(param->name, "number")) {
+ n = atoi(param->value);
+ }
+ }
+
+ procmime_mime_params_free(mparams);
+
+ if (t > 0 && n > 0 && t >= n && id_str) {
+ *total = t;
+ *part_id = id_str;
+ *number = n;
+ } else {
+ g_free(id_str);
+ }
+}
+
void procmime_scan_content_disposition(MimeInfo *mimeinfo,
const gchar *content_disposition)
{
diff --git a/libsylph/procmime.h b/libsylph/procmime.h
index 8d5b1855..4970f7c7 100644
--- a/libsylph/procmime.h
+++ b/libsylph/procmime.h
@@ -1,6 +1,6 @@
/*
* LibSylph -- E-Mail client library
- * Copyright (C) 1999-2007 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2010 Hiroyuki Yamamoto
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -156,6 +156,10 @@ void procmime_scan_content_type_str (const gchar *content_type,
gchar **charset,
gchar **name,
gchar **boundary);
+void procmime_scan_content_type_partial (const gchar *content_type,
+ gint *total,
+ gchar **part_id,
+ gint *number);
void procmime_scan_content_disposition (MimeInfo *mimeinfo,
const gchar *content_disposition);
MimeInfo *procmime_scan_mime_header (FILE *fp);
diff --git a/libsylph/procmsg.c b/libsylph/procmsg.c
index 2f6ebaad..6c384aa6 100644
--- a/libsylph/procmsg.c
+++ b/libsylph/procmsg.c
@@ -1,6 +1,6 @@
/*
* LibSylph -- E-Mail client library
- * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2010 Hiroyuki Yamamoto
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1724,6 +1724,149 @@ void procmsg_print_message_part(MsgInfo *msginfo, MimeInfo *partinfo,
g_free(prtmp);
}
+/**
+ * procmsg_concat_partial_messages:
+ * @mlist: list of MsgInfo* including message/partial messages.
+ * @file: output file name of concatenated message.
+ *
+ * Concatenate @mlist which consists of message/partial messages and
+ * output to @file. If @mlist has different partial id, the first one
+ * is used.
+ *
+ * Return value: 0 on success, or -1 if failed.
+ **/
+gint procmsg_concat_partial_messages(GSList *mlist, const gchar *file)
+{
+ static HeaderEntry hentry[] = {{"Content-Type:", NULL, FALSE},
+ {NULL, NULL, FALSE}};
+ FILE *fp;
+ gchar buf[BUFFSIZE];
+ FILE *tmp_fp;
+ gchar *part_id = NULL;
+ gint total = 0;
+ MsgInfo *msg_array[100] = {NULL};
+ MsgInfo *msginfo;
+ MimeInfo *mimeinfo;
+ GSList *cur;
+ gint i;
+
+ g_return_val_if_fail(mlist != NULL, -1);
+ g_return_val_if_fail(file != NULL, -1);
+
+ debug_print("procmsg_concat_partial_messages\n");
+
+ for (cur = mlist; cur != NULL; cur = cur->next) {
+ gint n = 0;
+ gint t = 0;
+ gchar *cur_id = NULL;
+
+ msginfo = (MsgInfo *)cur->data;
+
+ fp = procmsg_open_message_decrypted(msginfo, &mimeinfo);
+ if (!fp)
+ continue;
+ if (!mimeinfo->content_type ||
+ g_ascii_strcasecmp(mimeinfo->content_type, "message/partial") != 0)
+ goto skip;
+
+ rewind(fp);
+ if (procheader_get_one_field(buf, sizeof(buf), fp, hentry) == -1)
+ goto skip;
+
+ procmime_scan_content_type_partial(buf + strlen(hentry[0].name), &t, &cur_id, &n);
+ if (n == 0 || t > 100 || n > t) {
+ debug_print("skip\n");
+ g_free(cur_id);
+ goto skip;
+ }
+
+ debug_print("partial: %d/%d id=%s\n", n, t, cur_id);
+ if (!part_id)
+ part_id = g_strdup(cur_id);
+ if (total == 0)
+ total = t;
+
+ if (total != t || strcmp(part_id, cur_id) != 0) {
+ debug_print("skip\n");
+ g_free(cur_id);
+ goto skip;
+ }
+
+ msg_array[n - 1] = msginfo;
+
+ g_free(cur_id);
+skip:
+ fclose(fp);
+ procmime_mimeinfo_free_all(mimeinfo);
+ }
+
+ if (!part_id) {
+ debug_print("piece not found\n");
+ return -1;
+ }
+
+ g_print("part_id = %s , total = %d\n", part_id, total);
+ g_free(part_id);
+
+ /* check if all pieces exist */
+ for (i = 0; i < total; i++) {
+ if (msg_array[i] == NULL) {
+ debug_print("message part %d not exist\n", i + 1);
+ return -1;
+ }
+ }
+
+ /* concatenate parts */
+ if ((tmp_fp = g_fopen(file, "wb")) == NULL) {
+ FILE_OP_ERROR(file, "fopen");
+ return -1;
+ }
+
+ for (i = 0; i < total; i++) {
+ msginfo = msg_array[i];
+ off_t out_size;
+ gint empty_line_size = 0;
+
+ fp = procmsg_open_message_decrypted(msginfo, &mimeinfo);
+ if (!fp) {
+ g_warning("cannot open message part %d\n", i + 1);
+ fclose(tmp_fp);
+ g_unlink(file);
+ return -1;
+ }
+
+ out_size = get_left_file_size(fp);
+ if (out_size < 0) {
+ g_warning("cannot tell left file size of part %d\n", i + 1);
+ fclose(tmp_fp);
+ g_unlink(file);
+ return -1;
+ }
+ empty_line_size = get_last_empty_line_size(fp, out_size);
+ if (empty_line_size < 0) {
+ g_warning("cannot get last empty line size of part %d\n", i + 1);
+ fclose(tmp_fp);
+ g_unlink(file);
+ return -1;
+ }
+
+ if (append_file_part(fp, ftell(fp), out_size - empty_line_size,
+ tmp_fp) < 0) {
+ g_warning("write failed\n");
+ fclose(tmp_fp);
+ g_unlink(file);
+ return -1;
+ }
+
+ fclose(fp);
+ procmime_mimeinfo_free_all(mimeinfo);
+ }
+
+ fclose(tmp_fp);
+
+ return 0;
+}
+
static gboolean procmsg_get_flags(FolderItem *item, gint num,
MsgPermFlags *flags)
{
diff --git a/libsylph/procmsg.h b/libsylph/procmsg.h
index 32ec3dff..894e09f6 100644
--- a/libsylph/procmsg.h
+++ b/libsylph/procmsg.h
@@ -1,6 +1,6 @@
/*
* LibSylph -- E-Mail client library
- * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2010 Hiroyuki Yamamoto
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -325,6 +325,9 @@ void procmsg_print_message_part (MsgInfo *msginfo,
const gchar *cmdline,
gboolean all_headers);
+gint procmsg_concat_partial_messages (GSList *mlist,
+ const gchar *file);
+
MsgInfo *procmsg_get_msginfo (FolderItem *item,
gint num);
diff --git a/libsylph/utils.c b/libsylph/utils.c
index 145eccc6..23bb3b62 100644
--- a/libsylph/utils.c
+++ b/libsylph/utils.c
@@ -2422,6 +2422,49 @@ off_t get_left_file_size(FILE *fp)
return size;
}
+gint get_last_empty_line_size(FILE *fp, off_t size)
+{
+ glong pos;
+ gint lsize = 0;
+ gchar buf[4];
+ size_t nread;
+
+ if (size < 4)
+ return -1;
+
+ if ((pos = ftell(fp)) < 0) {
+ perror("ftell");
+ return -1;
+ }
+ if (fseek(fp, size - 4, SEEK_CUR) < 0) {
+ perror("fseek");
+ return -1;
+ }
+
+ /* read last 4 bytes */
+ nread = fread(buf, sizeof(buf), 1, fp);
+ if (nread != 1) {
+ perror("fread");
+ return -1;
+ }
+ g_print("last 4 bytes: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
+ if (buf[3] == '\n') {
+ if (buf[2] == '\n')
+ lsize = 1;
+ else if (buf[2] == '\r') {
+ if (buf[1] == '\n')
+ lsize = 2;
+ }
+ }
+
+ if (fseek(fp, pos, SEEK_SET) < 0) {
+ perror("fseek");
+ return -1;
+ }
+
+ return lsize;
+}
+
gboolean file_exist(const gchar *file, gboolean allow_fifo)
{
if (file == NULL)
@@ -2989,29 +3032,20 @@ gint move_file(const gchar *src, const gchar *dest, gboolean overwrite)
return 0;
}
-gint copy_file_part(FILE *fp, off_t offset, size_t length, const gchar *dest)
+gint append_file_part(FILE *fp, off_t offset, size_t length, FILE *dest_fp)
{
- FILE *dest_fp;
gint n_read;
gint bytes_left, to_read;
gchar buf[BUFSIZ];
- gboolean err = FALSE;
+
+ g_return_val_if_fail(fp != NULL, -1);
+ g_return_val_if_fail(dest_fp != NULL, -1);
if (fseek(fp, offset, SEEK_SET) < 0) {
perror("fseek");
return -1;
}
- if ((dest_fp = g_fopen(dest, "wb")) == NULL) {
- FILE_OP_ERROR(dest, "fopen");
- return -1;
- }
-
- if (change_file_mode_rw(dest_fp, dest) < 0) {
- FILE_OP_ERROR(dest, "chmod");
- g_warning("can't change file mode\n");
- }
-
bytes_left = length;
to_read = MIN(bytes_left, sizeof(buf));
@@ -3019,9 +3053,7 @@ gint copy_file_part(FILE *fp, off_t offset, size_t length, const gchar *dest)
if (n_read < to_read && ferror(fp))
break;
if (fwrite(buf, n_read, 1, dest_fp) < 1) {
- g_warning(_("writing to %s failed.\n"), dest);
- fclose(dest_fp);
- g_unlink(dest);
+ g_warning("append_file_part: writing to file failed.\n");
return -1;
}
bytes_left -= n_read;
@@ -3032,14 +3064,39 @@ gint copy_file_part(FILE *fp, off_t offset, size_t length, const gchar *dest)
if (ferror(fp)) {
perror("fread");
- err = TRUE;
+ return -1;
}
- if (fclose(dest_fp) == EOF) {
- FILE_OP_ERROR(dest, "fclose");
- err = TRUE;
+ if (fflush(dest_fp) == EOF) {
+ FILE_OP_ERROR("append_file_part", "fflush");
+ return -1;
}
- if (err) {
+ return 0;
+}
+
+gint copy_file_part(FILE *fp, off_t offset, size_t length, const gchar *dest)
+{
+ FILE *dest_fp;
+
+ if ((dest_fp = g_fopen(dest, "wb")) == NULL) {
+ FILE_OP_ERROR(dest, "fopen");
+ return -1;
+ }
+
+ if (change_file_mode_rw(dest_fp, dest) < 0) {
+ FILE_OP_ERROR(dest, "chmod");
+ g_warning("can't change file mode\n");
+ }
+
+ if (append_file_part(fp, offset, length, dest_fp) < 0) {
+ g_warning("writing to %s failed.\n", dest);
+ fclose(dest_fp);
+ g_unlink(dest);
+ return -1;
+ }
+
+ if (fclose(dest_fp) == EOF) {
+ FILE_OP_ERROR(dest, "fclose");
g_unlink(dest);
return -1;
}
diff --git a/libsylph/utils.h b/libsylph/utils.h
index 93d9533f..200f03b3 100644
--- a/libsylph/utils.h
+++ b/libsylph/utils.h
@@ -416,6 +416,9 @@ off_t get_file_size (const gchar *file);
off_t get_file_size_as_crlf (const gchar *file);
off_t get_left_file_size (FILE *fp);
+gint get_last_empty_line_size (FILE *fp,
+ off_t size);
+
gboolean file_exist (const gchar *file,
gboolean allow_fifo);
gboolean is_dir_exist (const gchar *dir);
@@ -447,6 +450,10 @@ gint copy_dir (const gchar *src,
gint move_file (const gchar *src,
const gchar *dest,
gboolean overwrite);
+gint append_file_part (FILE *fp,
+ off_t offset,
+ size_t length,
+ FILE *dest_fp);
gint copy_file_part (FILE *fp,
off_t offset,
size_t length,