Esempio n. 1
0
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;
}