(w32font_full_name): New function.
[bpt/emacs.git] / lib-src / fakemail.c
index 1e5bf53..993f90f 100644 (file)
@@ -1,11 +1,12 @@
 /* sendmail-like interface to /bin/mail for system V,
 /* sendmail-like interface to /bin/mail for system V,
-   Copyright (C) 1985 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1994, 1999, 2001, 2002, 2003, 2004,
+                 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 
 This file is part of GNU Emacs.
 
 GNU Emacs 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)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -15,21 +16,28 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 
+#define _XOPEN_SOURCE 500      /* for cuserid */
 
 
-#define NO_SHORTNAMES
-#include <../src/config.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 
-#if defined (BSD) && !defined (BSD4_1) && !defined (USE_FAKEMAIL)
+#if defined (BSD_SYSTEM) && !defined (BSD4_1) && !defined (USE_FAKEMAIL)
 /* This program isnot used in BSD, so just avoid loader complaints.  */
 /* This program isnot used in BSD, so just avoid loader complaints.  */
+int
 main ()
 {
 main ()
 {
+  return 0;
 }
 #else /* not BSD 4.2 (or newer) */
 #ifdef MSDOS
 }
 #else /* not BSD 4.2 (or newer) */
 #ifdef MSDOS
+int
 main ()
 {
 main ()
 {
+  return 0;
 }
 #else /* not MSDOS */
 /* This conditional contains all the rest of the file.  */
 }
 #else /* not MSDOS */
 /* This conditional contains all the rest of the file.  */
@@ -40,11 +48,8 @@ main ()
 #undef static
 #endif
 
 #undef static
 #endif
 
-#ifdef read
-#undef read
-#undef write
-#undef open
-#undef close
+#ifdef WINDOWSNT
+#include "ntlib.h"
 #endif
 
 #include <stdio.h>
 #endif
 
 #include <stdio.h>
@@ -52,6 +57,11 @@ main ()
 #include <ctype.h>
 #include <time.h>
 #include <pwd.h>
 #include <ctype.h>
 #include <time.h>
 #include <pwd.h>
+
+/* This is to declare cuserid.  */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 \f
 /* Type definitions */
 
 \f
 /* Type definitions */
 
@@ -59,6 +69,15 @@ main ()
 #define true 1
 #define false 0
 
 #define true 1
 #define false 0
 
+#define TM_YEAR_BASE 1900
+
+/* Nonzero if TM_YEAR is a struct tm's tm_year value that causes
+   asctime to have well-defined behavior.  */
+#ifndef TM_YEAR_IN_ASCTIME_RANGE
+# define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \
+    (1000 - TM_YEAR_BASE <= (tm_year) && (tm_year) <= 9999 - TM_YEAR_BASE)
+#endif
+
 /* Various lists */
 
 struct line_record
 /* Various lists */
 
 struct line_record
@@ -75,7 +94,7 @@ struct header_record
   struct header_record *previous;
 };
 typedef struct header_record *header;
   struct header_record *previous;
 };
 typedef struct header_record *header;
-                       
+
 struct stream_record
 {
   FILE *handle;
 struct stream_record
 {
   FILE *handle;
@@ -128,7 +147,6 @@ static boolean no_problems = true;
 
 extern FILE *popen ();
 extern int fclose (), pclose ();
 
 extern FILE *popen ();
 extern int fclose (), pclose ();
-extern char *malloc (), *realloc ();
 
 #ifdef CURRENT_USER
 extern struct passwd *getpwuid ();
 
 #ifdef CURRENT_USER
 extern struct passwd *getpwuid ();
@@ -156,32 +174,32 @@ error (s1, s2)
 /* Print error message and exit.  */
 
 static void
 /* Print error message and exit.  */
 
 static void
-fatal (s1, s2)
-     char *s1, *s2;
+fatal (s1)
+     char *s1;
 {
 {
-  error (s1, s2);
-  exit (1);
+  error ("%s", s1);
+  exit (EXIT_FAILURE);
 }
 
 /* Like malloc but get fatal error if memory is exhausted.  */
 
 }
 
 /* Like malloc but get fatal error if memory is exhausted.  */
 
-static char *
+static long *
 xmalloc (size)
      int size;
 {
 xmalloc (size)
      int size;
 {
-  char *result = malloc (((unsigned) size));
-  if (result == ((char *) NULL))
-    fatal ("virtual memory exhausted", 0);
+  long *result = (long *) malloc (((unsigned) size));
+  if (result == ((long *) NULL))
+    fatal ("virtual memory exhausted");
   return result;
 }
 
   return result;
 }
 
-static char *
+static long *
 xrealloc (ptr, size)
 xrealloc (ptr, size)
-     char *ptr;
+     long *ptr;
      int size;
 {
      int size;
 {
-  char *result = realloc (ptr, ((unsigned) size));
-  if (result == ((char *) NULL))
+  long *result = (long *) realloc (ptr, ((unsigned) size));
+  if (result == ((long *) NULL))
     fatal ("virtual memory exhausted");
   return result;
 }
     fatal ("virtual memory exhausted");
   return result;
 }
@@ -197,8 +215,7 @@ init_linebuffer (linebuffer)
 }
 
 /* Read a line of text from `stream' into `linebuffer'.
 }
 
 /* Read a line of text from `stream' into `linebuffer'.
- * Return the length of the line.  
- */
+   Return the length of the line.  */
 
 long
 readline (linebuffer, stream)
 
 long
 readline (linebuffer, stream)
@@ -215,8 +232,8 @@ readline (linebuffer, stream)
       if (p == end)
        {
          linebuffer->size *= 2;
       if (p == end)
        {
          linebuffer->size *= 2;
-         buffer = ((char *) xrealloc (buffer, linebuffer->size));
-         p += buffer - linebuffer->buffer;
+         buffer = ((char *) xrealloc ((long *)buffer, linebuffer->size));
+         p = buffer + (p - linebuffer->buffer);
          end = buffer + linebuffer->size;
          linebuffer->buffer = buffer;
        }
          end = buffer + linebuffer->size;
          linebuffer->buffer = buffer;
        }
@@ -231,6 +248,12 @@ readline (linebuffer, stream)
   return p - buffer;
 }
 \f
   return p - buffer;
 }
 \f
