diff options
-rw-r--r-- | comsat/action.c | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/comsat/action.c b/comsat/action.c new file mode 100644 index 000000000..1be35ca6e --- /dev/null +++ b/comsat/action.c @@ -0,0 +1,357 @@ +/* GNU mailutils - a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "comsat.h" +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free +#include <obstack.h> + +/* This module implements user-configurable actions for comsat. The + actions are kept in file .biffrc in the user's home directory and + are executed in sequence. Possible actions: + + beep -- Produce audible signal + echo STRING -- Output STRING to the user's tty + exec PROG ARGS... -- Execute given program (not yet implemented) + + Following metacharacters are accepted in strings: + + $u -- Expands to username + $h -- Expands to hostname + $H{name} -- Expands to value of message header `name' + $B(C,L) -- Expands to message body. C and L give maximum + number of characters and line in the expansion. + When omitted, they default to 400, 5. */ + +int +act_getline (FILE *fp, char **sptr, size_t *size) +{ + char buf[256]; + int cont = 1; + size_t used = 0; + + while (cont && fgets (buf, sizeof buf, fp)) + { + int len = strlen (buf); + if (buf[len-1] == '\n') + { + buf[--len] = 0; + if (buf[len-1] == '\\') + { + buf[--len] = 0; + cont = 1; + } + else + cont = 0; + } + else + cont = 1; + + if (len + used + 1 > *size) + { + *sptr = realloc (*sptr, len + used + 1); + if (!*sptr) + return -1; + *size = len + used + 1; + } + memcpy (*sptr + used, buf, len); + used += len; + } + + if (*sptr) + (*sptr)[used] = 0; + + return used; +} + +/* Convert second character of a backslash sequence to its ASCII + value: */ +int +backslash(int c) +{ + static char transtab[] = "a\ab\bf\fn\nr\rt\t"; + char *p; + + for (p = transtab; *p; p += 2) + { + if (*p == c) + return p[1]; + } + return c; +} + +int +expand_escape (char **pp, message_t msg, struct obstack *stk) +{ + char *p = *pp; + char *start, *sval, *namep; + int len; + header_t hdr; + body_t body; + stream_t stream; + int rc = 1; + size_t size, lncount; + + switch (*++p) /* skip past $ */ + { + case 'u': + len = strlen (username); + obstack_grow (stk, username, len); + *pp = p; + rc = 0; + break; + case 'h': + len = strlen (hostname); + obstack_grow (stk, hostname, len); + *pp = p; + rc = 0; + break; + case 'H': + /* Header field */ + if (*++p != '{') + break; + start = ++p; + p = strchr (p, '}'); + if (!p) + break; + len = p - start; + if (len == 0 + || (namep = malloc (len + 1)) == NULL) + break; + memcpy (namep, start, len); + namep[len] = 0; + if (message_get_header (msg, &hdr) == 0 + && header_aget_value (hdr, namep, &sval) == 0) + { + len = strlen (sval); + obstack_grow (stk, sval, len); + } + free (namep); + *pp = p; + rc = 0; + break; + case 'B': + /* Message body */ + if (*++p == '(') + { + size = strtoul (p + 1, &p, 0); + if (*p == ',') + lncount = strtoul (p + 1, &p, 0); + if (*p != ')') + break; + p++; + } + if (size == 0) + size = 400; + if (lncount == 0) + lncount = 5; + if (message_get_body (msg, &body) == 0 + && body_get_stream (body, &stream) == 0) + { + size_t nread; + char *buf = malloc (size+1); + + if (!buf) + break; + if (stream_read (stream, buf, size, 0, &nread) == 0) + { + char *q; + + buf[nread] = 0; + q = buf; + size = 0; + while (lncount--) + { + char *s = strchr (q, '\n'); + if (!q) + break; + size += s - q + 1; + q = s + 1; + } + obstack_grow (stk, buf, size); + } + free (buf); + } + *pp = p; + rc = 0; + } + return rc; +} + +char * +expand_line (char *str, char *cr, message_t msg) +{ + char *p; + int i, c, len; + size_t size; + struct obstack stk; + + if (!*str) + return NULL; + obstack_init (&stk); + for (p = str; *p; p++) + { + switch (*p) + { + case '\n': + len = strlen (cr); + obstack_grow (&stk, cr, len); + break; + case '\\': + p++; + switch (*p) + { + case 0: + obstack_1grow (&stk, c); + break; + case 'n': + len = strlen (cr); + obstack_grow (&stk, cr, len); + break; + default: + c = backslash (*p); + obstack_1grow (&stk, c); + } + break; + case '$': + if (expand_escape (&p, msg, &stk) == 0) + break; + /*FALLTHRU*/ + default: + obstack_1grow (&stk, *p); + } + } + obstack_1grow (&stk, 0); + str = strdup (obstack_finish (&stk)); + obstack_free (&stk, NULL); + return str; +} + +char *default_action = +"Mail to \a$u@$h\a ---\n" +"From: $H{from}\n" +"Subject: $H{Subject}\n" +"---\n" +"$B(,5)\n" +"---\n"; + +/* Take care to clear eighth bit, so we won't upset some stupid terminals */ +#define LB(c) ((c)&0x7f) + +void +action_beep (FILE *tty) +{ + fprintf (tty, "\a\a"); +} + +void +action_echo (FILE *tty, char *str) +{ + char *p; + + if (!str) + return; + for (p = str; *p; p++) + *p = LB (*p); + fprintf (tty, "%s", str); +} + +FILE * +open_rc (char *filename, FILE *tty) +{ + struct stat stb; + struct passwd *pw = getpwnam (username); + + if (stat (filename, &stb) == 0) + { + if (stb.st_uid != pw->pw_uid) + { + syslog (LOG_NOTICE, "%s's %s is not owned by %s", + username, filename, username); + return NULL; + } + if ((stb.st_mode & 0777) != 0600) + { + fprintf (tty, "Warning: your .biffrc has wrong permissions\r\n"); + syslog (LOG_NOTICE, "%s's %s has wrong permissions", + username, filename); + return NULL; + } + } + return fopen (filename, "r"); +} + +void +run_user_action (FILE *tty, char *cr, message_t msg) +{ + FILE *fp; + int nact = 0; + char *stmt = NULL; + size_t size = 0; + + fp = open_rc (BIFF_RC, tty); + if (fp) + { + int line = 0; + + while (act_getline (fp, &stmt, &size)) + { + char *str; + int argc; + char **argv; + + line++; + str = expand_line (stmt, cr, msg); + if (!str) + continue; + if (argcv_get (str, "", &argc, &argv) + || argc == 0 + || argv[0][0] == '#') + { + free (str); + argcv_free (argc, argv); + continue; + } + + if (strcmp (argv[0], "beep") == 0) + { + action_beep (tty); + nact++; + } + else if (strcmp (argv[0], "echo") == 0) + { + action_echo (tty, argv[1]); + nact++; + } + else + { + syslog (LOG_ERR, "%s:.biffrc:%d: unknown keyword %s", + username, line, argv[0]); + break; + } + } + fclose (fp); + } + + if (nact == 0) + { + char *str = expand_line (default_action, cr, msg); + action_echo (tty, str); + } +} + + |