summaryrefslogtreecommitdiff
path: root/mail/escape.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2005-08-11 08:35:06 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2005-08-11 08:35:06 +0000
commit9fdb4e5af89a211bc6d05f8c64b4051b174c7855 (patch)
treed63fe24be793c1dddb5184de01a4160f139ff63d /mail/escape.c
parenteffde3f568bd21ecd4f08c086d624cea59c6bd90 (diff)
downloadmailutils-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.c761
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;
+}

Return to:

Send suggestions and report system problems to the System administrator.