+/* Extract a colon-terminated keyword from the string FIELD.
+   Return that keyword as a string stored in a static buffer.
+   Store the address of the rest of the string into *REST.
+
+   If there is no keyword, return NULL and don't alter *REST.  */
+
 char *
 get_keyword (field, rest)
      register char *field;
 char *
 get_keyword (field, rest)
      register char *field;
@@ -238,22 +261,26 @@ get_keyword (field, rest)
 {
   static char keyword[KEYWORD_SIZE];
   register char *ptr;
 {
   static char keyword[KEYWORD_SIZE];
   register char *ptr;
-  register char c;
+  register int c;
 
   ptr = &keyword[0];
 
   ptr = &keyword[0];
-  c = *field++;
-  if ((isspace (c)) || (c == ':'))
+  c = (unsigned char) *field++;
+  if (isspace (c) || c == ':')
     return ((char *) NULL);
     return ((char *) NULL);
-  *ptr++ = ((islower (c)) ? (toupper (c)) : c);
-  while (((c = *field++) != ':') && (!(isspace (c))))
-    *ptr++ = ((islower (c)) ? (toupper (c)) : c);
+  *ptr++ = (islower (c) ? toupper (c) : c);
+  while (((c = (unsigned char) *field++) != ':') && ! isspace (c))
+    *ptr++ = (islower (c) ? toupper (c) : c);
   *ptr++ = '\0';
   *ptr++ = '\0';
-  while (isspace (c)) c = *field++;
-  if (c != ':') return ((char *) NULL);
+  while (isspace (c))
+    c = (unsigned char) *field++;
+  if (c != ':')
+    return ((char *) NULL);
   *rest = field;
   return &keyword[0];
 }
 
   *rest = field;
   return &keyword[0];
 }
 
+/* Nonzero if the string FIELD starts with a colon-terminated keyword.  */
+
 boolean
 has_keyword (field)
      char *field;
 boolean
 has_keyword (field)
      char *field;
@@ -262,6 +289,16 @@ has_keyword (field)
   return (get_keyword (field, &ignored) != ((char *) NULL));
 }
 
   return (get_keyword (field, &ignored) != ((char *) NULL));
 }
 
+/* Store the string FIELD, followed by any lines in THE_LIST,
+   into the buffer WHERE.
+   Concatenate lines, putting just a space between them.
+   Delete everything contained in parentheses.
+   When a recipient name contains <...>, we discard
+   everything except what is inside the <...>.
+
+   We don't pay attention to overflowing WHERE;
+   the caller has to make it big enough.  */
+
 char *
 add_field (the_list, field, where)
      line_list the_list;
 char *
 add_field (the_list, field, where)
      line_list the_list;
