Newsgroups: alt.sources Subject: inews-xt - a faster inews replacement for C News, v2.9 Followup-To: alt.sources.d,news.software.b,de.admin.news.software Keywords: cnews Archive-Name: inews-xt Submitted-By: Olaf Titz Environment: cnews, perl, unix This is a complete rewrite in perl of the "inews" script supplied with older versions of C News (as of Summer 1993, or C News XT 1.3, but can be used with new versions as well). It is much faster, does MIME encoding and header syntax checks. The script is self-contained, it doesn't need the auxiliary stuff in bin/inject. Some options have to be set at the top of the script before running. Olaf Titz #!/bin/sh # This is a shell archive (produced by GNU sharutils 4.1). # To extract the files from this archive, save it to some FILE, remove # everything before the `!/bin/sh' line above, then type `sh FILE'. # # Made on 1997-02-08 16:57 MET by . # Source directory was `/var/home/olaf/mysrc/inews.xt'. # # Existing files will *not* be overwritten unless `-c' is specified. # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 995 -r--r--r-- README.inews # 21003 -r-xr-xr-x inews # 1223 -r--r--r-- encodings # touch -am 1231235999 $$.touch >/dev/null 2>&1 if test ! -f 1231235999 && test -f $$.touch; then shar_touch=touch else shar_touch=: echo echo 'WARNING: not restoring timestamps. Consider getting and' echo "installing GNU \`touch', distributed in GNU File Utilities..." echo fi rm -f 1231235999 $$.touch # # ============= README.inews ============== if test -f 'README.inews' && test X"$1" != X"-c"; then echo 'x - skipping README.inews (file already exists)' else echo 'x - extracting README.inews (text)' sed 's/^X//' << 'SHAR_EOF' > 'README.inews' && This should be a plug-in compatible replacement for C News "inews". Look at the parameters at the beginning of the "inews" file, some of these must be configured. You have to install and customize the "encodings" file in the news control directory. X The encodings file specifies the "Content-Type" (charset parameter) and "Content-Transfer-Encoding" headers that are inserted into postings that contain 8-bit characters, and which encoding filter to use. Quoted-printable is builtin, other filters may be specified as external programs. The newsgroups header is matched against the patterns in this file, the first match counts (cf. "explist"). If none matches, postings with 8-bit characters are rejected. X There are two ways of inews operation: 1. leave the message in in.coming for processing by newsrun 2. invoke relaynews from inews For 1., set $userelay to 0. (inews calls newsspool.) For 2., set $userelay to 1, install inews setuid to the news account, and create $NEWSCTL/tmp mode 770. SHAR_EOF $shar_touch -am 0122210497 'README.inews' && chmod 0444 'README.inews' || echo 'restore of README.inews failed' shar_count="`wc -c < 'README.inews'`" test 995 -eq "$shar_count" || echo "README.inews: original size 995, current size $shar_count" fi # ============= inews ============== if test -f 'inews' && test X"$1" != X"-c"; then echo 'x - skipping inews (file already exists)' else echo 'x - extracting inews (text)' sed 's/^X//' << 'SHAR_EOF' > 'inews' && #!/usr/bin/perl # -*- perl -*- X # A rewrite of the ugly old C News inews (as of Jul.23, 1993 or C News XT 1.3) # Fast, feature enhanced and MIME conformant. # Written by Olaf Titz , Jun 95 - Jan 97. Public domain. # $Id: inews,v 2.9 1997/02/08 15:57:13 olaf Exp $ X # This is supposed to work like the original, except for the following # additional features: # - Adds MIME headers if article has 8-bit characters. # - Encodes quoted-printable or with an external program if desired. # - Encodes headers as of MIME if they have 8-bit characters. # - Deletes redundant/forbidden distributions. # - Various Message-ID formats configurable. # - Checks header syntax, esp. address and date lines. # - "Trusted" users may supply From/Sender lines. # - Check for excessive crossposting. # - -S (omit .signature) and -E (ignore empty article) options. # ...and missing features: # - The 64k size limit. # - Rewriting of obsolete control message syntax (get your readers fixed) # Options like -d and -x may appear only once due to getopts usage. X # ----------------------------------------------------------------------------- # Configurable options. Tailor this! X $Charset = "iso-8859-1"; # Default for headers *MakeID = MakeID_cr; # or _simple or _xt, see below *MakeAddr = MakeAddr_1; # or _2, see below $newsmaster = "news"; $maxpast = 30; # Reject if Date line older than this (no.days) $maxfuture = 180; # ...or if Expires more than this in the future $maxxpost = 8; # ...or if crossposted to more than this groups @trusted = ("root", "news", "uucp", "daemon"); # users who may supply their own From/Sender lines or LOGNAME $userelay = 1; # Set this to 1 if your relaynews (old) or this is setuid $inputpar = "\n\n"; # perhaps no use to change this $nodist = '^(world)|(de)$'; # Forbidden/redundant distributions (pattern) X # News configuration options # =()<$newsctl = "@@";>()= $newsctl = "/var/lib/news"; # =()<$newsbin = "@@";>()= $newsbin = "/var/lib/news/bin"; # =()@);>()= umask(022); # =()<$ENV{PATH} = "@@:$newsbin/relay:$newsbin/input:$newsbin";>()= $ENV{PATH} = "/bin:/usr/bin:/usr/local/bin:$newsbin/relay:$newsbin/input:$newsbin"; # End of configurable options. X # ----------------------------------------------------------------------------- $home=$ENV{HOME}; @Month=("Jan", "Feb", "Mar", "Apr", "May", "Jun", X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); $Suser="A-Za-z0-9._+!\$%&/=-"; # Characters that may appear in user names X # (but allowing for ! and % addressing) $Sdom="A-Za-z0-9_+\$/=-"; # ... in domain names $Saddr="[$Suser]+@[$Sdom]+((\\.[$Sdom]+)+)"; # internet address syntax # Don't change this. Code below depends on the correct order and nesting # of () subexpressions! $Ssanit="[A-Za-z0-9._,:+/-]+"; # Pattern to remove shell metachars $Sccom="[^ A-Za-z0-9!*+\/=-]"; # Set to encode in comment (name) fields $Sctxt="[\001-\037?_\177-\377]"; # Set to encode in text fields X select STDOUT; $|=1; require "getopts.pl"; &Getopts("pd:ANVWx:hMDt:n:e:F:d:a:f:o:C:SE"); X # inews -p : just feed given files to relaynews. # Obsolete! Does probably not work if not called by the news user. if ($opt_p) { X $_ = join(" ", @ARGV); X exec "cat $_ | relaynews -r"; X exit 1; } if ($opt_C) { # this is long gone X print STDERR "Use addgroup or generate a proper control message!\n"; X exit 1; } X $SIG{HUP}=$SIG{INT}=$SIG{PIPE}=$SIG{TERM}="Signal"; # Temporary files are in /var/lib/news/tmp if running setuid $ENV{"TMPDIR"} =~ /($Ssanit)/o; # for the sake of taint check $tmpdir = ($<==$>) ? ($1 || "/tmp") : "$newsctl/tmp"; $tmphdr="$tmpdir/in.$$.hdr"; $tmpinb="$tmpdir/in.$$.inb"; $tmpbdy="$tmpdir/in.$$.bdy"; $tmpres="$tmpdir/in.$$.res"; open(HEAD, ">$tmphdr") || &Bailout(""); # Article is assembled in $tmpinb first and then moved over to $tmpbdy open(BODY, ">$tmpinb") || &Bailout(""); select BODY; $|=1; print BODY "\n"; X # ----------------------------------------------------------------------------- # Try and find out the poster's name and host. if (open(F,"<$newsctl/mailname")) { X $host=; close F; } else { X $host=`newshostname`; X if ($host=~tr/.//c) { $host.=".UUCP"; } } $host=~tr/\021-\176//cd; $user=(getlogin || (getpwuid($<))[0]); $trusted_user=grep(/$user/, @trusted); if ($trusted_user) { X $user=$ENV{LOGNAME} if $ENV{LOGNAME}; } $user="nobody" unless $user; # the last resort $user=~s/\s.*//; $user=~s/[\!]*!//; $name=$ENV{NAME}; if (!$name) { X if (open(F, "<$home/.name")) { X $name=; $name=~tr/\021-\176//cd; close F; X } else { X @_=getpwnam($user); X if ($#_>0) { X $name = $_[6]; X } else { X $user=~/($Ssanit)/o; # sanitize X $name=`ypmatch "$1" passwd`; X @_=split(/:/, $name); $name=$_[4]; X } X $name=~s/,.*$//; X # Tailor: for BTL RJE format, use this: X # $name=~s/^[^-]*-\s*//; $name=~s/ \(.*$//; X # otherwise, Berkeley "&" notation: capitalized login name X $name=~s/&/\u$user/; X } } X # ----------------------------------------------------------------------------- # Construct the standard headers. $from=&MakeAddr($name, $user, $host); # Determine local time zone offset @G=gmtime($^T); @_=localtime($^T); $tz=($_[1]-$G[1])+($_[2]-$G[2])*60+($_[7]-$G[7])*1440+($_[5]-$G[5])*525600; $tz=sprintf("%+.2d%.2d", $tz/60, $tz%60); $_[5]+=1900 if ($_[5]<1900); X # Default headers %hdr=( X "path", "not-for-mail", # yes, this is standard usage by now X "from", $from, X "message-id", sprintf('<%s@%s>', &MakeID, $host), X "date", sprintf('%02d %s %04d %02d:%02d:%02d %s', X $_[3], $Month[$_[4]], $_[5], $_[2], $_[1], $_[0], $tz), X "organization", ($opt_o || $ENV{ORGANIZATION}), X ); # Standard headers in output order @hdr=("control", "newsgroups", "path", "from", "reply-to", "subject", X "message-id", "date", "sender", "distribution", "followup-to"); # No-override headers @thdr=("sender", "nntp-posting-host", "nntp-posting-user"); # Syntax modes %hmo=("from",1, "sender",1, "reply-to",1, "approved",1, # address field X "newsgroups",2, "message-id",2, "path",2, "control",2, X "followup-to",2, "references",2, "distribution",2, X "also-control",2, "supersedes",2, # control text X "date",3, "expires",4, # date X ); # everything else: arbitrary text X if ($opt_a) { $hdr{"approved"} = $opt_a; } if ($opt_c) { $hdr{"control"} = $opt_c; } if ($opt_d) { $hdr{"distribution"} = $opt_d; } if ($opt_e) { $hdr{"expires"} = $opt_e; } if ($opt_f) { $hdr{"from"} = $opt_f; } if ($opt_n) { $hdr{"newsgroups"} = $opt_n; } if ($opt_r) { $hdr{"reply-to"} = $opt_r; } if ($opt_t) { $hdr{"subject"} = $opt_t; } if ($opt_F) { $hdr{"references"} = $opt_F; } X # ----------------------------------------------------------------------------- # Read the input. First see if there are headers (ignore -h anyway) $lines=$contentlen=$UseMIME=0; $HeadErr=""; # Read first paragraph. Ignore multiple blank lines at end. # For subsequent paragraphs don't. $/=""; $_=<>; $/=$inputpar; if (/^[A-Za-z_-]+:\s+.*\n/) { # we have a header X s/\n[ \t]+/ /g; # squash continuations X foreach $i (split(/\n/, $_)) { X if ($i =~ /^([^ :]+):\s+(.*)/) { X ($n,$v) = ($1,$2); X $n =~ tr/A-Z/a-z/; X if (($hdr{$n}) && (grep(/$n/, @thdr))) { X $HeadErr = sprintf("Attempt to override %s header", X &canonhdr($n)); X } elsif (grep(/$n/, @hdr)) { X $hdr{$n} = $v; X } else { X $hdr{$n} .= "$;$v"; X } X } else { X print HEAD $i; # save the offending line X $HeadErr = "Header syntax error"; X # will bailout after reading article X } X } X $_=<>; } # Now read the body, one paragraph at a time for speed do { X tr/\001-\007\013\015-\037//d; # no dirty tricks here X print BODY; $contentlen+=length; X $lines+=tr/\n//; X if (tr/\200-\377//) { $UseMIME=1; } X if (!/\n$/) { print BODY "\n"; } # make sure last line is complete } while (<>); $/="\n"; X # ----------------------------------------------------------------------------- # Input is done. Do the rest in the background. if (!($opt_N||$opt_W)) { X if (fork()>0) { X exit 0; X } } X # Append signature, 4 lines is enough if ((!$opt_S) && (open(F, "<$home/.signature"))) { X print BODY "-- \n"; $siglines=1; X Sig: while() { X tr/\001-\007\013\015-\037//d; X print BODY; X if (tr/\200-\377//) { $UseMIME=1; } X if (++$siglines>4) { last Sig; } X } X close F; $lines+=$siglines; } close BODY; X # Additional header manipulations... if (!$hdr{"organization"}) { X if (open(F, "<$newsctl/organization")) { X $hdr{"organization"}=; chop $hdr{"organization"}; X close F; X } } $hdr{"path"}=~s/^$host\!//o; # for silly readers if (!$trusted_user) { X $hdr{"sender"}=""; X if ($hdr{"from"} ne $from) { X $hdr{"sender"}=$from; X } } $hdr{"lines"}=$lines; $hdr{"distribution"}=~s/$nodist//o; # Take out forbidden distribs $subj=$hdr{"subject"}; # save for later $hdr{"newsgroups"}=~/($Ssanit)/o; $ngs=$1; # sanitize # Check the vital headers if (!$ngs) { &Bailout("Required Newsgroups header missing"); } if (!$subj) { &Bailout("Required Subject header missing"); } X # ----------------------------------------------------------------------------- # Output the headers, required standard headers first foreach $i (@hdr) { X &printhdr($i, $hdr{$i}); X delete $hdr{$i}; } foreach $i (keys %hdr) { X &printhdr($i, $hdr{$i}); } close HEAD; X # ----------------------------------------------------------------------------- # Do additional encoding of the body, if required. $encoded=0; if ($hdr{"mime-version"}) { X $UseMIME=0; # MIME articles are left alone } if ($UseMIME) { X # encode if this article isn't MIME already, but needs encoding X # Find out which one to use. X $_=`gngp -a -r $ngs $newsctl/encodings 2>/dev/null`; X s/\n.*//g; X if (!$_) { X &Bailout("Can't find encoding for $ngs, 8bit chars not allowed"); X } X ($x,$Charset,$Encoding,$f) = split(/\s+/, $_, 4); X $Charset =~ tr/A-Z/a-z/; X $Encoding =~ tr/A-Z/a-z/; X if (($f) && ($f ne "-")) { X # Use an external program to encode X if (!system("$f <$tmpinb >$tmpbdy")) { X $encoded=1; X if (($Charset eq "-") || ($Encoding eq "-")) { X $UseMIME=0; X } X } else { X &Bailout("Error while encoding with $f"); X } X } elsif ($Encoding eq "quoted-printable") { X # Quoted-printable encoding X open(F, "<$tmpinb") || &Bailout(""); X open(BODY, ">$tmpbdy") || &Bailout(""); X while() { X chop; s/=/=3D/g; s/ $/=20/; s/\t$/=09/; X s+[^\040-\176]+sprintf("=%02X",unpack("C",$&))+ge; X while (length>76) { X if (substr($_,74,1) eq "=") { $i=73; X } elsif (substr($_,75,1) eq "=") { $i=74; X } else { $i=75; } X printf BODY "%s=\n", substr($_,0,$i); X substr($_,0,$i)=""; X } X print BODY "$_\n"; X } X close F; close BODY; $encoded=1; X } } if (!$encoded) { X unlink($tmpbdy); X link($tmpinb, $tmpbdy) || &Bailout(""); } X # ----------------------------------------------------------------------------- # Output additional headers. if ($UseMIME) { X open(HEAD, ">>$tmphdr") || &Bailout(""); X print HEAD "MIME-Version: 1.0 Content-Type: text/plain; charset=$Charset Content-Transfer-Encoding: $Encoding\n"; X # oops, this is nonstandard: Content-Length: $contentlen X close HEAD; } X # Check more headers # Do this now that we have the header/body files for saving to dead.article. if (!$contentlen) { X if ($opt_E) { X &Cleanup(0); # silently discard empty article X } else { X &Bailout("Empty article"); X } } if ($ngs=~/\s/) { &Bailout("Whitespace in Newsgroups header"); } if ($HeadErr) { &Bailout($HeadErr); } X # ----------------------------------------------------------------------------- # Now determine what to do with the article. # Look for the proper newsgroups $p=$hdr{"control"} ? "control" : $ngs; if (($p=~/,/) > $maxxpost) { X &Bailout("Crossposted to too many groups"); } $p=~s/([].*+()[])/\\$1/g; $p=~tr/,/|/; # make the newsgroups an egrep pattern open(F, "egrep -e '^($p) ' $newsctl/active |") || X &Bailout("Can't search the active file"); # egrep has proven to be faster than doing the search here $valid=0; while () { X /([^ ]+)\s+[^ ]+\s+[^ ]+\s+(.*)/; X ($i,$f) = ($1,$2); # split and sanitize X if ($f=~/^[nx]/) { X &Bailout("Posting to $i is not allowed"); X } X if (($f=~/^m/) && (!$hdr{"approved"}) && (!$mailto)) { X # Determine where the moderator is. X $_=`sed 's/^backbone[^A-Za-z0-9._-]/all /' $newsctl/mailpaths | gngp -a -r $i 2>/dev/null`; X s/\n.*//g; X if (!$_) { X &Bailout("Can't find the moderator for $i"); X } X ($p,$m)=split; X $i=~tr/./-/; X $mailto=sprintf($m, $i); X } X if ($f=~/^[ym]/) { X ++$valid; X } } close F; if (!$valid) { X &Bailout("No valid newsgroups in $ngs"); } X # ----------------------------------------------------------------------------- # Just print it # This is incompatible with C News as this won't mail an article to the # moderator if -N is given. I think this is more logical. if ($opt_N) { X if ($mailto) { X print STDOUT "# Would mail article to $mailto\n"; X } X system "cat $tmphdr $tmpbdy"; X &Cleanup(0); } X # ----------------------------------------------------------------------------- # Mail it to the moderator if ($mailto) { X $ret=system("cat $tmphdr $tmpbdy | mail $mailto") >>8; X if ($ret) { X &Bailout("Mail returned $ret"); X } else { X print STDOUT "inews: Mailing your article to $mailto\n"; X &Cleanup(0); X } } X # ----------------------------------------------------------------------------- # Look if we've got enough space. Wait for it if -A given. if ($opt_A) { X $rpt=0; X while (`spacefor 1 articles` < 1) { X if (++$rpt==5) { X if (open(F, "|mail $newsmaster")) { X print F "Subject: Out of disk space\n\n"; X print F "There is too little space for inews!"; X close F; X } X } X sleep 30; X } } else { X if (`spacefor 1 articles` < 1) { X &Bailout("Out of disk space while posting"); X } } X # ----------------------------------------------------------------------------- # Finally, post the article. $ropts="-s"; if ($opt_x) { $ropts.=" -x $opt_x"; } if ($opt_d) { $ropts.=" -d $opt_d"; } if (!$opt_V) { $ropts.=" >>$newsctl/log 2>>$newsctl/errlog"; } if ($userelay) { X $relaynews = "relaynews $ropts"; } else { X $relaynews = "newsspool -g0"; } X if (open(F, "<$newsctl/server")) { X $_=; /($Ssanit)/o; $server=$1; close F; X $_=`hostname`; /($Ssanit)/o; $me=$1; X if ($server eq $me) { $server=""; } } if ($server) { X # Post via rsh on the server machine. X open(F, ">$tmpres") || &Bailout(""); X select F; $|=1; X print F "PATH=$ENV{PATH}\nexport PATH\ntmpf=/tmp/irsh\$\$\n"; X print F "sed -e 's/^-//' >\$tmpf <<'_'\n"; X close F; X system("cat $tmphdr $tmpbdy | sed -e 's/^/-/' >>$tmpres"); X open(F, ">>$tmpres") || &Bailout(""); X print F "_\n$relaynews <\$tmpf\necho status \$?\nrm -f \$tmpf\n"; X close F; select STDOUT; X open(F, "rsh $server /bin/sh <$tmpres |") || X &Bailout("Can't rsh to $server"); X while() { X if (/^status (.*)/) { $remret=$1; } else { print STDOUT; } X } X close F; $ret=$?>>8; $rn="rsh"; } else { X $ret=system("cat $tmphdr $tmpbdy | $relaynews") >>8; X $rn=$relaynews; $rn=~s/\s.*//; } if ($remret) { X &Bailout("remote server returned $remret"); } if ($ret) { X &Bailout("$rn returned $ret"); } if (!-s "$newsctl/sys") { X &Bailout("warning: Article posted but won't be distributed - no sys file"); } X &Cleanup(0); X # ----------------------------------------------------------------------------- # Subroutines X # --- Canonicalize header name string sub canonhdr { X local($_)=@_; X tr/A-Z/a-z/; s/^(.)/\u$1/; s/-(.)/-\u$1/g; X if ($_ eq "Message-Id") { $_="Message-ID"; } X # defhdrs.awk claimed this is the correct spelling X s/^Nntp-/NNTP-/; X s/^Mime-/MIME-/; X return $_; } X # --- Check header syntax and RFC1522ize sub chkhdr { X local($f,$_)=@_; X local($t)=$hmo{$f}; X if ($t==1) { # address X /^\s*($Saddr)\s*$/o && do { X return $1; X }; X /^\s*($Saddr)\s+\((.*)\)\s*$/o && do { X local($a,$r)=($1,$4); X return &mungespace(sprintf("%s (%s)", $a, X &mimetag($r, $Sccom)), $f); X }; X /^([^<>()]*)\s*\<($Saddr)\>\s*$/ X && do { X local($r,$a)=($1,$2); X return &mungespace(sprintf("%s <%s>", X &mimetag($r, $Sccom), $a), $f); X }; X $HeadErr .= sprintf("%s header: address syntax error\n", X &canonhdr($f)); X return $_; X } X elsif ($t==2) { # verbatim X if (tr/\011\021-\176//c) { X $HeadErr .= sprintf("%s header: contains illegal characters\n", X &canonhdr($f)); X } X return &mungespace($_, $f); X } X elsif ($t>=3) { # current/future date X /([ A-Za-z0-9.,:+-]+)/; # sanitize X local($d) = `getabsdate '$1' 2>/dev/null`; X local($f1,$f2) = ($t==3?$maxpast:2, $t==3?2:$maxfuture); X if (!$d) { X $HeadErr .= sprintf("%s header: date syntax error\n", X &canonhdr($f)); X } elsif ($d<(time-3600*24*$f1)) { X $HeadErr .= sprintf("%s header: too far in the past\n", X &canonhdr($f)); X } elsif ($d>(time+3600*24*$f2)) { X $HeadErr .= sprintf("%s header: too far in the future\n", X &canonhdr($f)); X } X return &mungespace($_, $f); X } X else { # text X return &mungespace(&mimetag($_, $Sctxt), $f); X } } X # --- RFC1522ize header contents sub mimetag { X local($_,$Sc)=@_; X if (tr/\021-\176//c) { X # $UseMIME=1; the author of rfc1522 explicitly confirms that X # a MIME-Version header is unnecessary just for marking an rfc1522 X # encoded header line! X s/=/=3D/g; X s+$Sc+sprintf("=%02X",unpack("C",$&))+ge; X if (length($_)+length($Charset)>68) { X # Split long fields. This is rather suboptimal and doesn't obey X # the length limit in all cases, but better than nothing... X @_=split; X foreach $i (@_) { X if ($i=~tr/=//) { X $i=sprintf("=?%s?q?%s?=", $Charset, $i); X } X } X $_=join(" ", @_); X s/\?= =\?$Charset\?q\?/_/go; # Squash adjacent encoded-words X return $_; X } X s/ /_/g; X return sprintf("=?%s?q?%s?=", $Charset, $_); X } X return $_; } X # --- Canonicalize whitespace and split long lines in header sub mungespace { X local($_,$z)=@_; X local($a,$i,$w)=("",0,74-length($z)); X s/^[ \t]+//; s/[ \t]+$//; X s/[ \t]+/ /g; # squash whitespace X while (length>$w) { X $i=rindex($_, " ", $w); X last if ($i<0); # bail out XXX not RFC conformant! X $a.=substr($_,0,$i)."\n "; X substr($_,0,$i+1)=""; X $w=75; X } X return "$a$_"; } X # --- Output a header line sub printhdr { X local($f,$l)=@_; X foreach $_ (split(/$;/o, $l)) { X printf HEAD "%s: %s\n", &canonhdr($f), &chkhdr($f,$_) if ($_); X } } X # --- Generate Message-ID string X # Trivial algorithm sub MakeID_simple { X return sprintf("%ld.%d", time, $$); X # you could also use %l08X%04x or whatever } X # C News XT algorithm sub MakeID_xt { X $MakeID_xt="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; X $nMakeID_xt=length($MakeID_xt); X return &pMakeID_xt(int(time-627672773)/60) . &pMakeID_xt($$); X # Assumes PIDs won't wrap around in one minute. The magical constant X # is "the time I wrote this", according to mkid.c. } sub pMakeID_xt { X local($n,$_)=@_; X do { X $_.=substr($MakeID_xt,int($n%$nMakeID_xt),1); X $n=int($n/$nMakeID_xt); X } while($n); X return $_; } X # C News Cleanup Release algorithm sub MakeID_cr { X # $MakeID_cr="0123456789ABCDEFGHIJKLMnopqrstuvwxyz"; X # ouch, this is ugly, I prefer the following (no overlap possible): X $MakeID_cr="0123456789abcdefghijklmnopqrstuvwxyz"; X $nMakeID_cr=length($MakeID_cr); X return &pMakeID_cr(time) . "." . &pMakeID_cr($$); } sub pMakeID_cr { X local($n,$_)=@_; X do { X $_=substr($MakeID_cr,int($n%$nMakeID_cr),1).$_; X $n=int($n/$nMakeID_cr); X } while($n); X return $_; } X # --- Generate address string # gives From: Real Name sub MakeAddr_1 { X local($n,$u,$h)=@_; X return sprintf('%s <%s@%s>', $n, $u, $h); } # gives From: user@host (Real Name) sub MakeAddr_2 { X local($n,$u,$h)=@_; X if ($n) { X return sprintf('%s@%s (%s)', $u, $h, $n); X } X return sprintf('%s@%s', $u, $h); } X # --- Clean-up sub Signal { X &Bailout("Got SIG$_[0]"); } X sub Bailout { X local($_)=@_; X $_="Can't open temporary file" unless $_; # common case X print STDERR "inews: $_\n"; X close HEAD; close BODY; X $_ = (-s $tmpbdy) ? $tmpbdy : $tmpinb; # catch partially assembled body X if (open(TH, $tmphdr) && open(TB, $_)) { X unlink $tmphdr,$tmpinb,$tmpbdy,$tmpres; X $>=$<; # renounce setuid X $home =~ /($Ssanit)/o; # sanitize X if (open(DA, ">>$1/dead.article")) { X $/=""; X print DA , "\n"; X print DA while (); X print STDERR "inews: article in $1/dead.article\n"; X exit 1; X } X } X print STDERR "inews: can't write $1/dead.article\n"; X &Cleanup(2); } X sub Cleanup { X unlink $tmphdr,$tmpinb,$tmpbdy,$tmpres; X exit $_[0]; } # ----------------------------------------------------------------------------- SHAR_EOF $shar_touch -am 0208165797 'inews' && chmod 0555 'inews' || echo 'restore of inews failed' shar_count="`wc -c < 'inews'`" test 21003 -eq "$shar_count" || echo "inews: original size 21003, current size $shar_count" fi # ============= encodings ============== if test -f 'encodings' && test X"$1" != X"-c"; then echo 'x - skipping encodings (file already exists)' else echo 'x - extracting encodings (text)' sed 's/^X//' << 'SHAR_EOF' > 'encodings' && # Encodings control file. # This file is consulted when a local posting contains 8-bit # characters and no MIME header. # Each line specifies for a certain group pattern: # - the charset to use (assuming that given by the poster is OK) # - the encoding to use # See RFC1521 for details on these parameters. # - a filter program to call for encoding. If this is missing, # inews' internal encoders are invoked (currently for Q-P only). # First match counts! X # Groups Charset Encoding Filter # ------ ------- -------- ------ X # Example for internal filter de.comp.standards iso-8859-1 quoted-printable X # National hierarchies with charsets (8bit - don't filter) de,fr iso-8859-1 8bit relcom koi8-r 8bit # The above assumes that users always use the right charset for # postings in different hierarchies. If not, they have to supply their # own MIME headers. X # Gatewayed BBS stuff (German) maus,z-netz,t-netz iso-8859-1 8bit X # Local hierarchies ka,stgt iso-8859-1 8bit X # Additional examples: Filter without adding MIME headers # Somewhat unstable gateways here... fido.ger,ger,gernet - - iso2asc 2 X # Filter but add MIME headers too # foo.bar iso-8859-1 x-rfc1345 iso2asc 4 X # No default means 7 bit only. SHAR_EOF $shar_touch -am 1110231995 'encodings' && chmod 0444 'encodings' || echo 'restore of encodings failed' shar_count="`wc -c < 'encodings'`" test 1223 -eq "$shar_count" || echo "encodings: original size 1223, current size $shar_count" fi exit 0