Moved code from zotnet/mts to mts/generic. Also, unified generic
[mmh] / mts / generic / mts.c
diff --git a/mts/generic/mts.c b/mts/generic/mts.c
new file mode 100644 (file)
index 0000000..7d9b718
--- /dev/null
@@ -0,0 +1,523 @@
+
+/*
+ * mts.c -- definitions for the mail transport system
+ *
+ * $Id$
+ */
+
+#include "h/mh.h"   /* for snprintf() */
+#include <h/nmh.h>
+
+#define nmhetcdir(file) NMHETCDIR#file
+
+#include <ctype.h>
+#include <stdio.h>
+#include <mts.h>
+#include <pwd.h>
+#include <netdb.h>
+
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+
+#define        NOTOK   (-1)
+#define        OK        0
+
+extern int errno;
+
+/*
+ * static prototypes
+ */
+static char *tailor_value (char *);
+static void getuserinfo (void);
+
+/*
+ * *mmdfldir and *uucpldir are the maildrop directories.  If maildrops
+ * are kept in the user's home directory, then these should be empty
+ * strings.  In this case, the appropriate ...lfil array should contain
+ * the name of the file in the user's home directory.  Usually, this is
+ * something like ".mail".
+ */
+
+/*
+ * nmh mail transport interface customization file
+ */
+static char *mtsconf = nmhetcdir(/mts.conf);
+
+static char *localname   = "";
+static char *localdomain = "";
+static char *systemname  = "";
+
+char *mmdfldir = MAILSPOOL;
+char *mmdflfil = "";
+char *uucpldir = "/usr/spool/mail";
+char *uucplfil = "";
+
+char *mmdlm1 = "\001\001\001\001\n";
+char *mmdlm2 = "\001\001\001\001\n";
+
+/* Cache the username and fullname of the user */
+static char username[BUFSIZ];
+static char fullname[BUFSIZ];
+
+/* Variables for username masquerading: */
+       boolean  draft_from_masquerading = FALSE;  /* also used from post.c */
+static boolean  mmailid_masquerading = FALSE;
+       boolean  username_extension_masquerading = FALSE;  /* " from addrsbr.c */
+static char*    masquerade = "";
+
+/*
+ * MTS specific variables
+ */
+#if defined(SMTPMTS)
+static char *sm_method = "smtp";
+int  sm_mts    = MTS_SMTP;
+char *hostable = nmhetcdir(/hosts);
+char *sendmail = SENDMAILPATH;
+#endif
+
+/*
+ * SMTP/POP stuff
+ */
+char *clientname = NULL;
+char *servers    = "localhost \01localnet";
+char *pophost    = "";
+
+/*
+ * BBoards-specific variables
+ */
+char *bb_domain = "";
+
+
+/*
+ * POP BBoards-specific variables
+ */
+#ifdef BPOP
+char *popbbhost = "";
+char *popbbuser = "";
+char *popbblist = nmhetcdir(/hosts.popbb);
+#endif /* BPOP */
+
+/*
+ * Global MailDelivery file
+ */
+char *maildelivery = nmhetcdir(/maildelivery);
+
+
+/*
+ * Aliasing Facility (doesn't belong here)
+ */
+int Everyone = NOTOK;
+static char *everyone = "-1";
+char *NoShell = "";
+
+/*
+ * Customize the MTS settings for nmh by adjusting
+ * the file mts.conf in the nmh etc directory.
+ */
+
+struct bind {
+    char *keyword;
+    char **value;
+};
+
+static struct bind binds[] = {
+    { "localname", &localname },
+    { "localdomain", &localdomain },
+    { "systemname", &systemname },
+    { "mmdfldir", &mmdfldir },
+    { "mmdflfil", &mmdflfil },
+    { "uucpldir", &uucpldir },
+    { "uucplfil", &uucplfil },
+    { "mmdelim1", &mmdlm1 },
+    { "mmdelim2", &mmdlm2 },
+    { "masquerade", &masquerade },
+
+#if defined(SMTPMTS)
+    { "mts",      &sm_method },
+    { "hostable", &hostable  },
+    { "sendmail", &sendmail  },
+#endif
+
+    { "clientname",  &clientname },
+    { "servers", &servers },
+    { "pophost", &pophost },
+    { "bbdomain", &bb_domain },
+
+#ifdef BPOP
+    { "popbbhost", &popbbhost },
+    { "popbbuser", &popbbuser },
+    { "popbblist", &popbblist },
+#endif
+
+#ifdef NNTP
+    { "nntphost", &popbbhost },
+#endif
+
+    { "maildelivery", &maildelivery },
+    { "everyone", &everyone },
+    { "noshell", &NoShell },
+    { NULL, NULL }
+};
+
+
+/*
+ * Read the configuration file for the nmh interface
+ * to the mail transport system (MTS).
+ */
+
+void
+mts_init (char *name)
+{
+    char *bp, *cp, buffer[BUFSIZ];
+    struct bind *b;
+    FILE *fp;
+    static int inited = 0;
+
+    if (inited++ || (fp = fopen (mtsconf, "r")) == NULL)
+       return;
+
+    while (fgets (buffer, sizeof(buffer), fp)) {
+       if (!(cp = strchr(buffer, '\n')))
+           break;
+       *cp = 0;
+       if (*buffer == '#' || *buffer == '\0')
+           continue;
+       if (!(bp = strchr(buffer, ':')))
+           break;
+       *bp++ = 0;
+       while (isspace (*bp))
+           *bp++ = 0;
+
+       for (b = binds; b->keyword; b++)
+           if (!strcmp (buffer, b->keyword))
+               break;
+       if (b->keyword && (cp = tailor_value (bp)))
+           *b->value = cp;
+    }
+
+    fclose (fp);
+
+    Everyone = atoi (everyone);
+
+    if (strstr(masquerade, "draft_from") != NULL)
+       draft_from_masquerading = TRUE;
+
+    if (strstr(masquerade, "mmailid") != NULL)
+       mmailid_masquerading = TRUE;
+
+    if (strstr(masquerade, "username_extension") != NULL)
+       username_extension_masquerading = TRUE;
+
+#ifdef SMTPMTS
+    if (strcmp(sm_method, "smtp") == 0)
+        sm_mts = MTS_SMTP;
+    else if (strcmp(sm_method, "sendmail") == 0)
+        sm_mts = MTS_SENDMAIL;
+    else {
+        advise(NULL, "unsupported \"mts\" value in mts.conf: %s", sm_method);
+        sm_mts = MTS_SMTP;
+    }
+#endif
+}
+
+
+#define        QUOTE   '\\'
+
+/*
+ * Convert escaped values, malloc some new space,
+ * and copy string to malloc'ed memory.
+ */
+
+static char *
+tailor_value (char *s)
+{
+    int i, r;
+    char *bp;
+    char buffer[BUFSIZ];
+    size_t len;
+
+    for (bp = buffer; *s; bp++, s++) {
+       if (*s != QUOTE) {
+           *bp = *s;
+       } else {
+           switch (*++s) {
+               case 'b': *bp = '\b'; break;
+               case 'f': *bp = '\f'; break;
+               case 'n': *bp = '\n'; break;
+               case 't': *bp = '\t'; break;
+
+               case 0: s--;
+               case QUOTE: 
+                   *bp = QUOTE;
+                   break;
+
+               default: 
+                   if (!isdigit (*s)) {
+                       *bp++ = QUOTE;
+                       *bp = *s;
+                   }
+                   r = *s != '0' ? 10 : 8;
+                   for (i = 0; isdigit (*s); s++)
+                       i = i * r + *s - '0';
+                   s--;
+                   *bp = toascii (i);
+                   break;
+           }
+       }
+    }
+    *bp = 0;
+
+    len = strlen (buffer) + 1;
+    if ((bp = malloc (len)))
+       memcpy (bp, buffer, len);
+
+    return bp;
+}
+
+/*
+ * Get the fully qualified name of the local host.
+ */
+
+char *
+LocalName (void)
+{
+    static char buffer[BUFSIZ] = "";
+    struct hostent *hp;
+
+#ifdef HAVE_UNAME
+    struct utsname name;
+#endif
+
+    /* check if we have cached the local name */
+    if (buffer[0])
+       return buffer;
+
+    mts_init ("mts");
+
+    /* check if the mts.conf file specifies a "localname" */
+    if (*localname) {
+       strncpy (buffer, localname, sizeof(buffer));
+    } else {
+#ifdef HAVE_UNAME
+       /* first get our local name */
+       uname (&name);
+       strncpy (buffer, name.nodename, sizeof(buffer));
+#else
+       /* first get our local name */
+       gethostname (buffer, sizeof(buffer));
+#endif
+#ifdef HAVE_SETHOSTENT
+       sethostent (1);
+#endif 
+       /* now fully qualify our name */
+       if ((hp = gethostbyname (buffer)))
+           strncpy (buffer, hp->h_name, sizeof(buffer));
+    }
+
+    /*
+     * If the mts.conf file specifies a "localdomain",
+     * we append that now.  This should rarely be needed.
+     */
+    if (*localdomain) {
+       strcat (buffer, ".");
+       strcat (buffer, localdomain);
+    }
+
+    return buffer;
+}
+
+
+/*
+ * This is only for UUCP mail.  It gets the hostname
+ * as part of the UUCP "domain".
+ */
+
+char *
+SystemName (void)
+{
+    static char buffer[BUFSIZ] = "";
+
+#ifdef HAVE_UNAME
+    struct utsname name;
+#endif
+
+    /* check if we have cached the system name */
+    if (buffer[0])
+       return buffer;
+
+    mts_init ("mts");
+
+    /* check if mts.conf file specifies a "systemname" */
+    if (*systemname) {
+       strncpy (buffer, systemname, sizeof(buffer));
+       return buffer;
+    }
+
+#ifdef HAVE_UNAME
+    uname (&name);
+    strncpy (buffer, name.nodename, sizeof(buffer));
+#else
+    gethostname (buffer, sizeof(buffer));
+#endif
+
+    return buffer;
+}
+
+
+/*
+ * Get the username of current user
+ */
+
+char *
+getusername (void)
+{
+    if (username[0] == '\0')
+       getuserinfo();
+
+    return username;
+}
+
+
+/*
+ * Get full name of current user (typically from GECOS
+ * field of password file).
+ */
+
+char *
+getfullname (void)
+{
+    if (username[0] == '\0')
+       getuserinfo();
+
+    return fullname;
+}
+
+
+/*
+ * Find the user's username and full name, and cache them.
+ * Also, handle "mmailid" username masquerading controlled from the GECOS field
+ * of the passwd file. 
+ */
+
+static void
+getuserinfo (void)
+{
+    register char *cp, *np;
+    register struct passwd *pw;
+
+#ifdef KPOP
+    uid_t uid;
+
+    uid = getuid ();
+    if (uid == geteuid () && (cp = getenv ("USER")) != NULL
+       && (pw = getpwnam (cp)) != NULL)
+      strncpy (username, cp, sizeof(username));
+    else if ((pw = getpwuid (uid)) == NULL
+            || pw->pw_name == NULL
+            || *pw->pw_name == '\0') {
+#else /* KPOP */
+    if ((pw = getpwuid (getuid ())) == NULL
+           || pw->pw_name == NULL
+           || *pw->pw_name == '\0') {
+#endif /* KPOP */
+       strncpy (username, "unknown", sizeof(username));
+       snprintf (fullname, sizeof(fullname), "The Unknown User-ID (%d)",
+               (int) getuid ());
+       return;
+    }
+
+    np = pw->pw_gecos;
+
+    /* Get the user's real name from the GECOS field.  Stop once we hit a ',',
+       which some OSes use to separate other 'finger' information in the GECOS
+       field, like phone number.  Also, if mmailid masquerading is turned on due
+       to "mmailid" appearing on the "masquerade:" line of mts.conf, stop if we
+       hit a '<' (which should precede any ','s). */
+#ifndef BSD42
+    if (mmailid_masquerading)
+       /* Stop at ',' or '<'. */
+       for (cp = fullname; *np != '\0' && *np != ',' && *np != '<';
+            *cp++ = *np++)
+           continue;
+    else
+       /* Allow '<' as a legal character of the user's name.  This code is
+          basically a duplicate of the code above the "else" -- we don't
+          collapse it down to one copy and put the mmailid_masquerading check
+          inside the loop with "(x ? y : z)" because that's inefficient and the
+          value'll never change while it's in there. */
+       for (cp = fullname; *np != '\0' && *np != ',';
+            *cp++ = *np++)
+           continue;
+#else /* BSD42 */
+    /* On BSD(-derived) systems, the system utilities that deal with the GECOS
+       field (finger, mail, sendmail, etc.) translate any '&' character in it to
+       the login name, with the first letter capitalized.  So, for instance,
+       fingering a user "bob" with the GECOS field "& Jones" would reveal him to
+       be "In real life: Bob Jones".  Surprisingly, though, the OS doesn't do
+       the translation for you, so we have to do it manually here. */
+    if (mmailid_masquerading)
+       /* Stop at ',' or '<'. */
+       for (cp = fullname;
+            *np != '\0' && *np != ',' && *np != '<';) {
+           if (*np == '&')     {       /* blech! */
+               strcpy (cp, pw->pw_name);
+               *cp = toupper(*cp);
+               while (*cp)
+                   cp++;
+               np++;
+           } else {
+               *cp++ = *np++;
+           }
+       }
+    else
+       /* Allow '<' as a legal character of the user's name.  This code is
+          basically a duplicate of the code above the "else" -- we don't
+          collapse it down to one copy and put the mmailid_masquerading check
+          inside the loop with "(x ? y : z)" because that's inefficient and the
+          value'll never change while it's in there. */
+       for (cp = fullname;
+            *np != '\0' && *np != ',';) {
+           if (*np == '&')     {       /* blech! */
+               strcpy (cp, pw->pw_name);
+               *cp = toupper(*cp);
+               while (*cp)
+                   cp++;
+               np++;
+           } else {
+               *cp++ = *np++;
+           }
+       }
+#endif /* BSD42 */
+    *cp = '\0';
+
+    if (mmailid_masquerading) {
+       /* Do mmailid processing.  The GECOS field should have the form
+          "Full Name <fakeusername>".  For instance,
+          "Dan Harkless <Dan.Harkless>".  Naturally, you'll want your MTA to
+          have an alias (e.g. in /etc/aliases) from "fakeusername" to your
+          account name.  */ 
+       if (*np)
+           np++;
+       for (cp = username; *np && *np != '>'; *cp++ = *np++)
+           continue;
+       *cp = '\0';
+    }
+    if (!mmailid_masquerading || *np == '\0')
+       strncpy (username, pw->pw_name, sizeof(username));
+
+    /* The $SIGNATURE environment variable overrides the GECOS field's idea of
+       your real name. */
+    if ((cp = getenv ("SIGNATURE")) && *cp)
+       strncpy (fullname, cp, sizeof(fullname));
+
+    if (strchr(fullname, '.')) {               /*  quote any .'s */
+       char tmp[BUFSIZ];
+
+       /* should quote "'s too */
+       snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
+       strncpy (fullname, tmp, sizeof(fullname));
+    }
+
+    return;
+}