# $Id: newgroup.pl,v 1.1.2.1 2001/01/17 21:05:11 rra Exp $ # Copyright (c)1998 G.J. Andruk # newgroup.pl - The newgroup control message. # Parameters: params sender reply-to token site action[=log] approved sub control_newgroup { my ($artfh, $qgroup); my @params = split(/\s+/,shift); my $sender = shift; my $replyto = shift; my $token = shift; my $site = shift; my ($action, $logging) = split(/=/, shift); my $approved = shift; my $groupname = $params[0]; my $modflag = $params[1]; my $pid = $$; my $tempfile = "$inn::tmpdir/newgroup.$pid"; my ($errmsg, $status, $nc, @component, @oldgroup, $locktry, $ngname, $ngdesc, $modcmd); $modcmd = "y"; $modcmd = "m" if ($modflag eq "moderated"); # Check the group name. This is partially derived from C News. # Some checks are commented out if I think they're too strict or # language-dependent. Your mileage may vary. NEWGROUPSANITY: for ($groupname) { # whole-name checking if (/^$/) { $errmsg = "Empty group name"; } elsif (/\s/) { $errmsg = "Whitespace in group name"; } elsif (/[\`\/:;]/) { $errmsg = "unsafe group name"; } elsif (/^\./ || /\.$/ || /\.\./) { $errmsg = "Bad dots in group name"; } #elsif (/^[a-zA-Z0-9].+[a-zA-Z0-9]$/) { # $errmsg = "Group name does not begin/end with alphanumeric"; #} elsif (/^(junk|control)\./) { $errmsg = "Group name begins in control. or junk."; } #elsif (length($groupname) > 128) { # $errmsg = "Group name too long"; #} else { $errmsg = ""; } last NEWGROUPSANITY if $errmsg; # per-component checking $nc = (@component = split(/\./)); for ($i = 0; $i <= $#component; $i++) { $c = $component[$i]; if ($c =~ /^[0-9]+$/) { $errmsg = 'all-numeric name component'; } #elsif ($c !~ /^[a-zA-Z0-9]/) {# A-Z caught later # $errmsg = 'name component starts with non-alphanumeric'; #} #elsif ($c !~ /[a-zA-Z]/) {# A-Z caught later # $errmsg = 'name component does not contain letter'; #} elsif ($c eq 'all' || $c eq 'ctl') { $errmsg = "`all' || `ctl' used as name component"; } #elsif (length($c) > 30) { # $errmsg = 'name component longer than 30 characters'; #} #elsif ($c =~ /[A-Z]/) { # $errmsg = 'uppercase letter(s) in name'; #} elsif ($c =~ /[^a-z0-9+_\-.]/) { $errmsg = 'illegal character(s) in name'; } elsif ($c =~ /--|__|\+\+./) { # sigh, c++ etc must be allowed $errmsg = 'repeated punctuation in name'; } #elsif ($i+2 <= $#component && ($c eq $component[$i + 1]) && # ($c eq $component[$i + 2])) { # $errmsg = 'repeated component(s) in name'; #} } #prevent alt.a.b.c.d.e.f.g.w.x.y.z... $errmsg = "Too many components" if (! $errmsg) && ($nc > 9); } if ($errmsg) { if (!$logging) { logmsg('notice', 'skipping newgroup (%s)', $errmsg); } else { logger($token, $logging, "skipping newgroup ($errmsg)"); } } else { # Our group name survived. # Scan active to see what sort of change we are making. open ACTIVE, $inn::active; $qgroup = quotemeta ($groupname); @oldgroup = grep(/^$qgroup\s/, ); @oldgroup = split(/\s+/, $oldgroup[0]); #print "newgroup: $oldgroup[0] $oldgroup[1]"," # $oldgroup[2] $oldgroup[3] $modflag\n"; close ACTIVE; if (scalar @oldgroup) { if (($oldgroup[3] eq "m") && ($modflag ne "moderated")) { $status = "made unmoderated"; } elsif (($oldgroup[3] ne "m") && ($modflag eq "moderated")) { $status = "made moderated"; } else { $status = "no change"; } } elsif (! $approved) { $status = "unapproved"; } else { $status = "created"; } if ($action eq "mail" && ($status !~ /(no change|unapproved)/)) { open(TEMPFILE, ">$tempfile"); print TEMPFILE ("$sender asks for $groupname\n", "to be $status.\n\n", "If this is acceptable, type:\n", " $inn::newsbin/ctlinnd newgroup ", "$groupname $modcmd $sender\n\n", "The control message follows:\n\n"); $artfh = open_article($token); next if (!defined($artfh)); *ARTICLE = $artfh; print TEMPFILE $_ while
; close(ARTICLE); close(TEMPFILE); logger($tempfile, "mail", "newgroup $groupname $modcmd $sender\n"); unlink($tempfile); } elsif ($action eq "log") { if (!$logging) { logmsg ('notice', 'skipping newgroup %s %s %s (would be %s)', $groupname, $modcmd, $sender, $status); } else { logger($token, $logging, "skipping newgroup $groupname " . "$modcmd $sender (would be $status)"); } } elsif (($action eq "doit") && ($status !~ /(no change|unapproved)/)) { # Create the group. system("$inn::newsbin/ctlinnd", "-s", "newgroup", $groupname, $modcmd, $sender); # If there's a tag line, update newsgroups too. $artfh = open_article($token); next if (!defined($artfh)); *ARTICLE = $artfh; NEWSGROUPS: while (
) { chomp; if (/^For your newsgroups file:$/) { $ngline = (
); chomp $ngline; last NEWSGROUPS; } } ($ngname, $ngdesc) = split(/\s+/, $ngline, 2); if ($ngdesc) { $ngdesc =~ s/\s+\(moderated\)\s*$//i; $ngdesc .= " (Moderated)" if $modflag eq "moderated"; } if (($ngdesc) && ($ngname eq $groupname)) { # Get a lock on newsgroups $locktry = 0; GETNGLOCK: while ($locktry < 60) { if (system("$inn::newsbin/shlock", "-p", "$pid", "-f", "$inn::locks/LOCK.newsgroups")) { $locktry++; sleep(2); } else { $locktry = -1; last GETNGLOCK; } } if ($locktry > -1) { logmsg ('err', 'Cannot get lock %s', "$inn::locks/LOCK.newsgroups"); } else { open(NEWSGROUPS, "<$inn::newsgroups"); open(TEMPFILE, ">$tempfile"); while () { print TEMPFILE $_ if ! /$qgroup\s/; } print TEMPFILE ($ngname, "\t", $ngdesc, "\n"); open(TEMPFILE, "<$tempfile"); open(NEWSGROUPS, ">$inn::newsgroups"); print NEWSGROUPS $_ while ; close TEMPFILE; close NEWSGROUPS; unlink "$inn::locks/LOCK.newsgroups"; unlink($tempfile); } } # update newsgroups # Now, log what we did. if ($logging) { $errmsg = "newgroup $groupname "; ($modflag eq "moderated" ? $errmsg .= "m " : $errmsg .= "y "); $errmsg .= $status . " " . $sender; logger($token, $logging, $errmsg); } } } }