static CamelStream * insert_setup (CamelImapMessageCache *cache, const char *uid, const char *part_spec, char **path, char **key, CamelException *ex) { CamelStream *stream; int fd; #ifdef G_OS_WIN32 /* Trailing periods in file names are silently dropped on * Win32, argh. The code in this file requires the period to * be there. So in case part_spec is empty, use a tilde (just * a random choice) instead. */ if (!*part_spec) part_spec = "~"; #endif *path = g_strdup_printf ("%s/%s.%s", cache->path, uid, part_spec); *key = strrchr (*path, '/') + 1; stream = g_hash_table_lookup (cache->parts, *key); if (stream) camel_object_unref (CAMEL_OBJECT (stream)); fd = g_open (*path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0600); if (fd == -1) { camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to cache message %s: %s"), uid, g_strerror (errno)); g_free (*path); return NULL; } return camel_stream_fs_new_with_fd (fd); }
gint main (gint argc, gchar **argv) { struct dirent *dent; DIR *dir; gint fd; camel_test_init (argc, argv); camel_test_start ("Message Test Suite"); if (!(dir = opendir ("../data/messages"))) return 77; while ((dent = readdir (dir)) != NULL) { CamelMimeMessage *message; CamelStream *stream; gchar *filename; struct stat st; if (dent->d_name[0] == '.') continue; filename = g_strdup_printf ("../data/messages/%s", dent->d_name); if (g_stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { g_free (filename); continue; } if ((fd = open (filename, O_RDONLY)) == -1) { g_free (filename); continue; } push ("testing message '%s'", filename); g_free (filename); stream = camel_stream_fs_new_with_fd (fd); message = camel_mime_message_new (); camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (message), stream, NULL, NULL); g_seekable_seek ( G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); /*dump_mime_struct ((CamelMimePart *) message, 0);*/ test_message_compare (message); g_object_unref (message); g_object_unref (stream); pull (); } closedir (dir); camel_test_end (); return 0; }
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 }
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 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; }
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; }