diff options
Diffstat (limited to 'e-util/e-signature-utils.c')
-rw-r--r-- | e-util/e-signature-utils.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/e-util/e-signature-utils.c b/e-util/e-signature-utils.c index 5565ef9faf..0114ce6e06 100644 --- a/e-util/e-signature-utils.c +++ b/e-util/e-signature-utils.c @@ -29,6 +29,10 @@ #include <camel/camel-mime-filter-charset.h> #include <camel/camel-mime-filter-tohtml.h> +#ifndef G_OS_WIN32 +#include <sys/wait.h> +#endif + #include "e-util/e-util.h" static ESignatureList *global_signature_list; @@ -215,3 +219,129 @@ e_read_signature_file (ESignature *signature, return content; } + +gchar * +e_run_signature_script (const gchar *filename) +{ + /* FIXME Make this cross-platform, prefer GLib functions over + * POSIX, and report errors via GError instead of dumping + * messages to the terminal where users won't see them. */ + +#ifndef G_OS_WIN32 + gint in_fds[2]; + pid_t pid; + + g_return_val_if_fail (filename != NULL, NULL); + + if (pipe (in_fds) == -1) { + g_warning ( + "Failed to create pipe to '%s': %s", + filename, g_strerror (errno)); + return NULL; + } + + pid = fork (); + + /* Child Process */ + if (pid == 0) { + gint maxfd, ii; + + close (in_fds[0]); + if (dup2 (in_fds[1], STDOUT_FILENO) < 0) + _exit (255); + close (in_fds[1]); + + setsid (); + + maxfd = sysconf (_SC_OPEN_MAX); + for (ii = 3; ii < maxfd; ii++) { + if (ii == STDIN_FILENO) + continue; + if (ii == STDOUT_FILENO) + continue; + if (ii == STDERR_FILENO) + continue; + fcntl (ii, F_SETFD, FD_CLOEXEC); + } + + execlp ("/bin/sh", "/bin/sh", "-c", filename, NULL); + + g_warning ( + "Could not execute '%s': %s", + filename, g_strerror (errno)); + + _exit (255); + + /* Parent Process */ + } else if (pid > 0) { + CamelStream *output_stream; + CamelStream *input_stream; + GByteArray *buffer; + gchar *content; + gsize length; + gint result; + gint status; + + close (in_fds[1]); + + buffer = g_byte_array_new (); + output_stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array ( + CAMEL_STREAM_MEM (output_stream), buffer); + + input_stream = camel_stream_fs_new_with_fd (in_fds[0]); + camel_stream_write_to_stream (input_stream, output_stream); + camel_object_unref (input_stream); + + camel_object_unref (output_stream); + + /* Make sure the buffer is nul-terminated. */ + length = (gsize) buffer->len; + g_byte_array_append (buffer, (guchar *) "", 1); + content = (gchar *) g_byte_array_free (buffer, FALSE); + + /* Signature scripts are supposed to generate UTF-8 content, + * but because users are known to never read the manual, we + * try to do our best if the content isn't valid UTF-8 by + * assuming that the content is in the user's locale + * character set. */ + if (!g_utf8_validate (content, length, NULL)) { + gchar *utf8; + + /* XXX Should pass a GError here. */ + utf8 = g_locale_to_utf8 ( + content, length, NULL, NULL, NULL); + g_free (content); + content = utf8; + } + + /* Wait for the script process to terminate. */ + result = waitpid (pid, &status, 0); + + 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); + } + } + + return content; + + /* Forking Failed */ + } else { + g_warning ( + "Failed to create child process '%s': %s", + filename, g_strerror (errno)); + close (in_fds[0]); + close (in_fds[1]); + } +#endif + + return NULL; +} |