chiark / gitweb /
505ff3251d3920d07797411c9418e70e10fa0d5e
[modbot-ulm.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=watch.posters.list>Suspicious Posters List
758     <OPTION VALUE=bad.posters.list>Banned Posters List
759     <OPTION VALUE=watch.words.list>Suspicious Words List
760
761   </SELECT>
762   <INPUT TYPE=submit VALUE=\"Edit\">
763   <INPUT TYPE=reset VALUE=Reset>";
764
765   &link_to_help( "filter-lists", "filtering lists" );
766
767   print "</FORM><HR>";
768
769   if ($mod_log_access) {
770       print "<form>
771         Use this form to search logs of past moderation decisions:
772         <br>
773         <form method=$request_method action=$base_address>
774         <input name=action value=search_logs type=hidden>";
775
776       &html_print_credentials;
777
778       print "
779         Reference number: <input name=messagenum size=30>
780         <input type=submit value=\"Lookup\">";
781
782       print "
783         <input type=submit value=\"Download all logs\" name=\"download_logs\">"
784         if $mod_log_access >= 2;
785
786       print "</form><hr>\n";
787   }
788
789   print "
790
791   List of current moderators:<P>
792
793   <UL>\n";
794
795   foreach (keys %moderators) {
796       print "<LI> $_\n";
797   }
798
799   print "</UL>\n";
800
801   print "<HR><FORM METHOD=$request_method action=$base_address>";
802   &html_print_credentials;
803   print "<INPUT NAME=action VALUE=moderation_screen TYPE=hidden>
804          <INPUT TYPE=submit VALUE=\"Go to moderation screen\">
805          </FORM>";
806
807   &end_html;
808 }
809
810
811 # edit config list
812 sub edit_configuration_list {
813
814   my $list_to_edit = &required_parameter( 'list_to_edit' );
815
816   $list_to_edit = &check_config_list( $list_to_edit );
817
818   my $list_file = &full_config_file_name( $list_to_edit );
819
820   my $list_content = "";
821
822   if( open( LIST, $list_file ) ) {
823     $list_content .= $_ while( <LIST> );
824     close( LIST );
825   }
826
827   $list_content =~ s/\&/&amp;/g;
828   $list_content =~ s/</&lt;/g;
829   $list_content =~ s/>/&gt/g;
830
831   &begin_html( "Edit $list_to_edit" );
832
833   print
834 " <FORM METHOD=$request_method action=$base_address>
835  <INPUT NAME=action VALUE=set_config_list TYPE=hidden>
836  <INPUT NAME=list_to_edit VALUE=$list_to_edit TYPE=hidden>";
837   &html_print_credentials;
838   &link_to_help( $list_to_edit, "$list_to_edit" );
839   print "
840  Edit this list: <HR>
841 <TEXTAREA NAME=list rows=20 COLS=50>
842 $list_content</TEXTAREA>
843
844  <BR>
845  <INPUT TYPE=submit VALUE=\"Set\">
846  </FORM>
847 ";
848
849   &end_html;
850 }
851
852 # password change page
853 sub html_change_password{
854   &begin_html( "Change Password" );
855
856   print "All usernames and passwords are not case sensitive.\n";
857   print "<HR>Use this form to change your password:<BR>
858  <FORM METHOD=$request_method action=$base_address>
859  <INPUT NAME=action VALUE=validate_change_password TYPE=hidden>";
860   &html_print_credentials;
861   print "
862  <BR>
863  New Password: <INPUT NAME=new_password VALUE=\"\" SIZE=20>
864  <BR>
865  <INPUT TYPE=submit VALUE=Submit>
866  <INPUT TYPE=reset VALUE=Reset>
867  </FORM>
868 ";
869
870   &end_html;
871 }
872
873
874 # newsgroup creation form
875 sub init_request_newsgroup_creation{
876   my $newsgroup = &required_parameter( 'newsgroup' );
877
878   &begin_html( "Request Creation of $newsgroup" );
879
880   print "This page helps you ask the system administrator of your domain
881 to create <B>$newsgroup</B> on your server. Type in your domain name and
882 click SUBMIT. An email will be sent to news\@domain and usenet\@domain
883 and postmaster\@domain
884 asking them to create your newsgroup. Please do NOT abuse this system.
885 NOTE: You can give the URL of this page to your group readers so that 
886 they could request creation of their newsgroups by themselves.\n";
887
888   print "<HR>
889  <FORM METHOD=$request_method action=$base_address>
890  <INPUT NAME=action VALUE=complete_newsgroup_creation_request TYPE=hidden>\n";
891   &html_print_credentials;
892   print "
893  <BR>
894  Domain Name ONLY: <INPUT NAME=domain_name VALUE=\"\" SIZE=40>
895  <BR>
896  <INPUT TYPE=submit VALUE=Submit>
897  <INPUT TYPE=reset VALUE=Reset>
898  </FORM>
899 ";
900
901   &end_html;
902 }
903
904
905 # newsgroup creation completion
906 sub complete_newsgroup_creation_request{
907   my $newsgroup = &required_parameter( 'newsgroup' );
908   my $domain_name = &required_parameter( 'domain_name' );
909
910   if( !($domain_name =~ /(^[a-zA-Z0-9\.-_]+$)/) ) {
911     &user_error( "invalid domain name" );
912   }
913
914   $domain_name = $1;
915
916
917   my $request = "To: news\@$domain_name, usenet\@$domain_name, postmaster\@$domain_name
918 Subject: Please create $newsgroup (Moderated)
919 From: devnull\@algebra.com ($newsgroup Moderator)
920 Organization: stump.algebra.com
921
922 Dear News Administrator:
923
924 A user of $domain_name has requested that you create a newsgroup
925
926         $newsgroup (Moderated) 
927
928 on your server. $newsgroup
929 is a legitimately created moderated newsgroup that is available worldwide.
930
931 Thank you very much for your help and cooperation.
932
933 Sincerely,
934
935         - Moderator of $newsgroup.
936
937 ";
938
939   &email_message( $request, "news\@$domain_name" );
940   &email_message( $request, "usenet\@$domain_name" );
941   &email_message( $request, "postmaster\@$domain_name" );
942
943   &begin_html( "Request to create $newsgroup sent" );
944
945   print "The following request has been sent:<HR><PRE>\n";
946
947   print "$request</PRE>\n";
948
949   &end_html;
950 }
951
952 # displays help
953 sub display_help {
954   my $topic_name = &required_parameter( "topic" );
955
956   $topic_name =~ s/\///g;
957   $topic_name =~ s/\.\.//g;
958   $topic_name = &untaint( $topic_name );
959
960   my $file = "$webstump_home/doc/help/$topic_name.html";
961
962   &error( "Topic $topic_name not found in $file." ) 
963         if ! -r $file;
964
965   open( FILE, "$file" );
966   my $help = "";
967   $help .= $_ while( <FILE> );
968   close( FILE );
969
970   $help =~ s/##/$base_address?action=help&topic=/g;
971
972   &begin_html( "$topic_name" );
973
974   print $help;
975
976   print "<HR>";
977 }
978
979
980
981
982
983
984
985 1;