static gboolean empe_mp_alternative_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelMultipart *mp; gint i, nparts, bestid = 0; CamelMimePart *best = NULL; EMailExtensionRegistry *reg; reg = e_mail_parser_get_extension_registry (parser); mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); if (!CAMEL_IS_MULTIPART (mp)) return e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); /* as per rfc, find the last part we know how to display */ nparts = camel_multipart_get_number (mp); for (i = 0; i < nparts; i++) { CamelMimePart *mpart; CamelDataWrapper *data_wrapper; CamelContentType *type; gchar *mime_type; gsize content_size; if (g_cancellable_is_cancelled (cancellable)) return TRUE; /* is it correct to use the passed in *part here? */ mpart = camel_multipart_get_part (mp, i); if (mpart == NULL) continue; /* This may block even though the stream does not. * XXX Pretty inefficient way to test if the MIME part * is empty. Surely there's a quicker way? */ data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (mpart)); content_size = camel_data_wrapper_calculate_decoded_size_sync (data_wrapper, cancellable, NULL); if (content_size == 0) continue; type = camel_mime_part_get_content_type (mpart); mime_type = camel_content_type_simple (type); camel_strdown (mime_type); if (!e_mail_part_is_attachment (mpart) && ((camel_content_type_is (type, "multipart", "related") == 0) || !related_display_part_is_attachment (mpart)) && (e_mail_extension_registry_get_for_mime_type (reg, mime_type) || ((best == NULL) && (e_mail_extension_registry_get_fallback (reg, mime_type))))) { best = mpart; bestid = i; } g_free (mime_type); } if (best) { gint len = part_id->len; g_string_append_printf (part_id, ".alternative.%d", bestid); e_mail_parser_parse_part ( parser, best, part_id, cancellable, out_mail_parts); g_string_truncate (part_id, len); } else { e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); } return TRUE; }
/** * camel_url_new_with_base: * @base: a base URL * @url_string: the URL * * Parses @url_string relative to @base. * * Returns: a parsed #CamelURL **/ CamelURL * camel_url_new_with_base (CamelURL *base, const gchar *url_string) { CamelURL *url; const gchar *end, *hash, *colon, *semi, *at, *slash, *question; const gchar *p; #ifdef G_OS_WIN32 const gchar *start = url_string; #endif g_return_val_if_fail (url_string != NULL, NULL); url = g_new0 (CamelURL, 1); /* See RFC1808 for details. IF YOU CHANGE ANYTHING IN THIS * FUNCTION, RUN tests/misc/url AFTERWARDS. */ /* Find fragment. RFC 1808 2.4.1 */ end = hash = strchr (url_string, '#'); if (hash) { if (hash[1]) { url->fragment = g_strdup (hash + 1); camel_url_decode (url->fragment); } } else end = url_string + strlen (url_string); /* Find protocol: initial [a-z+.-]* substring until ":" */ p = url_string; while (p < end && (isalnum ((guchar) * p) || *p == '.' || *p == '+' || *p == '-')) p++; if (p > url_string && *p == ':') { url->protocol = g_strndup (url_string, p - url_string); camel_strdown (url->protocol); url_string = p + 1; } if (!*url_string && !base) return url; #ifdef G_OS_WIN32 if (url->protocol && !strcmp (url->protocol, "file")) { url->path = g_filename_from_uri (start, &url->host, NULL); return url; } #endif /* Check for authority */ if (strncmp (url_string, "//", 2) == 0) { url_string += 2; slash = url_string + strcspn (url_string, "/#"); at = strchr (url_string, '@'); if (at && at < slash) { colon = strchr (url_string, ':'); if (colon && colon < at) { /* XXX We used to extract and store the * password here, now we just eat it. */ } else { colon = at; } semi = strchr (url_string, ';'); if (semi && semi < colon && !g_ascii_strncasecmp (semi, ";auth=", 6)) { url->authmech = g_strndup ( semi + 6, colon - semi - 6); camel_url_decode (url->authmech); } else { url->authmech = NULL; semi = colon; } url->user = g_strndup (url_string, semi - url_string); camel_url_decode (url->user); url_string = at + 1; } else url->user = url->authmech = NULL; /* Find host and port. */ colon = strchr (url_string, ':'); if (colon && colon < slash) { url->host = g_strndup (url_string, colon - url_string); url->port = strtoul (colon + 1, NULL, 10); } else { url->host = g_strndup (url_string, slash - url_string); camel_url_decode (url->host); url->port = 0; } url_string = slash; } /* Find query */ question = memchr (url_string, '?', end - url_string); if (question) { if (question[1]) { url->query = g_strndup ( question + 1, end - (question + 1)); camel_url_decode (url->query); } end = question; } /* Find parameters */ semi = memchr (url_string, ';', end - url_string); if (semi) { if (semi[1]) { const gchar *cur, *p, *eq; gchar *name, *value; for (cur = semi + 1; cur < end; cur = p + 1) { p = memchr (cur, ';', end - cur); if (!p) p = end; eq = memchr (cur, '=', p - cur); if (eq) { name = g_strndup (cur, eq - cur); value = g_strndup (eq + 1, p - (eq + 1)); camel_url_decode (value); } else { name = g_strndup (cur, p - cur); value = g_strdup (""); } camel_url_decode (name); g_datalist_set_data_full ( &url->params, name, value, g_free); g_free (name); } } end = semi; } if (end != url_string) { url->path = g_strndup (url_string, end - url_string); camel_url_decode (url->path); } /* Apply base URL. Again, this is spelled out in RFC 1808. */ if (base && !url->protocol && url->host) url->protocol = g_strdup (base->protocol); else if (base && !url->protocol) { if (!url->user && !url->authmech && !url->host && !url->port && !url->path && !url->params && !url->query && !url->fragment) url->fragment = g_strdup (base->fragment); url->protocol = g_strdup (base->protocol); url->user = g_strdup (base->user); url->authmech = g_strdup (base->authmech); url->host = g_strdup (base->host); url->port = base->port; if (!url->path) { url->path = g_strdup (base->path); if (!url->params) { g_datalist_foreach (&base->params, copy_param, &url->params); if (!url->query) url->query = g_strdup (base->query); } } else if (*url->path != '/') { gchar *newpath, *last, *p, *q; /* the base->path is NULL if given Content-Base url was without last slash, * i.e. like "http://example.com" (this expected only "http://example.com/") */ last = base->path ? strrchr (base->path, '/') : NULL; if (last) { newpath = g_strdup_printf ( "%.*s/%s", (gint)(last - base->path), base->path, url->path); } else newpath = g_strdup_printf ("/%s", url->path); /* Remove "./" where "." is a complete segment. */ for (p = newpath + 1; *p; ) { if (*(p - 1) == '/' && *p == '.' && *(p + 1) == '/') memmove (p, p + 2, strlen (p + 2) + 1); else p++; } /* Remove "." at end. */ if (p > newpath + 2 && *(p - 1) == '.' && *(p - 2) == '/') *(p - 1) = '\0'; /* Remove "<segment>/../" where <segment> != ".." */ for (p = newpath + 1; *p; ) { if (!strncmp (p, "../", 3)) { p += 3; continue; } q = strchr (p + 1, '/'); if (!q) break; if (strncmp (q, "/../", 4) != 0) { p = q + 1; continue; } memmove (p, q + 4, strlen (q + 4) + 1); p = newpath + 1; } /* Remove "<segment>/.." at end */ q = strrchr (newpath, '/'); if (q && !strcmp (q, "/..")) { p = q - 1; while (p > newpath && *p != '/') p--; if (strncmp (p, "/../", 4) != 0) *(p + 1) = 0; } g_free (url->path); url->path = newpath; } } return url; }