--- /dev/null
+#! /usr/bin/perl
+use strict;
+use warnings;
+require Net::DNS;
+require Net::SMTP;
+use HTML::Entities;
+require URI::Query;
+use POSIX;
+
+die "arg required" if @ARGV!=!$ENV{"GATEWAY_INTERFACE"};
+my $arg=$ARGV[0];
+
+my $nl="\n";
+my $html;
+if ($ENV{"GATEWAY_INTERFACE"}) {
+ $nl="<br />$nl";
+ $html=1;
+ print <<"EOH";
+Content-type: text/html
+
+<html><head><title>Maximum Mail Size Query</title></head><body>
+EOH
+ my %q=URI::Query->new($ENV{"QUERY_STRING"})->hash();
+ my $domain=$q{"domain"};
+ if ($domain) {
+ if ($domain=~/([^-_a-zA-Z0-9.])/) {
+ print "<p><b>Error: Invalid character '".encode_entities($1)."' in specified domain name: ".encode_entities($domain)."</b></p>\n";
+ } else {
+ $arg=$domain;
+ }
+ }
+}
+sub query($) {
+ my($domain)=@_;
+ my $dns=Net::DNS::Resolver->new();
+ #my $dns=Net::DNS::Resolver->new("nameservers"=>["255.255.255.255"]);
+ my $reply=$dns->search($domain,"MX");
+ my $type="MX";
+ do { $type="AAAA"; $reply=$dns->search($domain,"AAAA") } if !$reply&&$dns->errorstring() eq "NOERROR";
+ do { $type="A" ; $reply=$dns->search($domain,"A" ) } if !$reply&&$dns->errorstring() eq "NOERROR";
+ if (!$reply) {
+ print $dns->errorstring().$nl if !$reply;
+ return;
+ }
+ print "Found $type$nl";
+ my @retval;
+ foreach my $rr ($reply->answer()) {
+ my $addr;
+ $addr=$rr->exchange() if $rr->type eq "MX";
+ $addr=$rr->address() if $rr->type=~/^(?:A|AAAA)$/;
+ do { print "Invalid RR: ".$rr->string()."$nl"; next; } if !defined $addr;
+ print "$addr...$nl";
+ my $smtp=Net::SMTP->new($addr,"Timeout"=>10);
+ do { print "Cannot connect to SMTP server $addr: $@$nl"; next; } if !$smtp;
+ my $size=($smtp->message()=~/^SIZE\s*(\d+)\s*$/mi)[0];
+ push @retval,[$addr,$size];
+ }
+ return @retval;
+}
+if ($arg) {
+ print "<pre>\n";
+ my @r=query $arg;
+ print "</pre>\n";
+ if (!@r) {
+ print "<p>Error: Unable to determine anything about domain ".encode_entities($arg)."</p>\n";
+ } else {
+ my $size=$r[0][1];
+ for my $r (@r) {
+ $size=undef if !$size||!$r->[1]||$size!=$r->[1];
+ }
+ sub sizecalc($) {
+ my($input_size)=@_;
+ # https://stackoverflow.com/a/1533248/2995591
+ my $code_size = ceil(($input_size * 4) / 3);
+ my $padding_size = ($input_size % 3) ? (3 - ($input_size % 3)) : 0;
+ my $crlfs_size = 2 + ceil(2 * ($code_size + $padding_size) / 72);
+ my $total_size = $code_size + $padding_size + $crlfs_size;
+ return $total_size;
+ }
+ sub rev($) {
+ my($size)=@_;
+ my $l=0;
+ my $r=$size;
+ while ($l+1<$r) {
+ my $m=int(($l+$r)/2);
+ my $x=sizecalc($m);
+ if ($x<$size) {
+ $l=$m;
+ } else {
+ $r=$m;
+ }
+ }
+ return $l;
+ }
+ sub human($) {
+ my($b)=@_;
+ my $kb=int($b/1000);
+ return "$b bytes" if !$kb;
+ my $mb=int($kb/1000);
+ return "$kb KB" if !$mb;
+ my $gb=int($kb/1000);
+ return "$mb MB" if !$gb;
+ return "$gb GB";
+ }
+ sub size($) {
+ my($size)=@_;
+ return "unknown" if !$size;
+ my $rev=rev($size);
+ return human($rev)." ($rev bytes; raw text mail size $size)";
+ }
+ if ($size) {
+ print "<p>Domain ".encode_entities($arg)." has maximum attachment size ".size($size)."</p>\n";
+ } else {
+ print "<p>Domain ".encode_entities($arg)." maximum attachment size depends on which server is contacted:</p>";
+ print "<table border=\"1\">\n";
+ for my $r (@r) {
+ print "<tr><td>".encode_entities($r->[0])."</td><td>".size($r->[1])."</td></tr>\n";
+ }
+ print "</table>\n";
+ }
+ }
+}
+if ($ENV{"GATEWAY_INTERFACE"}) {
+ print <<"EOH";
+<p>
+ <form action="/cgi-bin/smtpsize" method="get">
+ <input type="text" name="domain" size="32" value="@{[ encode_entities($arg||"") ]}" autofocus="autofocus" />
+ <input type="submit">
+ </form>
+</p>
+</body></html>
+EOH
+}