@@ -270,17 +307,48 @@ add_field (the_list, field, where)
   register char c;
   while (true)
     {
   register char c;
   while (true)
     {
+      char *this_recipient_where;
+      int in_quotes = 0;
+
       *where++ = ' ';
       *where++ = ' ';
+      this_recipient_where = where;
+
       while ((c = *field++) != '\0')
        {
       while ((c = *field++) != '\0')
        {
-         if (c == '(')
+         if (c == '\\')
+           *where++ = c;
+         else if (c == '"')
+           {
+             in_quotes = ! in_quotes;
+             *where++ = c;
+           }
+         else if (in_quotes)
+           *where++ = c;
+         else if (c == '(')
            {
              while (*field && *field != ')') ++field;
            {
              while (*field && *field != ')') ++field;
-             if (! (*field++)) break; /* no closer */
-             if (! (*field))   break; /* closerNULL */
-             c = *field;
+             if (! (*field++)) break; /* no close */
+             continue;
+           }
+         else if (c == ',')
+           {
+             *where++ = ' ';
+             /* When we get to the end of one recipient,
+                don't discard it if the next one has <...>.  */
+             this_recipient_where = where;
            }
            }
-         *where++ = ((c == ','||c=='>'||c=='<') ? ' ' : c);
+         else if (c == '<')
+           /* Discard everything we got before the `<'.  */
+           where = this_recipient_where;
+         else if (c == '>')
+           /* Discard the rest of this name that follows the `>'.  */
+           {
+             while (*field && *field != ',') ++field;
+             if (! (*field++)) break; /* no comma */
+             continue;
+           }
+         else
+           *where++ = c;
        }
       if (the_list == NIL) break;
       field = the_list->string;
        }
       if (the_list == NIL) break;
       field = the_list->string;
@@ -294,6 +362,7 @@ make_file_preface ()
 {
   char *the_string, *temp;
   long idiotic_interface;
 {
   char *the_string, *temp;
   long idiotic_interface;
+  struct tm *tm;
   long prefix_length;
   long user_length;
   long date_length;
   long prefix_length;
   long user_length;
   long date_length;
@@ -301,7 +370,13 @@ make_file_preface ()
 
   prefix_length = strlen (FROM_PREFIX);
   time (&idiotic_interface);
 
   prefix_length = strlen (FROM_PREFIX);
   time (&idiotic_interface);
-  the_date = ctime (&idiotic_interface);
+  /* Convert to a string, checking for out-of-range time stamps.
+     Don't use 'ctime', as that might dump core if the hardware clock
+     is set to a bizarre value.  */
+  tm = localtime (&idiotic_interface);
+  if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year)
+        && (the_date = asctime (tm))))
+    fatal ("current time is out of range");
   /* the_date has an unwanted newline at the end */
   date_length = strlen (the_date) - 1;
   the_date[date_length] = '\0';
   /* the_date has an unwanted newline at the end */
   date_length = strlen (the_date) - 1;
   the_date[date_length] = '\0';
@@ -309,9 +384,9 @@ make_file_preface ()
   user_length = strlen (temp);
   the_user = alloc_string (user_length + 1);
   strcpy (the_user, temp);
   user_length = strlen (temp);
   the_user = alloc_string (user_length + 1);
   strcpy (the_user, temp);
-  the_string = alloc_string (3 + prefix_length +
-                            user_length +
-                            date_length);
+  the_string = alloc_string (3 + prefix_length
+                            + user_length
+                            date_length);
   temp = the_string;
   strcpy (temp, FROM_PREFIX);
   temp = &temp[prefix_length];
   temp = the_string;
   strcpy (temp, FROM_PREFIX);
   temp = &temp[prefix_length];
@@ -351,7 +426,7 @@ close_the_streams ()
     no_problems = (no_problems &&
                   ((*rem->action) (rem->handle) == 0));
   the_streams = ((stream_list) NULL);
     no_problems = (no_problems &&
                   ((*rem->action) (rem->handle) == 0));
   the_streams = ((stream_list) NULL);
-  return (no_problems ? 0 : 1);
+  return (no_problems ? EXIT_SUCCESS : EXIT_FAILURE);
 }
 
 void
 }
 
 void
@@ -461,6 +536,10 @@ put_line (string)
 \f
 #define mail_error error
 
 \f
 #define mail_error error
 
+/* Handle an FCC field.  FIELD is the text of the first line (after
+   the header name), and THE_LIST holds the continuation lines if any.
+   Call open_a_file for each file.  */
+
 void
 setup_files (the_list, field)
      register line_list the_list;
 void
 setup_files (the_list, field)
      register line_list the_list;
