static void data_wrapper_construct_from_stream_thread (GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable) { AsyncContext *async_context; GError *error = NULL; async_context = g_simple_async_result_get_op_res_gpointer (simple); camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (object), async_context->stream, cancellable, &error); if (error != NULL) g_simple_async_result_take_error (simple, error); }
CamelMimeMessage * test_message_read_file (const gchar *name) { CamelStream *stream; CamelMimeMessage *msg2; stream = camel_stream_fs_new_with_name (name, O_RDONLY, 0, NULL); msg2 = camel_mime_message_new (); camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (msg2), stream, NULL, NULL); /* stream's refcount may be > 1 if the message is real big */ check (G_OBJECT (stream)->ref_count >=1); g_object_unref (stream); return msg2; }
gint test_message_write_file (CamelMimeMessage *msg, const gchar *name) { CamelStream *stream; gint ret; stream = camel_stream_fs_new_with_name ( name, O_CREAT | O_WRONLY, 0600, NULL); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (msg), stream, NULL, NULL); ret = camel_stream_close (stream, NULL, NULL); check (G_OBJECT (stream)->ref_count == 1); g_object_unref (stream); return ret; }
static void data_wrapper_dispose (GObject *object) { CamelDataWrapper *data_wrapper = CAMEL_DATA_WRAPPER (object); if (data_wrapper->mime_type != NULL) { camel_content_type_unref (data_wrapper->mime_type); data_wrapper->mime_type = NULL; } if (data_wrapper->stream != NULL) { g_object_unref (data_wrapper->stream); data_wrapper->stream = NULL; } /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (camel_data_wrapper_parent_class)->dispose (object); }
static void multipart_set_boundary (CamelMultipart *multipart, const gchar *boundary) { CamelDataWrapper *cdw = CAMEL_DATA_WRAPPER (multipart); gchar *bgen, bbuf[27], *p; guint8 *digest; gsize length; gint state, save; g_return_if_fail (cdw->mime_type != NULL); length = g_checksum_type_get_length (G_CHECKSUM_MD5); digest = g_alloca (length); if (!boundary) { GChecksum *checksum; /* Generate a fairly random boundary string. */ bgen = g_strdup_printf ("%p:%lu:%lu", (gpointer) multipart, (gulong) getpid (), (gulong) time (NULL)); checksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (checksum, (guchar *) bgen, -1); g_checksum_get_digest (checksum, digest, &length); g_checksum_free (checksum); g_free (bgen); strcpy (bbuf, "=-"); p = bbuf + 2; state = save = 0; p += g_base64_encode_step ( (guchar *) digest, length, FALSE, p, &state, &save); *p = '\0'; boundary = bbuf; } camel_content_type_set_param (cdw->mime_type, "boundary", boundary); }
static void data_wrapper_decode_to_stream_thread (GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable) { AsyncContext *async_context; GError *error = NULL; async_context = g_simple_async_result_get_op_res_gpointer (simple); async_context->bytes_written = camel_data_wrapper_decode_to_stream_sync ( CAMEL_DATA_WRAPPER (object), async_context->stream, cancellable, &error); if (error != NULL) { g_simple_async_result_set_from_error (simple, error); g_error_free (error); } }
static guint multipart_signed_get_number (CamelMultipart *multipart) { CamelMultipartSigned *mps = (CamelMultipartSigned *) multipart; CamelDataWrapper *data_wrapper; GByteArray *byte_array; data_wrapper = CAMEL_DATA_WRAPPER (multipart); byte_array = camel_data_wrapper_get_byte_array (data_wrapper); /* check what we have, so we return something reasonable */ if ((mps->content || mps->contentraw) && mps->signature) return 2; if (mps->start1 == -1 && multipart_signed_parse_content (mps) == -1) { if (byte_array->len == 0) return 0; else return 1; } else { return 2; } }
static void write_message_to_stream_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { GOutputStream *output_stream; gssize bytes_written; GError *local_error = NULL; output_stream = task_data; bytes_written = camel_data_wrapper_decode_to_output_stream_sync ( CAMEL_DATA_WRAPPER (source_object), output_stream, cancellable, &local_error); g_output_stream_close (output_stream, cancellable, local_error ? NULL : &local_error); if (local_error != NULL) { g_task_return_error (task, local_error); } else { g_task_return_int (task, bytes_written); } }
static gboolean sendmail_send_to_sync (CamelTransport *transport, CamelMimeMessage *message, CamelAddress *from, CamelAddress *recipients, gboolean *out_sent_message_saved, GCancellable *cancellable, GError **error) { CamelHeaderRaw *header, *savedbcc, *n, *tail; const gchar *from_addr, *addr; GPtrArray *argv_arr; gint i, len, fd[2], nullfd, wstat; CamelStream *filter; CamelMimeFilter *crlf; sigset_t mask, omask; CamelStream *out; CamelSendmailSettings *settings; const gchar *binary = SENDMAIL_PATH; gchar *custom_binary = NULL, *custom_args = NULL; gboolean success; pid_t pid; success = camel_internet_address_get ( CAMEL_INTERNET_ADDRESS (from), 0, NULL, &from_addr); if (!success) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Failed to read From address")); return FALSE; } settings = CAMEL_SENDMAIL_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE (transport))); if (!camel_sendmail_settings_get_send_in_offline (settings)) { CamelSession *session; gboolean is_online; session = camel_service_ref_session (CAMEL_SERVICE (transport)); is_online = session && camel_session_get_online (session); g_clear_object (&session); if (!is_online) { g_set_error ( error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE, _("Message send in offline mode is disabled")); return FALSE; } } if (camel_sendmail_settings_get_use_custom_binary (settings)) { custom_binary = camel_sendmail_settings_dup_custom_binary (settings); if (custom_binary && *custom_binary) binary = custom_binary; } if (camel_sendmail_settings_get_use_custom_args (settings)) { custom_args = camel_sendmail_settings_dup_custom_args (settings); /* means no arguments used */ if (!custom_args) custom_args = g_strdup (""); } g_object_unref (settings); len = camel_address_length (recipients); for (i = 0; i < len; i++) { success = camel_internet_address_get ( CAMEL_INTERNET_ADDRESS (recipients), i, NULL, &addr); if (!success) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Could not parse recipient list")); g_free (custom_binary); g_free (custom_args); return FALSE; } } argv_arr = parse_sendmail_args ( binary, custom_args ? custom_args : "-i -f %F -- %R", from_addr, recipients); if (!argv_arr) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Could not parse arguments")); g_free (custom_binary); g_free (custom_args); return FALSE; } /* unlink the bcc headers */ savedbcc = NULL; tail = (CamelHeaderRaw *) &savedbcc; header = (CamelHeaderRaw *) &CAMEL_MIME_PART (message)->headers; n = header->next; while (n != NULL) { if (!g_ascii_strcasecmp (n->name, "Bcc")) { header->next = n->next; tail->next = n; n->next = NULL; tail = n; } else { header = n; } n = header->next; } if (pipe (fd) == -1) { g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), _("Could not create pipe to '%s': %s: " "mail not sent"), binary, g_strerror (errno)); /* restore the bcc headers */ header->next = savedbcc; g_free (custom_binary); g_free (custom_args); g_ptr_array_free (argv_arr, TRUE); return FALSE; } /* Block SIGCHLD so the calling application doesn't notice * sendmail exiting before we do. */ sigemptyset (&mask); sigaddset (&mask, SIGCHLD); sigprocmask (SIG_BLOCK, &mask, &omask); pid = fork (); switch (pid) { case -1: g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), _("Could not fork '%s': %s: " "mail not sent"), binary, g_strerror (errno)); close (fd[0]); close (fd[1]); sigprocmask (SIG_SETMASK, &omask, NULL); /* restore the bcc headers */ header->next = savedbcc; g_free (custom_binary); g_free (custom_args); g_ptr_array_free (argv_arr, TRUE); return FALSE; case 0: /* Child process */ nullfd = open ("/dev/null", O_RDWR); dup2 (fd[0], STDIN_FILENO); if (nullfd != -1) { /*dup2 (nullfd, STDOUT_FILENO); dup2 (nullfd, STDERR_FILENO);*/ close (nullfd); } close (fd[1]); execv (binary, (gchar **) argv_arr->pdata); _exit (255); } g_ptr_array_free (argv_arr, TRUE); /* Parent process. Write the message out. */ close (fd[0]); out = camel_stream_fs_new_with_fd (fd[1]); /* XXX Workaround for lame sendmail implementations * that can't handle CRLF eoln sequences. */ filter = camel_stream_filter_new (out); crlf = camel_mime_filter_crlf_new ( CAMEL_MIME_FILTER_CRLF_DECODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); camel_stream_filter_add (CAMEL_STREAM_FILTER (filter), crlf); g_object_unref (crlf); g_object_unref (out); out = (CamelStream *) filter; if (camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (message), out, cancellable, error) == -1 || camel_stream_close (out, cancellable, error) == -1) { g_object_unref (out); g_prefix_error (error, _("Could not send message: ")); /* Wait for sendmail to exit. */ while (waitpid (pid, &wstat, 0) == -1 && errno == EINTR) ; sigprocmask (SIG_SETMASK, &omask, NULL); /* restore the bcc headers */ header->next = savedbcc; g_free (custom_binary); g_free (custom_args); return FALSE; } g_object_unref (out); /* Wait for sendmail to exit. */ while (waitpid (pid, &wstat, 0) == -1 && errno == EINTR) ; sigprocmask (SIG_SETMASK, &omask, NULL); /* restore the bcc headers */ header->next = savedbcc; if (!WIFEXITED (wstat)) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("'%s' exited with signal %s: mail not sent."), binary, g_strsignal (WTERMSIG (wstat))); g_free (custom_binary); g_free (custom_args); return FALSE; } else if (WEXITSTATUS (wstat) != 0) { if (WEXITSTATUS (wstat) == 255) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Could not execute '%s': mail not sent."), binary); } else { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("'%s' exited with status %d: " "mail not sent."), binary, WEXITSTATUS (wstat)); } g_free (custom_binary); g_free (custom_args); return FALSE; } g_free (custom_binary); g_free (custom_args); return TRUE; }
static CamelMimeMessage * mail_attachment_handler_get_selected_message (EAttachmentHandler *handler) { EAttachment *attachment; EAttachmentView *view; CamelMimePart *mime_part; CamelMimeMessage *message = NULL; CamelDataWrapper *outer_wrapper; CamelContentType *outer_content_type; CamelDataWrapper *inner_wrapper; CamelContentType *inner_content_type; GList *selected; gboolean inner_and_outer_content_types_match; view = e_attachment_handler_get_view (handler); selected = e_attachment_view_get_selected_attachments (view); g_return_val_if_fail (g_list_length (selected) == 1, NULL); attachment = E_ATTACHMENT (selected->data); mime_part = e_attachment_ref_mime_part (attachment); outer_wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); outer_content_type = camel_data_wrapper_get_mime_type_field (outer_wrapper); if (!camel_content_type_is (outer_content_type, "message", "rfc822")) goto exit; inner_wrapper = camel_medium_get_content (CAMEL_MEDIUM (outer_wrapper)); inner_content_type = camel_data_wrapper_get_mime_type_field (inner_wrapper); inner_and_outer_content_types_match = camel_content_type_is ( inner_content_type, outer_content_type->type, outer_content_type->subtype); if (!inner_and_outer_content_types_match) { CamelStream *mem; gboolean success; /* Create a message copy in case the inner content * type doesn't match the mime_part's content type, * which can happen for multipart/digest, where it * confuses the formatter on reply, which skips all * rfc822 subparts. */ mem = camel_stream_mem_new (); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (outer_wrapper), mem, NULL, NULL); g_seekable_seek ( G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL); message = camel_mime_message_new (); success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (message), mem, NULL, NULL); if (!success) g_clear_object (&message); g_object_unref (mem); } exit: if (message == NULL) message = g_object_ref (outer_wrapper); g_clear_object (&mime_part); g_list_free_full (selected, (GDestroyNotify) g_object_unref); return message; }
static void mail_attachment_handler_x_uid_list (EAttachmentView *view, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, EAttachmentHandler *handler) { static GdkAtom atom = GDK_NONE; EMailAttachmentHandlerPrivate *priv; CamelDataWrapper *wrapper; CamelMimeMessage *message; CamelMultipart *multipart; CamelMimePart *mime_part; CamelFolder *folder = NULL; EAttachment *attachment; EAttachmentStore *store; EMailSession *session; GPtrArray *uids; const gchar *data; const gchar *cp, *end; gchar *description; gpointer parent; gint length; guint ii; GError *local_error = NULL; if (G_UNLIKELY (atom == GDK_NONE)) atom = gdk_atom_intern_static_string ("x-uid-list"); if (gtk_selection_data_get_target (selection_data) != atom) return; store = e_attachment_view_get_store (view); priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler); parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); parent = gtk_widget_is_toplevel (parent) ? parent : NULL; uids = g_ptr_array_new (); data = (const gchar *) gtk_selection_data_get_data (selection_data); length = gtk_selection_data_get_length (selection_data); /* The UID list is delimited by NUL characters. * Brilliant. So we can't use g_strsplit(). */ cp = data; end = data + length; while (cp < end) { const gchar *start = cp; while (cp < end && *cp != '\0') cp++; /* Skip the first string. */ if (start > data) g_ptr_array_add (uids, g_strndup (start, cp - start)); cp++; } if (uids->len == 0) goto exit; session = e_mail_backend_get_session (priv->backend); /* The first string is the folder URI. */ /* FIXME Not passing a GCancellable here. */ folder = e_mail_session_uri_to_folder_sync ( session, data, 0, NULL, &local_error); if (folder == NULL) goto exit; /* Handle one message. */ if (uids->len == 1) { const gchar *message_uid; message_uid = g_ptr_array_index (uids, 0); /* FIXME Not passing a GCancellable here. */ message = camel_folder_get_message_sync ( folder, message_uid, NULL, &local_error); if (message == NULL) goto exit; attachment = e_attachment_new_for_message (message); e_attachment_store_add_attachment (store, attachment); e_attachment_load_async ( attachment, (GAsyncReadyCallback) call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL); g_object_unref (attachment); g_object_unref (message); goto exit; } /* Build a multipart/digest message out of the UIDs. */ multipart = camel_multipart_new (); wrapper = CAMEL_DATA_WRAPPER (multipart); camel_data_wrapper_set_mime_type (wrapper, "multipart/digest"); camel_multipart_set_boundary (multipart, NULL); for (ii = 0; ii < uids->len; ii++) { /* FIXME Not passing a GCancellable here. */ message = camel_folder_get_message_sync ( folder, uids->pdata[ii], NULL, &local_error); if (message == NULL) { g_object_unref (multipart); goto exit; } mime_part = camel_mime_part_new (); wrapper = CAMEL_DATA_WRAPPER (message); camel_mime_part_set_disposition (mime_part, "inline"); camel_medium_set_content ( CAMEL_MEDIUM (mime_part), wrapper); camel_mime_part_set_content_type (mime_part, "message/rfc822"); camel_multipart_add_part (multipart, mime_part); g_object_unref (mime_part); g_object_unref (message); } mime_part = camel_mime_part_new (); wrapper = CAMEL_DATA_WRAPPER (multipart); camel_medium_set_content (CAMEL_MEDIUM (mime_part), wrapper); description = g_strdup_printf ( ngettext ( "%d attached message", "%d attached messages", uids->len), uids->len); camel_mime_part_set_description (mime_part, description); g_free (description); attachment = e_attachment_new (); e_attachment_set_mime_part (attachment, mime_part); e_attachment_store_add_attachment (store, attachment); e_attachment_load_async ( attachment, (GAsyncReadyCallback) call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL); g_object_unref (attachment); g_object_unref (mime_part); g_object_unref (multipart); exit: if (local_error != NULL) { const gchar *folder_name = data; if (folder != NULL) folder_name = camel_folder_get_display_name (folder); e_alert_run_dialog_for_args ( parent, "mail-composer:attach-nomessages", folder_name, local_error->message, NULL); g_clear_error (&local_error); } if (folder != NULL) g_object_unref (folder); g_ptr_array_free (uids, TRUE); g_signal_stop_emission_by_name (view, "drag-data-received"); }
static void mail_attachment_handler_message_rfc822 (EAttachmentView *view, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, EAttachmentHandler *handler) { static GdkAtom atom = GDK_NONE; EAttachmentStore *store; EAttachment *attachment; CamelMimeMessage *message; CamelDataWrapper *wrapper; CamelStream *stream; const gchar *data; gboolean success = FALSE; gpointer parent; gint length; if (G_UNLIKELY (atom == GDK_NONE)) atom = gdk_atom_intern_static_string ("message/rfc822"); if (gtk_selection_data_get_target (selection_data) != atom) return; g_signal_stop_emission_by_name (view, "drag-data-received"); data = (const gchar *) gtk_selection_data_get_data (selection_data); length = gtk_selection_data_get_length (selection_data); stream = camel_stream_mem_new (); camel_stream_write (stream, data, length, NULL, NULL); g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); message = camel_mime_message_new (); wrapper = CAMEL_DATA_WRAPPER (message); if (!camel_data_wrapper_construct_from_stream_sync ( wrapper, stream, NULL, NULL)) goto exit; store = e_attachment_view_get_store (view); parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); parent = gtk_widget_is_toplevel (parent) ? parent : NULL; attachment = e_attachment_new_for_message (message); e_attachment_store_add_attachment (store, attachment); e_attachment_load_async ( attachment, (GAsyncReadyCallback) call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL); g_object_unref (attachment); success = TRUE; exit: g_object_unref (message); g_object_unref (stream); gtk_drag_finish (drag_context, success, FALSE, time); }
static void camel_multipart_encrypted_init (CamelMultipartEncrypted *multipart) { camel_data_wrapper_set_mime_type ( CAMEL_DATA_WRAPPER (multipart), "multipart/encrypted"); }
CamelMimeMessage * scalix_appointment_to_mime_message (ScalixObject * object) { CamelMimeMessage *message; CamelMultipart *multipart; CamelMimePart *part; CamelMedium *medium; CamelStream *stream; CamelDataWrapper *wrapper; ECalComponentDateTime dtstart, dtend; ECalComponent *comp; ECalComponentText text; icalcomponent_kind kind; icalcomponent *icalcomp, *toplevel_comp; icaltimezone *zone = NULL; GSList *attachment_list = NULL; GSList *attachment_list_new = NULL; GSList *siter = NULL; GList *part_list = NULL; GList *iter = NULL; char *msgid; char *str, *meeting_status; const char *ouid = NULL; char *file_contents = NULL; char *full_path, *filename, *mime_filename; char *cid; int size; g_object_get (SCALIX_APPOINTMENT (object), "timezone", &zone, NULL); comp = E_CAL_COMPONENT (scalix_object_clone (object)); message = camel_mime_message_new (); medium = CAMEL_MEDIUM (message); camel_medium_add_header (medium, "X-Scalix-Class", "IPM.Appointment"); /* Preserve msg id if there is already one */ if (scalix_appointment_get (SCALIX_APPOINTMENT (comp), X_SCALIX_MSG_ID, &msgid)) { scalix_appointment_unset (SCALIX_APPOINTMENT (comp), X_SCALIX_MSG_ID); } else { msgid = camel_header_msgid_generate (); } camel_mime_message_set_message_id (message, msgid); /* subject */ e_cal_component_get_summary (comp, &text); if (text.value != NULL) { camel_mime_message_set_subject (message, text.value); } /* start day */ e_cal_component_get_dtstart (comp, &dtstart); if (!icaltime_get_timezone (*dtstart.value)) icaltime_set_timezone (dtstart.value, icaltimezone_get_builtin_timezone_from_tzid (dtstart.tzid)); /* end day */ e_cal_component_get_dtend (comp, &dtend); if (!icaltime_get_timezone (*dtend.value)) icaltime_set_timezone (dtend.value, icaltimezone_get_builtin_timezone_from_tzid (dtend.tzid)); /* set From: and Sender: */ if (e_cal_component_has_organizer (comp)) { ECalComponentOrganizer organizer; e_cal_component_get_organizer (comp, &organizer); if (!strncasecmp (organizer.value, "MAILTO:", 7)) { camel_medium_add_header (medium, "Sender", organizer.value + 7); camel_medium_add_header (medium, "From", organizer.value + 7); } } /* set the appropriate recipient headers from the recipient table */ if (e_cal_component_has_attendees (comp) && e_cal_component_has_organizer (comp)) { GSList *iter, *attendees = NULL; CamelInternetAddress *recipients_to = NULL; CamelInternetAddress *recipients_cc = NULL; meeting_status = "1"; e_cal_component_get_attendee_list (comp, &attendees); for (iter = attendees; iter; iter = iter->next) { ECalComponentAttendee *attendee = iter->data; const char *mail = NULL; /* attendee entries must start with MAILTO: */ if (strncasecmp (attendee->value, "MAILTO:", 7)) { continue; } mail = attendee->value + 7; if (attendee->role == ICAL_ROLE_REQPARTICIPANT) { if (recipients_to == NULL) { recipients_to = camel_internet_address_new (); } camel_internet_address_add (recipients_to, attendee->cn, mail); } else if (attendee->role == ICAL_ROLE_OPTPARTICIPANT) { if (recipients_cc == NULL) { recipients_cc = camel_internet_address_new (); } camel_internet_address_add (recipients_cc, attendee->cn, mail); } else { continue; } } if (recipients_to != NULL) { camel_mime_message_set_recipients (message, "To", recipients_to); camel_object_unref (recipients_to); } if (recipients_cc != NULL) { camel_mime_message_set_recipients (message, "Cc", recipients_cc); camel_object_unref (recipients_cc); } } else { meeting_status = "0"; } /* Clear properties */ scalix_appointment_unset (SCALIX_APPOINTMENT (comp), X_SCALIX_IMAP_UID); /* Render the text/calendar */ e_cal_component_commit_sequence (comp); icalcomp = e_cal_component_get_icalcomponent (comp); kind = icalcomponent_isa (icalcomp); if (kind != ICAL_VCALENDAR_COMPONENT) { /* If its not a VCALENDAR, make it one to simplify below */ toplevel_comp = e_cal_util_new_top_level (); icalcomponent_add_component (toplevel_comp, icalcomp); icalcomp = toplevel_comp; } /* set METHOD to PUSBLISH */ icalcomponent_set_method (icalcomp, ICAL_METHOD_PUBLISH); /* Add the VTIMEZONE components for start- and/or end-times */ if (zone) { icalcomponent_add_component (icalcomp, icaltimezone_get_component (zone)); } else if (dtstart.tzid) { icalcomponent_add_component (icalcomp, icaltimezone_get_component (icaltimezone_get_builtin_timezone_from_tzid (dtstart.tzid))); } if (dtstart.tzid && dtend.tzid && strcmp (dtstart.tzid, dtend.tzid) != 0) { icalcomponent_add_component (icalcomp, icaltimezone_get_component (icaltimezone_get_builtin_timezone_from_tzid (dtend.tzid))); } /* FIXME: do we leek icalcomponents here? */ if (e_cal_component_has_attachments (comp)) { multipart = camel_multipart_new (); camel_multipart_set_boundary (multipart, NULL); e_cal_component_get_uid (comp, &ouid); e_cal_component_get_attachment_list (comp, &attachment_list); for (siter = attachment_list; siter; siter = siter->next) { if (siter->data == NULL) continue; if (strstr (siter->data, "file://") != siter->data) continue; full_path = ((char *) siter->data) + strlen ("file://"); filename = g_strrstr (full_path, "/") + 1; mime_filename = filename + strlen (ouid) + 1; size = 0; file_contents = get_file_contents (full_path, &size); if (file_contents == NULL) continue; stream = camel_stream_mem_new_with_buffer (file_contents, size); wrapper = camel_data_wrapper_new (); camel_data_wrapper_construct_from_stream (wrapper, stream); camel_object_unref (stream); part = camel_mime_part_new (); camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper); camel_mime_part_set_filename (part, mime_filename); camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64); cid = camel_header_msgid_generate (); camel_mime_part_set_content_id (part, cid); camel_mime_part_set_description (part, mime_filename); camel_mime_part_set_disposition (part, "attachment"); part_list = g_list_append (part_list, part); attachment_list_new = g_slist_append (attachment_list_new, g_strdup_printf ("CID:%s", cid)); g_free (cid); } e_cal_component_set_attachment_list (comp, attachment_list_new); str = icalcomponent_as_ical_string (icalcomp); part = camel_mime_part_new (); camel_mime_part_set_content (part, str, strlen (str), "text/calendar; method=PUBLISH; charset=UTF-8"); part_list = g_list_prepend (part_list, part); for (iter = part_list; iter; iter = iter->next) { part = (CamelMimePart *) iter->data; camel_multipart_add_part (multipart, part); camel_object_unref (part); } camel_medium_set_content_object (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart)); camel_object_unref (multipart); g_slist_free (attachment_list); g_slist_free (attachment_list_new); g_list_free (part_list); } else { str = icalcomponent_as_ical_string (icalcomp); camel_mime_part_set_content (CAMEL_MIME_PART (message), str, strlen (str), "text/calendar; method=PUBLISH; charset=UTF-8"); } scalix_appointment_set (SCALIX_APPOINTMENT (object), X_SCALIX_MSG_ID, msgid); return message; }
static int pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err, int wait_for_termination, GByteArray *output_buffer, GError **error) { int result, status, errnosav, fds[2], out_fds[2]; CamelStream *stream; char *program; pid_t pid; if (camel_debug_start ("junk")) { int i; printf ("pipe_to_sa "); for (i = 0; argv[i]; i++) printf ("%s ", argv[i]); printf ("\n"); camel_debug_end (); } program = g_find_program_in_path (argv [0]); if (program == NULL) { d(printf ("program not found, returning %d\n", rv_err)); g_set_error (error, EM_JUNK_ERROR, rv_err, _("SpamAssassin not found, code: %d"), rv_err); return rv_err; } g_free (program); if (pipe (fds) == -1) { errnosav = errno; d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno))); g_set_error (error, EM_JUNK_ERROR, errnosav, _("Failed to create pipe: %s"), strerror (errnosav)); errno = errnosav; return rv_err; } if (output_buffer && pipe (out_fds) == -1) { errnosav = errno; d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno))); g_set_error (error, EM_JUNK_ERROR, errnosav, _("Failed to create pipe: %s"), strerror (errnosav)); close (fds [0]); close (fds [1]); errno = errnosav; return rv_err; } if (!(pid = fork ())) { /* child process */ int maxfd, fd, nullfd; nullfd = open ("/dev/null", O_WRONLY); if (dup2 (fds[0], STDIN_FILENO) == -1 || dup2 (nullfd, STDERR_FILENO) == -1 || (output_buffer == NULL && dup2 (nullfd, STDOUT_FILENO) == -1) || (output_buffer != NULL && dup2 (out_fds[1], STDOUT_FILENO) == -1)) _exit (rv_err & 0377); close (fds [0]); if (output_buffer) close (out_fds [1]); setsid (); maxfd = sysconf (_SC_OPEN_MAX); for (fd = 3; fd < maxfd; fd++) fcntl (fd, F_SETFD, FD_CLOEXEC); execvp (argv[0], argv); _exit (rv_err & 0377); } else if (pid < 0) { errnosav = errno; close (fds[0]); close (fds[1]); if (output_buffer) { close (out_fds [0]); close (out_fds [1]); } if (errnosav != 0 && errnosav != -1) g_set_error (error, EM_JUNK_ERROR, errnosav, _("Error after fork: %s"), strerror (errnosav)); errno = errnosav; return rv_err; } /* parent process */ close (fds[0]); if (output_buffer) close (out_fds [1]); if (msg) { stream = camel_stream_fs_new_with_fd (fds[1]); camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (msg), stream); camel_stream_flush (stream); camel_stream_close (stream); camel_object_unref (stream); } else if (in) { camel_write (fds[1], in, strlen (in)); close (fds[1]); } if (output_buffer) { CamelStreamMem *memstream; stream = camel_stream_fs_new_with_fd (out_fds[0]); memstream = (CamelStreamMem *) camel_stream_mem_new (); camel_stream_mem_set_byte_array (memstream, output_buffer); camel_stream_write_to_stream (stream, (CamelStream *) memstream); camel_object_unref (stream); g_byte_array_append (output_buffer, (unsigned char *)"", 1); d(printf ("child process output: %s len: %d\n", output_buffer->data, output_buffer->len)); } if (wait_for_termination) { int res; d(printf ("wait for child %d termination\n", pid)); result = waitpid (pid, &status, 0); d(printf ("child %d terminated with result %d status %d exited %d exitstatus %d\n", pid, result, status, WIFEXITED (status), WEXITSTATUS (status))); if (result == -1 && errno == EINTR) { /* child process is hanging... */ kill (pid, SIGTERM); sleep (1); result = waitpid (pid, &status, WNOHANG); if (result == 0) { /* ...still hanging, set phasers to KILL */ kill (pid, SIGKILL); sleep (1); result = waitpid (pid, &status, WNOHANG); g_set_error (error, EM_JUNK_ERROR, -2, _("SpamAssassin child process does not respond, killing...")); } else g_set_error (error, EM_JUNK_ERROR, -3, _("Wait for Spamassassin child process interrupted, terminating...")); } if (result != -1 && WIFEXITED (status)) res = WEXITSTATUS (status); else res = rv_err; if (res != 0) g_set_error (error, EM_JUNK_ERROR, res, _("Pipe to SpamAssassin failed, error code: %d"), res); return res; } else return 0; }
static void load_snapshot_loaded_cb (GFile *snapshot_file, GAsyncResult *result, GSimpleAsyncResult *simple) { EShell *shell; GObject *object; LoadContext *context; EMsgComposer *composer; CamelMimeMessage *message; CamelStream *camel_stream; gchar *contents = NULL; gsize length; GError *local_error = NULL; context = g_simple_async_result_get_op_res_gpointer (simple); g_file_load_contents_finish ( snapshot_file, result, &contents, &length, NULL, &local_error); if (local_error != NULL) { g_warn_if_fail (contents == NULL); g_simple_async_result_take_error (simple, local_error); g_simple_async_result_complete (simple); return; } /* Create an in-memory buffer for the MIME parser to read from. * We have to do this because CamelStreams are syncrhonous-only, * and feeding the parser a direct file stream would block. */ message = camel_mime_message_new (); camel_stream = camel_stream_mem_new_with_buffer (contents, length); camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (message), camel_stream, NULL, &local_error); g_object_unref (camel_stream); g_free (contents); if (local_error != NULL) { g_simple_async_result_take_error (simple, local_error); g_simple_async_result_complete (simple); g_object_unref (message); return; } /* g_async_result_get_source_object() returns a new reference. */ object = g_async_result_get_source_object (G_ASYNC_RESULT (simple)); /* Create a new composer window from the loaded message and * restore its snapshot file so it continues auto-saving to * the same file. */ shell = E_SHELL (object); g_object_ref (snapshot_file); composer = e_msg_composer_new_with_message (shell, message, TRUE, NULL); g_object_set_data_full ( G_OBJECT (composer), SNAPSHOT_FILE_KEY, snapshot_file, (GDestroyNotify) delete_snapshot_file); context->composer = g_object_ref_sink (composer); g_object_unref (message); g_object_unref (object); g_simple_async_result_complete (simple); g_object_unref (simple); }
static void create_mime_message_cb (ESoapMessage *msg, gpointer user_data) { struct _create_mime_msg_data *create_data = user_data; CamelStream *mem, *filtered; CamelMimeFilter *filter; CamelContentType *content_type; GByteArray *bytes; gchar *base64; gint msgflag; guint32 message_camel_flags = 0; if (create_data->info) message_camel_flags = camel_message_info_flags (create_data->info); e_soap_message_start_element (msg, "Message", NULL, NULL); e_soap_message_start_element (msg, "MimeContent", NULL, NULL); /* This is horrid. We really need to extend ESoapMessage to allow us * to stream this directly rather than storing it in RAM. Which right * now we are doing about four times: the GByteArray in the mem stream, * then the base64 version, then the xmlDoc, then the soup request. */ camel_mime_message_set_best_encoding ( create_data->message, CAMEL_BESTENC_GET_ENCODING, CAMEL_BESTENC_8BIT); mem = camel_stream_mem_new (); filtered = camel_stream_filter_new (mem); filter = camel_mime_filter_crlf_new ( CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered), filter); g_object_unref (filter); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (create_data->message), filtered, NULL, NULL); camel_stream_flush (filtered, NULL, NULL); camel_stream_flush (mem, NULL, NULL); bytes = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem)); base64 = g_base64_encode (bytes->data, bytes->len); g_object_unref (mem); g_object_unref (filtered); e_soap_message_write_string (msg, base64); g_free (base64); e_soap_message_end_element (msg); /* MimeContent */ content_type = camel_mime_part_get_content_type (CAMEL_MIME_PART (create_data->message)); if (content_type && camel_content_type_is (content_type, "multipart", "report") && camel_content_type_param (content_type, "report-type") && g_ascii_strcasecmp (camel_content_type_param (content_type, "report-type"), "disposition-notification") == 0) { /* it's a disposition notification reply, set ItemClass too */ e_soap_message_start_element (msg, "ItemClass", NULL, NULL); e_soap_message_write_string (msg, "REPORT.IPM.NOTE.IPNRN"); e_soap_message_end_element (msg); /* ItemClass */ } e_ews_message_write_string_parameter_with_attribute ( msg, "Importance", NULL, (message_camel_flags & CAMEL_MESSAGE_FLAGGED) != 0 ? "High" : "Normal", NULL, NULL); /* more MAPI crap. You can't just set the IsDraft property * here you have to use the MAPI MSGFLAG_UNSENT extended * property Further crap is that Exchange 2007 assumes when it * sees this property that you're setting the value to 0 * ... it never checks */ msgflag = MAPI_MSGFLAG_READ; /* draft or sent is always read */ if ((message_camel_flags & CAMEL_MESSAGE_DRAFT) != 0) msgflag |= MAPI_MSGFLAG_UNSENT; e_ews_message_add_extended_property_tag_int (msg, 0x0e07, msgflag); if ((message_camel_flags & (CAMEL_MESSAGE_FORWARDED | CAMEL_MESSAGE_ANSWERED)) != 0) { gint icon; icon = (message_camel_flags & CAMEL_MESSAGE_ANSWERED) != 0 ? 0x105 : 0x106; e_ews_message_add_extended_property_tag_int (msg, 0x1080, icon); } if (create_data->info) { const gchar *followup, *completed, *dueby; time_t completed_tt = (time_t) 0 , dueby_tt = (time_t) 0; /* follow-up flags */ followup = camel_message_info_user_tag (create_data->info, "follow-up"); completed = camel_message_info_user_tag (create_data->info, "completed-on"); dueby = camel_message_info_user_tag (create_data->info, "due-by"); if (followup && !*followup) followup = NULL; if (completed && *completed) completed_tt = camel_header_decode_date (completed, NULL); if (dueby && *dueby) dueby_tt = camel_header_decode_date (dueby, NULL); /* PidTagFlagStatus */ e_ews_message_add_extended_property_tag_int (msg, 0x1090, followup ? (completed_tt != (time_t) 0 ? 0x01 /* followupComplete */: 0x02 /* followupFlagged */) : 0x0); if (followup) { /* PidLidFlagRequest */ e_ews_message_add_extended_property_distinguished_tag_string (msg, "Common", 0x8530, followup); /* PidTagToDoItemFlags */ e_ews_message_add_extended_property_tag_int (msg, 0x0e2b, 1); } if (followup && completed_tt != (time_t) 0) { /* minute precision */ completed_tt = completed_tt - (completed_tt % 60); /* PidTagFlagCompleteTime */ e_ews_message_add_extended_property_tag_time (msg, 0x1091, completed_tt); /* PidLidTaskDateCompleted */ e_ews_message_add_extended_property_distinguished_tag_time (msg, "Task", 0x810f, completed_tt); /* PidLidTaskStatus */ e_ews_message_add_extended_property_distinguished_tag_int (msg, "Task", 0x8101, 2); /* PidLidPercentComplete */ e_ews_message_add_extended_property_distinguished_tag_double (msg, "Task", 0x8102, 1.0); /* PidLidTaskComplete */ e_ews_message_add_extended_property_distinguished_tag_boolean (msg, "Task", 0x811c, TRUE); } if (followup && dueby_tt != (time_t) 0 && completed_tt == (time_t) 0) { /* PidLidTaskStatus */ e_ews_message_add_extended_property_distinguished_tag_int (msg, "Task", 0x8101, 0); /* PidLidPercentComplete */ e_ews_message_add_extended_property_distinguished_tag_double (msg, "Task", 0x8102, 0.0); /* PidLidTaskDueDate */ e_ews_message_add_extended_property_distinguished_tag_time (msg, "Task", 0x8105, dueby_tt); /* PidLidTaskComplete */ e_ews_message_add_extended_property_distinguished_tag_boolean (msg, "Task", 0x811c, FALSE); } } if (create_data->recipients) { GHashTable *recip_to, *recip_cc, *recip_bcc; recip_to = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); recip_cc = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); recip_bcc = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); filter_recipients (create_data->message, create_data->recipients, recip_to, recip_cc, recip_bcc); write_recipients (msg, "ToRecipients", recip_to); write_recipients (msg, "CcRecipients", recip_cc); write_recipients (msg, "BccRecipients", recip_bcc); g_hash_table_destroy (recip_to); g_hash_table_destroy (recip_cc); g_hash_table_destroy (recip_bcc); } e_ews_message_write_string_parameter_with_attribute ( msg, "IsRead", NULL, (message_camel_flags & CAMEL_MESSAGE_SEEN) != 0 ? "true" : "false", NULL, NULL); e_soap_message_end_element (msg); /* Message */ g_free (create_data); }
static gboolean nntp_folder_append_message_sync (CamelFolder *folder, CamelMimeMessage *message, CamelMessageInfo *info, gchar **appended_uid, GCancellable *cancellable, GError **error) { CamelStore *parent_store; CamelNNTPStore *nntp_store; CamelNNTPStream *nntp_stream = NULL; CamelStream *filtered_stream; CamelMimeFilter *crlffilter; gint ret; guint u; struct _camel_header_raw *header, *savedhdrs, *n, *tail; const gchar *full_name; gchar *group, *line; gboolean success = TRUE; GError *local_error = NULL; full_name = camel_folder_get_full_name (folder); parent_store = camel_folder_get_parent_store (folder); nntp_store = CAMEL_NNTP_STORE (parent_store); /* send 'POST' command */ ret = camel_nntp_command ( nntp_store, cancellable, error, NULL, &line, "post"); if (ret != 340) { if (ret == 440) { g_set_error ( error, CAMEL_FOLDER_ERROR, CAMEL_FOLDER_ERROR_INSUFFICIENT_PERMISSION, _("Posting failed: %s"), line); success = FALSE; } else if (ret != -1) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Posting failed: %s"), line); success = FALSE; } goto exit; } /* the 'Newsgroups: ' header */ group = g_strdup_printf ("Newsgroups: %s\r\n", full_name); /* remove mail 'To', 'CC', and 'BCC' headers */ savedhdrs = NULL; tail = (struct _camel_header_raw *) &savedhdrs; header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers; n = header->next; while (n != NULL) { if (!g_ascii_strcasecmp (n->name, "To") || !g_ascii_strcasecmp (n->name, "Cc") || !g_ascii_strcasecmp (n->name, "Bcc")) { header->next = n->next; tail->next = n; n->next = NULL; tail = n; } else { header = n; } n = header->next; } nntp_stream = camel_nntp_store_ref_stream (nntp_store); /* setup stream filtering */ filtered_stream = camel_stream_filter_new (CAMEL_STREAM (nntp_stream)); crlffilter = camel_mime_filter_crlf_new ( CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS); camel_stream_filter_add ( CAMEL_STREAM_FILTER (filtered_stream), crlffilter); g_object_unref (crlffilter); /* write the message */ if (local_error == NULL) camel_stream_write ( CAMEL_STREAM (nntp_stream), group, strlen (group), cancellable, &local_error); if (local_error == NULL) camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (message), filtered_stream, cancellable, &local_error); if (local_error == NULL) camel_stream_flush ( filtered_stream, cancellable, &local_error); if (local_error == NULL) camel_stream_write ( CAMEL_STREAM (nntp_stream), "\r\n.\r\n", 5, cancellable, &local_error); if (local_error == NULL) camel_nntp_stream_line ( nntp_stream, (guchar **) &line, &u, cancellable, &local_error); if (local_error == NULL && atoi (line) != 240) local_error = g_error_new_literal ( CAMEL_ERROR, CAMEL_ERROR_GENERIC, line); if (local_error != NULL) { g_propagate_prefixed_error ( error, local_error, _("Posting failed: ")); success = FALSE; } g_object_unref (filtered_stream); g_free (group); header->next = savedhdrs; exit: g_clear_object (&nntp_stream); return success; }
static void nntp_folder_append_message_online (CamelFolder *folder, CamelMimeMessage *mime_message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex) { CamelNNTPStore *nntp_store = (CamelNNTPStore *) folder->parent_store; CamelStream *stream = (CamelStream*)nntp_store->stream; CamelStreamFilter *filtered_stream; CamelMimeFilter *crlffilter; int ret; unsigned int u; struct _camel_header_raw *header, *savedhdrs, *n, *tail; char *group, *line; CAMEL_SERVICE_REC_LOCK(nntp_store, connect_lock); /* send 'POST' command */ ret = camel_nntp_command (nntp_store, ex, NULL, &line, "post"); if (ret != 340) { if (ret == 440) camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, _("Posting failed: %s"), line); else if (ret != -1) camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), line); CAMEL_SERVICE_REC_UNLOCK(nntp_store, connect_lock); return; } /* the 'Newsgroups: ' header */ group = g_strdup_printf ("Newsgroups: %s\r\n", folder->full_name); /* setup stream filtering */ crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS); filtered_stream = camel_stream_filter_new_with_stream (stream); camel_stream_filter_add (filtered_stream, crlffilter); camel_object_unref (crlffilter); /* remove mail 'To', 'CC', and 'BCC' headers */ savedhdrs = NULL; tail = (struct _camel_header_raw *) &savedhdrs; header = (struct _camel_header_raw *) &CAMEL_MIME_PART (mime_message)->headers; n = header->next; while (n != NULL) { if (!g_ascii_strcasecmp (n->name, "To") || !g_ascii_strcasecmp (n->name, "Cc") || !g_ascii_strcasecmp (n->name, "Bcc")) { header->next = n->next; tail->next = n; n->next = NULL; tail = n; } else { header = n; } n = header->next; } /* write the message */ if (camel_stream_write(stream, group, strlen(group)) == -1 || camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (mime_message), CAMEL_STREAM (filtered_stream)) == -1 || camel_stream_flush (CAMEL_STREAM (filtered_stream)) == -1 || camel_stream_write (stream, "\r\n.\r\n", 5) == -1 || (ret = camel_nntp_stream_line (nntp_store->stream, (unsigned char **)&line, &u)) == -1) { if (errno == EINTR) camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled")); else camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), g_strerror (errno)); } else if (atoi(line) != 240) { camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), line); } camel_object_unref (filtered_stream); g_free(group); header->next = savedhdrs; CAMEL_SERVICE_REC_UNLOCK(nntp_store, connect_lock); return; }
/* this is MIME specific, doesn't belong here really */ static gssize multipart_write_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelMultipart *multipart = CAMEL_MULTIPART (data_wrapper); const gchar *boundary; GList *node; gchar *content; gssize total = 0; gssize count; /* get the bundary text */ boundary = camel_multipart_get_boundary (multipart); /* we cannot write a multipart without a boundary string */ g_return_val_if_fail (boundary, -1); /* * write the preface text (usually something like * "This is a mime message, if you see this, then * your mail client probably doesn't support ...." */ if (multipart->preface) { count = camel_stream_write_string ( stream, multipart->preface, cancellable, error); if (count == -1) return -1; total += count; } /* * Now, write all the parts, separated by the boundary * delimiter */ node = multipart->parts; while (node) { content = g_strdup_printf ("\n--%s\n", boundary); count = camel_stream_write_string ( stream, content, cancellable, error); g_free (content); if (count == -1) return -1; total += count; count = camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (node->data), stream, cancellable, error); if (count == -1) return -1; total += count; node = node->next; } /* write the terminating boudary delimiter */ content = g_strdup_printf ("\n--%s--\n", boundary); count = camel_stream_write_string ( stream, content, cancellable, error); g_free (content); if (count == -1) return -1; total += count; /* and finally the postface */ if (multipart->postface) { count = camel_stream_write_string ( stream, multipart->postface, cancellable, error); if (count == -1) return -1; total += count; } return total; }
static gboolean empe_mp_signed_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelMimePart *cpart = NULL; CamelMultipart *multipart; CamelCipherContext *cipher = NULL; CamelContentType *content_type; CamelSession *session; guint32 validity_type; CamelCipherValidity *valid; const gchar *protocol = NULL; GError *local_error = NULL; gint i, nparts, len; gboolean secured; /* If the part is application/pgp-signature sub-part then skip it. */ if (!CAMEL_IS_MULTIPART (part)) { content_type = camel_mime_part_get_content_type (part); if (camel_content_type_is ( content_type, "application", "pgp-signature")) { return TRUE; } } multipart = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); if (CAMEL_IS_MULTIPART_SIGNED (multipart)) { cpart = camel_multipart_get_part ( multipart, CAMEL_MULTIPART_SIGNED_CONTENT); } if (cpart == NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse MIME message. " "Displaying as source.")); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); return TRUE; } content_type = camel_data_wrapper_get_mime_type_field ( CAMEL_DATA_WRAPPER (multipart)); if (content_type != NULL) protocol = camel_content_type_param (content_type, "protocol"); session = e_mail_parser_get_session (parser); /* FIXME: Should be done via a plugin interface */ /* FIXME: duplicated in em-format-html-display.c */ if (protocol != NULL) { #ifdef ENABLE_SMIME if (g_ascii_strcasecmp ("application/x-pkcs7-signature", protocol) == 0 || g_ascii_strcasecmp ("application/pkcs7-signature", protocol) == 0) { cipher = camel_smime_context_new (session); validity_type = E_MAIL_PART_VALIDITY_SMIME; } else { #endif if (g_ascii_strcasecmp ("application/pgp-signature", protocol) == 0) { cipher = camel_gpg_context_new (session); validity_type = E_MAIL_PART_VALIDITY_PGP; } #ifdef ENABLE_SMIME } #endif } if (cipher == NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Unsupported signature format")); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); return TRUE; } valid = camel_cipher_context_verify_sync ( cipher, part, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Error verifying signature: %s"), local_error->message); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); g_object_unref (cipher); g_error_free (local_error); return TRUE; } nparts = camel_multipart_get_number (multipart); secured = FALSE; len = part_id->len; for (i = 0; i < nparts; i++) { GQueue work_queue = G_QUEUE_INIT; GList *head, *link; CamelMimePart *subpart; subpart = camel_multipart_get_part (multipart, i); g_string_append_printf (part_id, ".signed.%d", i); g_warn_if_fail (e_mail_parser_parse_part ( parser, subpart, part_id, cancellable, &work_queue)); g_string_truncate (part_id, len); if (!secured) secured = e_mail_part_is_secured (subpart); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, validity_type | E_MAIL_PART_VALIDITY_SIGNED); } e_queue_transfer (&work_queue, out_mail_parts); } /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself. */ if (!secured) { GQueue work_queue = G_QUEUE_INIT; EMailPart *mail_part; g_string_append (part_id, ".signed.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, validity_type | E_MAIL_PART_VALIDITY_SIGNED); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } camel_cipher_validity_free (valid); g_object_unref (cipher); return TRUE; }
static gint multipart_signed_parse_content (CamelMultipartSigned *mps) { CamelMimeParser *cmp; CamelMultipart *mp = (CamelMultipart *) mps; CamelDataWrapper *data_wrapper; GByteArray *byte_array; CamelStream *stream; const gchar *boundary; gchar *buf; gsize len; gint state; boundary = camel_multipart_get_boundary (mp); g_return_val_if_fail (boundary != NULL, -1); data_wrapper = CAMEL_DATA_WRAPPER (mps); byte_array = camel_data_wrapper_get_byte_array (data_wrapper); stream = camel_stream_mem_new (); /* Do not give the stream ownership of the byte array. */ camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (stream), byte_array); /* This is all seriously complex. * This is so we can parse all cases properly, without altering the content. * All we are doing is finding part offsets. */ cmp = camel_mime_parser_new (); camel_mime_parser_init_with_stream (cmp, stream, NULL); camel_mime_parser_push_state (cmp, CAMEL_MIME_PARSER_STATE_MULTIPART, boundary); mps->start1 = -1; mps->end1 = -1; mps->start2 = -1; mps->end2 = -1; while ((state = camel_mime_parser_step (cmp, &buf, &len)) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) { if (mps->start1 == -1) { mps->start1 = camel_mime_parser_tell_start_headers (cmp); } else if (mps->start2 == -1) { mps->start2 = camel_mime_parser_tell_start_headers (cmp); mps->end1 = camel_mime_parser_tell_start_boundary (cmp); if (mps->end1 > mps->start1 && byte_array->data[mps->end1 - 1] == '\n') mps->end1--; if (mps->end1 > mps->start1 && byte_array->data[mps->end1 - 1] == '\r') mps->end1--; } else { g_warning ("multipart/signed has more than 2 parts, remaining parts ignored"); state = CAMEL_MIME_PARSER_STATE_MULTIPART_END; break; } if (multipart_signed_skip_content (cmp) == -1) break; } if (state == CAMEL_MIME_PARSER_STATE_MULTIPART_END) { mps->end2 = camel_mime_parser_tell_start_boundary (cmp); camel_multipart_set_preface (mp, camel_mime_parser_preface (cmp)); camel_multipart_set_postface (mp, camel_mime_parser_postface (cmp)); } g_object_unref (cmp); g_object_unref (stream); if (mps->end2 == -1 || mps->start2 == -1) { if (mps->end1 == -1) mps->start1 = -1; return -1; } return 0; }
gint main (gint argc, gchar **argv) { CamelService *service; CamelSession *session; CamelStore *store; CamelFolder *folder; CamelMimeMessage *msg; gint i, j; CamelStream *mbox; CamelFilterDriver *driver; GError *error = NULL; camel_test_init (argc, argv); camel_test_provider_init (1, local_drivers); /* clear out any camel-test data */ system ("/bin/rm -rf /tmp/camel-test"); camel_test_start ("Simple filtering of mbox"); session = camel_test_session_new ("/tmp/camel-test"); /* todo: cross-check everything with folder_info checks as well */ /* todo: work out how to do imap/pop/nntp tests */ push ("getting store"); service = camel_session_add_service ( session, "test-uid", "mbox:///tmp/camel-test/mbox", CAMEL_PROVIDER_STORE, &error); check_msg (error == NULL, "getting store: %s", error->message); check (CAMEL_IS_STORE (service)); store = CAMEL_STORE (service); g_clear_error (&error); pull (); push ("Creating output folders"); for (i = 0; i < G_N_ELEMENTS (mailboxes); i++) { push ("creating %s", mailboxes[i].name); mailboxes[i].folder = folder = camel_store_get_folder_sync ( store, mailboxes[i].name, CAMEL_STORE_FOLDER_CREATE, NULL, &error); check_msg (error == NULL, "%s", error->message); check (folder != NULL); /* we need an empty folder for this to work */ test_folder_counts (folder, 0, 0); g_clear_error (&error); pull (); } pull (); /* append a bunch of messages with specific content */ push ("creating 100 test message mbox"); mbox = camel_stream_fs_new_with_name ("/tmp/camel-test/inbox", O_WRONLY|O_CREAT|O_EXCL, 0600, NULL); for (j = 0; j < 100; j++) { gchar *content, *subject; push ("creating test message"); msg = test_message_create_simple (); content = g_strdup_printf ("data%d content\n", j); test_message_set_content_simple ((CamelMimePart *)msg, 0, "text/plain", content, strlen (content)); test_free (content); subject = g_strdup_printf ("Test%d message%d subject", j, 100-j); camel_mime_message_set_subject (msg, subject); camel_mime_message_set_date (msg, j * 60 * 24, 0); pull (); camel_stream_write_string (mbox, "From \n", NULL, NULL); check (camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (msg), mbox, NULL, NULL) != -1); #if 0 push ("appending simple message %d", j); camel_folder_append_message (folder, msg, NULL, ex); check_msg (error == NULL, "%s", error->message); g_clear_error (&error); pull (); #endif test_free (subject); check_unref (msg, 1); } check (camel_stream_close (mbox, NULL, NULL) != -1); check_unref (mbox, 1); pull (); push ("Building filters"); driver = camel_filter_driver_new (session); camel_filter_driver_set_folder_func (driver, get_folder, NULL); for (i = 0; i < G_N_ELEMENTS (rules); i++) { camel_filter_driver_add_rule (driver, rules[i].name, rules[i].match, rules[i].action); } pull (); push ("Executing filters"); camel_filter_driver_set_default_folder (driver, mailboxes[0].folder); #if 0 /* FIXME We no longer filter mbox files. */ camel_filter_driver_filter_mbox ( driver, "/tmp/camel-test/inbox", NULL, NULL, &error); #endif check_msg (error == NULL, "%s", error->message); /* now need to check the folder counts/etc */ check_unref (driver, 1); g_clear_error (&error); pull (); /* this tests that invalid rules are caught */ push ("Testing broken match rules"); for (i = 0; i < G_N_ELEMENTS (brokens); i++) { push ("rule %s", brokens[i].match); driver = camel_filter_driver_new (session); camel_filter_driver_set_folder_func (driver, get_folder, NULL); camel_filter_driver_add_rule (driver, brokens[i].name, brokens[i].match, brokens[i].action); #if 0 /* FIXME We no longer filter mbox files. */ camel_filter_driver_filter_mbox ( driver, "/tmp/camel-test/inbox", NULL, NULL, &error); #endif check (error != NULL); check_unref (driver, 1); g_clear_error (&error); pull (); } pull (); push ("Testing broken action rules"); for (i = 0; i < G_N_ELEMENTS (brokena); i++) { push ("rule %s", brokena[i].action); driver = camel_filter_driver_new (session); camel_filter_driver_set_folder_func (driver, get_folder, NULL); camel_filter_driver_add_rule (driver, brokena[i].name, brokena[i].match, brokena[i].action); #if 0 /* FIXME We no longer filter mbox files. */ camel_filter_driver_filter_mbox ( driver, "/tmp/camel-test/inbox", NULL, NULL, &error); #endif check (error != NULL); check_unref (driver, 1); g_clear_error (&error); pull (); } pull (); for (i = 0; i < G_N_ELEMENTS (mailboxes); i++) { check_unref (mailboxes[i].folder, 1); } check_unref (store, 1); check_unref (session, 1); camel_test_end (); return 0; }
static gssize multipart_signed_write_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelMultipartSigned *mps = (CamelMultipartSigned *) data_wrapper; CamelMultipart *mp = (CamelMultipart *) mps; GByteArray *byte_array; const gchar *boundary; gssize total = 0; gssize count; gchar *content; byte_array = camel_data_wrapper_get_byte_array (data_wrapper); /* we have 3 basic cases: * 1. constructed, we write out the data wrapper stream we got * 2. signed content, we create and write out a new stream * 3. invalid */ /* 1 */ /* FIXME: locking? */ if (byte_array->len > 0) { return camel_stream_write ( stream, (gchar *) byte_array->data, byte_array->len, cancellable, error); } /* 3 */ if (mps->contentraw == NULL) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("No content available")); return -1; } /* 3 */ if (mps->signature == NULL) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("No signature available")); return -1; } /* 2 */ boundary = camel_multipart_get_boundary (mp); if (mp->preface) { count = camel_stream_write_string ( stream, mp->preface, cancellable, error); if (count == -1) return -1; total += count; } /* first boundary */ content = g_strdup_printf ("\n--%s\n", boundary); count = camel_stream_write_string ( stream, content, cancellable, error); g_free (content); if (count == -1) return -1; total += count; /* output content part */ /* XXX Both CamelGpgContext and CamelSMIMEContext set this * to a memory stream, so assume it's always seekable. */ g_seekable_seek ( G_SEEKABLE (mps->contentraw), 0, G_SEEK_SET, NULL, NULL); count = camel_stream_write_to_stream ( mps->contentraw, stream, cancellable, error); if (count == -1) return -1; total += count; /* boundary */ content = g_strdup_printf ("\n--%s\n", boundary); count = camel_stream_write_string ( stream, content, cancellable, error); g_free (content); if (count == -1) return -1; total += count; /* signature */ count = camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (mps->signature), stream, cancellable, error); if (count == -1) return -1; total += count; /* write the terminating boudary delimiter */ content = g_strdup_printf ("\n--%s--\n", boundary); count = camel_stream_write_string ( stream, content, cancellable, error); g_free (content); if (count == -1) return -1; total += count; /* and finally the postface */ if (mp->postface) { count = camel_stream_write_string ( stream, mp->postface, cancellable, error); if (count == -1) return -1; total += count; } return total; }
static gboolean empe_inlinepgp_encrypted_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelCipherContext *cipher; CamelCipherValidity *valid; CamelMimePart *opart; CamelDataWrapper *dw; gchar *mime_type; gint len; GQueue work_queue = G_QUEUE_INIT; GList *head, *link; GError *local_error = NULL; if (g_cancellable_is_cancelled (cancellable)) return FALSE; cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); opart = camel_mime_part_new (); /* Decrypt the message */ valid = camel_cipher_context_decrypt_sync ( cipher, part, opart, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse PGP message: %s"), local_error->message); g_error_free (local_error); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); g_object_unref (cipher); g_object_unref (opart); return TRUE; } dw = camel_medium_get_content ((CamelMedium *) opart); mime_type = camel_data_wrapper_get_mime_type (dw); /* this ensures to show the 'opart' as inlined, if possible */ if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) { const gchar *snoop; snoop = e_mail_part_snoop_type (opart); if (snoop != NULL) { camel_data_wrapper_set_mime_type (dw, snoop); /* Set the MIME type on the 'opart' itself as well. * If it's "text/plain", then we want the TextPlain * parser extension to treat it as "text/plain" and * NOT wrap it as an attachment. */ camel_data_wrapper_set_mime_type ( CAMEL_DATA_WRAPPER (opart), snoop); } } e_mail_part_preserve_charset_in_content_type (part, opart); g_free (mime_type); /* Pass it off to the real formatter */ len = part_id->len; g_string_append (part_id, ".inlinepgp_encrypted"); g_warn_if_fail (e_mail_parser_parse_part_as ( parser, opart, part_id, camel_data_wrapper_get_mime_type (dw), cancellable, &work_queue)); g_string_truncate (part_id, len); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); } e_queue_transfer (&work_queue, out_mail_parts); /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself */ if (!e_mail_part_is_secured (opart)) { EMailPart *mail_part; g_string_append (part_id, ".inlinepgp_encrypted.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } /* Clean Up */ camel_cipher_validity_free (valid); g_object_unref (opart); g_object_unref (cipher); return TRUE; }
static CamelMimePart * multipart_signed_get_part (CamelMultipart *multipart, guint index) { CamelMultipartSigned *mps = (CamelMultipartSigned *) multipart; CamelDataWrapper *data_wrapper; CamelStream *stream; GByteArray *byte_array; data_wrapper = CAMEL_DATA_WRAPPER (multipart); byte_array = camel_data_wrapper_get_byte_array (data_wrapper); switch (index) { case CAMEL_MULTIPART_SIGNED_CONTENT: if (mps->content) return mps->content; if (mps->contentraw) { g_return_val_if_fail ( G_IS_SEEKABLE (mps->contentraw), NULL); stream = g_object_ref (mps->contentraw); } else if (mps->start1 == -1 && multipart_signed_parse_content (mps) == -1 && byte_array->len == 0) { g_warning ("Trying to get content on an invalid multipart/signed"); return NULL; } else if (byte_array->len == 0) { return NULL; } else if (mps->start1 == -1) { stream = camel_stream_mem_new (); camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (stream), byte_array); } else { stream = multipart_signed_clip_stream ( mps, mps->start1, mps->end1); } g_seekable_seek ( G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); mps->content = camel_mime_part_new (); camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (mps->content), stream, NULL, NULL); g_object_unref (stream); return mps->content; case CAMEL_MULTIPART_SIGNED_SIGNATURE: if (mps->signature) return mps->signature; if (mps->start1 == -1 && multipart_signed_parse_content (mps) == -1) { g_warning ("Trying to get signature on invalid multipart/signed"); return NULL; } else if (byte_array->len == 0) { return NULL; } stream = multipart_signed_clip_stream ( mps, mps->start2, mps->end2); g_seekable_seek ( G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); mps->signature = camel_mime_part_new (); camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (mps->signature), stream, NULL, NULL); g_object_unref (stream); return mps->signature; default: g_warning ("trying to get object out of bounds for multipart"); } return NULL; }
static gint run_command (struct _CamelSExp *f, gint argc, struct _CamelSExpResult **argv, FilterMessageSearch *fms) { CamelMimeMessage *message; CamelStream *stream; gint i; gint pipe_to_child; GPid child_pid; GError *error = NULL; GPtrArray *args; child_watch_data_t child_watch_data; GSource *source; GMainContext *context; if (argc < 1 || argv[0]->value.string[0] == '\0') return 0; args = g_ptr_array_new (); for (i = 0; i < argc; i++) g_ptr_array_add (args, argv[i]->value.string); g_ptr_array_add (args, NULL); if (!g_spawn_async_with_pipes (NULL, (gchar **) args->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, child_setup_func, NULL, &child_pid, &pipe_to_child, NULL, NULL, &error)) { g_ptr_array_free (args, TRUE); g_set_error ( fms->error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Failed to create child process '%s': %s"), argv[0]->value.string, error->message); g_error_free (error); return -1; } g_ptr_array_free (args, TRUE); message = camel_filter_search_get_message (fms, f); stream = camel_stream_fs_new_with_fd (pipe_to_child); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (message), stream, NULL, NULL); camel_stream_flush (stream, NULL, NULL); g_object_unref (stream); context = g_main_context_new (); child_watch_data.loop = g_main_loop_new (context, FALSE); g_main_context_unref (context); source = g_child_watch_source_new (child_pid); g_source_set_callback (source, (GSourceFunc) child_watch, &child_watch_data, NULL); g_source_attach (source, g_main_loop_get_context (child_watch_data.loop)); g_source_unref (source); g_main_loop_run (child_watch_data.loop); g_main_loop_unref (child_watch_data.loop); #ifndef G_OS_WIN32 if (WIFEXITED (child_watch_data.child_status)) return WEXITSTATUS (child_watch_data.child_status); else return -1; #else return child_watch_data.child_status; #endif }
gboolean e_composer_autosave_snapshot (EMsgComposer *composer) { GtkhtmlEditor *editor; CamelMimeMessage *message; AutosaveState *state; CamelStream *stream; gint camelfd; const gchar *errmsg; g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), FALSE); editor = GTKHTML_EDITOR (composer); /* If the contents are unchanged, exit early. */ if (!gtkhtml_editor_get_changed (editor)) return TRUE; state = g_object_get_data (G_OBJECT (composer), "autosave"); g_return_val_if_fail (state != NULL, FALSE); /* Open the autosave file on-demand. */ if (!composer_autosave_state_open (state, NULL)) { errmsg = _("Could not open autosave file"); goto fail; } /* Extract a MIME message from the composer. */ message = e_msg_composer_get_message_draft (composer); if (message == NULL) { errmsg = _("Unable to retrieve message from editor"); goto fail; } /* Move to the beginning of the autosave file. */ if (lseek (state->fd, (off_t) 0, SEEK_SET) < 0) { camel_object_unref (message); errmsg = g_strerror (errno); goto fail; } /* Destroy the contents of the autosave file. */ if (ftruncate (state->fd, (off_t) 0) < 0) { camel_object_unref (message); errmsg = g_strerror (errno); goto fail; } /* Duplicate the file descriptor for Camel. */ if ((camelfd = dup (state->fd)) < 0) { camel_object_unref (message); errmsg = g_strerror (errno); goto fail; } /* Open a CamelStream to the autosave file. */ stream = camel_stream_fs_new_with_fd (camelfd); /* Write the message to the CamelStream. */ if (camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream) < 0) { camel_object_unref (message); camel_object_unref (stream); errmsg = g_strerror (errno); goto fail; } /* Close the CamelStream. */ if (camel_stream_close (CAMEL_STREAM (stream)) < 0) { camel_object_unref (message); camel_object_unref (stream); errmsg = g_strerror (errno); goto fail; } /* Snapshot was successful; set various flags. */ gtkhtml_editor_set_changed (editor, FALSE); e_composer_autosave_set_saved (composer, TRUE); camel_object_unref (message); camel_object_unref (stream); return TRUE; fail: e_error_run ( GTK_WINDOW (composer), "mail-composer:no-autosave", (state->filename != NULL) ? state->filename : "", errmsg, NULL); return FALSE; }