chiark / gitweb /
Add more whitespace (formatting improvement)
[modbot-uram.git] / webstump / scripts / html_output.pl
1 #
2 # This is a module with functions for HTML output.
3 #
4 # I separate it from the main STUMP stuff because these functions are
5 # bulky and not very interesting.
6 #
7 #
8
9 use POSIX;
10 use CGI qw/escapeHTML/;
11
12 sub begin_html {
13   my $title = pop( @_ );
14   print 
15 "Content-Type: text/html\n\n
16 <TITLE>$title</TITLE>
17 <BODY>
18 <H1>$title</H1>\n\n";
19
20   if( &is_demo_mode ) {
21     print "<B> You are operating in demonstration mode. User actions will have no effect.</B><HR>\n";
22   }
23   
24 }
25
26 sub end_html {
27   print "\n<HR>Thank you for using <A HREF=$STUMP_URL>STUMP Robomoderator</A>.
28 <!-- <BR>
29 Click <A HREF=$base_address>here</A> to return to WebSTUMP. -->
30 ";
31 }
32
33 # prints a link to help
34 # accepts topic id and topic name.
35 #
36 sub link_to_help {
37   my $topic_name = pop( @_ );
38   my $topic = pop( @_ );
39
40   #&print_image( "help.gif", "" );
41
42   print "<A HREF=$base_address?action=help&topic=$topic TARGET=new>Click here for help on $topic_name</A>\n";
43 }
44
45 #
46 # prints image and an alt text
47 #
48 sub print_image { # image_file, alt_text
49   my $alt = pop( @_ );
50   my $file = pop( @_ );
51
52   print "<IMG SRC=$base_address_for_files/images/$file ALT=\"$alt\" ALIGN=BOTTOMP>\n";
53 }
54
55 # prints the welcome page and login screen.
56 sub html_welcome_page {
57   &begin_html( "Welcome to WebSTUMP" );
58
59   print 
60
61 "Welcome to WebSTUMP, the moderators' front end for <A
62 HREF=http://www.algebra.com/~ichudov/stump>STUMP</A> users -- USENET newsgroup
63 moderators. Only authorized users are allowed to log into this
64 program.
65
66 <HR>";
67
68   my $motd_file = "$webstump_home/config/motd";
69
70   if( -f $motd_file && -r $motd_file ){
71     open( MOTD, $motd_file );
72     print "<B>Message of the Day:</B><BR><PRE>\n";
73     print while( <MOTD> );
74     close( MOTD );
75     print "</PRE><HR>\n";
76   }
77
78   print "
79 Newsgroups Status:<BR>
80 <TABLE BORDER=3>\n";
81
82   for( sort @newsgroups_array ) {
83     print "<TR><TD>";
84     
85     my $count = &get_article_count( $_ );
86
87     print " <A HREF=$base_address?action=login_screen\&newsgroup=$_>$_</A>";
88     &print_image( "smiley.gif", "" ) if $count;
89     print "</TD>";
90
91
92     print "<TD>$count messages in queue<BR></TD>";
93 #    print "<TD><A HREF=$base_address?action=init_request_newsgroup_creation\&newsgroup=$_>Request creation</A></TD>\n";
94   }
95
96   print "</TABLE>\n";
97   print "<HR>Note: click on the newsgroup to login in as moderator. 
98 <!-- Click on 'Request Creation' to ask a sysadmin at a specific domain
99 to carry your newsgroup. -->\n<HR>
100 <A HREF=$base_address?action=admin_login>Click here to administer this WebSTUMP installation</A>
101 ";
102   &end_html;
103 }
104
105 # prints the login screen for newsgroup.
106 sub html_login_screen {
107   my $newsgroup = $request{'newsgroup'} || &error( "newsgroup not defined" );
108
109   my $count = &get_article_count( $newsgroup );
110
111
112   if( $count ) {
113     &begin_html( "$count articles in queue for $newsgroup" );
114   } else {
115     &begin_html( "Empty Queue for $newsgroup" );
116   }
117
118   print
119 " Welcome to the Moderation  Center for  $newsgroup. Please bookmark
120 this page. <HR>";
121
122
123   my $color = "", $end_color = "";
124
125   if( $count ) {
126     $color = "<font color=red>";
127     $end_color = "<font color=black>";
128   }
129
130   print 
131 "<FORM METHOD=$request_method action=$base_address>
132  <INPUT NAME=action VALUE=moderation_screen TYPE=hidden>
133   $color ($count ";
134   
135   &print_image( "new_tiny2.gif", "new" ) if $count;
136
137   print " articles available)<BR> $end_color
138  Login: <INPUT NAME=moderator VALUE=\"\" SIZE=20>
139  <BR>
140  Password: <INPUT NAME=password TYPE=password VALUE=\"\" SIZE=20>
141  <BR>
142  <INPUT TYPE=submit VALUE=\"Proceed with Login\">
143  <INPUT TYPE=reset VALUE=\"Reset\">
144  <INPUT NAME=newsgroup VALUE=\"$newsgroup\" TYPE=hidden>
145  </FORM><HR>
146   Please log into $newsgroup. You can only log in if you know your login id
147   and know the secret password. You should not give your password to any
148   unauthorized user. Your login id and password are NOT case sentitive, 
149   which means that,
150   for example, \"xyzzy\" and \"XyZZY\" are equally valid.<P>
151 ";
152
153 #  print "
154 # Log in as \"admin\" if you want to 
155 #<UL>
156 #  <LI> edit filtering lists.";
157 #
158 #  &link_to_help( "filter-lists", "Filter Lists" );
159 #
160 #  print "
161 #  <LI> add/delete users or change their passwords.
162 #  <LI> First Time Users: You have to log in as admin and add a moderator user
163 #  who will be able to moderate the newsgroup. Then log in again as that
164 #  user. If you are a new user, you have to have your admin password assigned to
165 #  you by the administrator.
166 #</UL>
167 #
168 #";
169   &end_html;
170 }
171
172 # prints the login screen for newsgroup.
173 sub admin_login_screen {
174   &begin_html( "Administrative login" );
175
176   print
177 "
178 Attention: this page is only for the maintainer of the whole WebSTUMP
179 installation. Please return to the main page if you are not the maintainer
180 of this installation. <HR>
181 ";
182
183   print 
184 "<FORM METHOD=$request_method action=$base_address>
185  <INPUT NAME=action VALUE=webstump_admin_screen TYPE=hidden>
186  Password: <INPUT NAME=password TYPE=password VALUE=\"\" SIZE=20>
187  <BR>
188  <INPUT TYPE=submit VALUE=\"Proceed with Login\">
189  <INPUT TYPE=reset VALUE=\"Reset\">
190  </FORM>
191 ";
192
193   &end_html;
194 }
195
196 # main moderation page -- single-article version
197 sub html_moderate_article {
198   my $newsgroup = &required_parameter( 'newsgroup' );
199   my $moderator = $request{'moderator'};
200   my $password = $request{'password'};
201   my $file = shift @_ || &required_parameter('file');
202
203   &begin_html( "Main Moderation Screen: $newsgroup" );
204   print "<HR>\n";
205
206   &read_rejection_reasons;
207
208   my $dir = "$queues_dir/$newsgroup";
209
210   if( -d "$dir/$file" && open( TEXT_FILES, "$dir/$file/text.files.lst" ) ) {
211
212       print "<HR>\n" if &print_article_warning( $file );
213
214       print "<PRE>\n";
215       my $filename;
216       my $inhead= 1;
217       while( $filename = <TEXT_FILES> ) {
218         open( ARTICLE, "$dir/$file/$filename" );
219         while( <ARTICLE> ) {
220           $embolden= m/^(?:from|subject)\s*\:/i;
221           s/\&/&amp;/g;
222           s/</&lt;/g;
223           s/>/&gt;/g;
224           $_= "<strong>$_</strong>" if $embolden;
225           print;
226           $inhead= 0 unless m/\S/;
227         }
228         close( ARTICLE );
229         $inhead= 0;
230       }
231
232       print "\n</PRE>\n\n";
233
234       &print_images( $newsgroup, "$dir/$file", $file);
235
236   } else {
237     print "This message ($dir/$file) no longer exists -- maybe it was " .
238           "approved or rejected by another moderator.";
239   }
240
241       print "<HR>
242 <FORM NAME=decision METHOD=$request_method action=$base_address>
243 ";
244
245   print "
246 <INPUT NAME=action VALUE=approval_decision TYPE=hidden>";
247   &html_print_credentials;
248         print "<INPUT TYPE=radio NAME=\"decision_$file\" VALUE=approve>Approve\n";
249         print "<INPUT TYPE=radio NAME=\"decision_$file\" VALUE=skip>Leave\n";
250         print "<INPUT TYPE=radio NAME=\"decision_$file\" VALUE=leave>Back of queue\n";
251         foreach (@short_rejection_reasons) {
252           print "<INPUT TYPE=radio NAME=\"decision_$file\" VALUE=\"reject $_\">Reject \u$_\n";
253         }
254
255       print "<BR> <BR> Comment (to poster, in rejection message): <INPUT NAME=comment VALUE=\"\" SIZE=80><BR>";
256
257   print "<BR>
258 <INPUT TYPE=radio NAME=poster_decision VALUE=nothing CHECKED>Don't change poster's status</INPUT>
259 <INPUT TYPE=radio NAME=poster_decision VALUE=preapprove 
260 >White-list poster</INPUT>
261 <INPUT TYPE=radio NAME=poster_decision VALUE=ban 
262   ONCLICK=\"alert( 'Banning a poster is a controversial practice'); \"
263 > Ban All Posts by this Person (Careful!)</INPUT>
264
265 <BR><BR>
266 <I>
267 NOTE: Decisions to ban and whitelist posters can be reversed by 
268 logging in as \"admin\" and editing respective lists of whitelisted
269 and banned threads.
270 ";
271
272   &link_to_help( "filter-lists", "automatic filtering and filter lists, blacklisting and preapproved threads." );
273
274   print "Be really careful about blacklisting of everyone except spammers.</I><BR><BR>
275
276 <INPUT TYPE=radio NAME=next_screen VALUE=single CHECKED> 
277         Review ONE article in next screen
278 <INPUT TYPE=radio NAME=next_screen VALUE=multiple> 
279         Review multiple articles in next screen
280 <HR>
281
282 <INPUT TYPE=submit VALUE=\"Submit\">
283 <INPUT TYPE=submit NAME=skip_submit VALUE=\"Skip\">
284 <INPUT TYPE=reset VALUE=\"Reset\">
285 ";
286
287       print "</FORM>\n\n";
288   print "<BR><A HREF=$base_address?action=change_password&newsgroup=$newsgroup&" .
289         "moderator=$moderator&password=$password>Change Password</A>";
290
291   closedir( QUEUE );
292   &end_html;
293 }
294
295 # WebSTUMP administrative screen
296 sub webstump_admin_screen {
297
298   &verify_admin_password;
299
300   my $password = $request{'password'};
301
302   &begin_html( "WebSTUMP Administration" );
303   print "
304 <FORM METHOD=$request_method action=$base_address>
305 <INPUT NAME=action VALUE=admin_add_newsgroup TYPE=hidden>
306 <INPUT NAME=password VALUE=\"$password\" TYPE=hidden>\n";
307
308
309   print "
310 <HR>
311 Create a new newsgroup on the server:<BR>
312
313 Newsgroup:<BR> <INPUT NAME=newsgroup_name VALUE=\"\" SIZE=50><BR>
314 Address to send approved/rejected messages <BR>
315         <INPUT NAME=newsgroup_approved_address VALUE=\"\" SIZE=30><BR>
316 Admin Password For this group:<BR> <INPUT NAME=newsgroup_password VALUE=\"\" SIZE=10><BR>
317 <INPUT TYPE=submit VALUE=\"Submit\">
318 <INPUT TYPE=reset VALUE=\"Reset\"><HR>
319 ";
320
321       print "</FORM>\n\n<PRE>\n";
322
323   &end_html;
324 }
325
326 # WebSTUMP "add newsgroup" function
327 sub admin_add_newsgroup {
328
329   &verify_admin_password;
330
331   my $newsgroup = &required_parameter( 'newsgroup_name' );
332
333   $newsgroup =~ s/\///g;
334   $newsgroup = &untaint( $newsgroup );
335
336   my $address = &required_parameter( 'newsgroup_approved_address' );
337   my $password = &required_parameter( 'newsgroup_password' );
338
339   &user_error( "Newsgroup $newsgroup already exists" )
340     if defined $newsgroups_index{$newsgroup};
341
342   &user_error( "Password may only contain letters and digits" )
343     if( ! ($password =~ /^[a-zA-Z0-9]+$/ ) );
344
345   &begin_html( "WebSTUMP Administration: Newsgroup created" );
346
347   print "<PRE>\n\n";
348
349   print "Adding $newsgroup to $webstump_home/config/newsgroups.lst...";
350   mkdir "$webstump_home/queues/$newsgroup", 0755;
351   print " done.\n";
352   
353   $dir = "$webstump_home/config/newsgroups/$newsgroup";
354   
355   print "Creating $dir...";
356   mkdir $dir, 0755;
357   print " done.\n";
358   
359   print "Creating files in $dir...";
360   
361   &append_to_file( "$dir/address.txt", "$address\n" );
362   &append_to_file( "$dir/moderators", "ADMIN \U$password\n" );
363   &append_to_file( "$dir/rejection-reasons",
364 "offtopic::a blatantly offtopic article, spam
365 harassing::message of harassing content
366 charter::message poorly formatted
367 " );
368   print " done.\n";
369
370
371   print "</PRE>\n";
372
373   &end_html;
374 }
375
376 #
377 #
378 sub print_images {
379   $web_subdir = pop( @_ );
380   $subdir = pop( @_ );
381   $newsgroup = pop( @_ );
382
383   opendir( SUBDIR, $subdir );
384
385   my $count = 0;
386
387   while( $_ = readdir( SUBDIR ) ) {
388     my $file = "$subdir/$_";
389     next if( ! -f $file || ! -r $file );
390     my $extension = $file;
391     $extension =~ s/^.*\.//;
392     $extension = "\L$extension";
393     
394     if( $extension eq "gif" || $extension eq "jpg" || $extension eq "jpeg" ) {
395       print "<CENTER> <IMG SRC=$base_address_for_files/queues/$newsgroup/$web_subdir/$_></CENTER><HR>\n";
396       $count++;
397     } else {
398       my $filename = $_;
399       $filename =~ s/^.*\///;
400       next if $filename eq "skeleton.skeleton" 
401               || $filename eq "headers.txt"
402               || $filename eq "full_message.txt"
403               || $filename eq "text.files.lst"
404               || $filename eq "stump-prolog.txt"
405               || $filename eq "stump-warning.txt"
406               || $filename =~ /msg-.*\.doc/;
407       
408       &print_image( "no_image.gif", "security warning" );
409       print "<B>Non-image attachment:</B><CODE>$filename</CODE> NOT SHOWN for security reasons.<BR>\n";
410     }
411   }
412   return $count;
413 }
414
415 # prints warning if there is warning stored about the article
416 sub print_article_warning { # short-subdir
417   my $file = pop( @_ );
418
419   my $warning_file = &article_file_name( $file ) . "/stump-warning.txt";
420
421   if( -r $warning_file ) {
422     open( WARNING, $warning_file );
423     while ($warning = <WARNING>) {
424         next unless $warning =~ m/\S/;
425         $warning =~ s/\&/&amp;/g;
426         $warning =~ s/</&lt;/g;
427         $warning =~ s/>/&gt;/g;
428         &print_image( "star.gif", "warning" );
429         print "<FONT COLOR=red>$warning</FONT><br>\n";
430     }
431     close( WARNING );
432     return 1;
433   }
434
435   return 0;
436 }
437
438 sub get_queue_list ($) {
439     my ($newsgroup) = @_;
440     my $dir = "$queues_dir/$newsgroup";
441     my %sortkeys;
442
443     opendir(QUEUED, $dir) or &error("could not open directory $dir");
444
445     for (;;) {
446         $!=0;
447         my $subdir= scalar readdir(QUEUED);
448         last unless defined $subdir;
449
450         my $subpath= "$dir/$subdir";
451         next if $subdir =~ /^\.+/;
452         next unless -d $subpath;
453         my $sortkey;
454         if (!stat "$subpath/stump-warning.txt") {
455             $!==&ENOENT or die "$subpath $!";
456             $sortkey= 0;
457         } else {
458             $sortkey= (stat _)[9];
459         }
460         $sortkeys{$subdir}= $sortkey;
461     }
462     closedir( QUEUED );
463     my @articles= sort { $sortkeys{$a} <=> $sortkeys{$b} } keys %sortkeys;
464     return ($dir, @articles);
465 }
466
467 # main moderation page -- multiple-articles version
468 sub html_moderation_screen {
469   my $newsgroup = &required_parameter( 'newsgroup' );
470   my $moderator = $request{'moderator'};
471   my $password = $request{'password'};
472
473
474   if( $request{'next_screen'} eq 'single' ) {
475     # we show a single article if the user so requested.
476     # just get the first article from the queue if any, otherwise show 
477     # an empty main screen.
478    
479     my ($dir, @articles)= get_queue_list($newsgroup);
480
481     my $i;
482     for ($i=0; $i<@articles; $i++) {
483         my $subdir= shift @articles;
484         push @articles, $subdir;
485         last if $request{"decision_$subdir"};
486     }
487
488     while( $subdir = shift @articles ) {
489       if( -d "$dir/$subdir" && !($subdir =~ /^\.+/) 
490           && open( PROLOG, "$dir/$subdir/stump-prolog.txt" ) ) {
491               &html_moderate_article( $subdir );
492               return;
493       }
494     }
495   } else {
496         # otherwise just show the moderator an empty main screen.
497   }
498     
499   &begin_html( "Main Moderation Screen: $newsgroup" );
500   print "Welcome to the main moderation screen. Its main purpose is to 
501 help you process most messages extremely quickly. For every message, it 
502 presents you who sent it, as well as the first three non-blank lines.
503 For those messages where the decision is obvious, simply select your
504 decision (approve/reject etc) and click submit. For those messages which
505 you would like to review in more details, do not select anything and
506 use Review/Comment function from this screen or from a subsequent screen.
507 Remember that if you do not make any decision, the article would stay in the
508 queue.\n";
509
510   &read_rejection_reasons;
511
512   my ($dir, @articles)= get_queue_list($newsgroup);
513
514   print "
515   <FORM METHOD=$request_method action=$base_address>
516   <INPUT NAME=action VALUE=approval_decision TYPE=hidden>";
517     &html_print_credentials;
518
519     print "<HR> <INPUT TYPE=submit VALUE=Submit>
520 <INPUT TYPE=reset VALUE=Reset>
521 ";
522   
523   my $file, $subject = "No Subject", $from = "From nobody";
524   my $form_not_empty = "";
525   my $article_count = 0;
526   my $warning = "";
527   while( ($subdir = shift @articles) && $article_count++ < 40 ) {
528     $file=$subdir;
529     if( -d "$dir/$subdir" && !($subdir =~ /^\.+/) 
530         && open( PROLOG, "$dir/$subdir/stump-prolog.txt" ) ) {
531         while( <PROLOG> ) {
532           chop;
533           if( /^Real-Subject: /i ) {
534             s/\&/&amp;/g;
535             s/</&lt;/g;
536             s/>/&gt;/g;
537             s/^Real-Subject: //g;
538             $subject = substr( $_, 0, 50 );
539           } elsif( /^From: /i ){
540             s/\&/&amp;/g;
541             s/</&lt;/g;
542             s/>/&gt;/g;
543             $from = substr( $_, 0, 50 );
544           } elsif( /^$/ ) {
545             last;
546           }
547         }
548
549         print "<HR><B>$from: $subject</B>(";
550         print "<A HREF=$base_address?action=moderate_article&newsgroup=$newsgroup&" .
551               "moderator=$moderator&password=$password&file=$subdir>Review/Comment/Whitelist</A>)<BR>\n";
552         print "<INPUT TYPE=radio NAME=\"decision_$file\" VALUE=approve>Approve\n";
553         print "<INPUT TYPE=radio NAME=\"decision_$file\" VALUE=skip>Leave\n";
554         print "<INPUT TYPE=radio NAME=\"decision_$file\" VALUE=leave>Back of queue\n";
555         foreach (@short_rejection_reasons) {
556           print "<INPUT TYPE=radio NAME=\"decision_$file\" VALUE=\"reject $_\">Reject \u$_\n";
557         }
558
559         print "<BR>\n";
560
561         &print_article_warning( $file );
562
563         print "<PRE>\n";
564
565         my $i = 0;
566
567         while( ($_ = <PROLOG>) && $i < 5 ) {
568             chop;
569             next if m/^\>/;
570             s/\&/&amp;/g;
571             s/</&lt;/g;
572             s/>/&gt;/g;
573             if( $_ ne "" ) {
574               print "]  " . substr( $_, 0, 75 ) . "\n";
575               $i++;
576             }
577         }
578
579         print "</PRE>";
580         $form_not_empty = "yes";
581         close( PROLOG );
582         $article_count += &print_images( $newsgroup, "$dir/$subdir", $subdir );
583     }
584   }
585
586   if( $form_not_empty ) {
587     print "<HR> <INPUT TYPE=submit VALUE=Submit>
588 <INPUT TYPE=reset VALUE=Reset>
589 ";
590   } else {
591     print "
592 <HR>
593 No articles present in the queue
594 <INPUT TYPE=submit VALUE=Refresh>
595 <HR>\n";
596   }
597
598   print "<A HREF=$base_address?action=change_password&newsgroup=$newsgroup&" .
599         "moderator=$moderator&password=$password>Change Password</A>";
600
601   print "</FORM>\n\n";
602
603   print "<FORM METHOD=$request_method action=$base_address>";
604   &html_print_credentials;
605   print "<INPUT NAME=action VALUE=moderator_admin TYPE=hidden>
606          <INPUT TYPE=submit VALUE=\"Management\">
607          </FORM>";
608
609   &end_html;
610 }
611
612 # prints hidden fields -- credentials
613 sub html_print_credentials {
614   my $newsgroup = $request{'newsgroup'};
615   my $moderator = $request{'moderator'};
616   my $password = $request{'password'};
617
618   print "
619  <INPUT NAME=newsgroup VALUE=\"$newsgroup\" TYPE=hidden>
620  <INPUT NAME=moderator VALUE=\"$moderator\" TYPE=hidden>
621  <INPUT NAME=password VALUE=\"$password\" TYPE=hidden>\n";
622 }
623
624 # logs
625
626 sub scanlogs ($$$) {
627     my ($forwards, $gotr, $callback) = @_;
628     my $dir= "$webstump_home/..";
629     opendir LOGSDIR, "$dir" or die "$dir $!";
630     my $num= sub {
631         local ($_) = @_;
632         return $forwards * (
633             m/^errs$/ ? -1 :
634             m/^errs\.(\d+)(?:\.gz$)$/ ? $1 :
635             undef
636                            );
637     };
638     foreach my $leaf (
639                       sort { $num->($a) <=> $num->($b) }
640                       grep { defined $num->($_) }
641                       readdir LOGSDIR
642                       ) {
643         my $file= "$dir/$leaf";
644         if ($file =~ m/\.gz$/) {
645             open LOGFILE, "zcat $file |" or die "zcat $file $!";
646         } else {
647             open LOGFILE, "< $file" or die "$file $!";
648         }
649         while (<LOGFILE>) {
650             my $tgot= $callback->();
651             next unless $tgot;
652             $$gotr= $tgot if $tgot > $$gotr;
653             last if $tgot > 1;
654         }
655         $!=0; $?=0; close LOGFILE or die "$file $? $!";
656         last if $$gotr > 1;
657     }
658     closedir LOGSDIR or die "$dir $!";
659 }        
660
661 sub html_search_logs {
662   &begin_html("Search logs for $request{'newsgroup'}");
663   my $reqnum;
664   my $forwards=1;
665   my $min= 9;
666   if ($request{'download_logs'}) {
667       print "<h2>Complete log download</h2>\n";
668       $min= 2;
669   } elsif ($request{'messagenum'} =~ m/^\s*(\d+)\s*$/) {
670       $reqnum= $1;
671       $forwards= -1;
672       $min= 1;
673       print "<h2>Log entry for single message $reqnum</h2>\n";
674   } else {
675       print "<h2>Log lookup - bad reference</h2>
676 Please supply the numerical reference as found in the \"recent activity\"
677 log or message headers.  Reference numbers consist entirely of digits,
678 and are often quoted in message headers in [square brackets].<p>
679         ";
680       &end_html;
681       return;
682   }
683   if ($mod_log_access < $min) {
684       print "Not permitted [$mod_log_access<$min].  Consult administrator.\n";
685       &end_html;
686       return;
687   }
688
689   my $sofar= 0;
690   &scanlogs($forwards, \$sofar, sub {
691       return 0 unless chomp;
692       return 0 unless m/^DECISION: /;
693       my @vals = split / \| /, $';
694       return 0 unless @vals >= 5;
695       my $subj= pop @vals;
696       my ($group,$dir,$act,$reason,$timet) = @vals;
697       my $date= $timet ? (strftime "%Y-%m-%d %H:%M:%S GMT", gmtime $timet)
698           : "(unknown)";
699       return 0 unless $group eq $request{'newsgroup'};
700       return 0 unless $subj =~ m,/(\d+)$,;
701       my $treqnum= $1;
702       return 0 if defined($reqnum) and $treqnum ne $reqnum;
703       print "<table rules=all><tr><th>Date<th>Reference<th>Disposal<th>Reason</tr>\n"
704           unless $sofar;
705       print "<tr>", (map { "<td>".escapeHTML($_) }
706                      $date,$treqnum,$act,$reason);
707       print "</tr>\n";
708       return defined($reqnum) ? 2 : 1;
709   });
710   if ($sofar) {
711       print "</table>" if $sofar;
712       print "\n";
713   } else {
714       print "Reference not found.".
715           "  (Perhaps message has expired, or is still in the queue?)";
716   }
717   &end_html;
718 }
719
720 # newsgroup admin page
721 sub html_newsgroup_management {
722   &begin_html( "Administer $request{'newsgroup'}" );
723
724   print "All usernames and passwords are not case sensitive.\n";
725   print "<HR>Use this form to add new moderators or change passwords:<BR>
726  <FORM METHOD=$request_method action=$base_address>
727  <INPUT NAME=action VALUE=add_user TYPE=hidden>";
728   &html_print_credentials;
729   print "
730  Username: <INPUT NAME=user VALUE=\"\" SIZE=20>
731  <BR>
732  Password: <INPUT NAME=new_password VALUE=\"\" SIZE=20>
733  <BR>
734  <INPUT TYPE=submit VALUE=\"Add/Change\">
735  <INPUT TYPE=reset VALUE=Reset>
736  </FORM>
737 ";
738
739   print "<HR>Use this form to delete moderators:<BR>
740  <FORM METHOD=$request_method action=$base_address>
741  <INPUT NAME=action VALUE=delete_user TYPE=hidden>";
742   &html_print_credentials;
743   print "
744  Username: <INPUT NAME=user VALUE=\"\" SIZE=20>
745  <BR>
746  <INPUT TYPE=submit VALUE=\"Delete Moderator\">
747  <INPUT TYPE=reset VALUE=Reset>
748  </FORM><HR>
749
750  <FORM METHOD=$request_method action=$base_address>
751  <INPUT NAME=action VALUE=edit_list TYPE=hidden>";
752   &html_print_credentials;
753   print "
754   Configuration List: <SELECT NAME=list_to_edit>
755
756     <OPTION VALUE=good.posters.list>Good Posters List
757     <OPTION VALUE=bad.posters.list>Banned Posters List
758     <OPTION VALUE=watch.words.list>Suspicious Words List
759
760   </SELECT>
761   <INPUT TYPE=submit VALUE=\"Edit\">
762   <INPUT TYPE=reset VALUE=Reset>";
763
764   &link_to_help( "filter-lists", "filtering lists" );
765
766   print "</FORM><HR>";
767
768   if ($mod_log_access) {
769       print "<form>
770         Use this form to search logs of past moderation decisions:
771         <br>
772         <form method=$request_method action=$base_address>
773         <input name=action value=search_logs type=hidden>";
774
775       &html_print_credentials;
776
777       print "
778         Reference number: <input name=messagenum size=30>
779         <input type=submit value=\"Lookup\">";
780
781       print "
782         <input type=submit value=\"Download all logs\" name=\"download_logs\">"
783         if $mod_log_access >= 2;
784
785       print "</form><hr>\n";
786   }
787
788   print "
789
790   List of current moderators:<P>
791
792   <UL>\n";
793
794   foreach (keys %moderators) {
795       print "<LI> $_\n";
796   }
797
798   print "</UL>\n";
799
800   print "<HR><FORM METHOD=$request_method action=$base_address>";
801   &html_print_credentials;
802   print "<INPUT NAME=action VALUE=moderation_screen TYPE=hidden>
803          <INPUT TYPE=submit VALUE=\"Go to moderation screen\">
804          </FORM>";
805
806   &end_html;
807 }
808
809
810 # edit config list
811 sub edit_configuration_list {
812
813   my $list_to_edit = &required_parameter( 'list_to_edit' );
814
815   $list_to_edit = &check_config_list( $list_to_edit );
816
817   my $list_file = &full_config_file_name( $list_to_edit );
818
819   my $list_content = "";
820
821   if( open( LIST, $list_file ) ) {
822     $list_content .= $_ while( <LIST> );
823     close( LIST );
824   }
825
826   $list_content =~ s/\&/&amp;/g;
827   $list_content =~ s/</&lt;/g;
828   $list_content =~ s/>/&gt/g;
829
830   &begin_html( "Edit $list_to_edit" );
831
832   print
833 " <FORM METHOD=$request_method action=$base_address>
834  <INPUT NAME=action VALUE=set_config_list TYPE=hidden>
835  <INPUT NAME=list_to_edit VALUE=$list_to_edit TYPE=hidden>";
836   &html_print_credentials;
837   &link_to_help( $list_to_edit, "$list_to_edit" );
838   print "
839  Edit this list: <HR>
840 <TEXTAREA NAME=list rows=20 COLS=50>
841 $list_content</TEXTAREA>
842
843  <BR>
844  <INPUT TYPE=submit VALUE=\"Set\">
845  </FORM>
846 ";
847
848   &end_html;
849 }
850
851 # password change page
852 sub html_change_password{
853   &begin_html( "Change Password" );
854
855   print "All usernames and passwords are not case sensitive.\n";
856   print "<HR>Use this form to change your password:<BR>
857  <FORM METHOD=$request_method action=$base_address>
858  <INPUT NAME=action VALUE=validate_change_password TYPE=hidden>";
859   &html_print_credentials;
860   print "
861  <BR>
862  New Password: <INPUT NAME=new_password VALUE=\"\" SIZE=20>
863  <BR>
864  <INPUT TYPE=submit VALUE=Submit>
865  <INPUT TYPE=reset VALUE=Reset>
866  </FORM>
867 ";
868
869   &end_html;
870 }
871
872
873 # newsgroup creation form
874 sub init_request_newsgroup_creation{
875   my $newsgroup = &required_parameter( 'newsgroup' );
876
877   &begin_html( "Request Creation of $newsgroup" );
878
879   print "This page helps you ask the system administrator of your domain
880 to create <B>$newsgroup</B> on your server. Type in your domain name and
881 click SUBMIT. An email will be sent to news\@domain and usenet\@domain
882 and postmaster\@domain
883 asking them to create your newsgroup. Please do NOT abuse this system.
884 NOTE: You can give the URL of this page to your group readers so that 
885 they could request creation of their newsgroups by themselves.\n";
886
887   print "<HR>
888  <FORM METHOD=$request_method action=$base_address>
889  <INPUT NAME=action VALUE=complete_newsgroup_creation_request TYPE=hidden>\n";
890   &html_print_credentials;
891   print "
892  <BR>
893  Domain Name ONLY: <INPUT NAME=domain_name VALUE=\"\" SIZE=40>
894  <BR>
895  <INPUT TYPE=submit VALUE=Submit>
896  <INPUT TYPE=reset VALUE=Reset>
897  </FORM>
898 ";
899
900   &end_html;
901 }
902
903
904 # newsgroup creation completion
905 sub complete_newsgroup_creation_request{
906   my $newsgroup = &required_parameter( 'newsgroup' );
907   my $domain_name = &required_parameter( 'domain_name' );
908
909   if( !($domain_name =~ /(^[a-zA-Z0-9\.-_]+$)/) ) {
910     &user_error( "invalid domain name" );
911   }
912
913   $domain_name = $1;
914
915
916   my $request = "To: news\@$domain_name, usenet\@$domain_name, postmaster\@$domain_name
917 Subject: Please create $newsgroup (Moderated)
918 From: devnull\@algebra.com ($newsgroup Moderator)
919 Organization: stump.algebra.com
920
921 Dear News Administrator:
922
923 A user of $domain_name has requested that you create a newsgroup
924
925         $newsgroup (Moderated) 
926
927 on your server. $newsgroup
928 is a legitimately created moderated newsgroup that is available worldwide.
929
930 Thank you very much for your help and cooperation.
931
932 Sincerely,
933
934         - Moderator of $newsgroup.
935
936 ";
937
938   &email_message( $request, "news\@$domain_name" );
939   &email_message( $request, "usenet\@$domain_name" );
940   &email_message( $request, "postmaster\@$domain_name" );
941
942   &begin_html( "Request to create $newsgroup sent" );
943
944   print "The following request has been sent:<HR><PRE>\n";
945
946   print "$request</PRE>\n";
947
948   &end_html;
949 }
950
951 # displays help
952 sub display_help {
953   my $topic_name = &required_parameter( "topic" );
954
955   $topic_name =~ s/\///g;
956   $topic_name =~ s/\.\.//g;
957   $topic_name = &untaint( $topic_name );
958
959   my $file = "$webstump_home/doc/help/$topic_name.html";
960
961   &error( "Topic $topic_name not found in $file." ) 
962         if ! -r $file;
963
964   open( FILE, "$file" );
965   my $help = "";
966   $help .= $_ while( <FILE> );
967   close( FILE );
968
969   $help =~ s/##/$base_address?action=help&topic=/g;
970
971   &begin_html( "$topic_name" );
972
973   print $help;
974
975   print "<HR>";
976 }
977
978
979
980
981
982
983
984 1;