aboutsummaryrefslogtreecommitdiff
path: root/libsylph
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2006-03-16 03:37:22 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2006-03-16 03:37:22 +0000
commitd73dca3feec6442544458a69afdc157d8e4e8921 (patch)
tree6c2805c4a963980687e17616ee2e68148431278e /libsylph
parentdbd7b17de343dd5900d475844ba8a8c861bce8c9 (diff)
implemented RFC 2231 parameter value extension.
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@1050 ee746299-78ed-0310-b773-934348b2243d
Diffstat (limited to 'libsylph')
-rw-r--r--libsylph/procmime.c380
1 files changed, 310 insertions, 70 deletions
diff --git a/libsylph/procmime.c b/libsylph/procmime.c
index 8ff1b722..c79a2e59 100644
--- a/libsylph/procmime.c
+++ b/libsylph/procmime.c
@@ -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
@@ -379,105 +379,345 @@ void procmime_scan_content_type(MimeInfo *mimeinfo, const gchar *content_type)
mimeinfo->mime_type = MIME_TEXT;
}
-void procmime_scan_content_type_str(const gchar *content_type,
- gchar **mime_type, gchar **charset,
- gchar **name, gchar **boundary)
+typedef struct
{
- gchar *delim, *p;
- gchar *buf;
+ gchar *name;
+ gchar *value;
+} MimeParam;
- Xstrdup_a(buf, content_type, return);
+typedef struct
+{
+ gchar *hvalue;
+ GSList *plist;
+} MimeParams;
- if ((delim = strchr(buf, ';'))) *delim = '\0';
- if (mime_type)
- *mime_type = g_strdup(g_strstrip(buf));
+static gchar *procmime_find_parameter_delimiter(const gchar *param,
+ const gchar **eq)
+{
+ register const gchar *p = param;
+ gboolean quoted = FALSE;
+ const gchar *delim = NULL;
- if (!delim) return;
- p = delim + 1;
+ while (*p) {
+ if (*p == '=')
+ break;
+ else if (*p == ';' || g_ascii_isspace(*p)) {
+ delim = p;
+ break;
+ }
+ ++p;
+ }
+ if (*p != '=') {
+ *eq = NULL;
+ return (gchar *)delim;
+ }
+ *eq = p;
- for (;;) {
- gchar *eq;
- gchar *attr, *value;
+ ++p;
+ if (*p == '"') {
+ quoted = TRUE;
+ ++p;
+ }
+
+ while (*p) {
+ if (quoted == TRUE) {
+ if (*p == '"')
+ quoted = FALSE;
+ } else if (*p == ';' || g_ascii_isspace(*p)) {
+ delim = p;
+ break;
+ }
+ ++p;
+ }
+
+ return (gchar *)delim;
+}
- if ((delim = strchr(p, ';'))) *delim = '\0';
+static gchar *procmime_convert_value(const gchar *value, const gchar *charset)
+{
+ if (charset) {
+ gchar *utf8_value;
- if (!(eq = strchr(p, '='))) break;
+ utf8_value = conv_codeset_strdup(value, charset, CS_INTERNAL);
+ if (utf8_value)
+ return utf8_value;
+ }
- *eq = '\0';
- attr = p;
- g_strstrip(attr);
- value = eq + 1;
- g_strstrip(value);
+ return g_strdup(value);
+}
+static MimeParams *procmime_parse_mime_parameter(const gchar *str)
+{
+ gchar *hvalue;
+ gchar *param, *name, *value;
+ gchar *charset = NULL, *lang = NULL;
+ const gchar *p, *delim;
+ gint count, prev_count;
+ gchar *cont_name;
+ gchar *cont_value;
+ MimeParam *mparam;
+ MimeParams *mparams;
+ GSList *plist = NULL;
+
+ if ((p = strchr(str, ';')))
+ hvalue = g_strndup(str, p - str);
+ else
+ hvalue = g_strdup(str);
+
+ g_strstrip(hvalue);
+
+ mparams = g_new(MimeParams, 1);
+ mparams->hvalue = hvalue;
+ mparams->plist = NULL;
+
+ if (!p)
+ return mparams;
+ ++p;
+ count = prev_count = -1;
+ cont_name = cont_value = NULL;
+
+ for (;;) {
+ gboolean encoded = FALSE;
+ gchar *begin;
+ gchar *dec_value;
+ const gchar *eq;
+ gchar *ast = NULL;
+
+ while (*p == ';' || g_ascii_isspace(*p))
+ ++p;
+ if (*p == '\0')
+ break;
+
+ delim = procmime_find_parameter_delimiter(p, &eq);
+ if (!eq)
+ break;
+ if (delim)
+ param = g_strndup(p, delim - p);
+ else
+ param = g_strdup(p);
+
+ name = g_strndup(p, eq - p);
+ if (*name != '*' && (ast = strchr(name, '*'))) {
+ const gchar *next = ast + 1;
+
+ if (*next == '\0') {
+ encoded = TRUE;
+ } else if (g_ascii_isdigit(*next)) {
+ count = atoi(next);
+ while (g_ascii_isdigit(*next))
+ ++next;
+ if (*next == '*')
+ encoded = TRUE;
+ if (prev_count + 1 != count) {
+ g_warning("procmime_parse_mime_parameter(): invalid count: %s\n", str);
+ g_free(name);
+ g_free(param);
+ break;
+ }
+ } else {
+ g_warning("procmime_parse_mime_parameter(): invalid name: %s\n", str);
+ g_free(name);
+ g_free(param);
+ break;
+ }
+
+ *ast = '\0';
+ }
+
+ value = g_strdup(param + (eq - p) + 1);
if (*value == '"')
extract_quote(value, '"');
- else {
- eliminate_parenthesis(value, '(', ')');
- g_strstrip(value);
+
+ begin = value;
+
+ if (encoded) {
+ gchar *sq1, *sq2;
+
+ if ((sq1 = strchr(value, '\''))) {
+ if (sq1 > value) {
+ if (charset)
+ g_free(charset);
+ charset = g_strndup(value, sq1 - value);
+ }
+ if ((sq2 = strchr(sq1 + 1, '\''))) {
+ if (sq2 > sq1 + 1) {
+ if (lang)
+ g_free(lang);
+ lang = g_strndup(sq1 + 1,
+ sq2 - sq1 - 1);
+ }
+ begin = sq2 + 1;
+ }
+ }
+ }
+
+#define CONCAT_CONT_VALUE(s) \
+{ \
+ if (cont_value) { \
+ gchar *tmp; \
+ tmp = g_strconcat(cont_value, s, NULL); \
+ g_free(cont_value); \
+ cont_value = tmp; \
+ } else \
+ cont_value = g_strdup(s); \
+}
+
+ if (count >= 0) {
+ if (count > 0 && cont_name) {
+ if (strcmp(cont_name, name) != 0) {
+ g_warning("procmime_parse_mime_parameter(): mismatch parameter name: %s\n", str);
+ g_free(name);
+ g_free(value);
+ g_free(param);
+ break;
+ }
+ } else
+ cont_name = g_strdup(name);
+
+ if (encoded) {
+ dec_value = g_malloc(strlen(begin) + 1);
+ decode_uri(dec_value, begin);
+ CONCAT_CONT_VALUE(dec_value);
+ g_free(dec_value);
+ } else {
+ CONCAT_CONT_VALUE(begin);
+ }
+ }
+
+#undef CONCAT_CONT_VALUE
+
+ if (count == -1 && cont_name && cont_value) {
+ mparam = g_new(MimeParam, 1);
+ mparam->name = cont_name;
+ cont_name = NULL;
+ mparam->value = procmime_convert_value
+ (cont_value, charset);
+ g_free(cont_value);
+ cont_value = NULL;
+ plist = g_slist_prepend(plist, mparam);
}
- if (*value) {
- if (charset && !g_ascii_strcasecmp(attr, "charset"))
- *charset = g_strdup(value);
- else if (name && !g_ascii_strcasecmp(attr, "name"))
- *name = conv_unmime_header(value, NULL);
- else if (boundary &&
- !g_ascii_strcasecmp(attr, "boundary"))
- *boundary = g_strdup(value);
+ if (count == -1) {
+ mparam = g_new(MimeParam, 1);
+ mparam->name = name;
+ if (encoded) {
+ dec_value = g_malloc(strlen(begin) + 1);
+ decode_uri(dec_value, begin);
+ mparam->value = procmime_convert_value
+ (dec_value, charset);
+ g_free(dec_value);
+ } else {
+ if (!ast &&
+ (!g_ascii_strcasecmp(name, "name") ||
+ !g_ascii_strcasecmp(name, "filename")))
+ mparam->value =
+ conv_unmime_header(begin, NULL);
+ else
+ mparam->value = g_strdup(begin);
+ }
+ name = NULL;
+ plist = g_slist_prepend(plist, mparam);
}
- if (!delim) break;
- p = delim + 1;
+ g_free(name);
+ g_free(value);
+ g_free(param);
+
+ prev_count = count;
+ count = -1;
+
+ if (delim)
+ p = delim + 1;
+ else
+ break;
+ }
+
+ if (cont_name && cont_value) {
+ mparam = g_new(MimeParam, 1);
+ mparam->name = cont_name;
+ cont_name = NULL;
+ mparam->value = procmime_convert_value(cont_value, charset);
+ plist = g_slist_prepend(plist, mparam);
}
+
+ g_free(cont_name);
+ g_free(cont_value);
+ g_free(lang);
+ g_free(charset);
+
+ plist = g_slist_reverse(plist);
+ mparams->plist = plist;
+
+ return mparams;
}
-void procmime_scan_content_disposition(MimeInfo *mimeinfo,
- const gchar *content_disposition)
+static void procmime_mime_params_free(MimeParams *mparams)
{
- gchar *delim, *p, *dispos;
- gchar *buf;
+ GSList *cur;
- Xstrdup_a(buf, content_disposition, return);
+ if (!mparams)
+ return;
+
+ g_free(mparams->hvalue);
+ for (cur = mparams->plist; cur != NULL; cur = cur->next) {
+ MimeParam *mparam = (MimeParam *)cur->data;
+ g_free(mparam->name);
+ g_free(mparam->value);
+ g_free(mparam);
+ }
+ g_slist_free(mparams->plist);
+ g_free(mparams);
+}
- if ((delim = strchr(buf, ';'))) *delim = '\0';
- mimeinfo->content_disposition = dispos = g_strdup(g_strstrip(buf));
+void procmime_scan_content_type_str(const gchar *content_type,
+ gchar **mime_type, gchar **charset,
+ gchar **name, gchar **boundary)
+{
+ MimeParams *mparams;
+ GSList *cur;
- if (!delim) return;
- p = delim + 1;
+ mparams = procmime_parse_mime_parameter(content_type);
- for (;;) {
- gchar *eq;
- gchar *attr, *value;
+ if (mime_type)
+ *mime_type = g_strdup(mparams->hvalue);
+
+ for (cur = mparams->plist; cur != NULL; cur = cur->next) {
+ MimeParam *param = (MimeParam *)cur->data;
+ if (charset && !g_ascii_strcasecmp(param->name, "charset")) {
+ *charset = g_strdup(param->value);
+ charset = NULL;
+ } else if (name && !g_ascii_strcasecmp(param->name, "name")) {
+ *name = g_strdup(param->value);
+ name = NULL;
+ } else if (boundary &&
+ !g_ascii_strcasecmp(param->name, "boundary")) {
+ *boundary = g_strdup(param->value);
+ boundary = NULL;
+ }
+ }
- if ((delim = strchr(p, ';'))) *delim = '\0';
+ procmime_mime_params_free(mparams);
+}
- if (!(eq = strchr(p, '='))) break;
+void procmime_scan_content_disposition(MimeInfo *mimeinfo,
+ const gchar *content_disposition)
+{
+ MimeParams *mparams;
+ GSList *cur;
- *eq = '\0';
- attr = p;
- g_strstrip(attr);
- value = eq + 1;
- g_strstrip(value);
+ mparams = procmime_parse_mime_parameter(content_disposition);
- if (*value == '"')
- extract_quote(value, '"');
- else {
- eliminate_parenthesis(value, '(', ')');
- g_strstrip(value);
- }
+ mimeinfo->content_disposition = g_strdup(mparams->hvalue);
- if (*value) {
- if (!g_ascii_strcasecmp(attr, "filename")) {
- g_free(mimeinfo->filename);
- mimeinfo->filename =
- conv_unmime_header(value, NULL);
- break;
- }
+ for (cur = mparams->plist; cur != NULL; cur = cur->next) {
+ MimeParam *param = (MimeParam *)cur->data;
+ if (!g_ascii_strcasecmp(param->name, "filename")) {
+ mimeinfo->filename = g_strdup(param->value);
+ break;
}
-
- if (!delim) break;
- p = delim + 1;
}
+
+ procmime_mime_params_free(mparams);
}
enum