static gint multipart_signed_skip_content (CamelMimeParser *cmp) { gchar *buf; gsize len; gint state; switch (camel_mime_parser_state (cmp)) { case CAMEL_MIME_PARSER_STATE_HEADER: /* body part */ while (camel_mime_parser_step (cmp, &buf, &len) != CAMEL_MIME_PARSER_STATE_BODY_END) /* NOOP */ ; break; case CAMEL_MIME_PARSER_STATE_MESSAGE: /* message body part */ (void) camel_mime_parser_step (cmp, &buf, &len); multipart_signed_skip_content (cmp); /* clean up followon state if any, see camel-mime-message.c */ state = camel_mime_parser_step (cmp, &buf, &len); switch (state) { case CAMEL_MIME_PARSER_STATE_EOF: case CAMEL_MIME_PARSER_STATE_FROM_END: /* these doesn't belong to us */ camel_mime_parser_unstep (cmp); case CAMEL_MIME_PARSER_STATE_MESSAGE_END: break; default: g_error ("Bad parser state: Expecting MESSAGE_END or EOF or EOM, got: %u", camel_mime_parser_state (cmp)); camel_mime_parser_unstep (cmp); return -1; } break; case CAMEL_MIME_PARSER_STATE_MULTIPART: /* embedded multipart */ while (camel_mime_parser_step (cmp, &buf, &len) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) multipart_signed_skip_content (cmp); break; default: g_warning ("Invalid state encountered???: %u", camel_mime_parser_state (cmp)); } return 0; }
static gint multipart_signed_construct_from_parser (CamelMultipart *multipart, CamelMimeParser *mp) { gint err; CamelContentType *content_type; CamelMultipartSigned *mps = (CamelMultipartSigned *) multipart; CamelDataWrapper *data_wrapper; GByteArray *byte_array; gchar *buf; gsize len; /* we *must not* be in multipart state, otherwise the mime parser will * parse the headers which is a no no @#$@# stupid multipart/signed spec */ g_assert (camel_mime_parser_state (mp) == CAMEL_MIME_PARSER_STATE_HEADER); /* All we do is copy it to a memstream */ content_type = camel_mime_parser_content_type (mp); camel_multipart_set_boundary (multipart, camel_content_type_param (content_type, "boundary")); data_wrapper = CAMEL_DATA_WRAPPER (multipart); byte_array = camel_data_wrapper_get_byte_array (data_wrapper); /* Wipe any previous contents from the byte array. */ g_byte_array_set_size (byte_array, 0); while (camel_mime_parser_step (mp, &buf, &len) != CAMEL_MIME_PARSER_STATE_BODY_END) g_byte_array_append (byte_array, (guint8 *) buf, len); mps->start1 = -1; if (mps->content) { g_object_unref (mps->content); mps->content = NULL; } if (mps->contentraw) { g_object_unref (mps->contentraw); mps->contentraw = NULL; } if (mps->signature) { g_object_unref (mps->signature); mps->signature = NULL; } err = camel_mime_parser_errno (mp); if (err != 0) { errno = err; return -1; } else return 0; }
static gboolean mime_message_construct_from_parser_sync (CamelMimePart *dw, CamelMimeParser *mp, GCancellable *cancellable, GError **error) { CamelMimePartClass *mime_part_class; gchar *buf; gsize len; gint state; gint err; gboolean success; /* let the mime-part construct the guts ... */ mime_part_class = CAMEL_MIME_PART_CLASS (camel_mime_message_parent_class); success = mime_part_class->construct_from_parser_sync ( dw, mp, cancellable, error); if (!success) return FALSE; /* ... then clean up the follow-on state */ state = camel_mime_parser_step (mp, &buf, &len); switch (state) { case CAMEL_MIME_PARSER_STATE_EOF: case CAMEL_MIME_PARSER_STATE_FROM_END: /* these doesn't belong to us */ camel_mime_parser_unstep (mp); case CAMEL_MIME_PARSER_STATE_MESSAGE_END: break; default: g_error ("Bad parser state: Expecing MESSAGE_END or EOF or EOM, got: %u", camel_mime_parser_state (mp)); camel_mime_parser_unstep (mp); return FALSE; } err = camel_mime_parser_errno (mp); if (err != 0) { errno = err; g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), "%s", g_strerror (errno)); success = FALSE; } return success; }
static gint multipart_construct_from_parser (CamelMultipart *multipart, CamelMimeParser *mp) { gint err; CamelContentType *content_type; CamelMimePart *bodypart; gchar *buf; gsize len; g_assert (camel_mime_parser_state (mp) == CAMEL_MIME_PARSER_STATE_MULTIPART); /* FIXME: we should use a came-mime-mutlipart, not jsut a camel-multipart, but who cares */ d(printf("Creating multi-part\n")); content_type = camel_mime_parser_content_type (mp); camel_multipart_set_boundary (multipart, camel_content_type_param(content_type, "boundary")); while (camel_mime_parser_step (mp, &buf, &len) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) { camel_mime_parser_unstep (mp); bodypart = camel_mime_part_new (); camel_mime_part_construct_from_parser_sync ( bodypart, mp, NULL, NULL); camel_multipart_add_part (multipart, bodypart); g_object_unref (bodypart); } /* these are only return valid data in the MULTIPART_END state */ camel_multipart_set_preface (multipart, camel_mime_parser_preface (mp)); camel_multipart_set_postface (multipart, camel_mime_parser_postface (mp)); err = camel_mime_parser_errno (mp); if (err != 0) { errno = err; return -1; } else return 0; }
static CamelMimeMessage * mbox_folder_get_message_sync (CamelFolder *folder, const gchar *uid, GCancellable *cancellable, GError **error) { CamelLocalFolder *lf = (CamelLocalFolder *) folder; CamelMimeMessage *message = NULL; CamelMboxMessageInfo *info; CamelMimeParser *parser = NULL; gint fd, retval; gint retried = FALSE; goffset frompos; d (printf ("Getting message %s\n", uid)); /* lock the folder first, burn if we can't, need write lock for summary check */ if (camel_local_folder_lock (lf, CAMEL_LOCK_WRITE, error) == -1) return NULL; /* check for new messages always */ if (camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, cancellable, error) == -1) { camel_local_folder_unlock (lf); return NULL; } retry: /* get the message summary info */ info = (CamelMboxMessageInfo *) camel_folder_summary_get (folder->summary, uid); if (info == NULL) { set_cannot_get_message_ex ( error, CAMEL_FOLDER_ERROR_INVALID_UID, uid, lf->folder_path, _("No such message")); goto fail; } if (info->frompos == -1) { camel_message_info_unref (info); goto fail; } frompos = info->frompos; camel_message_info_unref (info); /* we use an fd instead of a normal stream here - the reason is subtle, camel_mime_part will cache * the whole message in memory if the stream is non-seekable (which it is when built from a parser * with no stream). This means we dont have to lock the mbox for the life of the message, but only * while it is being created. */ fd = g_open (lf->folder_path, O_LARGEFILE | O_RDONLY | O_BINARY, 0); if (fd == -1) { set_cannot_get_message_ex ( error, CAMEL_ERROR_GENERIC, uid, lf->folder_path, g_strerror (errno)); goto fail; } /* we use a parser to verify the message is correct, and in the correct position */ parser = camel_mime_parser_new (); camel_mime_parser_init_with_fd (parser, fd); camel_mime_parser_scan_from (parser, TRUE); camel_mime_parser_seek (parser, frompos, SEEK_SET); if (camel_mime_parser_step (parser, NULL, NULL) != CAMEL_MIME_PARSER_STATE_FROM || camel_mime_parser_tell_start_from (parser) != frompos) { g_warning ("Summary doesn't match the folder contents! eek!\n" " expecting offset %ld got %ld, state = %d", (glong) frompos, (glong) camel_mime_parser_tell_start_from (parser), camel_mime_parser_state (parser)); g_object_unref (parser); parser = NULL; if (!retried) { retried = TRUE; camel_local_summary_check_force ((CamelLocalSummary *) folder->summary); retval = camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, cancellable, error); if (retval != -1) goto retry; } set_cannot_get_message_ex ( error, CAMEL_FOLDER_ERROR_INVALID, uid, lf->folder_path, _("The folder appears to be irrecoverably corrupted.")); goto fail; } message = camel_mime_message_new (); if (!camel_mime_part_construct_from_parser_sync ( (CamelMimePart *) message, parser, cancellable, error)) { g_prefix_error ( error, _("Cannot get message %s from folder %s: "), uid, lf->folder_path); g_object_unref (message); message = NULL; goto fail; } camel_medium_remove_header ((CamelMedium *) message, "X-Evolution"); fail: /* and unlock now we're finished with it */ camel_local_folder_unlock (lf); if (parser) g_object_unref (parser); /* use the opportunity to notify of changes (particularly if we had a rebuild) */ if (camel_folder_change_info_changed (lf->changes)) { camel_folder_changed (folder, lf->changes); camel_folder_change_info_clear (lf->changes); } return message; }
/* Well, since Solaris is a tad broken wrt its 'mbox' folder format, * we must convert it to a real mbox format. Thankfully this is * mostly pretty easy */ static gint camel_movemail_solaris (gint oldsfd, gint dfd, GError **error) { CamelMimeParser *mp; gchar *buffer; gint len; gint sfd; CamelMimeFilter *ffrom; gint ret = 1; gchar *from = NULL; /* need to dup as the mime parser will close on finish */ sfd = dup (oldsfd); if (sfd == -1) { g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), _("Error copying mail temp file: %s"), g_strerror (errno)); return -1; } mp = camel_mime_parser_new (); camel_mime_parser_scan_from (mp, TRUE); camel_mime_parser_init_with_fd (mp, sfd); ffrom = camel_mime_filter_from_new (); while (camel_mime_parser_step (mp, &buffer, &len) == CAMEL_MIME_PARSER_STATE_FROM) { g_return_val_if_fail (camel_mime_parser_from_line (mp), -1); from = g_strdup (camel_mime_parser_from_line (mp)); if (camel_mime_parser_step (mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_FROM_END) { CamelNameValueArray *headers; const gchar *cl; gint length; gint start, body; goffset newpos; ret = 0; start = camel_mime_parser_tell_start_from (mp); body = camel_mime_parser_tell (mp); if (write (dfd, from, strlen (from)) != strlen (from)) goto fail; /* write out headers, but NOT content-length header */ headers = camel_mime_parser_dup_headers (mp); if (solaris_header_write (dfd, headers) == -1) { camel_name_value_array_free (headers); goto fail; } camel_name_value_array_free (headers); cl = camel_mime_parser_header (mp, "content-length", NULL); if (cl == NULL) { g_warning ("Required Content-Length header is missing from solaris mail box @ %d", (gint) camel_mime_parser_tell (mp)); camel_mime_parser_drop_step (mp); camel_mime_parser_drop_step (mp); camel_mime_parser_step (mp, &buffer, &len); camel_mime_parser_unstep (mp); length = camel_mime_parser_tell_start_from (mp) - body; newpos = -1; } else { length = atoi (cl); camel_mime_parser_drop_step (mp); camel_mime_parser_drop_step (mp); newpos = length + body; } /* copy body->length converting From lines */ if (camel_movemail_copy_filter (sfd, dfd, body, length, ffrom) == -1) goto fail; if (newpos != -1) camel_mime_parser_seek (mp, newpos, SEEK_SET); } else { g_error ("Inalid parser state: %d", camel_mime_parser_state (mp)); } g_free (from); } g_object_unref (mp); g_object_unref (ffrom); return ret; fail: g_free (from); g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), _("Error copying mail temp file: %s"), g_strerror (errno)); g_object_unref (mp); g_object_unref (ffrom); return -1; }