Annotation of 43BSD/contrib/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 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: #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 PROGRAM_NAME "/bin/mail"
                    109: #define FROM_PREFIX "From"
                    110: #define MY_NAME "fakemail"
                    111: #define NIL ((line_list) NULL)
                    112: #define INITIAL_LINE_SIZE 200
                    113: 
                    114: static char *my_name;
                    115: static char *the_date;
                    116: static char *the_user;
                    117: static line_list file_preface;
                    118: static stream_list the_streams;
                    119: static boolean no_problems = true;
                    120: 
                    121: extern FILE *popen ();
                    122: extern int fclose (), pclose ();
                    123: extern char *malloc (), *realloc ();
                    124: 
                    125: #ifdef CURRENT_USER
                    126: extern struct passwd *getpwuid ();
                    127: extern unsigned short geteuid ();
                    128: static struct passwd *my_entry;
                    129: #define cuserid(s)                             \
                    130: (my_entry = getpwuid (((int) geteuid ())),     \
                    131:  my_entry->pw_name)
                    132: #endif
                    133: 
                    134: /* Utilities */
                    135: 
                    136: /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
                    137: 
                    138: static void
                    139: error (s1, s2)
                    140:      char *s1, *s2;
                    141: {
                    142:   printf ("%s: ", my_name);
                    143:   printf (s1, s2);
                    144:   printf ("\n");
                    145:   no_problems = false;
                    146: }
                    147: 
                    148: /* Print error message and exit.  */
                    149: 
                    150: static void
                    151: fatal (s1, s2)
                    152:      char *s1, *s2;
                    153: {
                    154:   error (s1, s2);
                    155:   exit (1);
                    156: }
                    157: 
                    158: /* Like malloc but get fatal error if memory is exhausted.  */
                    159: 
                    160: static char *
                    161: xmalloc (size)
                    162:      int size;
                    163: {
                    164:   char *result = malloc (((unsigned) size));
                    165:   if (result == ((char *) NULL))
                    166:     fatal ("virtual memory exhausted", 0);
                    167:   return result;
                    168: }
                    169: 
                    170: static char *
                    171: xrealloc (ptr, size)
                    172:      char *ptr;
                    173:      int size;
                    174: {
                    175:   char *result = realloc (ptr, ((unsigned) size));
                    176:   if (result == ((char *) NULL))
                    177:     fatal ("virtual memory exhausted");
                    178:   return result;
                    179: }
                    180: 
                    181: /* Initialize a linebuffer for use */
                    182: 
                    183: void
                    184: init_linebuffer (linebuffer)
                    185:      struct linebuffer *linebuffer;
                    186: {
                    187:   linebuffer->size = INITIAL_LINE_SIZE;
                    188:   linebuffer->buffer = ((char *) xmalloc (INITIAL_LINE_SIZE));
                    189: }
                    190: 
                    191: /* Read a line of text from `stream' into `linebuffer'.
                    192:  * Return the length of the line.  
                    193:  */
                    194: 
                    195: long
                    196: readline (linebuffer, stream)
                    197:      struct linebuffer *linebuffer;
                    198:      FILE *stream;
                    199: {
                    200:   char *buffer = linebuffer->buffer;
                    201:   char *p = linebuffer->buffer;
                    202:   char *end = p + linebuffer->size;
                    203: 
                    204:   while (true)
                    205:     {
                    206:       int c = getc (stream);
                    207:       if (p == end)
                    208:        {
                    209:          linebuffer->size *= 2;
                    210:          buffer = ((char *) xrealloc (buffer, linebuffer->size));
                    211:          p += buffer - linebuffer->buffer;
                    212:          end += buffer - linebuffer->buffer;
                    213:          linebuffer->buffer = buffer;
                    214:        }
                    215:       if (c < 0 || c == '\n')
                    216:        {
                    217:          *p = 0;
                    218:          break;
                    219:        }
                    220:       *p++ = c;
                    221:     }
                    222: 
                    223:   return p - buffer;
                    224: }
                    225: 
                    226: char *
                    227: get_keyword (field, rest)
                    228:      register char *field;
                    229:      char **rest;
                    230: {
                    231:   static char keyword[KEYWORD_SIZE];
                    232:   register char *ptr;
                    233:   register char c;
                    234: 
                    235:   ptr = &keyword[0];
                    236:   c = *field++;
                    237:   if ((isspace (c)) || (c == ':'))
                    238:     return ((char *) NULL);
                    239:   *ptr++ = ((islower (c)) ? (toupper (c)) : c);
                    240:   while (((c = *field++) != ':') && (!(isspace (c))))
                    241:     *ptr++ = ((islower (c)) ? (toupper (c)) : c);
                    242:   *ptr++ = '\0';
                    243:   while (isspace (c)) c = *field++;
                    244:   if (c != ':') return ((char *) NULL);
                    245:   *rest = field;
                    246:   return &keyword[0];
                    247: }
                    248: 
                    249: boolean
                    250: has_keyword (field)
                    251:      char *field;
                    252: {
                    253:   char *ignored;
                    254:   return (get_keyword (field, &ignored) != ((char *) NULL));
                    255: }
                    256: 
                    257: char *
                    258: add_field (the_list, field, where)
                    259:      line_list the_list;
                    260:      register char *field, *where;
                    261: {
                    262:   register char c;
                    263:   while (true)
                    264:     {
                    265:       *where++ = ' ';
                    266:       while ((c = *field++) != '\0')
                    267:        *where++ = ((c == ',') ? ' ' : c);
                    268:       if (the_list == NIL) break;
                    269:       field = the_list->string;
                    270:       the_list = the_list->continuation;
                    271:     }
                    272:   return where;
                    273: }
                    274: 
                    275: line_list
                    276: make_file_preface ()
                    277: {
                    278:   char *the_string, *temp;
                    279:   long idiotic_interface;
                    280:   long prefix_length;
                    281:   long user_length;
                    282:   long date_length;
                    283:   line_list result;
                    284: 
                    285:   prefix_length = strlen (FROM_PREFIX);
                    286:   time (&idiotic_interface);
                    287:   the_date = ctime (&idiotic_interface);
                    288:   /* the_date has an unwanted newline at the end */
                    289:   date_length = strlen (the_date) - 1;
                    290:   the_date[date_length] = '\0';
                    291:   temp = cuserid ((char *) NULL);
                    292:   user_length = strlen (temp);
                    293:   the_user = alloc_string (user_length + 1);
                    294:   strcpy (the_user, temp);
                    295:   the_string = alloc_string (3 + prefix_length +
                    296:                             user_length +
                    297:                             date_length);
                    298:   temp = the_string;
                    299:   strcpy (temp, FROM_PREFIX);
                    300:   temp = &temp[prefix_length];
                    301:   *temp++ = ' ';
                    302:   strcpy (temp, the_user);
                    303:   temp = &temp[user_length];
                    304:   *temp++ = ' ';
                    305:   strcpy (temp, the_date);
                    306:   result = new_list ();
                    307:   result->string = the_string;
                    308:   result->continuation = ((line_list) NULL);
                    309:   return result;
                    310: }
                    311: 
                    312: void
                    313: write_line_list (the_list, the_stream)
                    314:      register line_list the_list;
                    315:      FILE *the_stream;
                    316: {
                    317:   for ( ;
                    318:       the_list != ((line_list) NULL) ;
                    319:       the_list = the_list->continuation)
                    320:     {
                    321:       fputs (the_list->string, the_stream);
                    322:       putc ('\n', the_stream);
                    323:     }
                    324:   return;
                    325: }
                    326: 
                    327: int
                    328: close_the_streams ()
                    329: {
                    330:   register stream_list rem;
                    331:   for (rem = the_streams;
                    332:        rem != ((stream_list) NULL);
                    333:        rem = rem->rest_streams)
                    334:     no_problems = (no_problems &&
                    335:                   (rem->action (rem->handle) == 0));
                    336:   the_streams = ((stream_list) NULL);
                    337:   return (no_problems ? 0 : 1);
                    338: }
                    339: 
                    340: void
                    341: add_a_stream (the_stream, closing_action)
                    342:      FILE *the_stream;
                    343:      int (*closing_action)();
                    344: {
                    345:   stream_list old = the_streams;
                    346:   the_streams = new_stream ();
                    347:   the_streams->handle = the_stream;
                    348:   the_streams->action = closing_action;
                    349:   the_streams->rest_streams = old;
                    350:   return;
                    351: }
                    352: 
                    353: int
                    354: my_fclose (the_file)
                    355:      FILE *the_file;
                    356: {
                    357:   putc ('\n', the_file);
                    358:   fflush (the_file);
                    359:   return fclose (the_file);
                    360: }
                    361: 
                    362: boolean
                    363: open_a_file (name)
                    364:      char *name;
                    365: {
                    366:   FILE *the_stream = fopen (name, "a");
                    367:   if (the_stream != ((FILE *) NULL))
                    368:     {
                    369:       add_a_stream (the_stream, my_fclose);
                    370:       if (the_user == ((char *) NULL))
                    371:        file_preface = make_file_preface ();
                    372:       write_line_list (file_preface, the_stream);
                    373:       return true;
                    374:     }
                    375:   return false;
                    376: }
                    377: 
                    378: void
                    379: put_string (s)
                    380:      char *s;
                    381: {
                    382:   register stream_list rem;
                    383:   for (rem = the_streams;
                    384:        rem != ((stream_list) NULL);
                    385:        rem = rem->rest_streams)
                    386:     fputs (s, rem->handle);
                    387:   return;
                    388: }
                    389: 
                    390: void
                    391: put_line (s)
                    392:      char *s;
                    393: {
                    394:   register stream_list rem;
                    395:   for (rem = the_streams;
                    396:        rem != ((stream_list) NULL);
                    397:        rem = rem->rest_streams)
                    398:     {
                    399:       fputs (s, rem->handle);
                    400:       putc ('\n', rem->handle);
                    401:     }
                    402:   return;
                    403: }
                    404: 
                    405: #define mail_error error
                    406: 
                    407: void
                    408: setup_files (the_list, field)
                    409:      register line_list the_list;
                    410:      register char *field;
                    411: {
                    412:   register char *start;
                    413:   register char c;
                    414:   while (true)
                    415:     {
                    416:       while (((c = *field) != '\0') &&
                    417:             ((c == ' ') ||
                    418:              (c == '\t') ||
                    419:              (c == ',')))
                    420:        field += 1;
                    421:       if (c != '\0')
                    422:        {
                    423:          start = field;
                    424:          while (((c = *field) != '\0') &&
                    425:                 (c != ' ') &&
                    426:                 (c != '\t') &&
                    427:                 (c != ','))
                    428:            field += 1;
                    429:          *field = '\0';
                    430:          if (!open_a_file (start))
                    431:            mail_error ("Could not open file %s", start);
                    432:          *field = c;
                    433:          if (c != '\0') continue;
                    434:        }
                    435:       if (the_list == ((line_list) NULL)) return;
                    436:       field = the_list->string;
                    437:       the_list = the_list->continuation;
                    438:     }
                    439: }
                    440: 
                    441: int
                    442: args_size (the_header)
                    443:      header the_header;
                    444: {
                    445:   register header old = the_header;
                    446:   register line_list rem;
                    447:   register int size = 0;
                    448:   do
                    449:     {
                    450:       char *field;
                    451:       register char *keyword = get_keyword (the_header->text->string, &field);
                    452:       if ((strcmp (keyword, "TO") == 0) ||
                    453:          (strcmp (keyword, "CC") == 0) ||
                    454:          (strcmp (keyword, "BCC") == 0))
                    455:        {
                    456:          size += 1 + strlen (field);
                    457:          for (rem = the_header->text->continuation;
                    458:               rem != NIL;
                    459:               rem = rem->continuation)
                    460:            size += 1 + strlen (rem->string);
                    461:        }
                    462:       the_header = the_header->next;
                    463:     } while (the_header != old);
                    464:   return size;
                    465: }
                    466: 
                    467: parse_header (the_header, where)
                    468:      header the_header;
                    469:      register char *where;
                    470: {
                    471:   register header old = the_header;
                    472:   do
                    473:     {
                    474:       char *field;
                    475:       register char *keyword = get_keyword (the_header->text->string, &field);
                    476:       if (strcmp (keyword, "TO") == 0)
                    477:        where = add_field (the_header->text->continuation, field, where);
                    478:       else if (strcmp (keyword, "CC") == 0)
                    479:        where = add_field (the_header->text->continuation, field, where);
                    480:       else if (strcmp (keyword, "BCC") == 0)
                    481:        {
                    482:          where = add_field (the_header->text->continuation, field, where);
                    483:          the_header->previous->next = the_header->next;
                    484:          the_header->next->previous = the_header->previous;
                    485:        }
                    486:       else if (strcmp (keyword, "FCC") == 0)
                    487:        setup_files (the_header->text->continuation, field);
                    488:       the_header = the_header->next;
                    489:     } while (the_header != old);
                    490:   *where = '\0';
                    491:   return;
                    492: }
                    493:     
                    494: header
                    495: read_header ()
                    496: {
                    497:   register header the_header = ((header) NULL);
                    498:   register line_list *next_line = ((line_list *) NULL);
                    499: 
                    500:   init_linebuffer (&lb);
                    501: 
                    502:   do
                    503:     {
                    504:       long length;
                    505:       register char *line;
                    506: 
                    507:       readline (&lb, stdin);
                    508:       line = lb.buffer;
                    509:       length = strlen (line);
                    510:       if (length == 0) break;
                    511: 
                    512:       if (has_keyword (line))
                    513:        {
                    514:          register header old = the_header;
                    515:          the_header = new_header ();
                    516:          if (old == ((header) NULL))
                    517:            {
                    518:              the_header->next = the_header;
                    519:              the_header->previous = the_header;
                    520:            }
                    521:          else
                    522:            {
                    523:              the_header->previous = old;
                    524:              the_header->next = old->next;
                    525:              old->next = the_header;
                    526:            }
                    527:          next_line = &(the_header->text);
                    528:        }
                    529: 
                    530:       if (next_line == ((line_list *) NULL))
                    531:        {
                    532:          /* Not a valid header */
                    533:          exit (1);
                    534:        }
                    535:       *next_line = new_list ();
                    536:       (*next_line)->string = alloc_string (length);
                    537:       strcpy (((*next_line)->string), line);
                    538:       next_line = &((*next_line)->continuation);
                    539:       *next_line = NIL;
                    540: 
                    541:     } while (true);
                    542: 
                    543:   return the_header->next;
                    544: }
                    545: 
                    546: void
                    547: write_header (the_header)
                    548:      header the_header;
                    549: {
                    550:   register header old = the_header;
                    551:   do
                    552:     {
                    553:       register line_list the_list;
                    554:       for (the_list = the_header->text;
                    555:           the_list != NIL;
                    556:           the_list = the_list->continuation)
                    557:        put_line (the_list->string);
                    558:       the_header = the_header->next;
                    559:     } while (the_header != old);
                    560:   put_line ("");
                    561:   return;
                    562: }
                    563: 
                    564: void
                    565: main (argc, argv)
                    566:      int argc;
                    567:      char **argv;
                    568: {
                    569:   char *command_line;
                    570:   header the_header;
                    571:   long name_length = strlen (PROGRAM_NAME);
                    572:   char buf[BUFLEN + 1];
                    573:   register int size;
                    574:   FILE *the_pipe;
                    575: 
                    576:   my_name = MY_NAME;
                    577:   the_streams = ((stream_list) NULL);
                    578:   the_date = ((char *) NULL);
                    579:   the_user = ((char *) NULL);
                    580: 
                    581:   the_header = read_header ();
                    582:   command_line = alloc_string (name_length + args_size (the_header));
                    583:   strcpy (command_line, PROGRAM_NAME);
                    584:   parse_header (the_header, &command_line[name_length]);
                    585:   
                    586:   the_pipe = popen (command_line, "w");
                    587:   if (the_pipe == ((FILE *) NULL))
                    588:     fatal ("cannot open pipe to real mailer");
                    589: 
                    590:   add_a_stream (the_pipe, pclose);
                    591: 
                    592:   write_header (the_header);
                    593: 
                    594:   /* Dump the message itself */
                    595: 
                    596:   while (!feof (stdin))
                    597:     {
                    598:       size = fread (buf, 1, BUFLEN, stdin);
                    599:       buf[size] = '\0';
                    600:       put_string (buf);
                    601:     }
                    602: 
                    603:   exit (close_the_streams ());
                    604: }
                    605: 
                    606: #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.