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