5 m2n - a mail2news(1) replacement
13 A replacement for I<mail2news> from the newsgate package. Uses I<rnews> instead
14 of I<inews> by default, and is much less insistent on removing useful headers.
18 Long option names may be abbreviated to uniqueness.
24 Send output to standard output rather than directly to I<rnews>.
26 =item B<-a>, B<--approved>=I<approved>
28 Approved: line, if none is specified.
30 =item B<-d>, B<--distribution>=I<distribution>
32 Distribution: line, if none is specified.
34 =item B<-n>, B<--newsgroups>=I<newsgroups>
36 Newsgroups: line, overriding any such provided. Newsgroups: lines in the input
37 will be saved in X-Mail2News-Newsgroups: lines.
39 =item B<-o>, B<--organization>=I<organization>
41 Organization: line, if none is specified.
43 =item B<-s>, B<--subject>=I<subject>
45 Subject: line, if none is specified; the default is "no subject".
47 =item B<-x>, B<--path>=I<path>
49 Path: prefix, if none is specified; the default is "gateway".
53 =head1 ERROR REPORTING
55 Errors will be logged using syslog(3).
63 I<m2n> and this manual page were written by Colin Watson
64 E<lt>cjwatson@chiark.greenend.org.ukE<gt>.
71 use Digest::MD5 qw(md5_base64);
73 use Sys::Syslog qw(:DEFAULT setlogsock);
75 $ENV{PATH} = '/usr/bin:/bin';
77 # Use syslog(3) for error output.
80 openlog 'mail2news', 'pid', 'news';
92 my ($approved, $distribution, $newsgroups, $organization);
93 my $subject = 'no subject';
96 Getopt::Long::Configure qw(bundling bundling_override);
98 "stdout" => \$tostdout,
99 "approved|a=s" => \$approved,
100 "distribution|d=s" => \$distribution,
101 "newsgroups|n=s" => \$newsgroups,
102 "organization|o=s" => \$organization,
103 "subject|s=s" => \$subject,
104 "path|x=s" => \$path);
108 my $headerblock = '';
111 my ($hname, $hvalue);
118 syslogdie 'No headers found, aborting' unless defined $hname;
119 $headers{lc $hname} = $hvalue;
129 syslogdie "Continuation line at start of headers: '$line'"
130 unless defined $hvalue;
133 elsif (/^(.*?):[ \t](.*)/)
135 $headers{lc $hname} = $hvalue if defined $hname;
139 if ($hname =~ /newsgroups/i && defined $newsgroups)
141 $hname = 'X-Mail2News-Newsgroups';
142 $headerblock .= "Newsgroups: $newsgroups\n";
143 $headers{newsgroups} = $newsgroups;
146 elsif ($hname =~ /path/i && defined $path)
148 $hvalue = "$path!$hvalue";
150 $_ = "$hname: $hvalue\n";
154 $headers{lc $hname} = $hvalue if defined $hname;
158 if ($hname =~ /newsgroups/i && defined $newsgroups)
160 $hname = 'X-Mail2News-Newsgroups';
161 $headerblock .= "Newsgroups: $newsgroups\n";
162 $headers{newsgroups} = $newsgroups;
165 elsif ($hname =~ /path/i && defined $path)
169 $_ = "$hname: $hvalue\n";
174 syslogdie "Invalid header line: '$line'";
177 if ($overridden) { $extra .= $_; }
178 else { $headerblock .= $_; }
184 # Headers from command line
186 $extra .= "Approved: $approved\n"
187 if defined $approved and not defined $headers{approved};
188 $extra .= "Distribution: $distribution\n"
189 if defined $distribution and not defined $headers{distribution};
190 $extra .= "Newsgroups: $newsgroups\n"
191 if defined $newsgroups and not defined $headers{newsgroups};
192 $extra .= "Organization: $organization\n"
193 if defined $organization and not defined $headers{organization};
194 $extra .= "Subject: $subject\n"
195 if defined $subject and not defined $headers{subject};
196 $headerblock = "Path: $path\n$headerblock"
197 if defined $path and not defined $headers{path};
199 # Other required header checks
201 syslogdie 'No From: line, aborting' unless defined $headers{from};
202 $extra .= time2str 'Date: %a, %e %h %Y %T GMT' . "\n", time, 'GMT'
203 unless defined $headers{date};
204 $extra .= sprintf "Message-ID: <mail2news.\%x.\%s\@riva.ucam.org>\n",
205 time, md5_base64($body) unless defined $headers{'message-id'};
207 # Output to stdout or rnews.
211 print $headerblock, $extra, "\n", $body;
215 $SIG{PIPE} = 'IGNORE';
216 open RNEWS, '| rnews -v 2>/dev/null' or syslogdie "can't fork: \%m";
217 print RNEWS $headerblock, $extra, "\n", $body
218 or syslogdie "can't write: \%m";
219 close RNEWS or syslogdie "can't close: \%m";