diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-08-11 08:35:06 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-08-11 08:35:06 +0000 |
commit | 9fdb4e5af89a211bc6d05f8c64b4051b174c7855 (patch) | |
tree | d63fe24be793c1dddb5184de01a4160f139ff63d /mail/escape.c | |
parent | effde3f568bd21ecd4f08c086d624cea59c6bd90 (diff) | |
download | mailutils-9fdb4e5af89a211bc6d05f8c64b4051b174c7855.tar.gz mailutils-9fdb4e5af89a211bc6d05f8c64b4051b174c7855.tar.bz2 |
Renamed mail/var.c to mail/escape.c to fix a long-standing historical
inconsistency.
(var_shell,var_command,var_help,var_sign,var_bcc)
(var_cc,var_deadletter,var_editor,var_print,var_headers)
(var_insert,var_quote,var_type_input,var_read,var_subj)
(var_to,var_visual,var_write,var_exit,var_pipe): Renamed:
s/var_/escape_/. All callers updated
Diffstat (limited to 'mail/escape.c')
-rw-r--r-- | mail/escape.c | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/mail/escape.c b/mail/escape.c new file mode 100644 index 000000000..6987fd96b --- /dev/null +++ b/mail/escape.c @@ -0,0 +1,761 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2001, 2002, 2005 Free Software Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Mailutils is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA */ + +/* Functions for handling escape variables */ + +#include "mail.h" +#include <sys/stat.h> + +static void +dump_headers (FILE *fp, compose_env_t *env) +{ + char buffer[512]; + stream_t stream = NULL; + size_t off = 0, n; + + header_get_stream (env->header, &stream); + while (stream_read (stream, buffer, sizeof buffer - 1, off, &n) == 0 + && n != 0) + { + buffer[n] = 0; + fprintf (fp, "%s", buffer); + off += n; + } +} + +#define STATE_INIT 0 +#define STATE_READ 1 +#define STATE_BODY 2 + +static int +parse_headers (FILE *fp, compose_env_t *env) +{ + int status; + header_t header; + char *name = NULL; + char *value = NULL; + char *buf = NULL; + int state = STATE_INIT; + size_t n = 0; + int errcnt = 0, line = 0; + + if ((status = header_create (&header, NULL, 0, NULL)) != 0) + { + util_error (_("Cannot create header: %s"), mu_strerror (status)); + return 1; + } + + while (state != STATE_BODY + && errcnt == 0 && getline (&buf, &n, fp) > 0 && n > 0) + { + int len = strlen (buf); + if (len > 0 && buf[len-1] == '\n') + buf[len-1] = 0; + + line++; + switch (state) + { + case STATE_INIT: + if (!buf[0] || isspace (buf[0])) + continue; + else + state = STATE_READ; + /*FALLTHRU*/ + + case STATE_READ: + if (buf[0] == 0) + state = STATE_BODY; + else if (isspace (buf[0])) + { + /* A continuation line */ + if (name) + { + char *p = NULL; + asprintf (&p, "%s\n%s", value, buf); + free (value); + value = p; + } + else + { + util_error (_("%d: not a header line"), line); + errcnt++; + } + } + else + { + char *p; + + if (name) + { + header_set_value (header, name, value[0] ? value : NULL, 0); + free (name); + free (value); + name = value = NULL; + } + p = strchr (buf, ':'); + if (p) + { + *p++ = 0; + while (*p && isspace(*p)) + p++; + value = strdup (p); + name = strdup (buf); + } + else + { + util_error (_("%d: not a header line"), line); + errcnt++; + } + } + break; + } + } + + free (buf); + if (name) + { + header_set_value (header, name, value, 0); + free (name); + free (value); + } + + if (errcnt) + { + char *p; + + header_destroy (&header, NULL); + p = ml_readline (_("Edit again?")); + if (mu_true_answer_p (p) == 1) + return -1; + else + return 1; + } + + header_destroy (&env->header, NULL); + env->header = header; + return 0; +} + +static void +escape_continue (void) +{ + fprintf (stdout, _("(continue)\n")); +} + +static int +escape_check_args (int argc, char **argv) +{ + if (argc == 1) + { + char *escape = "~"; + util_getenv (&escape, "escape", Mail_env_string, 0); + util_error (_("%c%s requires an argument"), escape[0], argv[0]); + return 1; + } + return 0; +} + +/* ~![shell-command] */ +int +escape_shell (int argc, char **argv, compose_env_t *env) +{ + int status; + ofile = env->ofile; + ++*argv; + status = mail_execute (1, argc, argv); + ofile = env->file; + return status; +} + +/* ~:[mail-command] */ +/* ~-[mail-command] */ +int +escape_command (int argc, char **argv, compose_env_t *env) +{ + struct mail_command_entry *entry; + int status; + + if (escape_check_args (argc, argv)) + return 1; + if (argv[1][0] == '#') + return 0; + entry = mail_find_command (argv[1]); + if (!entry) + { + util_error (_("Unknown command: %s"), argv[1]); + return 1; + } + if (entry->flags & (EF_FLOW | EF_SEND)) + { + util_error (_("Command not allowed in an escape sequence\n")); + return 1; + } + + ofile = env->ofile; + status = (*entry->func) (argc - 1, argv + 1); + ofile = env->file; + return status; +} + +/* ~? */ +int +escape_help (int argc, char **argv, compose_env_t *env ARG_UNUSED) +{ + int status; + if (argc < 2) + status = mail_escape_help (NULL); + else + while (--argc) + status |= mail_escape_help (*++argv); + escape_continue (); + return status; +} + +/* ~A */ +/* ~a */ +int +escape_sign (int argc ARG_UNUSED, char **argv, compose_env_t *env ARG_UNUSED) +{ + char *p; + + if (util_getenv (&p, isupper (argv[0][0]) ? "Sign" : "sign", + Mail_env_string, 1) == 0) + { + if (isupper (argv[0][0])) + { + char *name = util_fullpath (p); + FILE *fp = fopen (name, "r"); + char *buf = NULL; + size_t n = 0; + + if (!fp) + { + util_error (_("Cannot open %s: %s"), name, strerror (errno)); + free (name); + } + + fprintf (stdout, _("Reading %s\n"), name); + while (getline (&buf, &n, fp) > 0) + fprintf (ofile, "%s", buf); + + fclose (fp); + free (buf); + free (name); + } + else + fprintf (ofile, "%s", p); + escape_continue (); + } + return 0; +} + +/* ~b[bcc-list] */ +int +escape_bcc (int argc, char **argv, compose_env_t *env) +{ + while (--argc) + compose_header_set (env, MU_HEADER_BCC, *++argv, COMPOSE_SINGLE_LINE); + return 0; +} + +/* ~c[cc-list] */ +int +escape_cc (int argc, char **argv, compose_env_t *env) +{ + while (--argc) + compose_header_set (env, MU_HEADER_CC, *++argv, COMPOSE_SINGLE_LINE); + return 0; +} + +/* ~d */ +int +escape_deadletter (int argc ARG_UNUSED, char **argv ARG_UNUSED, + compose_env_t *env ARG_UNUSED) +{ + FILE *dead = fopen (getenv ("DEAD"), "r"); + int c; + + while ((c = fgetc (dead)) != EOF) + fputc (c, ofile); + fclose (dead); + return 0; +} + +static int +run_editor (char *ed, char *arg) +{ + char *argv[3]; + + argv[0] = ed; + argv[1] = arg; + argv[2] = NULL; + return mail_execute (1, 2, argv); +} + +static int +escape_run_editor (char *ed, int argc, char **argv, compose_env_t *env) +{ + if (!util_getenv (NULL, "editheaders", Mail_env_boolean, 0)) + { + char *filename; + int fd = mu_tempfile (NULL, &filename); + FILE *fp = fdopen (fd, "w+"); + char buffer[512]; + int rc; + + dump_headers (fp, env); + + rewind (env->file); + while (fgets (buffer, sizeof (buffer), env->file)) + fputs (buffer, fp); + + fclose (env->file); + + do + { + fclose (fp); + run_editor (ed, filename); + fp = fopen (filename, "r"); + } + while ((rc = parse_headers (fp, env)) < 0); + + if (rc == 0) + { + env->file = fopen (env->filename, "w"); + while (fgets (buffer, sizeof (buffer), fp)) + fputs (buffer, env->file); + + fclose (env->file); + } + fclose (fp); + unlink (filename); + free (filename); + } + else + { + fclose (env->file); + ofile = env->ofile; + run_editor (ed, env->filename); + } + + env->file = fopen (env->filename, "a+"); + ofile = env->file; + + escape_continue (); + return 0; +} + +/* ~e */ +int +escape_editor (int argc, char **argv, compose_env_t *env) +{ + return escape_run_editor (getenv ("EDITOR"), argc, argv, env); +} + +/* ~v */ +int +escape_visual (int argc, char **argv, compose_env_t *env) +{ + return escape_run_editor (getenv ("VISUAL"), argc, argv, env); +} + +/* ~f[mesg-list] */ +/* ~F[mesg-list] */ +int +escape_print (int argc, char **argv, compose_env_t *env ARG_UNUSED) +{ + return mail_print (argc, argv); +} + +void +reread_header (compose_env_t *env, char *hdr, char *prompt) +{ + char *p; + p = strdup (compose_header_get (env, hdr, "")); + ml_reread (prompt, &p); + compose_header_set (env, hdr, p, COMPOSE_REPLACE); + free (p); +} + +/* ~h */ +int +escape_headers (int argc, char **argv, compose_env_t *env) +{ + reread_header (env, MU_HEADER_TO, "To: "); + reread_header (env, MU_HEADER_CC, "Cc: "); + reread_header (env, MU_HEADER_BCC, "Bcc: "); + reread_header (env, MU_HEADER_SUBJECT, "Subject: "); + escape_continue (); + return 0; +} + +/* ~i[var-name] */ +int +escape_insert (int argc, char **argv, compose_env_t *send_env ARG_UNUSED) +{ + struct mail_env_entry *env; + + if (escape_check_args (argc, argv)) + return 1; + env = util_find_env (argv[1], 0); + if (env) + switch (env->type) + { + case Mail_env_string: + fprintf (ofile, "%s", env->value.string); + break; + + case Mail_env_number: + fprintf (ofile, "%d", env->value.number); + break; + + case Mail_env_boolean: + fprintf (ofile, "%s", env->set ? "yes" : "no"); + break; + + default: + break; + } + return 0; +} + +/* ~m[mesg-list] */ +/* ~M[mesg-list] */ + +int +quote0 (msgset_t *mspec, message_t mesg, void *data) +{ + header_t hdr; + body_t body; + stream_t stream; + char buffer[512]; + off_t off = 0; + size_t n = 0; + char *prefix = "\t"; + + fprintf (stdout, _("Interpolating: %d\n"), mspec->msg_part[0]); + + util_getenv (&prefix, "indentprefix", Mail_env_string, 0); + + if (*(int*)data) + { + size_t i, num = 0; + char buf[512]; + + message_get_header (mesg, &hdr); + header_get_field_count (hdr, &num); + + for (i = 1; i <= num; i++) + { + header_get_field_name (hdr, i, buf, sizeof buf, NULL); + if (mail_header_is_visible (buf)) + { + char *value; + + fprintf (ofile, "%s%s: ", prefix, buf); + if (header_aget_value (hdr, buf, &value) == 0) + { + int i; + char *p, *s; + + for (i = 0, p = strtok_r (value, "\n", &s); p; + p = strtok_r (NULL, "\n", &s), i++) + { + if (i) + fprintf (ofile, "%s", prefix); + fprintf (ofile, "%s\n", p); + } + free (value); + } + } + } + fprintf (ofile, "%s\n", prefix); + message_get_body (mesg, &body); + body_get_stream (body, &stream); + } + else + message_get_stream (mesg, &stream); + + while (stream_readline (stream, buffer, sizeof buffer - 1, off, &n) == 0 + && n != 0) + { + buffer[n] = '\0'; + fprintf (ofile, "%s%s", prefix, buffer); + off += n; + } + return 0; +} + +int +escape_quote (int argc, char **argv, compose_env_t *env) +{ + int lower = islower (argv[0][0]); + util_foreach_msg (argc, argv, MSG_NODELETED|MSG_SILENT, quote0, &lower); + escape_continue (); + return 0; +} + +/* ~p */ +int +escape_type_input (int argc, char **argv, compose_env_t *env) +{ + char buffer[512]; + + fprintf (env->ofile, _("Message contains:\n")); + + dump_headers (env->ofile, env); + + rewind (env->file); + while (fgets (buffer, sizeof (buffer), env->file)) + fputs (buffer, env->ofile); + + escape_continue (); + + return 0; +} + +/* ~r[filename] */ +int +escape_read (int argc, char **argv, compose_env_t *env ARG_UNUSED) +{ + char *filename; + FILE *inf; + size_t size, lines; + char buf[512]; + + if (escape_check_args (argc, argv)) + return 1; + filename = util_fullpath (argv[1]); + inf = fopen (filename, "r"); + if (!inf) + { + util_error (_("Cannot open %s: %s"), filename, strerror (errno)); + free (filename); + return 1; + } + + size = lines = 0; + while (fgets (buf, sizeof (buf), inf)) + { + lines++; + size += strlen (buf); + fputs (buf, ofile); + } + fclose (inf); + fprintf (stdout, "\"%s\" %lu/%lu\n", filename, + (unsigned long) lines, (unsigned long) size); + free (filename); + return 0; +} + +/* ~s[string] */ +int +escape_subj (int argc, char **argv, compose_env_t *env) +{ + if (escape_check_args (argc, argv)) + return 1; + compose_header_set (env, MU_HEADER_SUBJECT, argv[1], COMPOSE_REPLACE); + return 0; +} + +/* ~t[name-list] */ +int +escape_to (int argc, char **argv, compose_env_t *env) +{ + while (--argc) + compose_header_set (env, MU_HEADER_TO, *++argv, COMPOSE_SINGLE_LINE); + return 0; +} + +/* ~w[filename] */ +int +escape_write (int argc, char **argv, compose_env_t *env) +{ + char *filename; + FILE *fp; + size_t size, lines; + char buf[512]; + + if (escape_check_args (argc, argv)) + return 1; + + filename = util_fullpath (argv[1]); + fp = fopen (filename, "w"); /*FIXME: check for the existence first */ + + if (!fp) + { + util_error (_("Cannot open %s: %s"), filename, strerror (errno)); + free (filename); + return 1; + } + + rewind (env->file); + size = lines = 0; + while (fgets (buf, sizeof (buf), env->file)) + { + lines++; + size += strlen (buf); + fputs (buf, fp); + } + fclose (fp); + fprintf (stdout, "\"%s\" %lu/%lu\n", filename, + (unsigned long) lines, (unsigned long) size); + free (filename); + return 0; +} + +/* ~|[shell-command] */ +int +escape_pipe (int argc, char **argv, compose_env_t *env) +{ + int p[2]; + pid_t pid; + int fd; + + if (argc == 1) + { + /* TRANSLATORS: 'pipe' is a command name. Do not translate it! */ + util_error (_("pipe: no command specified")); + return 1; + } + + if (pipe (p)) + { + util_error ("pipe: %s", strerror (errno)); + return 1; + } + + fd = mu_tempfile (NULL, NULL); + if (fd == -1) + return 1; + + if ((pid = fork ()) < 0) + { + close (p[0]); + close (p[1]); + close (fd); + util_error ("fork: %s", strerror (errno)); + return 1; + } + else if (pid == 0) + { + /* Child */ + int i; + char **xargv; + + /* Attache the pipes */ + close (0); + dup (p[0]); + close (p[0]); + close (p[1]); + + close (1); + dup (fd); + close (fd); + + /* Execute the process */ + xargv = xcalloc (argc, sizeof (xargv[0])); + for (i = 0; i < argc - 1; i++) + xargv[i] = argv[i + 1]; + xargv[i] = NULL; + execvp (xargv[0], xargv); + util_error (_("Cannot exec process `%s': %s"), xargv[0], strerror (errno)); + exit (1); + } + else + { + FILE *fp; + char *buf = NULL; + size_t n; + size_t lines, size; + int rc = 1; + int status; + + close (p[0]); + + /* Parent */ + fp = fdopen (p[1], "w"); + + fclose (env->file); + env->file = fopen (env->filename, "r"); + + lines = size = 0; + while (getline (&buf, &n, env->file) > 0) + { + lines++; + size += n; + fputs (buf, fp); + } + fclose (env->file); + fclose (fp); /* Closes p[1] */ + + waitpid (pid, &status, 0); + if (!WIFEXITED (status)) + { + util_error (_("Child terminated abnormally: %d"), WEXITSTATUS (status)); + } + else + { + struct stat st; + if (fstat (fd, &st)) + { + util_error (_("Cannot stat output file: %s"), strerror (errno)); + } + else if (st.st_size > 0) + rc = 0; + } + + fprintf (stdout, "\"|%s\" in: %lu/%lu ", argv[1], + (unsigned long) lines, (unsigned long) size); + if (rc) + { + fprintf (stdout, _("no lines out\n")); + } + else + { + /* Ok, replace the old tempfile */ + fp = fdopen (fd, "r"); + rewind (fp); + + env->file = fopen (env->filename, "w+"); + + lines = size = 0; + while (getline (&buf, &n, fp) > 0) + { + lines++; + size += n; + fputs (buf, env->file); + } + fclose (env->file); + + fprintf (stdout, "out: %lu/%lu\n", + (unsigned long) lines, (unsigned long) size); + } + + /* Clean up the things */ + if (buf) + free (buf); + + env->file = fopen (env->filename, "a+"); + ofile = env->file; + } + + close (fd); + + return 0; +} |