Annotation of GNUtools/emacs/etc/fakemail.c, revision 1.1.1.1

1.1       root        1: /* sendmail-like interface to /bin/mail for system V,
                      2:    Copyright (C) 1985 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU Emacs.
                      5: 
                      6: GNU Emacs is free software; you can redistribute it and/or modify
                      7: it under the terms of the GNU General Public License as published by
                      8: the Free Software Foundation; either version 1, or (at your option)
                      9: any later version.
                     10: 
                     11: GNU Emacs is distributed in the hope that it will be useful,
                     12: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: GNU General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU Emacs; see the file COPYING.  If not, write to
                     18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     19: 
                     20: 
                     21: #define NO_SHORTNAMES
                     22: #include "../src/config.h"
                     23: 
                     24: #if defined (BSD) && !defined (BSD4_1)
                     25: /* This program isnot used in BSD, so just avoid loader complaints.  */
                     26: main ()
                     27: {
                     28: }
                     29: #else /* not BSD 4.2 (or newer) */
                     30: /* This conditional contains all the rest of the file.  */
                     31: 
                     32: /* These are defined in config in some versions. */
                     33: 
                     34: #ifdef static
                     35: #undef static
                     36: #endif
                     37: 
                     38: #ifdef read
                     39: #undef read
                     40: #undef write
                     41: #undef open
                     42: #undef close
                     43: #endif
                     44: 
                     45: #include <stdio.h>
                     46: #include <string.h>
                     47: #include <ctype.h>
                     48: #include <time.h>
                     49: #include <pwd.h>
                     50: 
                     51: /* Type definitions */
                     52: 
                     53: #define boolean int
                     54: #define true 1
                     55: #define false 0
                     56: 
                     57: /* Various lists */
                     58: 
                     59: struct line_record
                     60: {
                     61:   char *string;
                     62:   struct line_record *continuation;
                     63: };
                     64: typedef struct line_record *line_list;
                     65: 
                     66: struct header_record
                     67: {
                     68:   line_list text;
                     69:   struct header_record *next;
                     70:   struct header_record *previous;
                     71: };
                     72: typedef struct header_record *header;
                     73:                        
                     74: struct stream_record
                     75: {
                     76:   FILE *handle;
                     77:   int (*action)();
                     78:   struct stream_record *rest_streams;
                     79: };
                     80: typedef struct stream_record *stream_list;
                     81: 
                     82: /* A `struct linebuffer' is a structure which holds a line of text.
                     83:  * `readline' reads a line from a stream into a linebuffer
                     84:  * and works regardless of the length of the line.
                     85:  */
                     86: 
                     87: struct linebuffer
                     88: {
                     89:   long size;
                     90:   char *buffer;
                     91: };
                     92: 
                     93: struct linebuffer lb;
                     94: 
                     95: #define new_list()                                     \
                     96:   ((line_list) xmalloc (sizeof (struct line_record)))
                     97: #define new_header()                           \
                     98:   ((header) xmalloc (sizeof (struct header_record)))
                     99: #define new_stream()                           \
                    100:   ((stream_list) xmalloc (sizeof (struct stream_record)))
                    101: #define alloc_string(nchars)                           \
                    102:   ((char *) xmalloc ((nchars) + 1))
                    103: 
                    104: /* Global declarations */
                    105: 
                    106: #define BUFLEN 1024
                    107: #define KEYWORD_SIZE 256
                    108: #define FROM_PREFIX "From"
                    109: #define MY_NAME "fakemail"
                    110: #define NIL ((line_list) NULL)
                    111: #define INITIAL_LINE_SIZE 200
                    112: 
                    113: #ifndef MAIL_PROGRAM_NAME
                    114: #define MAIL_PROGRAM_NAME "/bin/mail"
                    115: #endif
                    116: 
                    117: static char *my_name;
                    118: static char *the_date;
                    119: static char *the_user;
                    120: static line_list file_preface;
                    121: static stream_list the_streams;
                    122: static boolean no_problems = true;
                    123: 
                    124: extern FILE *popen ();
                    125: extern int fclose (), pclose ();
                    126: extern char *malloc (), *realloc ();
                    127: 
                    128: #ifdef CURRENT_USER
                    129: extern struct passwd *getpwuid ();
                    130: extern unsigned short geteuid ();
                    131: static struct passwd *my_entry;
                    132: #define cuserid(s)                             \
                    133: (my_entry = getpwuid (((int) geteuid ())),     \
                    134:  my_entry->pw_name)
                    135: #endif
                    136: 
                    137: /* Utilities */
                    138: 
                    139: /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
                    140: 
                    141: static void
                    142: error (s1, s2)
                    143:      char *s1, *s2;
                    144: {
                    145:   printf ("%s: ", my_name);
                    146:   printf (s1, s2);
                    147:   printf ("\n");
                    148:   no_problems = false;
                    149: }
                    150: 
                    151: /* Print error message and exit.  */
                    152: 
                    153: static void
                    154: fatal (s1, s2)
                    155:      char *s1, *s2;
                    156: {
                    157:   error (s1, s2);
                    158:   exit (1);
                    159: }
                    160: 
                    161: /* Like malloc but get fatal error if memory is exhausted.  */
                    162: 
                    163: static char *
                    164: xmalloc (size)
                    165:      int size;
                    166: {
                    167:   char *result = malloc (((unsigned) size));
                    168:   if (result == ((char *) NULL))
                    169:     fatal ("virtual memory exhausted", 0);
                    170:   return result;
                    171: }
                    172: 
                    173: static char *
                    174: xrealloc (ptr, size)
                    175:      char *ptr;
                    176:      int size;
                    177: {
                    178:   char *result = realloc (ptr, ((unsigned) size));
                    179:   if (result == ((char *) NULL))
                    180:     fatal ("virtual memory exhausted");
                    181:   return result;
                    182: }
                    183: 
                    184: /* Initialize a linebuffer for use */
                    185: 
                    186: void
                    187: init_linebuffer (linebuffer)
                    188:      struct linebuffer *linebuffer;
                    189: {
                    190:   linebuffer->size = INITIAL_LINE_SIZE;
                    191:   linebuffer->buffer = ((char *) xmalloc (INITIAL_LINE_SIZE));
                    192: }
                    193: 
                    194: /* Read a line of text from `stream' into `linebuffer'.
                    195:  * Return the length of the line.  
                    196:  */
                    197: 
                    198: long
                    199: readline (linebuffer, stream)
                    200:      struct linebuffer *linebuffer;
                    201:      FILE *stream;
                    202: {
                    203:   char *buffer = linebuffer->buffer;
                    204:   char *p = linebuffer->buffer;
                    205:   char *end = p + linebuffer->size;
                    206: 
                    207:   while (true)
                    208:     {
                    209:       int c = getc (stream);
                    210:       if (p == end)
                    211:        {
                    212:          linebuffer->size *= 2;
                    213:          buffer = ((char *) xrealloc (buffer, linebuffer->size));
                    214:          p += buffer - linebuffer->buffer;
                    215:          end += buffer - linebuffer->buffer;
                    216:          linebuffer->buffer = buffer;
                    217:        }
                    218:       if (c < 0 || c == '\n')
                    219:        {
                    220:          *p = 0;
                    221:          break;
                    222:        }
                    223:       *p++ = c;
                    224:     }
                    225: 
                    226:   return p - buffer;
                    227: }
                    228: 
                    229: char *
                    230: get_keyword (field, rest)
                    231:      register char *field;
                    232:      char **rest;
                    233: {
                    234:   static char keyword[KEYWORD_SIZE];
                    235:   register char *ptr;
                    236:   register char c;
                    237: 
                    238:   ptr = &keyword[0];
                    239:   c = *field++;
                    240:   if ((isspace (c)) || (c == ':'))
                    241:     return ((char *) NULL);
                    242:   *ptr++ = ((islower (c)) ? (toupper (c)) : c);
                    243:   while (((c = *field++) != ':') && (!(isspace (c))))
                    244:     *ptr++ = ((islower (c)) ? (toupper (c)) : c);
                    245:   *ptr++ = '\0';
                    246:   while (isspace (c)) c = *field++;
                    247:   if (c != ':') return ((char *) NULL);
                    248:   *rest = field;
                    249:   return &keyword[0];
                    250: }
                    251: 
                    252: boolean
                    253: has_keyword (field)
                    254:      char *field;
                    255: {
                    256:   char *ignored;
                    257:   return (get_keyword (field, &ignored) != ((char *) NULL));
                    258: }
                    259: 
                    260: char *
                    261: add_field (the_list, field, where)
                    262:      line_list the_list;
                    263:      register char *field, *where;
                    264: {
                    265:   register char c;
                    266:   while (true)
                    267:     {
                    268:       *where++ = ' ';
                    269:       while ((c = *field++) != '\0')
                    270:        *where++ = ((c == ',') ? ' ' : c);
                    271:       if (the_list == NIL) break;
                    272:       field = the_list->string;
                    273:       the_list = the_list->continuation;
                    274:     }
                    275:   return where;
                    276: }
                    277: 
                    278: line_list
                    279: make_file_preface ()
                    280: {
                    281:   char *the_string, *temp;
                    282:   long idiotic_interface;
                    283:   long prefix_length;
                    284:   long user_length;
                    285:   long date_length;
                    286:   line_list result;
                    287: 
                    288:   prefix_length = strlen (FROM_PREFIX);
                    289:   time (&idiotic_interface);
                    290:   the_date = ctime (&idiotic_interface);
                    291:   /* the_date has an unwanted newline at the end */
                    292:   date_length = strlen (the_date) - 1;
                    293:   the_date[date_length] = '\0';
                    294:   temp = cuserid ((char *) NULL);
                    295:   user_length = strlen (temp);
                    296:   the_user = alloc_string (user_length + 1);
                    297:   strcpy (the_user, temp);
                    298:   the_string = alloc_string (3 + prefix_length +
                    299:                             user_length +
                    300:                             date_length);
                    301:   temp = the_string;
                    302:   strcpy (temp, FROM_PREFIX);
                    303:   temp = &temp[prefix_length];
                    304:   *temp++ = ' ';
                    305:   strcpy (temp, the_user);
                    306:   temp = &temp[user_length];
                    307:   *temp++ = ' ';
                    308:   strcpy (temp, the_date);
                    309:   result = new_list ();
                    310:   result->string = the_string;
                    311:   result->continuation = ((line_list) NULL);
                    312:   return result;
                    313: }
                    314: 
                    315: void
                    316: write_line_list (the_list, the_stream)
                    317:      register line_list the_list;
                    318:      FILE *the_stream;
                    319: {
                    320:   for ( ;
                    321:       the_list != ((line_list) NULL) ;
                    322:       the_list = the_list->continuation)
                    323:     {
                    324:       fputs (the_list->string, the_stream);
                    325:       putc ('\n', the_stream);
                    326:     }
                    327:   return;
                    328: }
                    329: 
                    330: int
                    331: close_the_streams ()
                    332: {
                    333:   register stream_list rem;
                    334:   for (rem = the_streams;
                    335:        rem != ((stream_list) NULL);
                    336:        rem = rem->rest_streams)
                    337:     no_problems = (no_problems &&
                    338:                   ((*rem->action) (rem->handle) == 0));
                    339:   the_streams = ((stream_list) NULL);
                    340:   return (no_problems ? 0 : 1);
                    341: }
                    342: 
                    343: void
                    344: add_a_stream (the_stream, closing_action)
                    345:      FILE *the_stream;
                    346:      int (*closing_action)();
                    347: {
                    348:   stream_list old = the_streams;
                    349:   the_streams = new_stream ();
                    350:   the_streams->handle = the_stream;
                    351:   the_streams->action = closing_action;
                    352:   the_streams->rest_streams = old;
                    353:   return;
                    354: }
                    355: 
                    356: int
                    357: my_fclose (the_file)
                    358:      FILE *the_file;
                    359: {
                    360:   putc ('\n', the_file);
                    361:   fflush (the_file);
                    362:   return fclose (the_file);
                    363: }
                    364: 
                    365: boolean
                    366: open_a_file (name)
                    367:      char *name;
                    368: {
                    369:   FILE *the_stream = fopen (name, "a");
                    370:   if (the_stream != ((FILE *) NULL))
                    371:     {
                    372:       add_a_stream (the_stream, my_fclose);
                    373:       if (the_user == ((char *) NULL))
                    374:        file_preface = make_file_preface ();
                    375:       write_line_list (file_preface, the_stream);
                    376:       return true;
                    377:     }
                    378:   return false;
                    379: }
                    380: 
                    381: void
                    382: put_string (s)
                    383:      char *s;
                    384: {
                    385:   register stream_list rem;
                    386:   for (rem = the_streams;
                    387:        rem != ((stream_list) NULL);
                    388:        rem = rem->rest_streams)
                    389:     fputs (s, rem->handle);
                    390:   return;
                    391: }
                    392: 
                    393: void
                    394: put_line (s)
                    395:      char *s;
                    396: {
                    397:   register stream_list rem;
                    398:   for (rem = the_streams;
                    399:        rem != ((stream_list) NULL);
                    400:        rem = rem->rest_streams)
                    401:     {
                    402:       fputs (s, rem->handle);
                    403:       putc ('\n', rem->handle);
                    404:     }
                    405:   return;
                    406: }
                    407: 
                    408: #define mail_error error
                    409: 
                    410: void
                    411: setup_files (the_list, field)
                    412:      register line_list the_list;
                    413:      register char *field;
                    414: {
                    415:   register char *start;
                    416:   register char c;
                    417:   while (true)
                    418:     {
                    419:       while (((c = *field) != '\0') &&
                    420:             ((c == ' ') ||
                    421:              (c == '\t') ||
                    422:              (c == ',')))
                    423:        field += 1;
                    424:       if (c != '\0')
                    425:        {
                    426:          start = field;
                    427:          while (((c = *field) != '\0') &&
                    428:                 (c != ' ') &&
                    429:                 (c != '\t') &&
                    430:                 (c != ','))
                    431:            field += 1;
                    432:          *field = '\0';
                    433:          if (!open_a_file (start))
                    434:            mail_error ("Could not open file %s", start);
                    435:          *field = c;
                    436:          if (c != '\0') continue;
                    437:        }
                    438:       if (the_list == ((line_list) NULL)) return;
                    439:       field = the_list->string;
                    440:       the_list = the_list->continuation;
                    441:     }
                    442: }
                    443: 
                    444: int
                    445: args_size (the_header)
                    446:      header the_header;
                    447: {
                    448:   register header old = the_header;
                    449:   register line_list rem;
                    450:   register int size = 0;
                    451:   do
                    452:     {
                    453:       char *field;
                    454:       register char *keyword = get_keyword (the_header->text->string, &field);
                    455:       if ((strcmp (keyword, "TO") == 0) ||
                    456:          (strcmp (keyword, "CC") == 0) ||
                    457:          (strcmp (keyword, "BCC") == 0))
                    458:        {
                    459:          size += 1 + strlen (field);
                    460:          for (rem = the_header->text->continuation;
                    461:               rem != NIL;
                    462:               rem = rem->continuation)
                    463:            size += 1 + strlen (rem->string);
                    464:        }
                    465:       the_header = the_header->next;
                    466:     } while (the_header != old);
                    467:   return size;
                    468: }
                    469: 
                    470: parse_header (the_header, where)
                    471:      header the_header;
                    472:      register char *where;
                    473: {
                    474:   register header old = the_header;
                    475:   do
                    476:     {
                    477:       char *field;
                    478:       register char *keyword = get_keyword (the_header->text->string, &field);
                    479:       if (strcmp (keyword, "TO") == 0)
                    480:        where = add_field (the_header->text->continuation, field, where);
                    481:       else if (strcmp (keyword, "CC") == 0)
                    482:        where = add_field (the_header->text->continuation, field, where);
                    483:       else if (strcmp (keyword, "BCC") == 0)
                    484:        {
                    485:          where = add_field (the_header->text->continuation, field, where);
                    486:          the_header->previous->next = the_header->next;
                    487:          the_header->next->previous = the_header->previous;
                    488:        }
                    489:       else if (strcmp (keyword, "FCC") == 0)
                    490:        setup_files (the_header->text->continuation, field);
                    491:       the_header = the_header->next;
                    492:     } while (the_header != old);
                    493:   *where = '\0';
                    494:   return;
                    495: }
                    496:     
                    497: header
                    498: read_header ()
                    499: {
                    500:   register header the_header = ((header) NULL);
                    501:   register line_list *next_line = ((line_list *) NULL);
                    502: 
                    503:   init_linebuffer (&lb);
                    504: 
                    505:   do
                    506:     {
                    507:       long length;
                    508:       register char *line;
                    509: 
                    510:       readline (&lb, stdin);
                    511:       line = lb.buffer;
                    512:       length = strlen (line);
                    513:       if (length == 0) break;
                    514: 
                    515:       if (has_keyword (line))
                    516:        {
                    517:          register header old = the_header;
                    518:          the_header = new_header ();
                    519:          if (old == ((header) NULL))
                    520:            {
                    521:              the_header->next = the_header;
                    522:              the_header->previous = the_header;
                    523:            }
                    524:          else
                    525:            {
                    526:              the_header->previous = old;
                    527:              the_header->next = old->next;
                    528:              old->next = the_header;
                    529:            }
                    530:          next_line = &(the_header->text);
                    531:        }
                    532: 
                    533:       if (next_line == ((line_list *) NULL))
                    534:        {
                    535:          /* Not a valid header */
                    536:          exit (1);
                    537:        }
                    538:       *next_line = new_list ();
                    539:       (*next_line)->string = alloc_string (length);
                    540:       strcpy (((*next_line)->string), line);
                    541:       next_line = &((*next_line)->continuation);
                    542:       *next_line = NIL;
                    543: 
                    544:     } while (true);
                    545: 
                    546:   return the_header->next;
                    547: }
                    548: 
                    549: void
                    550: write_header (the_header)
                    551:      header the_header;
                    552: {
                    553:   register header old = the_header;
                    554:   do
                    555:     {
                    556:       register line_list the_list;
                    557:       for (the_list = the_header->text;
                    558:           the_list != NIL;
                    559:           the_list = the_list->continuation)
                    560:        put_line (the_list->string);
                    561:       the_header = the_header->next;
                    562:     } while (the_header != old);
                    563:   put_line ("");
                    564:   return;
                    565: }
                    566: 
                    567: void
                    568: main (argc, argv)
                    569:      int argc;
                    570:      char **argv;
                    571: {
                    572:   char *command_line;
                    573:   header the_header;
                    574:   long name_length = strlen (MAIL_PROGRAM_NAME);
                    575:   char buf[BUFLEN + 1];
                    576:   register int size;
                    577:   FILE *the_pipe;
                    578: 
                    579:   my_name = MY_NAME;
                    580:   the_streams = ((stream_list) NULL);
                    581:   the_date = ((char *) NULL);
                    582:   the_user = ((char *) NULL);
                    583: 
                    584:   the_header = read_header ();
                    585:   command_line = alloc_string (name_length + args_size (the_header));
                    586:   strcpy (command_line, MAIL_PROGRAM_NAME);
                    587:   parse_header (the_header, &command_line[name_length]);
                    588:   
                    589:   the_pipe = popen (command_line, "w");
                    590:   if (the_pipe == ((FILE *) NULL))
                    591:     fatal ("cannot open pipe to real mailer");
                    592: 
                    593:   add_a_stream (the_pipe, pclose);
                    594: 
                    595:   write_header (the_header);
                    596: 
                    597:   /* Dump the message itself */
                    598: 
                    599:   while (!feof (stdin))
                    600:     {
                    601:       size = fread (buf, 1, BUFLEN, stdin);
                    602:       buf[size] = '\0';
                    603:       put_string (buf);
                    604:     }
                    605: 
                    606:   exit (close_the_streams ());
                    607: }
                    608: 
                    609: #endif /* not BSD 4.2 (or newer) */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.