@@ -470,18 +549,18 @@ setup_files (the_list, field)
   register char c;
   while (true)
     {
   register char c;
   while (true)
     {
-      while (((c = *field) != '\0') &&
-            ((c == ' ') ||
-             (c == '\t') ||
-             (c == ',')))
+      while (((c = *field) != '\0')
+            && (c == ' '
+                || c == '\t'
+                || c == ','))
        field += 1;
       if (c != '\0')
        {
          start = field;
        field += 1;
       if (c != '\0')
        {
          start = field;
-         while (((c = *field) != '\0') &&
-                (c != ' ') &&
-                (c != '\t') &&
-                (c != ','))
+         while (((c = *field) != '\0')
+                && c != ' '
+                && c != '\t'
+                && c != ',')
            field += 1;
          *field = '\0';
          if (!open_a_file (start))
            field += 1;
          *field = '\0';
          if (!open_a_file (start))
@@ -489,12 +568,16 @@ setup_files (the_list, field)
          *field = c;
          if (c != '\0') continue;
        }
          *field = c;
          if (c != '\0') continue;
        }
-      if (the_list == ((line_list) NULL)) return;
+      if (the_list == ((line_list) NULL))
+       return;
       field = the_list->string;
       the_list = the_list->continuation;
     }
 }
 \f
       field = the_list->string;
       the_list = the_list->continuation;
     }
 }
 \f
+/* Compute the total size of all recipient names stored in THE_HEADER.
+   The result says how big to make the buffer to pass to parse_header.  */
+
 int
 args_size (the_header)
      header the_header;
 int
 args_size (the_header)
      header the_header;
@@ -506,9 +589,9 @@ args_size (the_header)
     {
       char *field;
       register char *keyword = get_keyword (the_header->text->string, &field);
     {
       char *field;
       register char *keyword = get_keyword (the_header->text->string, &field);
-      if ((strcmp (keyword, "TO") == 0) ||
-         (strcmp (keyword, "CC") == 0) ||
-         (strcmp (keyword, "BCC") == 0))
+      if ((strcmp (keyword, "TO") == 0)
+         || (strcmp (keyword, "CC") == 0)
+         || (strcmp (keyword, "BCC") == 0))
        {
          size += 1 + strlen (field);
          for (rem = the_header->text->continuation;
        {
          size += 1 + strlen (field);
          for (rem = the_header->text->continuation;
@@ -521,6 +604,13 @@ args_size (the_header)
   return size;
 }
 
   return size;
 }
 
+/* Scan the header described by the lists THE_HEADER,
+   and put all recipient names into the buffer WHERE.
+   Precede each recipient name with a space.
+
+   Also, if the header has any FCC fields, call setup_files for each one.  */
+
+void
 parse_header (the_header, where)
      header the_header;
      register char *where;
 parse_header (the_header, where)
      header the_header;
      register char *where;
@@ -547,7 +637,13 @@ parse_header (the_header, where)
   *where = '\0';
   return;
 }
   *where = '\0';
   return;
 }
-\f    
+\f
+/* Read lines from the input until we get a blank line.
+   Create a list of `header' objects, one for each header field,
+   each of which points to a list of `line_list' objects,
+   one for each line in that field.
+   Continuation lines are grouped in the headers they continue.  */
+
 header
 read_header ()
 {
 header
 read_header ()
 {
@@ -587,7 +683,7 @@ read_header ()
       if (next_line == ((line_list *) NULL))
        {
          /* Not a valid header */
       if (next_line == ((line_list *) NULL))
        {
          /* Not a valid header */
-         exit (1);
+         exit (EXIT_FAILURE);
        }
       *next_line = new_list ();
       (*next_line)->string = alloc_string (length);
        }
       *next_line = new_list ();
       (*next_line)->string = alloc_string (length);
@@ -597,6 +693,8 @@ read_header ()
 
     } while (true);
 
 
     } while (true);
 
+  if (! the_header)
+    fatal ("input message has no header");
   return the_header->next;
 }
 \f
   return the_header->next;
 }
 \f
@@ -618,7 +716,7 @@ write_header (the_header)
   return;
 }
 \f
   return;
 }
 \f
-void
+int
 main (argc, argv)
      int argc;
      char **argv;
 main (argc, argv)
      int argc;
      char **argv;
@@ -647,7 +745,7 @@ main (argc, argv)
   command_line = alloc_string (name_length + args_size (the_header));
   strcpy (command_line, mail_program_name);
   parse_header (the_header, &command_line[name_length]);
   command_line = alloc_string (name_length + args_size (the_header));
   strcpy (command_line, mail_program_name);
   parse_header (the_header, &command_line[name_length]);
-  
+
   the_pipe = popen (command_line, "w");
   if (the_pipe == ((FILE *) NULL))
     fatal ("cannot open pipe to real mailer");
   the_pipe = popen (command_line, "w");
   if (the_pipe == ((FILE *) NULL))
     fatal ("cannot open pipe to real mailer");
@@ -670,3 +768,8 @@ main (argc, argv)
 
 #endif /* not MSDOS */
 #endif /* not BSD 4.2 (or newer) */
 
 #endif /* not MSDOS */
 #endif /* not BSD 4.2 (or newer) */
+
+/* arch-tag: acb0afa6-315a-4c5b-b9e3-def5725c8783
+   (do not change this comment) */
+
+/* fakemail.c ends here */