Esempio n. 1
0
static char*
mime_part_get_filename (GMimeObject *mobj, unsigned index,
			gboolean construct_if_needed)
{
	gchar *fname;

	fname = NULL;

	if (GMIME_IS_PART (mobj)) {
		/* the easy case: the part has a filename */
		fname = (gchar*)g_mime_part_get_filename (GMIME_PART(mobj));
		if (fname) /* don't include directory components */
			fname = g_path_get_basename (fname);
	}

	if (!fname && !construct_if_needed)
		return NULL;

	if (GMIME_IS_MESSAGE_PART(mobj)) {
		GMimeMessage *msg;
		const char *subj;
		msg  = g_mime_message_part_get_message
			(GMIME_MESSAGE_PART(mobj));
		subj = g_mime_message_get_subject (msg);
		fname = g_strdup_printf ("%s.eml", subj ? subj : "message");
	}

	if (!fname)
		fname =	g_strdup_printf ("%u.part", index);

	/* remove slashes, spaces, colons... */
	cleanup_filename (fname);
	return fname;
}
Esempio n. 2
0
static void process_message_callback(GMimeObject *part, gpointer user_data)
{
	struct mime_cbinfo *cbinfo = user_data;

	cbinfo->count++;

	/* We strip off the headers before we get here, so should only see GMIME_IS_PART */
	if (GMIME_IS_MESSAGE_PART(part)) {
		ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PART\n");
		return;
	} else if (GMIME_IS_MESSAGE_PARTIAL(part)) {
		ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PARTIAL\n");
		return;
	} else if (GMIME_IS_MULTIPART(part)) {
		GList *l;
		
		ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MULTIPART, trying to process subparts\n");
		l = GMIME_MULTIPART(part)->subparts;
		while (l) {
			process_message_callback(l->data, cbinfo);
			l = l->next;
		}
	} else if (GMIME_IS_PART(part)) {
		const char *filename;

		if (ast_strlen_zero(filename = g_mime_part_get_filename(GMIME_PART(part)))) {
			ast_debug(1, "Skipping part with no filename\n");
			return;
		}

		post_raw(GMIME_PART(part), cbinfo->post_dir, filename);
	} else {
		ast_log(LOG_ERROR, "Encountered unknown MIME part. This should never happen!\n");
	}
}
Esempio n. 3
0
static void
reply_part_content (GMimeObject *part)
{
    GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));
    GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (part);

    if (g_mime_content_type_is_type (content_type, "multipart", "*") ||
	g_mime_content_type_is_type (content_type, "message", "rfc822"))
    {
	/* Output nothing, since multipart subparts will be handled individually. */
    }
    else if (g_mime_content_type_is_type (content_type, "application", "pgp-encrypted") ||
	     g_mime_content_type_is_type (content_type, "application", "pgp-signature"))
    {
	/* Ignore PGP/MIME cruft parts */
    }
    else if (g_mime_content_type_is_type (content_type, "text", "*") &&
	!g_mime_content_type_is_type (content_type, "text", "html"))
    {
	GMimeStream *stream_stdout = NULL, *stream_filter = NULL;
	GMimeDataWrapper *wrapper;
	const char *charset;

	charset = g_mime_object_get_content_type_parameter (part, "charset");
	stream_stdout = g_mime_stream_file_new (stdout);
	if (stream_stdout) {
	    g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
	    stream_filter = g_mime_stream_filter_new(stream_stdout);
	    if (charset) {
		g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
					 g_mime_filter_charset_new(charset, "UTF-8"));
	    }
	}
	g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
				 g_mime_filter_reply_new(TRUE));
	wrapper = g_mime_part_get_content_object (GMIME_PART (part));
	if (wrapper && stream_filter)
	    g_mime_data_wrapper_write_to_stream (wrapper, stream_filter);
	if (stream_filter)
	    g_object_unref(stream_filter);
	if (stream_stdout)
	    g_object_unref(stream_stdout);
    }
    else
    {
	if (disposition &&
	    strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0)
	{
	    const char *filename = g_mime_part_get_filename (GMIME_PART (part));
	    printf ("Attachment: %s (%s)\n", filename,
		    g_mime_content_type_to_string (content_type));
	}
	else
	{
	    printf ("Non-text part: %s\n",
		    g_mime_content_type_to_string (content_type));
	}
    }
}
Esempio n. 4
0
static void
format_part_reply (mime_node_t *node)
{
    int i;

    if (node->envelope_file) {
	printf ("On %s, %s wrote:\n",
		notmuch_message_get_header (node->envelope_file, "date"),
		notmuch_message_get_header (node->envelope_file, "from"));
    } else if (GMIME_IS_MESSAGE (node->part)) {
	GMimeMessage *message = GMIME_MESSAGE (node->part);
	InternetAddressList *recipients;
	const char *recipients_string;

	printf ("> From: %s\n", g_mime_message_get_sender (message));
	recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_TO);
	recipients_string = internet_address_list_to_string (recipients, 0);
	if (recipients_string)
	    printf ("> To: %s\n",
		    recipients_string);
	recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_CC);
	recipients_string = internet_address_list_to_string (recipients, 0);
	if (recipients_string)
	    printf ("> Cc: %s\n",
		    recipients_string);
	printf ("> Subject: %s\n", g_mime_message_get_subject (message));
	printf ("> Date: %s\n", g_mime_message_get_date_as_string (message));
	printf (">\n");
    } else if (GMIME_IS_PART (node->part)) {
	GMimeContentType *content_type = g_mime_object_get_content_type (node->part);
	GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (node->part);

	if (g_mime_content_type_is_type (content_type, "application", "pgp-encrypted") ||
	    g_mime_content_type_is_type (content_type, "application", "pgp-signature")) {
	    /* Ignore PGP/MIME cruft parts */
	} else if (g_mime_content_type_is_type (content_type, "text", "*") &&
		   !g_mime_content_type_is_type (content_type, "text", "html")) {
	    GMimeStream *stream_stdout = g_mime_stream_file_new (stdout);
	    g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
	    show_text_part_content (node->part, stream_stdout, NOTMUCH_SHOW_TEXT_PART_REPLY);
	    g_object_unref(stream_stdout);
	} else if (disposition &&
		   strcasecmp (g_mime_content_disposition_get_disposition (disposition),
			       GMIME_DISPOSITION_ATTACHMENT) == 0) {
	    const char *filename = g_mime_part_get_filename (GMIME_PART (node->part));
	    printf ("Attachment: %s (%s)\n", filename,
		    g_mime_content_type_to_string (content_type));
	} else {
	    printf ("Non-text part: %s\n",
		    g_mime_content_type_to_string (content_type));
	}
    }

    for (i = 0; i < node->nchildren; i++)
	format_part_reply (mime_node_child (node, i));
}
Esempio n. 5
0
static void
reply_part_content (GMimeObject *part)
{
    GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));
    GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (part);

    if (g_mime_content_type_is_type (content_type, "text", "*") &&
	!g_mime_content_type_is_type (content_type, "text", "html"))
    {
	GMimeStream *stream_stdout = NULL, *stream_filter = NULL;
	GMimeDataWrapper *wrapper;
	const char *charset;

	charset = g_mime_object_get_content_type_parameter (part, "charset");
	stream_stdout = g_mime_stream_file_new (stdout);
	if (stream_stdout) {
	    g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
	    stream_filter = g_mime_stream_filter_new(stream_stdout);
	    if (charset) {
		g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
					 g_mime_filter_charset_new(charset, "UTF-8"));
	    }
	}
	g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
				 g_mime_filter_reply_new(TRUE));
	wrapper = g_mime_part_get_content_object (GMIME_PART (part));
	if (wrapper && stream_filter)
	    g_mime_data_wrapper_write_to_stream (wrapper, stream_filter);
	if (stream_filter)
	    g_object_unref(stream_filter);
	if (stream_stdout)
	    g_object_unref(stream_stdout);
    }
    else
    {
	if (disposition &&
	    strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0)
	{
	    const char *filename = g_mime_part_get_filename (GMIME_PART (part));
	    printf ("Attachment: %s (%s)\n", filename,
		    g_mime_content_type_to_string (content_type));
	}
	else
	{
	    printf ("Non-text part: %s\n",
		    g_mime_content_type_to_string (content_type));
	}
    }
}
Esempio n. 6
0
static void
format_part_content_json (GMimeObject *part)
{
    GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));
    GMimeStream *stream_memory = g_mime_stream_mem_new ();
    const char *cid = g_mime_object_get_content_id (part);
    void *ctx = talloc_new (NULL);
    GByteArray *part_content;

    printf (", \"content-type\": %s",
	    json_quote_str (ctx, g_mime_content_type_to_string (content_type)));

    if (cid != NULL)
	    printf(", \"content-id\": %s", json_quote_str (ctx, cid));

    if (GMIME_IS_PART (part))
    {
	const char *filename = g_mime_part_get_filename (GMIME_PART (part));
	if (filename)
	    printf (", \"filename\": %s", json_quote_str (ctx, filename));
    }

    if (g_mime_content_type_is_type (content_type, "text", "*") &&
	!g_mime_content_type_is_type (content_type, "text", "html"))
    {
	show_text_part_content (part, stream_memory);
	part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory));

	printf (", \"content\": %s", json_quote_chararray (ctx, (char *) part_content->data, part_content->len));
    }
    else if (g_mime_content_type_is_type (content_type, "multipart", "*"))
    {
	printf (", \"content\": [");
    }
    else if (g_mime_content_type_is_type (content_type, "message", "rfc822"))
    {
	printf (", \"content\": [{");
    }

    talloc_free (ctx);
    if (stream_memory)
	g_object_unref (stream_memory);
}
Esempio n. 7
0
MuxMessagePart*
mux_message_part_new (const char *path, GMimeObject *mobj)
{
        MuxMessagePart *self;

	g_return_val_if_fail (path, NULL);
	g_return_val_if_fail (GMIME_IS_OBJECT(mobj), NULL);

        self = MUX_MESSAGE_PART(g_object_new(MUX_TYPE_MESSAGE_PART, NULL));

	self->path		  = ext_path (path);
	self->content_type	  = g_mime_object_get_content_type (mobj);
	self->content_id	  = g_mime_object_get_content_id (mobj);
	self->content_disposition = g_mime_object_get_content_disposition (mobj);
	
	if (GMIME_IS_PART (mobj))
		self->file_name = g_mime_part_get_filename ((GMimePart*)mobj);

	self->mime_object = g_object_ref (mobj);

	return self;
}
Esempio n. 8
0
static void
format_part_content_text (GMimeObject *part)
{
    const char *cid = g_mime_object_get_content_id (part);
    GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));

    if (GMIME_IS_PART (part))
    {
	const char *filename = g_mime_part_get_filename (GMIME_PART (part));
	if (filename)
	    printf (", Filename: %s", filename);
    }

    if (cid)
	printf (", Content-id: %s", cid);

    printf (", Content-type: %s\n", g_mime_content_type_to_string (content_type));

    if (g_mime_content_type_is_type (content_type, "text", "*") &&
	!g_mime_content_type_is_type (content_type, "text", "html"))
    {
	GMimeStream *stream_stdout = g_mime_stream_file_new (stdout);
	g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
	show_text_part_content (part, stream_stdout);
	g_object_unref(stream_stdout);
    }
    else if (g_mime_content_type_is_type (content_type, "multipart", "*") ||
	     g_mime_content_type_is_type (content_type, "message", "rfc822"))
    {
	/* Do nothing for multipart since its content will be printed
	 * when recursing. */
    }
    else
    {
	printf ("Non-text part: %s\n",
		g_mime_content_type_to_string (content_type));
    }
}
Esempio n. 9
0
 * Process a MIME part of the mail message
 */
