]> mj.ucw.cz Git - maildups.git/commitdiff
...
authorMartin Mares <mj@ucw.cz>
Sun, 8 Jan 2006 12:03:38 +0000 (12:03 +0000)
committerMartin Mares <mj@ucw.cz>
Sun, 8 Jan 2006 12:03:38 +0000 (12:03 +0000)
Makefile
mdup.c
smail.c [new file with mode: 0644]

index 65127cc37bed92942d8acf639fab274a90e1e788..6496a26c32e0206610e098c0a67d2304b9d6ee56 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,17 +4,19 @@ CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -W
 VERSION=0.1
 YEAR=2006
 
-all: mdup
+all: mdup smail
 
 mdup: mdup.o util.o sha1.o
+smail: smail.o util.o
 
 mdup.o: mdup.c util.h
+smail.o: smail.c util.h
 util.o: util.c util.h
 sha1.o: sha1.c util.h
 
 clean:
        rm -f `find . -name "*~" -or -name "*.[oa]" -or -name "\#*\#" -or -name TAGS -or -name core`
-       rm -f mdup
+       rm -f mdup smail
        rm -rf maint/dist
 
 distclean: clean
diff --git a/mdup.c b/mdup.c
index 0d3554179f73ac0d0e8fe8bb0952381279b32680..877d375fe0672e10c23a4294f6caed3afc017f7b 100644 (file)
--- a/mdup.c
+++ b/mdup.c
@@ -216,7 +216,7 @@ parse_header_line(char *line, uns cnt, struct item *item)
       uns lul = strlen(local_user);
       if (!strcasecmp(rhs, local_domain) &&
          !strncasecmp(lhs, local_user, lul) &&
-         !strncasecmp(lhs+lul, "+md+", 4))
+         !strncasecmp(lhs+lul, "+md-", 4))
        {
          verb(1, "Detected local Message-ID");
          item->timestamp = 2;
diff --git a/smail.c b/smail.c
new file mode 100644 (file)
index 0000000..c6cd754
--- /dev/null
+++ b/smail.c
@@ -0,0 +1,208 @@
+/*
+ *     Sendmail Wrapper :)
+ *
+ *     (c) 2006 Martin Mares <mj@ucw.cz>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/wait.h>
+
+#include "util.h"
+
+static char *local_user;
+static char *local_domain;
+static char *from_user;
+static char *from_domain;
+
+static time_t now;
+static struct tm *now_tm;
+
+static pid_t sm_pid;
+static FILE *sm_fh;
+
+static void
+start_sendmail(char **oargv, int oargc)
+{
+  char **argv = xmalloc(sizeof(char *) * (oargc+4));
+  int argc = 0;
+  argv[argc++] = "/usr/sbin/sendmail";
+
+  char from[strlen(from_user) + strlen(from_domain) + 16];
+  if (from_user)
+    {
+      sprintf(from, "%s+f-%04d%02d%02d@%s", from_user, now_tm->tm_year + 1900, now_tm->tm_mon + 1, now_tm->tm_mday, from_domain);
+      argv[argc++] = "-f";
+      argv[argc++] = from;
+      verb(1, "Using -f %s", from);
+    }
+
+  memcpy(argv+argc, oargv, sizeof(char *) * oargc);
+  argc += oargc;
+  argv[argc] = NULL;
+
+  // for (uns i=0; argv[i]; i++) verb(2, "Option: <%s>", argv[i]);
+
+  int pfd[2];
+  if (pipe(pfd) < 0)
+    die("pipe failed: %m");
+
+  sm_pid = fork();
+  if (sm_pid < 0)
+    die("fork failed: %m");
+  if (!sm_pid)
+    {
+      dup2(pfd[0], 0);
+      close(pfd[0]);
+      close(pfd[1]);
+      execvp(argv[0], argv);
+      die("Cannot exec %s: %m", argv[0]);
+    }
+  close(pfd[0]);
+  sm_fh = fdopen(pfd[1], "w");
+  if (!sm_fh)
+    die("fdopen() failed: %m");
+  verb(1, "Forked pid %d for %s", sm_pid, argv[0]);
+}
+
+static void
+close_sendmail(void)
+{
+  if (ferror(sm_fh) || fclose(sm_fh))
+    die("Error occured when writing to sendmail pipe");
+  for (;;)
+    {
+      int st;
+      pid_t p = wait(&st);
+      if (p < 0)
+       die("wait failed: %m");
+      if (p == sm_pid)
+       {
+         verb(1, "Subprocess %d finished with status 0x%x", p, st);
+         if (WIFEXITED(st))
+           {
+             if (WEXITSTATUS(st))
+               die("Sendmail process failed with exit code %d", WEXITSTATUS(st));
+             return;
+           }
+         if (WIFSIGNALED(st))
+           die("Sendmail process died on signal %d", WIFSIGNALED(st));
+         die("Sendmail process died with unknown status 0x%x", st);
+       }
+    }
+}
+
+static void
+process_header(void)
+{
+  char hdr[1024];
+
+  for (;;)
+    {
+      if (!fgets(hdr, sizeof(hdr), stdin))
+       die("Malformed mail headers: unexpected EOF");
+      char *nl = strchr(hdr, '\n');
+      if (!nl)
+       die("Malformed mail headers: line too long");
+      if (hdr[0] == '\r' || hdr[0] == '\n')
+       break;
+      if (strncasecmp(hdr, "Message-ID:", 11))
+       {
+         fputs(hdr, sm_fh);
+         *nl = 0;
+       }
+    }
+
+  if (local_user)
+    {
+      char hostname[64];
+      if (gethostname(hostname, sizeof(hostname)))
+       hostname[0] = 0;
+      else
+       hostname[sizeof(hostname)-1] = 0;
+      fprintf(sm_fh, "Message-ID: <%s+md-%04d%02d%02d.%02d%02d%02d.%d.%s@%s>\n",
+             local_user,
+             now_tm->tm_year + 1900, now_tm->tm_mon + 1, now_tm->tm_mday,
+             now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec,
+             getpid(), hostname,
+             local_domain);
+    }
+  fputs("\n", sm_fh);
+}
+
+static void
+process_body(void)
+{
+  char buf[1024];
+  int n;
+  while ((n = fread(buf, 1, sizeof(buf), stdin)) > 0)
+    fwrite(buf, 1, n, sm_fh);
+  if (n < 0)
+    die("Malformed mail body: %m");
+}
+
+static void NONRET
+usage(void)
+{
+  fprintf(stderr, "Usage: smail [<options>] -- <sendmail-options>\n\
+\n\
+Options:\n\
+-f<user>@<domain>\tGenerate envelope sender address for easy identification of bounces\n\
+-l<user>@<domain>\tAdd Message-ID for detection of messages looped back\n\
+-v\t\t\tIncrease verbosity\n\
+\n\
+MailDups " STR(VERSION) ", (c) " STR(YEAR) " Martin Mares <mj@ucw.cz>\n\
+It can be freely distributed and used according to the GNU GPL v2.\n\
+");
+  exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c;
+  while ((c = getopt(argc, argv, "f:l:v")) >= 0)
+    switch (c)
+      {
+      case 'f':
+       {
+         char *c = strchr(optarg, '@');
+         if (!c)
+           usage();
+         *c++ = 0;
+         from_user = optarg;
+         from_domain = c;
+         break;
+       }
+      case 'l':
+       {
+         char *c = strchr(optarg, '@');
+         if (!c)
+           usage();
+         *c++ = 0;
+         local_user = optarg;
+         local_domain = c;
+         break;
+       }
+      case 'v':
+       verbose++;
+       break;
+      default:
+       usage();
+      }
+
+  now = time(NULL);
+  if (!(now_tm = gmtime(&now)))
+    die("gmtime() failed: %m");
+
+  start_sendmail(argv+optind, argc-optind);
+  process_header();
+  process_body();
+  close_sendmail();
+  return 0;
+}