Mercurial > hg > mlmmj
changeset 298:57d116ad0ea0
New perl-admin, hdradd before mime
line wrap: on
line diff
--- a/ChangeLog Wed Aug 18 15:38:21 2004 +1000 +++ b/ChangeLog Fri Aug 20 21:01:50 2004 +1000 @@ -1,3 +1,9 @@ +1.0.0-RC1 + o Add web-interface. Thanks Christian Laursen for new perl-admin + o Dump the customheaders before any Mime headers + o Implement +get-N functionality, so it's possible to send a mail to + foolist+get-101@domain.tld to retrieve mail 101 from that list. It's + deliberately only possible to request one mail at a time. o Make sure that only either root or the listdir owner can execute the binaries when it has something to do with lists. o Don't leave bounces-help@ mails lying around in queue/
--- a/Makefile.am Wed Aug 18 15:38:21 2004 +1000 +++ b/Makefile.am Fri Aug 20 21:01:50 2004 +1000 @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = foreign dist-bzip2 EXTRA_DIST = include VERSION LICENSE UPGRADE listtexts src/log_error.c FAQ \ - TUNABLES README.access + TUNABLES README.access contrib CLEANFILES = *~ mlmmj-*.tar.* dist-hook:
--- a/VERSION Wed Aug 18 15:38:21 2004 +1000 +++ b/VERSION Fri Aug 20 21:01:50 2004 +1000 @@ -1,1 +1,1 @@ -0.8.4 +1.0.0-RC1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/conf/config.pl Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,2 @@ +$topdir = "/var/spool/mlmmj"; +$templatedir = "/home/mlmmj/templates";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/conf/tunables.pl Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,61 @@ +mlmmj_boolean("closedlist", + "Closed list", + "If this option is set, subscribtion and unsubscription via mail is disabled."); + +mlmmj_boolean("moderated", + "Moderated", + "If this option is set, the emailaddresses in the file listdir/control/moderators will act as moderators for the list."); + +mlmmj_list("moderators", + "Moderators", + "If the list is moderated, this is the list of moderators."); + +mlmmj_boolean("tocc", + "To: Cc:", + "If this option is set, the list address does not have to be in the To: or Cc: header of the email to the list."); + +mlmmj_boolean("addtohdr", + "Add To: header", + "If this option is set, a To: header including the recipients emailaddress will be added to outgoing mail. ". + "Recommended usage is to remove existing To: headers with delheaders (see below) first."); + +mlmmj_boolean("subonlypost", + "Subscribers only post", + "If this option is set, only people who are subscribed to the list, are allowed to post to it. ". + "The check is made against the \"From:\" header."); + +mlmmj_string("prefix", + "Prefix", + "The prefix for the Subject: line of mails to the list. This will alter the Subject: line, ". + "and add a prefix if it's not present elsewhere."); + +mlmmj_list("owner", + "Owner", + "The emailaddresses in this list will get mails to ".encode_entities($list)."+owner"); + +mlmmj_list("delheaders", + "Delete headers", + "In this file is specified *ONE* headertoken to match pr. line. ". + "If the file consists of: Received: Message-ID: Then all occurences of these headers in incoming list mail will be deleted. ". + "\"From \" and \"Return-Path:\" are deleted no matter what."); + +mlmmj_list("access", + "Access", + "If this option is set, all headers of a post to the list is matched against the rules. The first rule to match wins. ". + "See README.access for syntax and examples. NOTE: If this field is empty access control is *disabled*, ". + "unlike having an empty control/access file."); + +mlmmj_string("memorymailsize", + "Memory mail size", + "Here is specified in bytes how big a mail can be and still be prepared for sending in memory. ". + "It's greatly reducing the amount of write system calls to prepare it in memory before sending it, ". + "but can also lead to denial of service attacks. Default is 16k (16384 bytes)."); + +mlmmj_string("relayhost", + "Relay host", + "The host specified (IP address og domainname, both works) in this file will be used for relaying the mail sent to the list. ". + "Defaults to 127.0.0.1."); + +mlmmj_boolean("notifysub", + "Notify subscribers", + "If this option is set, the owner(s) will get a mail with the address of someone sub/unsubscribing to a mailinglist.");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/htdocs/dot.htaccess Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,4 @@ +Require valid-user +AuthType Basic +AuthName "mlmmj web-interface" +AuthUserFile /home/mlmmj/htpasswd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/htdocs/edit.cgi Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,121 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2004 Morten K. Poulsen <morten at afdelingp.dk> +# Copyright (C) 2004 Christian Laursen <christian@pil.dk> +# +# $Id$ +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +use strict; +use CGI; +use CGI::FastTemplate; +use HTML::Entities; + +use vars qw($topdir $templatedir $list); + +if (exists $ENV{CONFIG_PATH}) { + require $ENV{CONFIG_PATH}; +} else { + require "../conf/config.pl"; +} + +my $tpl = new CGI::FastTemplate($templatedir); + +my $q = new CGI; +$list = $q->param("list"); + +die "non-existent list" unless -d("$topdir/$list"); + +$tpl->define(main => "edit.html", + boolean => "edit_boolean.html", + string => "edit_string.html", + list => "edit_list.html"); + +$tpl->assign(LIST => encode_entities($list)); + +my $tunables_file = "../conf/tunables.pl"; +if (exists $ENV{TUNABLES_PATH}) { + $tunables_file = $ENV{TUNABLES_PATH}; +} + +do $tunables_file; + +print "Content-type: text/html\n\n"; +$tpl->parse(CONTENT => "main"); +$tpl->print; + +sub mlmmj_boolean { + my ($name, $nicename, $text) = @_; + my $checked = -f "$topdir/$list/control/$name"; + + $tpl->assign(NAME => encode_entities($name)); + $tpl->assign(NICENAME => encode_entities($nicename)); + $tpl->assign(TEXT => encode_entities($text)); + $tpl->assign(CHECKED => $checked ? ' checked' : ''); + + $tpl->parse(ROWS => ".boolean"); +} + +sub mlmmj_string { + my ($name, $nicename, $text) = @_; + my $file = "$topdir/$list/control/$name"; + my $value; + + if (! -f $file) { + $value = ""; + } else { + open(F, $file) or die("can't open $file"); + $value = <F>; + close(F); + chomp($value); + } + + $tpl->assign(NAME => encode_entities($name)); + $tpl->assign(NICENAME => encode_entities($nicename)); + $tpl->assign(TEXT => encode_entities($text)); + $tpl->assign(VALUE => encode_entities($value)); + + $tpl->parse(ROWS => ".string"); +} + +sub mlmmj_list { + my ($name, $nicename, $text) = @_; + my $file = "$topdir/$list/control/$name"; + my $value; + + if (! -f $file) { + $value = ""; + } else { + open(F, $file) or die("can't open $file"); + while (<F>) { + $value .= $_; + } + close(F); + chomp($value); + } + + $tpl->assign(NAME => encode_entities($name)); + $tpl->assign(NICENAME => encode_entities($nicename)); + $tpl->assign(TEXT => encode_entities($text)); + $tpl->assign(VALUE => encode_entities($value)); + + $tpl->parse(ROWS => ".list"); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/htdocs/index.cgi Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,56 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2004 Morten K. Poulsen <morten at afdelingp.dk> +# Copyright (C) 2004 Christian Laursen <christian@pil.dk> +# +# $Id$ +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +use strict; +use URI::Escape; +use HTML::Entities; +use CGI::FastTemplate; + +use vars qw($topdir $templatedir); + +if (exists $ENV{CONFIG_PATH}) { + require $ENV{CONFIG_PATH}; +} else { + require "../conf/config.pl"; +} + +my $tpl = new CGI::FastTemplate($templatedir); + +$tpl->define(main => "index.html"); + +my $lists = ""; +opendir(DIR, $topdir) or die "Couldn't open $topdir for reading: $!"; +while (my $list = readdir(DIR)) { + next if $list =~ /^\./; + $lists .= "<a href=\"edit.cgi?list=".uri_escape($list)."\">".encode_entities($list)."</a><br />\n"; +} +closedir(DIR); + +$tpl->assign(LISTS => $lists); + +print "Content-type: text/html\n\n"; + +$tpl->parse(CONTENT => "main"); +$tpl->print;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/htdocs/save.cgi Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,97 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2004 Morten K. Poulsen <morten at afdelingp.dk> +# Copyright (C) 2004 Christian Laursen <christian@pil.dk> +# +# $Id$ +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# We might want some kind of validation of the values we are about to save, +# but that would require save.cgi to know about all kind of options that mlmmj +# accepts. I am not sure we want that. -- mortenp 20040709 + +use strict; +use CGI; +use CGI::FastTemplate; +use HTML::Entities; + +use vars qw($topdir $templatedir $list); + +if (exists $ENV{CONFIG_PATH}) { + require $ENV{CONFIG_PATH}; +} else { + require "../conf/config.pl"; +} + +my $tpl = new CGI::FastTemplate($templatedir); + +my $q = new CGI; +$list = $q->param("list"); + +die "non-existent list" unless -d("$topdir/$list"); + +$tpl->define(main => "save.html"); +$tpl->assign(LIST => encode_entities($list)); + +my $tunables_file = "../conf/tunables.pl"; +if (exists $ENV{TUNABLES_PATH}) { + $tunables_file = $ENV{TUNABLES_PATH}; +} + +do $tunables_file; + +print "Content-type: text/html\n\n"; +$tpl->parse(CONTENT => "main"); +$tpl->print; + +sub mlmmj_boolean { + my ($name, $nicename, $text) = @_; + + my $file = "$topdir/$list/control/$name"; + + my $value = $q->param($name); + if ($value) { + open (FILE, ">$file") or die "Couldn't open $file for writing: $!"; + close FILE; + } else { + unlink $file; + } +} + +sub mlmmj_string { + mlmmj_list(@_); +} + +sub mlmmj_list { + my ($name, $nicename, $text) = @_; + + my $file = "$topdir/$list/control/$name"; + + my $value = $q->param($name); + + if (defined $value && $value !~ /^\s*$/) { + $value .= "\n" if $value !~ /\n$/; + open (FILE, ">$file") or die "Couldn't open $file for writing: $!"; + print FILE $value; + close FILE; + } else { + unlink $file; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/templates/edit.html Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,10 @@ +<html><head><title>mlmmj config</title></head><body> +<h1>mlmmj config</h1> +<form method="post" action="save.cgi"> +<input type="hidden" name="list" value="$LIST"> +<table border="1"> +$ROWS +</table> +<input type="submit" name="submit" /> +</form> +</body></html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/templates/edit_boolean.html Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,1 @@ +<tr><td>$NICENAME</td><td><input type="checkbox" name="$NAME" value="1"$CHECKED></td><td>$TEXT</td></tr>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/templates/edit_list.html Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,1 @@ +<tr><td>$NICENAME</td><td><textarea name="$NAME" columns="40">$VALUE</textarea></td><td>$TEXT</td></tr>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/templates/edit_string.html Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,1 @@ +<tr><td>$NICENAME</td><td><input type="text" name="$NAME" value="$VALUE"></td><td>$TEXT</td></tr>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/templates/index.html Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,4 @@ +<html><head><title>mlmmj config</title></head><body> +<h1>mlmmj config</h1> +$LISTS +</body></html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/web/perl-admin/templates/save.html Fri Aug 20 21:01:50 2004 +1000 @@ -0,0 +1,9 @@ +<html><head><title>mlmmj config</title></head><body> +<h1>mlmmj config</h1> +<p> +$LIST control values saved! +</p> +<p> +<a href="index.cgi">Index</a> | <a href="edit.cgi?list=$LIST">$LIST</a> +</p> +</body></html>
--- a/src/do_all_the_voodo_here.c Wed Aug 18 15:38:21 2004 +1000 +++ b/src/do_all_the_voodo_here.c Fri Aug 20 21:01:50 2004 +1000 @@ -80,31 +80,38 @@ struct strlist *allhdrs, const char *prefix) { char *hdrline, *subject, *unqp; + int hdrsadded = 0; allhdrs->count = 0; allhdrs->strs = NULL; while((hdrline = gethdrline(infd))) { /* Done with headers? Then add extra if wanted*/ - if((strlen(hdrline) == 1) && (hdrline[0] == '\n')){ - if(hdrfd >= 0) { + if((strncasecmp(hdrline, "mime", 4) == NULL) || + ((strlen(hdrline) == 1) && (hdrline[0] == '\n'))){ + if(!hdrsadded && hdrfd >= 0) { if(dumpfd2fd(hdrfd, outfd) < 0) { log_error(LOG_ARGS, "Could not " "add extra headers"); myfree(hdrline); return -1; - } - } - if(writen(outfd, hdrline, strlen(hdrline)) < 0) { - myfree(hdrline); - log_error(LOG_ARGS, "Error writing hdrs."); - return -1; + } else + hdrsadded = 1; } fsync(outfd); myfree(hdrline); + if(hdrline[0] == '\n') { + if(writen(outfd, hdrline, strlen(hdrline)) + < 0) { + myfree(hdrline); + log_error(LOG_ARGS, + "Error writing hdrs."); + return -1; + } break; } + } /* Do we want info from hdrs? Get it before it's gone */ if(readhdrs) getinfo(hdrline, readhdrs);
--- a/src/listcontrol.c Wed Aug 18 15:38:21 2004 +1000 +++ b/src/listcontrol.c Fri Aug 20 21:01:50 2004 +1000 @@ -29,6 +29,7 @@ #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> +#include <ctype.h> #include "mlmmj.h" #include "listcontrol.h" @@ -49,6 +50,7 @@ CTRL_BOUNCES, CTRL_MODERATE, CTRL_HELP, + CTRL_GET, CTRL_END /* end marker, must be last */ }; @@ -67,7 +69,8 @@ { "confunsub", 1 }, { "bounces", 1 }, { "moderate", 1 }, - { "help", 0 } + { "help", 0 }, + { "get", 1 } }; @@ -78,6 +81,7 @@ { char *atsign, *recipdelimsign, *bouncenr, *tmpstr; char *controlstr, *param, *conffilename, *moderatefilename; + char *c, *archivefilename; size_t len; struct stat stbuf; int closedlist, tmpfd; @@ -248,6 +252,29 @@ mlmmjsend); break; + case CTRL_GET: + errno = 0; + unlink(mailname); + if(!param) /* malformed get, ignore silently */ + exit(EXIT_SUCCESS); + else { /* sanity check--is it all digits? */ + for(c = param; *c != '\0'; c++) { + if(!isdigit((int)*c)) + exit(EXIT_SUCCESS); + } + archivefilename = concatstr(3, listdir, "/archive/", + param); + if(stat(archivefilename, &stbuf) < 0) + exit(EXIT_SUCCESS); + else + execlp(mlmmjsend, mlmmjsend, + "-T", fromemails->emaillist[0], + "-L", listdir, + "-l", "6", + "-m", archivefilename, + "-a", "-D", 0); + } + break; } unlink(mailname);
--- a/src/mlmmj-send.c Wed Aug 18 15:38:21 2004 +1000 +++ b/src/mlmmj-send.c Fri Aug 20 21:01:50 2004 +1000 @@ -444,6 +444,7 @@ " '3' means 'resend failed list mail'\n" " '4' means 'send to file with recipients'\n" " '5' means 'bounceprobe'\n" + " '6' means 'single listmail to single recipient'\n" " -L: Full path to list directory\n" " -m: Full path to mail file\n" " -r: Relayhost IP address (defaults to 127.0.0.1)\n" @@ -568,6 +569,7 @@ case '3': case '4': case '5': + case '6': archive = 0; default: break; @@ -654,7 +656,13 @@ myfree(body); exit(EXIT_FAILURE); } - + case '6': + archive = 0; + deletewhensent = 0; + archivefilename = mystrdup(mailfilename); + bounceaddr = bounce_from_adr(to_addr, listaddr, + archivefilename); + break; default: /* normal list mail -- now handled when forking */ break; } @@ -688,6 +696,7 @@ switch(listctrl[0]) { case '1': /* A single mail is to be sent */ + case '6': initsmtp(&sockfd, relay); sendres = send_mail(sockfd, bounceaddr, to_addr, replyto, mailmap, st.st_size, listdir, NULL,