static void process_part(GMimeObject *parent __attribute__((unused)),
			 GMimeObject *part,
			 gpointer user_data __attribute__((unused)))
{
	GMimeStream *stream;
	GMimeDataWrapper *content;
	char file[NAME_MAX + 1];
	int fd;
	static int npart = 0;
	FILE *fp;

	fp = fopen("00INDEX", "a");
	snprintf(file, sizeof(file), "part-%03d.obj", npart++);
	fprintf(fp, "%s\t%s\n", file, (char *)g_mime_part_get_filename(
				(GMimePart *)part));
	fclose(fp);

	fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
	stream = g_mime_stream_fs_new(fd);
	content = g_mime_part_get_content_object((GMimePart *)part);
	g_mime_data_wrapper_write_to_stream(content, stream);
	g_mime_stream_flush(stream);
	close(fd);

	g_object_unref(content);
	g_object_unref(stream);
}

/*
 * Process a mail message, passed on by sendmail
Esempio n. 10
0
void
format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first)
{
    /* Any changes to the JSON format should be reflected in the file
     * devel/schemata. */

    if (node->envelope_file) {
        printf ("{");
        format_message_json (ctx, node->envelope_file);

        printf ("\"headers\": ");
        format_headers_json (ctx, GMIME_MESSAGE (node->part), FALSE);

        printf (", \"body\": [");
        format_part_json (ctx, mime_node_child (node, 0), first);

        printf ("]}");
        return;
    }

    void *local = talloc_new (ctx);
    /* The disposition and content-type metadata are associated with
     * the envelope for message parts */
    GMimeObject *meta = node->envelope_part ?
                        GMIME_OBJECT (node->envelope_part) : node->part;
    GMimeContentType *content_type = g_mime_object_get_content_type (meta);
    const char *cid = g_mime_object_get_content_id (meta);
    const char *filename = GMIME_IS_PART (node->part) ?
                           g_mime_part_get_filename (GMIME_PART (node->part)) : NULL;
    const char *terminator = "";
    int i;

    if (!first)
        printf (", ");

    printf ("{\"id\": %d", node->part_num);

    if (node->decrypt_attempted)
        printf (", \"encstatus\": [{\"status\": \"%s\"}]",
                node->decrypt_success ? "good" : "bad");

    if (node->verify_attempted) {
        printf (", \"sigstatus\": ");
        format_part_sigstatus_json (node);
    }

    printf (", \"content-type\": %s",
            json_quote_str (local, g_mime_content_type_to_string (content_type)));

    if (cid)
        printf (", \"content-id\": %s", json_quote_str (local, cid));

    if (filename)
        printf (", \"filename\": %s", json_quote_str (local, filename));

    if (GMIME_IS_PART (node->part)) {
        /* For non-HTML text parts, we include the content in the
         * JSON. Since JSON must be Unicode, we handle charset
         * decoding here and do not report a charset to the caller.
         * For text/html parts, we do not include the content. If a
         * caller is interested in text/html parts, it should retrieve
         * them separately and they will not be decoded. Since this
         * makes charset decoding the responsibility on the caller, we
         * report the charset for text/html parts.
         */
        if (g_mime_content_type_is_type (content_type, "text", "html")) {
            const char *content_charset = g_mime_object_get_content_type_parameter (meta, "charset");

            if (content_charset != NULL)
                printf (", \"content-charset\": %s", json_quote_str (local, content_charset));
        } else if (g_mime_content_type_is_type (content_type, "text", "*")) {
            GMimeStream *stream_memory = g_mime_stream_mem_new ();
            GByteArray *part_content;
            show_text_part_content (node->part, stream_memory, 0);
            part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory));

            printf (", \"content\": %s", json_quote_chararray (local, (char *) part_content->data, part_content->len));
            g_object_unref (stream_memory);
        }
    } else if (GMIME_IS_MULTIPART (node->part)) {
        printf (", \"content\": [");
        terminator = "]";
    } else if (GMIME_IS_MESSAGE (node->part)) {
        printf (", \"content\": [{");
        printf ("\"headers\": ");
        format_headers_json (local, GMIME_MESSAGE (node->part), FALSE);

        printf (", \"body\": [");
        terminator = "]}]";
    }

    talloc_free (local);

    for (i = 0; i < node->nchildren; i++)
        format_part_json (ctx, mime_node_child (node, i), i == 0);

    printf ("%s}", terminator);
}
Esempio n. 11
0
static notmuch_status_t
format_part_text (const void *ctx, mime_node_t *node,
                  int indent, const notmuch_show_params_t *params)
{
    /* The disposition and content-type metadata are associated with
     * the envelope for message parts */
    GMimeObject *meta = node->envelope_part ?
                        GMIME_OBJECT (node->envelope_part) : node->part;
    GMimeContentType *content_type = g_mime_object_get_content_type (meta);
    const notmuch_bool_t leaf = GMIME_IS_PART (node->part);
    const char *part_type;
    int i;

    if (node->envelope_file) {
        notmuch_message_t *message = node->envelope_file;

        part_type = "message";
        printf ("\f%s{ id:%s depth:%d match:%d excluded:%d filename:%s\n",
                part_type,
                notmuch_message_get_message_id (message),
                indent,
                notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? 1 : 0,
                notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 1 : 0,
                notmuch_message_get_filename (message));
    } else {
        GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (meta);
        const char *cid = g_mime_object_get_content_id (meta);
        const char *filename = leaf ?
                               g_mime_part_get_filename (GMIME_PART (node->part)) : NULL;

        if (disposition &&
                strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0)
            part_type = "attachment";
        else
            part_type = "part";

        printf ("\f%s{ ID: %d", part_type, node->part_num);
        if (filename)
            printf (", Filename: %s", filename);
        if (cid)
            printf (", Content-id: %s", cid);
        printf (", Content-type: %s\n", g_mime_content_type_to_string (content_type));
    }

    if (GMIME_IS_MESSAGE (node->part)) {
        GMimeMessage *message = GMIME_MESSAGE (node->part);
        InternetAddressList *recipients;
        const char *recipients_string;

        printf ("\fheader{\n");
        if (node->envelope_file)
            printf ("%s\n", _get_one_line_summary (ctx, node->envelope_file));
        printf ("Subject: %s\n", g_mime_message_get_subject (message));
        printf ("From: %s\n", g_mime_message_get_sender (message));
        recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_TO);
        recipients_string = internet_address_list_to_string (recipients, 0);
        if (recipients_string)
            printf ("To: %s\n", recipients_string);
        recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_CC);
        recipients_string = internet_address_list_to_string (recipients, 0);
        if (recipients_string)
            printf ("Cc: %s\n", recipients_string);
        printf ("Date: %s\n", g_mime_message_get_date_as_string (message));
        printf ("\fheader}\n");

        printf ("\fbody{\n");
    }

    if (leaf) {
        if (g_mime_content_type_is_type (content_type, "text", "*") &&
                !g_mime_content_type_is_type (content_type, "text", "html"))
        {
            GMimeStream *stream_stdout = g_mime_stream_file_new (stdout);
            g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
            show_text_part_content (node->part, stream_stdout, 0);
            g_object_unref(stream_stdout);
        } else {
            printf ("Non-text part: %s\n",
                    g_mime_content_type_to_string (content_type));
        }
    }

    for (i = 0; i < node->nchildren; i++)
        format_part_text (ctx, mime_node_child (node, i), indent, params);

    if (GMIME_IS_MESSAGE (node->part))
        printf ("\fbody}\n");

    printf ("\f%s}\n", part_type);

    return NOTMUCH_STATUS_SUCCESS;
}
Esempio n. 12
0
static ssize_t
write_content (GMimePart *part, GMimeStream *stream)
{
	ssize_t nwritten, total = 0;
	
	if (!part->content)
		return 0;
	
	/* Evil Genius's "slight" optimization: Since GMimeDataWrapper::write_to_stream()
	 * decodes its content stream to the raw format, we can cheat by requesting its
	 * content stream and not doing any encoding on the data if the source and
	 * destination encodings are identical.
	 */
	
	if (part->encoding != g_mime_data_wrapper_get_encoding (part->content)) {
		GMimeStream *filtered_stream;
		const char *filename;
		GMimeFilter *filter;
		
		switch (part->encoding) {
		case GMIME_CONTENT_ENCODING_UUENCODE:
			filename = g_mime_part_get_filename (part);
			nwritten = g_mime_stream_printf (stream, "begin 0644 %s\n",
							 filename ? filename : "unknown");
			if (nwritten == -1)
				return -1;
			
			total += nwritten;
			
			/* fall thru... */
		case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
		case GMIME_CONTENT_ENCODING_BASE64:
			filtered_stream = g_mime_stream_filter_new (stream);
			filter = g_mime_filter_basic_new (part->encoding, TRUE);
			g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter);
			g_object_unref (filter);
			break;
		default:
			filtered_stream = stream;
			g_object_ref (stream);
			break;
		}
		
		nwritten = g_mime_data_wrapper_write_to_stream (part->content, filtered_stream);
		g_mime_stream_flush (filtered_stream);
		g_object_unref (filtered_stream);
		
		if (nwritten == -1)
			return -1;
		
		total += nwritten;
		
		if (part->encoding == GMIME_CONTENT_ENCODING_UUENCODE) {
			/* FIXME: get rid of this special-case x-uuencode crap */
			nwritten = g_mime_stream_write (stream, "end\n", 4);
			if (nwritten == -1)
				return -1;
			
			total += nwritten;
		}
	} else {
		GMimeStream *content_stream;
		
		content_stream = g_mime_data_wrapper_get_stream (part->content);
		g_mime_stream_reset (content_stream);
		nwritten = g_mime_stream_write_to_stream (content_stream, stream);
		g_mime_stream_reset (content_stream);
		
		if (nwritten == -1)
			return -1;
		
		total += nwritten;
	}
	
	return total;
}
Esempio n. 13
0
void
format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node,
		      notmuch_bool_t first, notmuch_bool_t output_body,
		      notmuch_bool_t include_html)
{
    /* Any changes to the JSON or S-Expression format should be
     * reflected in the file devel/schemata. */

    if (node->envelope_file) {
	sp->begin_map (sp);
	format_message_sprinter (sp, node->envelope_file);

	sp->map_key (sp, "headers");
	format_headers_sprinter (sp, GMIME_MESSAGE (node->part), FALSE);

	if (output_body) {
	    sp->map_key (sp, "body");
	    sp->begin_list (sp);
	    format_part_sprinter (ctx, sp, mime_node_child (node, 0), first, TRUE, include_html);
	    sp->end (sp);
	}
	sp->end (sp);
	return;
    }

    /* The disposition and content-type metadata are associated with
     * the envelope for message parts */
    GMimeObject *meta = node->envelope_part ?
	GMIME_OBJECT (node->envelope_part) : node->part;
    GMimeContentType *content_type = g_mime_object_get_content_type (meta);
    const char *cid = g_mime_object_get_content_id (meta);
    const char *filename = GMIME_IS_PART (node->part) ?
	g_mime_part_get_filename (GMIME_PART (node->part)) : NULL;
    int nclose = 0;
    int i;

    sp->begin_map (sp);

    sp->map_key (sp, "id");
    sp->integer (sp, node->part_num);

    if (node->decrypt_attempted) {
	sp->map_key (sp, "encstatus");
	sp->begin_list (sp);
	sp->begin_map (sp);
	sp->map_key (sp, "status");
	sp->string (sp, node->decrypt_success ? "good" : "bad");
	sp->end (sp);
	sp->end (sp);
    }

    if (node->verify_attempted) {
	sp->map_key (sp, "sigstatus");
	format_part_sigstatus_sprinter (sp, node);
    }

    sp->map_key (sp, "content-type");
    sp->string (sp, g_mime_content_type_to_string (content_type));

    if (cid) {
	sp->map_key (sp, "content-id");
	sp->string (sp, cid);
    }

    if (filename) {
	sp->map_key (sp, "filename");
	sp->string (sp, filename);
    }

    if (GMIME_IS_PART (node->part)) {
	/* For non-HTML text parts, we include the content in the
	 * JSON. Since JSON must be Unicode, we handle charset
	 * decoding here and do not report a charset to the caller.
	 * For text/html parts, we do not include the content unless
	 * the --include-html option has been passed. If a html part
	 * is not included, it can be requested directly. This makes
	 * charset decoding the responsibility on the caller so we
	 * report the charset for text/html parts.
	 */
	if (g_mime_content_type_is_type (content_type, "text", "*") &&
	    (include_html ||
	     ! g_mime_content_type_is_type (content_type, "text", "html")))
	{
	    GMimeStream *stream_memory = g_mime_stream_mem_new ();
	    GByteArray *part_content;
	    show_text_part_content (node->part, stream_memory, 0);
	    part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory));
	    sp->map_key (sp, "content");
	    sp->string_len (sp, (char *) part_content->data, part_content->len);
	    g_object_unref (stream_memory);
	} else {
	    format_omitted_part_meta_sprinter (sp, meta, GMIME_PART (node->part));
	}
    } else if (GMIME_IS_MULTIPART (node->part)) {
	sp->map_key (sp, "content");
	sp->begin_list (sp);
	nclose = 1;
    } else if (GMIME_IS_MESSAGE (node->part)) {
	sp->map_key (sp, "content");
	sp->begin_list (sp);
	sp->begin_map (sp);

	sp->map_key (sp, "headers");
	format_headers_sprinter (sp, GMIME_MESSAGE (node->part), FALSE);

	sp->map_key (sp, "body");
	sp->begin_list (sp);
	nclose = 3;
    }

    for (i = 0; i < node->nchildren; i++)
	format_part_sprinter (ctx, sp, mime_node_child (node, i), i == 0, TRUE, include_html);

    /* Close content structures */
    for (i = 0; i < nclose; i++)
	sp->end (sp);
    /* Close part map */
    sp->end (sp);
}
Esempio n. 14
0
static void collect_part(GMimeObject *part, PartCollectorData *fdata, gboolean multipart_parent) {
  GMimeContentType        *content_type = g_mime_object_get_content_type(part);
  GMimeContentDisposition *disposition  = g_mime_object_get_content_disposition(part);

  if (!content_type)
    return;

  GMimeDataWrapper *wrapper = g_mime_part_get_content_object(GMIME_PART(part));
  if (!wrapper)
    return;

  // All the information will be collected in the CollectedPart
  CollectedPart *c_part = new_collected_part(fdata->part_id);

  gboolean is_attachment = FALSE;
  if (disposition) {
    c_part->disposition = g_ascii_strdown(disposition->disposition, -1);
    is_attachment = !g_ascii_strcasecmp(disposition->disposition, GMIME_DISPOSITION_ATTACHMENT);
  }

  // If a filename is given, collect it always
  const gchar *filename = g_mime_part_get_filename(GMIME_PART(part));
  if (filename)
    c_part->filename = g_strdup(filename);

  // If a contentID is given, collect it always
  const char* content_id = g_mime_part_get_content_id (GMIME_PART(part));
  if (content_id)
    c_part->content_id = g_strdup(content_id);

  // Get the contentType in lowercase
  gchar *content_type_str = g_mime_content_type_to_string(content_type);
  c_part->content_type = g_ascii_strdown(content_type_str, -1);
  g_free(content_type_str);

  // To qualify as a message body, a MIME entity MUST NOT have a Content-Disposition header with the value "attachment".
  if (!is_attachment && g_mime_content_type_is_type(content_type, "text", "*")) {
    gboolean is_text_plain    = g_mime_content_type_is_type(content_type, "text", "plain");
    gboolean is_text_html     = g_mime_content_type_is_type(content_type, "text", "html");
    gboolean is_text_rtf      = g_mime_content_type_is_type(content_type, "text", "rtf");
    gboolean is_text_enriched = g_mime_content_type_is_type(content_type, "text", "enriched");

    gboolean is_new_text = !fdata->text_part && is_text_plain;
    gboolean is_new_html = !fdata->html_part && (is_text_html || is_text_enriched || is_text_rtf);

    GMimeStream *mem_stream = g_mime_stream_mem_new();
    g_mime_stream_mem_set_owner(GMIME_STREAM_MEM(mem_stream), FALSE);
    GMimeStream *filtered_mem_stream = g_mime_stream_filter_new(mem_stream);

    const gchar *charset = g_mime_object_get_content_type_parameter(part, "charset");
    if (charset && g_ascii_strcasecmp(charset, UTF8_CHARSET)) {
      GMimeFilter *utf8_charset_filter = g_mime_filter_charset_new(charset, UTF8_CHARSET);
      g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), utf8_charset_filter);
      g_object_unref(utf8_charset_filter);
    }

    if (!fdata->raw && is_new_text) {
      GMimeFilter *strip_filter = g_mime_filter_strip_new();
      g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), strip_filter);
      g_object_unref(strip_filter);

      GMimeFilter *crlf_filter = g_mime_filter_crlf_new(FALSE, FALSE);
      g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), crlf_filter);
      g_object_unref(crlf_filter);

      GMimeFilter *html_filter = g_mime_filter_html_new(
         GMIME_FILTER_HTML_CONVERT_NL        |
         GMIME_FILTER_HTML_CONVERT_SPACES    |
         GMIME_FILTER_HTML_CONVERT_URLS      |
         GMIME_FILTER_HTML_MARK_CITATION     |
         GMIME_FILTER_HTML_CONVERT_ADDRESSES |
         GMIME_FILTER_HTML_CITE, CITATION_COLOUR);
      g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), html_filter);
      g_object_unref(html_filter);
    }

    if (!fdata->raw && (is_new_text || is_new_html)) {
      GMimeFilter *from_filter = g_mime_filter_from_new(GMIME_FILTER_FROM_MODE_ESCAPE);
      g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), from_filter);
      g_object_unref(from_filter);
    }

    // Add Enriched/RTF filter for this content
    if (!fdata->raw && (is_new_html && (is_text_enriched || is_text_rtf))) {
      guint flags = 0;
      if (is_text_rtf)
        flags = GMIME_FILTER_ENRICHED_IS_RICHTEXT;

      GMimeFilter *enriched_filter = g_mime_filter_enriched_new(flags);
      g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), enriched_filter);
      g_object_unref(enriched_filter);
    }
    g_mime_data_wrapper_write_to_stream(wrapper, filtered_mem_stream);

    // Very important! Flush the the stream and get all content through.
    g_mime_stream_flush(filtered_mem_stream);

    // Freed by the mem_stream on its own (owner) [transfer none]
    c_part->content = g_mime_stream_mem_get_byte_array(GMIME_STREAM_MEM(mem_stream));

    // After we unref the mem_stream, part_content is NOT available anymore
    g_object_unref(filtered_mem_stream);
    g_object_unref(mem_stream);

    // Without content, the collected body part is of no use, so we ignore it.
    if (c_part->content->len == 0) {
      free_collected_part(c_part);
      return;
    }

    // We accept only the first text and first html content, everything
    // else is considered an alternative body
    if (is_new_text) {
      fdata->text_part = c_part;
    } else if (is_new_html) {
      fdata->html_part = c_part;
    } else {
      g_ptr_array_add(fdata->alternative_bodies, c_part);
    }

  } else {
    GMimeStream *attachment_mem_stream = g_mime_stream_mem_new();
    g_mime_stream_mem_set_owner (GMIME_STREAM_MEM(attachment_mem_stream), FALSE);
    g_mime_data_wrapper_write_to_stream(wrapper, attachment_mem_stream);
    g_mime_stream_flush(attachment_mem_stream);

    c_part->content = g_mime_stream_mem_get_byte_array(GMIME_STREAM_MEM(attachment_mem_stream));
    g_object_unref(attachment_mem_stream);

    // Some content may not have disposition defined so we need to determine better what it is
    if ((disposition && !g_ascii_strcasecmp(disposition->disposition, GMIME_DISPOSITION_INLINE)) ||
        g_mime_part_get_content_id(GMIME_PART(part))) {
      g_ptr_array_add(fdata->inlines, c_part);
    } else {
      // All other disposition should be kept within attachments
      g_ptr_array_add(fdata->attachments, c_part);
    }

  }
}