diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | ChangeLog.ja | 8 | ||||
-rw-r--r-- | libsylph/codeconv.c | 111 | ||||
-rw-r--r-- | libsylph/codeconv.h | 5 | ||||
-rw-r--r-- | libsylph/prefs_common.c | 2 | ||||
-rw-r--r-- | libsylph/prefs_common.h | 7 | ||||
-rw-r--r-- | libsylph/procmime.c | 4 | ||||
-rw-r--r-- | libsylph/utils.c | 24 | ||||
-rw-r--r-- | libsylph/utils.h | 2 | ||||
-rw-r--r-- | src/compose.c | 58 |
10 files changed, 215 insertions, 14 deletions
@@ -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; |