aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--ChangeLog.ja8
-rw-r--r--libsylph/codeconv.c111
-rw-r--r--libsylph/codeconv.h5
-rw-r--r--libsylph/prefs_common.c2
-rw-r--r--libsylph/prefs_common.h7
-rw-r--r--libsylph/procmime.c4
-rw-r--r--libsylph/utils.c24
-rw-r--r--libsylph/utils.h2
-rw-r--r--src/compose.c58
10 files changed, 215 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index b8ad059e..5dae46e9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2006-03-17
+
+ * libsylph/utils.[ch]
+ libsylph/prefs_common.[ch]
+ libsylph/procmime.c
+ libsylph/codeconv.[ch]
+ src/compose.c: implemented RFC 2231 filename encoding on send.
+
2006-03-16
* libsylph/procmime.c: implemented RFC 2231 parameter value extension.
diff --git a/ChangeLog.ja b/ChangeLog.ja
index ef9e5b15..dd902a1e 100644
--- a/ChangeLog.ja
+++ b/ChangeLog.ja
@@ -1,3 +1,11 @@
+2006-03-17
+
+ * libsylph/utils.[ch]
+ libsylph/prefs_common.[ch]
+ libsylph/procmime.c
+ libsylph/codeconv.[ch]
+ src/compose.c: 送信時の RFC 2231 ファイル名エンコーディングを実装。
+
2006-03-16
* libsylph/procmime.c: RFC 2231 パラメータ値拡張を実装。
diff --git a/libsylph/codeconv.c b/libsylph/codeconv.c
index 6cf3de66..76d75336 100644
--- a/libsylph/codeconv.c
+++ b/libsylph/codeconv.c
@@ -2271,6 +2271,117 @@ void conv_encode_header(gchar *dest, gint len, const gchar *src,
#undef LBREAK_IF_REQUIRED
+#define INT_TO_HEX_UPPER(outp, val) \
+{ \
+ if ((val) < 10) \
+ *outp = '0' + (val); \
+ else \
+ *outp = 'A' + (val) - 10; \
+}
+
+#define IS_ESCAPE_CHAR(c) \
+ (c < 0x20 || c > 0x7f || \
+ strchr("\t \r\n*'%!#$&~`,{}|()<>@,;:\\\"/[]?=", c))
+
+static gchar *encode_rfc2231_filename(const gchar *str)
+{
+ const gchar *p;
+ gchar *out;
+ gchar *outp;
+
+ outp = out = g_malloc(strlen(str) * 3 + 1);
+
+ for (p = str; *p != '\0'; ++p) {
+ guchar ch = *(guchar *)p;
+
+ if (IS_ESCAPE_CHAR(ch)) {
+ *outp++ = '%';
+ INT_TO_HEX_UPPER(outp, ch >> 4);
+ ++outp;
+ INT_TO_HEX_UPPER(outp, ch & 0x0f);
+ ++outp;
+ } else
+ *outp++ = ch;
+ }
+
+ *outp = '\0';
+ return out;
+}
+
+gchar *conv_encode_filename(const gchar *src, const gchar *param_name,
+ const gchar *out_encoding)
+{
+ gint name_len, max_linelen;
+ gchar *out_str, *enc_str;
+ gchar cur_param[80];
+ GString *string;
+ gint count = 0;
+ gint cur_left_len;
+ gchar *p;
+
+ g_return_val_if_fail(src != NULL, NULL);
+ g_return_val_if_fail(param_name != NULL, NULL);
+
+ if (is_ascii_str(src))
+ return g_strdup_printf(" %s=\"%s\"", param_name, src);
+
+ name_len = strlen(param_name);
+ max_linelen = MAX_LINELEN - name_len - 3;
+
+ if (!out_encoding)
+ out_encoding = conv_get_outgoing_charset_str();
+ if (!strcmp(out_encoding, CS_US_ASCII))
+ out_encoding = CS_ISO_8859_1;
+
+ out_str = conv_codeset_strdup(src, CS_INTERNAL, out_encoding);
+ if (!out_str)
+ return NULL;
+ enc_str = encode_rfc2231_filename(out_str);
+ g_free(out_str);
+
+ if (strlen(enc_str) <= max_linelen) {
+ gchar *ret;
+ ret = g_strdup_printf(" %s*=%s''%s",
+ param_name, out_encoding, enc_str);
+ g_free(enc_str);
+ return ret;
+ }
+
+ string = g_string_new(NULL);
+ g_string_printf(string, " %s*0*=%s''", param_name, out_encoding);
+ cur_left_len = MAX_LINELEN - string->len;
+
+ p = enc_str;
+
+ while (*p != '\0') {
+ if ((*p == '%' && cur_left_len < 4) ||
+ (*p != '%' && cur_left_len < 2)) {
+ gint len;
+
+ g_string_append(string, ";\n");
+ ++count;
+ len = g_snprintf(cur_param, sizeof(cur_param),
+ " %s*%d*=", param_name, count);
+ g_string_append(string, cur_param);
+ cur_left_len = MAX_LINELEN - len;
+ }
+
+ if (*p == '%') {
+ g_string_append_len(string, p, 3);
+ p += 3;
+ cur_left_len -= 3;
+ } else {
+ g_string_append_c(string, *p);
+ ++p;
+ --cur_left_len;
+ }
+ }
+
+ g_free(enc_str);
+
+ return g_string_free(string, FALSE);
+}
+
gint conv_copy_file(const gchar *src, const gchar *dest, const gchar *encoding)
{
FILE *src_fp, *dest_fp;
diff --git a/libsylph/codeconv.h b/libsylph/codeconv.h
index 1920c8f0..700e83b0 100644
--- a/libsylph/codeconv.h
+++ b/libsylph/codeconv.h
@@ -1,6 +1,6 @@
/*
* LibSylph -- E-Mail client library
- * Copyright (C) 1999-2005 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2006 Hiroyuki Yamamoto
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -230,6 +230,9 @@ void conv_encode_header (gchar *dest,
gint header_len,
gboolean addr_field,
const gchar *out_encoding);
+gchar *conv_encode_filename (const gchar *src,
+ const gchar *param_name,
+ const gchar *out_encoding);
gint conv_copy_file (const gchar *src,
const gchar *dest,
diff --git a/libsylph/prefs_common.c b/libsylph/prefs_common.c
index 8360d0ce..5c4bfca5 100644
--- a/libsylph/prefs_common.c
+++ b/libsylph/prefs_common.c
@@ -57,6 +57,8 @@ static PrefParam param[] = {
{"filter_sent_message", "FALSE", &prefs_common.filter_sent, P_BOOL},
{"encoding_method", "0", &prefs_common.encoding_method, P_ENUM},
+ {"mime_filename_encoding_method", "0",
+ &prefs_common.mime_fencoding_method, P_ENUM},
{"allow_jisx0201_kana", "FALSE", &prefs_common.allow_jisx0201_kana,
P_BOOL},
diff --git a/libsylph/prefs_common.h b/libsylph/prefs_common.h
index de3a53c8..6f12e877 100644
--- a/libsylph/prefs_common.h
+++ b/libsylph/prefs_common.h
@@ -44,6 +44,12 @@ typedef enum {
CTE_8BIT
} TransferEncodingMethod;
+typedef enum {
+ FENC_MIME,
+ FENC_RFC2231,
+ FENC_NONE
+} MIMEFilenameEncodingMethod;
+
struct _PrefsCommon
{
/* Receive */
@@ -62,6 +68,7 @@ struct _PrefsCommon
gboolean savemsg;
gboolean filter_sent;
TransferEncodingMethod encoding_method;
+ MIMEFilenameEncodingMethod mime_fencoding_method;
gboolean allow_jisx0201_kana;
diff --git a/libsylph/procmime.c b/libsylph/procmime.c
index c79a2e59..28bb9d1f 100644
--- a/libsylph/procmime.c
+++ b/libsylph/procmime.c
@@ -576,7 +576,7 @@ static MimeParams *procmime_parse_mime_parameter(const gchar *str)
if (encoded) {
dec_value = g_malloc(strlen(begin) + 1);
- decode_uri(dec_value, begin);
+ decode_xdigit_encoded_str(dec_value, begin);
CONCAT_CONT_VALUE(dec_value);
g_free(dec_value);
} else {
@@ -602,7 +602,7 @@ static MimeParams *procmime_parse_mime_parameter(const gchar *str)
mparam->name = name;
if (encoded) {
dec_value = g_malloc(strlen(begin) + 1);
- decode_uri(dec_value, begin);
+ decode_xdigit_encoded_str(dec_value, begin);
mparam->value = procmime_convert_value
(dec_value, charset);
g_free(dec_value);
diff --git a/libsylph/utils.c b/libsylph/utils.c
index a2c3bd3e..914fd007 100644
--- a/libsylph/utils.c
+++ b/libsylph/utils.c
@@ -1629,8 +1629,8 @@ void decode_uri(gchar *decoded_uri, const gchar *encoded_uri)
while (*enc) {
if (*enc == '%') {
enc++;
- if (isxdigit((guchar)enc[0]) &&
- isxdigit((guchar)enc[1])) {
+ if (g_ascii_isxdigit((guchar)enc[0]) &&
+ g_ascii_isxdigit((guchar)enc[1])) {
*dec = axtoi(enc);
dec++;
enc += 2;
@@ -1648,6 +1648,26 @@ void decode_uri(gchar *decoded_uri, const gchar *encoded_uri)
*dec = '\0';
}
+void decode_xdigit_encoded_str(gchar *decoded, const gchar *encoded)
+{
+ gchar *dec = decoded;
+ const gchar *enc = encoded;
+
+ while (*enc) {
+ if (*enc == '%') {
+ enc++;
+ if (g_ascii_isxdigit((guchar)enc[0]) &&
+ g_ascii_isxdigit((guchar)enc[1])) {
+ *dec++ = axtoi(enc);
+ enc += 2;
+ }
+ } else
+ *dec++ = *enc++;
+ }
+
+ *dec = '\0';
+}
+
gchar *encode_uri(const gchar *filename)
{
gchar *uri;
diff --git a/libsylph/utils.h b/libsylph/utils.h
index 43372bb0..63bb7861 100644
--- a/libsylph/utils.h
+++ b/libsylph/utils.h
@@ -348,6 +348,8 @@ gchar *get_uri_path (const gchar *uri);
gint get_uri_len (const gchar *str);
void decode_uri (gchar *decoded_uri,
const gchar *encoded_uri);
+void decode_xdigit_encoded_str (gchar *decoded,
+ const gchar *encoded);
gchar *encode_uri (const gchar *filename);
gchar *uriencode_for_filename (const gchar *filename);
gint scan_mailto_url (const gchar *mailto,
diff --git a/src/compose.c b/src/compose.c
index 7e34a88d..7c0ab52c 100644
--- a/src/compose.c
+++ b/src/compose.c
@@ -269,6 +269,10 @@ static void compose_convert_header (Compose *compose,
gint header_len,
gboolean addr_field,
const gchar *encoding);
+static gchar *compose_convert_filename (Compose *compose,
+ const gchar *src,
+ const gchar *param_name,
+ const gchar *encoding);
static void compose_generate_msgid (Compose *compose,
gchar *buf,
gint len);
@@ -3427,7 +3431,6 @@ static void compose_write_attach(Compose *compose, FILE *fp,
gboolean valid;
AttachInfo *ainfo;
FILE *attach_fp;
- gchar filename[BUFFSIZE];
gint len;
EncodingType encoding;
@@ -3453,14 +3456,35 @@ static void compose_write_attach(Compose *compose, FILE *fp,
encoding == ENC_BASE64)
encoding = ENC_8BIT;
} else {
- compose_convert_header(compose,
- filename, sizeof(filename),
- ainfo->name, 12, FALSE, charset);
- fprintf(fp, "Content-Type: %s;\n"
- " name=\"%s\"\n",
- ainfo->content_type, filename);
- fprintf(fp, "Content-Disposition: attachment;\n"
- " filename=\"%s\"\n", filename);
+ if (prefs_common.mime_fencoding_method ==
+ FENC_RFC2231) {
+ gchar *param;
+
+ param = compose_convert_filename
+ (compose, ainfo->name, "name", charset);
+ fprintf(fp, "Content-Type: %s;\n"
+ "%s\n",
+ ainfo->content_type, param);
+ g_free(param);
+ param = compose_convert_filename
+ (compose, ainfo->name, "filename",
+ charset);
+ fprintf(fp, "Content-Disposition: attachment;\n"
+ "%s\n", param);
+ g_free(param);
+ } else {
+ gchar filename[BUFFSIZE];
+
+ compose_convert_header(compose, filename,
+ sizeof(filename),
+ ainfo->name, 12, FALSE,
+ charset);
+ fprintf(fp, "Content-Type: %s;\n"
+ " name=\"%s\"\n",
+ ainfo->content_type, filename);
+ fprintf(fp, "Content-Disposition: attachment;\n"
+ " filename=\"%s\"\n", filename);
+ }
#if USE_GPGME
/* force encoding to protect trailing spaces */
@@ -3965,6 +3989,22 @@ static void compose_convert_header(Compose *compose, gchar *dest, gint len,
g_free(src_);
}
+static gchar *compose_convert_filename(Compose *compose, const gchar *src,
+ const gchar *param_name,
+ const gchar *encoding)
+{
+ gchar *str;
+
+ g_return_val_if_fail(src != NULL, NULL);
+
+ if (!encoding)
+ encoding = conv_get_charset_str(compose->out_encoding);
+
+ str = conv_encode_filename(src, param_name, encoding);
+
+ return str;
+}
+
static void compose_generate_msgid(Compose *compose, gchar *buf, gint len)
{
struct tm *lt;