static MessageData *convert_message(GMimeMessage *message, guint content_option) { if (!message) return NULL; MessageData *md = new_message_data(); const gchar *message_id = g_mime_message_get_message_id(message); if (message_id) md->message_id = g_strdup(message_id); md->from = get_from_addresses(message); md->reply_to = get_reply_to_addresses(message); md->to = get_to_addresses(message); md->cc = get_cc_addresses(message); md->bcc = get_bcc_addresses(message); const gchar *subject = g_mime_message_get_subject(message); if (subject) md->subject = g_strdup(subject); md->date = g_mime_message_get_date_as_string(message); const gchar *in_reply_to = g_mime_object_get_header(GMIME_OBJECT (message), "In-Reply-To"); if (in_reply_to) { gchar *in_reply_to_str = g_mime_utils_header_decode_text(in_reply_to); md->in_reply_to = g_mime_references_decode(in_reply_to_str); g_free(in_reply_to_str); } const gchar *references = g_mime_object_get_header(GMIME_OBJECT (message), "References"); if (references) { gchar *references_str = g_mime_utils_header_decode_text(references); md->references = g_mime_references_decode(references_str); g_free(references_str); } if (content_option) { PartCollectorData *pc = collect_parts(message, content_option); if (pc->text_part) md->text = get_body(pc->text_part, (content_option != COLLECT_RAW_CONTENT), NULL); if (pc->html_part) md->html = get_body(pc->html_part, (content_option != COLLECT_RAW_CONTENT), pc->inlines); md->attachments = get_attachments(pc); free_part_collector_data(pc); } return md; }
static int envelope_decode_nstring (SpruceIMAPEngine *engine, char **nstring, gboolean rfc2047, GError **err) { spruce_imap_token_t token; unsigned char *literal; size_t n; if (spruce_imap_engine_next_token (engine, &token, err) == -1) return -1; switch (token.token) { case SPRUCE_IMAP_TOKEN_NIL: *nstring = NULL; break; case SPRUCE_IMAP_TOKEN_ATOM: if (rfc2047) *nstring = g_mime_utils_header_decode_text (token.v.atom); else *nstring = g_strdup (token.v.atom); break; case SPRUCE_IMAP_TOKEN_QSTRING: if (rfc2047) *nstring = g_mime_utils_header_decode_text (token.v.qstring); else *nstring = g_strdup (token.v.qstring); break; case SPRUCE_IMAP_TOKEN_LITERAL: if (spruce_imap_engine_literal (engine, &literal, &n, err) == -1) return -1; if (rfc2047) { *nstring = g_mime_utils_header_decode_text ((char *) literal); g_free (literal); } else *nstring = (char *) literal; break; default: spruce_imap_utils_set_unexpected_token_error (err, engine, &token); return -1; } return 0; }
/* As a special-case, a value of NULL for header_desired will force * the entire header to be parsed if it is not parsed already. This is * used by the _notmuch_message_file_get_headers_end function. */ const char * notmuch_message_file_get_header (notmuch_message_file_t *message, const char *header_desired) { int contains; char *header, *decoded_value; const char *s, *colon; int match; static int initialized = 0; if (! initialized) { g_mime_init (0); initialized = 1; } message->parsing_started = 1; if (header_desired == NULL) contains = 0; else contains = g_hash_table_lookup_extended (message->headers, header_desired, NULL, (gpointer *) &decoded_value); if (contains && decoded_value) return decoded_value; if (message->parsing_finished) return ""; #define NEXT_HEADER_LINE(closure) \ while (1) { \ ssize_t bytes_read = getline (&message->line, \ &message->line_size, \ message->file); \ if (bytes_read == -1) { \ message->parsing_finished = 1; \ break; \ } \ if (*message->line == '\n') { \ message->parsing_finished = 1; \ break; \ } \ if (closure && \ (*message->line == ' ' || *message->line == '\t')) \ { \ copy_header_unfolding ((closure), message->line); \ } \ if (*message->line == ' ' || *message->line == '\t') \ message->header_size += strlen (message->line); \ else \ break; \ } if (message->line == NULL) NEXT_HEADER_LINE (NULL); while (1) { if (message->parsing_finished) break; colon = strchr (message->line, ':'); if (colon == NULL) { message->broken_headers++; /* A simple heuristic for giving up on things that just * don't look like mail messages. */ if (message->broken_headers >= 10 && message->good_headers < 5) { message->parsing_finished = 1; break; } NEXT_HEADER_LINE (NULL); continue; } message->header_size += strlen (message->line); message->good_headers++; header = xstrndup (message->line, colon - message->line); if (message->restrict_headers && ! g_hash_table_lookup_extended (message->headers, header, NULL, NULL)) { free (header); NEXT_HEADER_LINE (NULL); continue; } s = colon + 1; while (*s == ' ' || *s == '\t') s++; message->value.len = 0; copy_header_unfolding (&message->value, s); NEXT_HEADER_LINE (&message->value); if (header_desired == 0) match = 0; else match = (strcasecmp (header, header_desired) == 0); decoded_value = g_mime_utils_header_decode_text (message->value.str); g_hash_table_insert (message->headers, header, decoded_value); if (match) return decoded_value; } if (message->parsing_finished) { fclose (message->file); message->file = NULL; } if (message->line) free (message->line); message->line = NULL; if (message->value.size) { free (message->value.str); message->value.str = NULL; message->value.size = 0; message->value.len = 0; } /* We've parsed all headers and never found the one we're looking * for. It's probably just not there, but let's check that we * didn't make a mistake preventing us from seeing it. */ if (message->restrict_headers && header_desired && ! g_hash_table_lookup_extended (message->headers, header_desired, NULL, NULL)) { INTERNAL_ERROR ("Attempt to get header \"%s\" which was not\n" "included in call to notmuch_message_file_restrict_headers\n", header_desired); } return ""; }
/* As a special-case, a value of NULL for header_desired will force * the entire header to be parsed if it is not parsed already. This is * used by the _notmuch_message_file_get_headers_end function. * Another special case is the Received: header. For this header we * want to concatenate all instances of the header instead of just * hashing the first instance as we use this when analyzing the path * the mail has taken from sender to recipient. */ const char * notmuch_message_file_get_header (notmuch_message_file_t *message, const char *header_desired) { int contains; char *header, *decoded_value, *header_sofar, *combined_header; const char *s, *colon; int match, newhdr, hdrsofar, is_received; static int initialized = 0; is_received = (strcmp(header_desired,"received") == 0); if (! initialized) { g_mime_init (0); initialized = 1; } message->parsing_started = 1; if (header_desired == NULL) contains = 0; else contains = g_hash_table_lookup_extended (message->headers, header_desired, NULL, (gpointer *) &decoded_value); if (contains && decoded_value) return decoded_value; if (message->parsing_finished) return ""; #define NEXT_HEADER_LINE(closure) \ while (1) { \ ssize_t bytes_read = getline (&message->line, \ &message->line_size, \ message->file); \ if (bytes_read == -1) { \ message->parsing_finished = 1; \ break; \ } \ if (*message->line == '\n') { \ message->parsing_finished = 1; \ break; \ } \ if (closure && \ (*message->line == ' ' || *message->line == '\t')) \ { \ copy_header_unfolding ((closure), message->line); \ } \ if (*message->line == ' ' || *message->line == '\t') \ message->header_size += strlen (message->line); \ else \ break; \ } if (message->line == NULL) NEXT_HEADER_LINE (NULL); while (1) { if (message->parsing_finished) break; colon = strchr (message->line, ':'); if (colon == NULL) { message->broken_headers++; /* A simple heuristic for giving up on things that just * don't look like mail messages. */ if (message->broken_headers >= 10 && message->good_headers < 5) { message->parsing_finished = 1; break; } NEXT_HEADER_LINE (NULL); continue; } message->header_size += strlen (message->line); message->good_headers++; header = xstrndup (message->line, colon - message->line); if (message->restrict_headers && ! g_hash_table_lookup_extended (message->headers, header, NULL, NULL)) { free (header); NEXT_HEADER_LINE (NULL); continue; } s = colon + 1; while (*s == ' ' || *s == '\t') s++; message->value.len = 0; copy_header_unfolding (&message->value, s); NEXT_HEADER_LINE (&message->value); if (header_desired == NULL) match = 0; else match = (strcasecmp (header, header_desired) == 0); decoded_value = g_mime_utils_header_decode_text (message->value.str); header_sofar = (char *)g_hash_table_lookup (message->headers, header); /* we treat the Received: header special - we want to concat ALL of * the Received: headers we encounter. * for everything else we return the first instance of a header */ if (strcasecmp(header, "received") == 0) { if (header_sofar == NULL) { /* first Received: header we encountered; just add it */ g_hash_table_insert (message->headers, header, decoded_value); } else { /* we need to add the header to those we already collected */ newhdr = strlen(decoded_value); hdrsofar = strlen(header_sofar); combined_header = g_malloc(hdrsofar + newhdr + 2); strncpy(combined_header,header_sofar,hdrsofar); *(combined_header+hdrsofar) = ' '; strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1); g_free (decoded_value); g_hash_table_insert (message->headers, header, combined_header); } } else { if (header_sofar == NULL) { /* Only insert if we don't have a value for this header, yet. */ g_hash_table_insert (message->headers, header, decoded_value); } else { free (header); g_free (decoded_value); decoded_value = header_sofar; } } /* if we found a match we can bail - unless of course we are * collecting all the Received: headers */ if (match && !is_received) return decoded_value; } if (message->parsing_finished) { fclose (message->file); message->file = NULL; } if (message->line) free (message->line); message->line = NULL; if (message->value.size) { free (message->value.str); message->value.str = NULL; message->value.size = 0; message->value.len = 0; } /* For the Received: header we actually might end up here even * though we found the header (as we force continued parsing * in that case). So let's check if that's the header we were * looking for and return the value that we found (if any) */ if (is_received) return (char *)g_hash_table_lookup (message->headers, "received"); /* We've parsed all headers and never found the one we're looking * for. It's probably just not there, but let's check that we * didn't make a mistake preventing us from seeing it. */ if (message->restrict_headers && header_desired && ! g_hash_table_lookup_extended (message->headers, header_desired, NULL, NULL)) { INTERNAL_ERROR ("Attempt to get header \"%s\" which was not\n" "included in call to notmuch_message_file_restrict_headers\n", header_desired); } return ""; }
MNMessage * mn_message_new_from_mime_message_full (GType type, MNMailbox *mailbox, GMimeMessage *mime_message, const char *mid, const char *uri, MNMessageFlags flags, gboolean handle_status) { MNMessage *message; const char *id; time_t sent_time; const char *from; const char *subject; char *decoded_from; char *decoded_subject; g_return_val_if_fail(type != 0, NULL); g_return_val_if_fail(MN_IS_MAILBOX(mailbox), NULL); g_return_val_if_fail(GMIME_IS_MESSAGE(mime_message), NULL); if (is_spam(mime_message)) return NULL; if (handle_status) { const char *status; status = g_mime_message_get_header(mime_message, "Status"); if (status && strchr(status, 'R')) return NULL; /* the message was read */ else if (status && strchr(status, 'O')) flags &= ~MN_MESSAGE_NEW; else flags |= MN_MESSAGE_NEW; } id = g_mime_message_get_message_id(mime_message); g_mime_message_get_date(mime_message, &sent_time, NULL); from = g_mime_message_get_sender(mime_message); subject = g_mime_message_get_subject(mime_message); decoded_from = from ? g_mime_utils_header_decode_text(from) : NULL; decoded_subject = subject ? g_mime_utils_header_decode_text(subject) : NULL; message = g_object_new(type, MN_MESSAGE_PROP_MAILBOX(mailbox), MN_MESSAGE_PROP_SENT_TIME(sent_time), MN_MESSAGE_PROP_ID((char *) id), MN_MESSAGE_PROP_MID((char *) mid), MN_MESSAGE_PROP_FROM(decoded_from), MN_MESSAGE_PROP_SUBJECT(decoded_subject), MN_MESSAGE_PROP_URI((char *) uri), MN_MESSAGE_PROP_FLAGS(flags), NULL); g_free(decoded_from); g_free(decoded_subject); return message; }