#!/usr/local/bin/perl
#
# ruboard 1.2.1, Copyright (c) 1998 by Andrew Maltsev, <am@amsoft.ru>
# $Id: ruboard.PL,v 1.18 1998/10/30 18:49:07 am Exp $
#
# To alter supported languages search for @LANG@. Only russian and
# english languages are supported now.
#
##############################################################################
# 
# Common subroutines
#
require "/usr/local/libexec/ruboard/rublib.pl";

# The mask for messages and index. We'll change it when required.
#
umask 022;

# Get Form Information
#
&parse_form;

# It's antispam redirection?
#
if($FORM{'mto'} ne "" && $FORM{'a2'} ne "")
{ $addr="mailto:" . $FORM{'mto'} . '@' . $FORM{'a2'};
  print <<EOH;
Location: $addr

Please go <A HREF="$addr">here</A>
EOH
  exit(0);
}

# Get config, it may depend on form's content
#
&read_config;

# Get the sequence number and lock it. The number does not really
# required here, but locking does.
#
&lock_number;
open(NUMBER,$datafile);
$num = <NUMBER>;
close(NUMBER);
$num++;

# Put items into nice variables
#
&get_variables;

# Open the new file and write information to it.
#
&new_file;

# Modifying main page
#
&main_page;

# Now threading the messaged
#
&thread_pages if $num_followups >= 1;

# Return the user HTML
#
&return_html;

# Increment sequence
#
$_=umask(077);
open(NUM,">$datafile") || die $!;
print NUM "$num\n";
close(NUM);
umask($um);
&unlock_number;

# Finishing
#
exit(0);

###############################################################################
# Fixing form, retrieving form variables, checks.
#
sub get_variables
{ if($FORM{'followup'})
   { $followup = "1";
     @followup_num = split(/,/,$FORM{'followup'});
     $num_followups = @followups = @followup_num;
     $last_message = pop(@followups);
     $origdate = "$FORM{'origdate'}";
     $origname = "$FORM{'origname'}";
     $origsubject = "$FORM{'origsubject'}";
     $origemail = "$FORM{'origemail'}";
   }
  else
   { $followup = "0";
   }

  $name = $FORM{'name'};
  $passwd = $FORM{'passwd'};
  $email = $FORM{'email'} if $FORM{'email'} =~ /.*\@.*\..*/ && ($acc_email==0 || $acc_email==1);
  $subject = $FORM{'subject'};
  if($FORM{'url'} =~ /.*\:.*\..*/ && defined($FORM{'url_title'}))
   { $message_url = "$FORM{'url'}";
     $message_url_title = "$FORM{'url_title'}";
   }
  $message_img = $FORM{'img'} if $FORM{'img'} =~ /.*tp:\/\/.*\..*/;
  $body = $FORM{'body'};
  $body =~ s/\r//g;
  ($date,$long_date)=&calc_date(time,$use_time);

# Is our ip address blocked for all or not?
#
  &check_ip($ENV{'REMOTE_ADDR'}) if $acc_ip==2;

# Are we posting?
#
  if(defined($FORM{"post"}) || ($body eq "" && $subject eq "" && $name eq ""))
   { &print_html_head($title,$title);
     print "<CENTER>";
#@LANG@#
     if($language eq "russian")
      { $_=($acc_policy==2 ? "Пароль, " : "");
        print "Заполните как минимум поля Имя, ${_}Тема и текст сообщения.\n";
        print "<BR>\n"
            . "Если у Вас нет пароля, то <A HREF=\"$acc_form_url\">зарегистрируйтесь</A>,\n"
            . "пожалуйста.\n" if $acc_policy;
      }
     else
      { $_=($acc_policy==2 ? "Password, " : "");
        print "Please fill at least Name, ${_}Subject and message body fields.\n";
        print "<BR>\n"
            . "If you have no password yet, please <A HREF=\"$acc_form_url\">register</A>!\n" if $acc_policy;
      }
     print "</CENTER>\n";
     &rest_of_form(0);
     exit(0);
   }

# Can we post?
#
  if($acc_policy!=0 || $passwd ne "")
   { &error('bad_user') if $name eq "" || $name =~ /:/;
     undef $crpass;
     if(open(F,$acc_passwd))
      { while(<F>)			# The lock is in place
         { split(/:/);
           if($_[0] eq $name || $_[1] eq $name)
            { $fname=$_[1];
              $crpass=$_[2];
              last;
            }
         }
        close(F);
      }
     &error('existing_user') if $acc_policy==1 && $crpass && $passwd eq "";
     &error('bad_user') unless ($acc_policy==1 && !$crpass && $passwd eq "") ||
                               ($crpass && crypt($passwd,$crpass) eq $crpass);
     $name=$fname if $fname ne "";
   }
  $authorized=($passwd eq "" ? 0 : 1);
  &check_ip($ENV{'REMOTE_ADDR'}) if $acc_ip==1 && !$authorized;

# Can we post images and/or refs?
#
  undef $message_img if ($acc_image==1 && !$authorized) || $acc_image==2;
  $message_url=undef $message_url_title if ($acc_url==1 && !$authorized) || $acc_url==2;

# Various small fixes
#
  $subject =~ s/^\s+//;
  $body =~ s/^\n+//g;
  $body =~ s/\n+$/\n/g;

# Formatting body. It may be used as a feature - leave the name blank
# and preview how your text was formatted.
#
  $body=&format_text($body);

# Incomplete form
#
  &error("no_name") if $name eq "";
  &error("no_subject") if $subject eq "";
  &error("no_body") if $body eq "";
  &error("no_email") if $acc_email==1 && $email eq "";
  &error("banned") if &is_banned($body,$subject,$message_url_title,$name);
}

###############################################################################
# Print message buttons
#
sub print_msg_buttons
{ print <<EOH;
<FONT SIZE=-1>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
<TR BGCOLOR=$bg_sep$bg_sep_img>
EOH
  print "<TD ALIGN=CENTER><A HREF=\"#followups\">$t_followups</A></TD>\n" .
        "<TD ALIGN=CENTER><A HREF=\"#postfp\">$t_post_followup</A></TD>\n" if $show_refs;
  print "<TD ALIGN=CENTER><A HREF=\"$mainpage\">$title</A></TD>\n";
  print "<TD ALIGN=CENTER><A HREF=\"$faqfile\">$t_faq</A></TD>\n" if $show_faq;
  print "</TR></TABLE></FONT>\n";
}
 
################################################
# New File Subroutine
#
sub new_file
{ open(SAVESTD,">&STDOUT");
  open(STDOUT,">$basedir/$mesgdir/$num\.$ext") || die "Can't open message: $!\n";
  $printing_to_file=1;

  if($acc_ip)
   { local($m)=umask(077);
     if(open(F,">>$acc_ip_msgs"))
      { print F $num.":".$ENV{'REMOTE_ADDR'}.":".time.":$name\n";
        close(F);
      }
     umask($m);
   }

  &print_html_head("$subject ($title)");
  &print_msg_buttons;

  $h_subject=&to_html_text($subject);
  $h_subject=$ap_subj_pre.$h_subject.$ap_subj_post if $ap_subj_pre ne "";
  print <<EOH;
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
<TR BGCOLOR=$bg_subject$bg_subj_img><TH COLSPAN=2>$h_subject</TH></TR>
<TR BGCOLOR=$bg_sep$bg_sep_img>
EOH
  print "<TD>&nbsp;$t_author: ";
  print &build_mailto($email) if $email;
  print &to_html_text($name);
  print "</A>" if $email;
  print "</TD>\n<TD ALIGN=RIGHT>$long_date&nbsp;</TD></TR>\n";

  if($followup == 1)
   { print "<TR BGCOLOR=$bg_sep$bg_sep_img><TD COLSPAN=2 ALIGN=CENTER><FONT SIZE=-1><I>";
#@LANG@#
     if($language eq "russian")
      { print "в ответ на:\n";
        print "<B><A HREF=\"$last_message\.$ext\">$origsubject</A></B> (автор\n";
        print &build_mailto($origemail) if $origemail;
        print &to_html_text($origname);
        print "</A>" if $origemail;
        print ") $origdate\n";
      }
     else
      { print "in reply to:\n";
        print "<B><A HREF=\"$last_message\.$ext\">$origsubject</A></B> posted by\n";
        print &build_mailto($origemail) if $origemail;
        print &to_html_text($origname);
        print "</A>" if $origemail;
        print " on $origdate\n";
      }
     print "</I></FONT></TD></TR>\n";
   }
  print "</TABLE>\n";

# Image
#
  print "<CENTER><IMG SRC=\"$message_img\"></CENTER><P>\n" if $message_img;

# Body
#
  if($allow_html)
   { local($cs)=&to_html_text($cite_symbol);
     split(/\n/,$body);
     foreach(@_)
      { local(@e)=split(/$cite_symbol/,"$_$cite_symbol");
        local($i);
        $_="";
        for($i=0; $i!=@e; $i++)
         { if($e[$i]=~/^\s*$/)
            { $_.="$cs ";
            }
           else
            { $_.=join($cite_symbol,@e[$i..$#e]);
              last;
            }
         }
      }
     $_=join("\n",@_);
   }
  else
   { $_=&to_html_text($body);
   }
  if($followup)
   { split(/\n/);
     local($cs)=&to_html_text($cite_symbol);
     for($i=0; $i!=@_; $i++)
      { if($_[$i] =~ /^${cs}/)
         { $_[$i]=~s|</?I>||ig;
           $_[$i]="<I>$_[$i]</I>";
         }
      }
     $_=join("\n",@_);
   }
  s/\n/<BR>\n/g;
  s/\(c\)/&copy;/ig;
  print <<EOH;
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
<TR><TD>&nbsp;&nbsp;&nbsp;</TD>
<TD WIDTH=100%>
$_
EOH
  print "<P><CENTER><B><A HREF=\"$message_url\">" . &to_html_text($message_url_title) . "</A></B></CENTER>\n"
   if $message_url;
  print <<EOH;
</TD>
<TD>&nbsp;&nbsp;&nbsp</TD>
</TR>
<TR BGCOLOR=$bg_sep$bg_sep_img>
<TH COLSPAN=3>&nbsp;<A NAME="followups">$t_followups</A></TH></TR>
<TR><TD>&nbsp;</TD><TD>
<UL><!--insert: $num-->
</UL><!--end: $num-->
</TD><TD></TD></TR>
<TR BGCOLOR=$bg_sep$bg_sep_img>
<TH COLSPAN=3>&nbsp;<A NAME="postfp">$t_post_followup</A></TH></TR>
<TR><TD></TD><TD>
EOH
  $origname=$name;
  $name="";
  $passwd="";
  $origemail=$email;
  $email="";
  $origsubject=$subject;
  $subject="Re: $subject" unless $subject =~ "^[rR][eE]: ";
  $origdate=$long_date;
  $origmessage_url=$message_url;
  $message_url="";
  $origmessage_url_title=$message_url_title;
  $message_url_title="";
  $origmessage_img=$message_img;
  $message_img="";
  $tmp_body=$body;
  if($quote_text)
   { chop($body) while $body =~ /\n$/;
     $body=~s/\n/\n${cite_symbol} /g;
     $body="$cite_symbol $body";
   }
  else
   { $body="";
   }
  push(@followup_num,$num); $followup=1;
  &rest_of_form(1);				# Form for followup
  $subject=$origsubject;
  $name=$origname;
  $message_url=$origmessage_url;
  $message_url_title=$origmessage_url_title;
  $message_img=$origmessage_img;
  $followup=0 if scalar(@followup_num) == 1;
  print <<EOH;
</TD><TD></TD>
</TR>
<TR BGCOLOR=$bg_sep$bg_sep_img><TD COLSPAN=3 ALIGN=RIGHT>
EOH
  &print_html_footer(1);
  print "&nbsp;&nbsp;</TD></TR></TABLE>\n";
  print "</BODY></HTML>\n";
  close(STDOUT);
  open(STDOUT,">&SAVESTD");
  $printing_to_file=0;
}

###############################################################################
# Main WWWBoard Page Subroutine
#
sub main_page
{ open(MAIN,$mesgfile) || die $!;
  @main = <MAIN>;
  close(MAIN);
  $_=scalar(@main);

  open(MAIN,">$mesgfile") || die $!;
  if (!$followup)
   { $entries=1;
     foreach $main_line (@main)
      { if ($main_line =~ /<!--begin-->/)
         { print MAIN $main_line;
	   print MAIN "<!--tla: $num--><li><a href=\"$mesgdir/$num\.$ext\">$subject</a> " .
	              "- <b>$name</b> <i>$date</i>\n";
           print MAIN "(<!--responses: $num-->0)\n";
           print MAIN "<ul><!--insert: $num-->\n";
           print MAIN "</ul><!--end: $num-->\n";
           next;
         }
        elsif (!$skip && $max_entries && $main_line =~ /<!--tla: \d+-->/)
         { $skip=1 if ++$entries > $max_entries;
         }
        elsif ($skip && $main_line =~ /<!--end-->/)
         { $skip=0;
         }
        print MAIN "$main_line" unless $skip;
      }
   }
  else
   { foreach $main_line (@main)
      { $work = 0;
        if ($main_line =~ /<!--insert: $last_message-->/)
         { print MAIN $main_line;
           print MAIN "<!--top: $num--><li><a href=\"$mesgdir/$num\.$ext\">$subject</a> " .
                      "- <b>$name</b> <i>$date</i>\n";
           print MAIN "(<!--responses: $num-->0)\n";
           print MAIN "<ul><!--insert: $num-->\n";
           print MAIN "</ul><!--end: $num-->\n";
         }
        elsif ($main_line =~ /\(<!--responses: (.*)-->(.*)\)/)
         { $response_num = $1;
           $num_responses = $2;
           $num_responses++;
           foreach $followup_num (@followup_num)
            { if ($followup_num == $response_num)
               { print MAIN "(<!--responses: $followup_num-->$num_responses)\n";
		 $work = 1;
               }
            }
           print MAIN $main_line if $work != 1;
         }
        else
         { print MAIN $main_line;
         }
      }
   }
  close(MAIN);
}

###############################################################################
# Add Followup Threading to Individual Pages
#
sub thread_pages
{ foreach $followup_num (@followup_num)
   { open(FOLLOWUP,"$basedir/$mesgdir/$followup_num\.$ext");
     @followup_lines = <FOLLOWUP>;
     close(FOLLOWUP);

     open(FOLLOWUP,">$basedir/$mesgdir/$followup_num\.$ext");
     foreach $followup_line (@followup_lines)
      { $work = 0;
        if ($followup_line =~ /<!--insert: $last_message-->/)
         { print FOLLOWUP $followup_line;
           print FOLLOWUP "<!--top: $num--><LI><A HREF=\"$num\.$ext\">$subject</A>\n" .
                          "<B>$name</B> <I>$date</I>\n";
           print FOLLOWUP "(<!--responses: $num-->0)\n";
           print FOLLOWUP "<UL><!--insert: $num-->\n";
           print FOLLOWUP "</UL><!--end: $num-->\n";
         }
        elsif ($followup_line =~ /\(<!--responses: (.*)-->(.*)\)/)
         { $response_num = $1;
           $num_responses = $2;
           $num_responses++;
           foreach $followup_num (@followup_num)
            { if ($followup_num == $response_num)
               { print FOLLOWUP "(<!--responses: $followup_num-->$num_responses)\n";
                 $work = 1;
               }
            }
           if ($work != 1)
            { print FOLLOWUP "$followup_line";
            }
         }
        else
         { print FOLLOWUP "$followup_line";
         }
      }
     close(FOLLOWUP);
   }
}

###############################################################################
# We'd created message on disk. Now pointing browser to it.
#
sub return_html
{ local($url)=$post_redir ? $mainpage."?".time : "$baseurl/$mesgdir/$num.$ext";
  print <<EOH
Location: $url

Please go <A HREF="$url">here</A>.
EOH
}

###############################################################################
# Incrementing message number and unlocking
#
sub increment_num
{ local($um)=umask(077);
  open(NUM,">$datafile") || die $!;
  print NUM "$num\n";
  close(NUM);
  umask($um);
  &unlock_number;
}

###############################################################################
# Error message heading
#
sub print_err_head
{ &print_html_head("Error: $_[0] ($title)","Error: $_[0]");
  print "<CENTER>\n" . $_[1] . "\n";
  print "Please correct error below and re-submit form.\n" unless $_[2];
  print "</CENTER>\n";
  &print_html_hr;
}

###############################################################################
# Error message
#
sub error {
   local($error) = $_[0];
   local($errtext) = $_[1];

   $printing_to_file=0;
   if ($error eq 'no_name')
    { &print_err_head("no Name field",
                      "You forgot to fill in the 'Name' field in your posting.");
      &rest_of_form(0);
    }
   elsif ($error eq 'no_subject')
    { &print_err_head("no Subject field",
                      "You forgot to fill in the 'Subject' field in your posting.");
      &rest_of_form(0);
    }
   elsif ($error eq 'no_body')
    { &print_err_head("no message body",
                      "Empty messages disallowed!");
      &rest_of_form(0);
    }
   elsif ($error eq 'no_email')
    { &print_err_head("no message body",
                      "Messages with no E-mail disallowed!");
      &rest_of_form(0);
    }
   elsif ($error eq 'banned')
    { &print_err_head("banned words used"
                     ,"You have used banned words in your message!");
      &rest_of_form(0);
    }
   elsif ($error eq 'bad_user')
    { &print_err_head("bad user name or password",
                      "You've supplied wrong user name and/or password.\n"
                     ."Please mail to <A HREF=\"mailto:$adm_email\">board administrator</A> if\n"
                     ."you forgot your password or <A HREF=\"$acc_form_url\">register</A> if you\n"
                     ."had no one.");
      &rest_of_form(0);
    }
   elsif ($error eq 'existing_user')
    { &print_err_head("existing user name",
                      "Sorry, user name you entered belongs to registered user. Change it please\n"
                     ."or provide the password!<BR>\n"
                     ."Please mail to <A HREF=\"mailto:$adm_email\">board administrator</A> if\n"
                     ."you forgot your password!\n",
                     1);
      &rest_of_form(0);
    }
   elsif ($error eq 'ip_denied')
    { &print_html_head("Error: Access denied","-");
      print <<EOH;
Access is denied for your IP address ($ENV{'REMOTE_ADDR'}).
Mail complaints to <A HREF=\"mailto:$adm_email\">board administrator</A>
if you're sure it was done by a mistake.
<P>
EOH
      &print_html_footer;
    }
   elsif ($error eq 'no_config')
    { &print_err_head("no configuration found",
                      "Hm.. System error or attempted hacking -- no configuration file found.",
                      1);
      &print_html_footer;
    }
   elsif ($error eq 'wrong_cf')
    { &print_err_head("wrong configuration",
                      "System error, configuration is wrong: $errtext");
      &rest_of_form(0);
    }
   else
    { &print_err_head("undefined error");
      &rest_of_form(0);
    }
   &unlock_number;
   exit(0);
}

###############################################################################
# The form itself. If some values are known they used as defaults.
#
sub rest_of_form
{ print "<FORM METHOD=POST ACTION=\"$cgi_url\">\n";
  print "<INPUT TYPE=HIDDEN NAME=config VALUE=$config>\n" if $config;
  if ($followup == 1)
   { $h_origsubject=&hf($origsubject);
     $h_origname=&hf($origname);
     $h_origemail=&hf($origemail);
     $h_followup="";
     foreach $_ (@followup_num)
      { $h_followup.="$_,";
      }
     chop($h_followup);
     print <<EOH;
<INPUT TYPE=HIDDEN NAME="origsubject" value="$h_origsubject">
<INPUT TYPE=HIDDEN NAME="origname" value="$h_origname">
<INPUT TYPE=HIDDEN NAME="origemail" value="$h_origemail">
<INPUT TYPE=HIDDEN NAME="origdate" value="$origdate">
<INPUT TYPE=HIDDEN NAME="followup" value="$h_followup">
EOH
   }
  $h_name=&hf($name);
  $h_passwd=&hf($passwd);
  $h_email=&hf($email);
  $h_subject=&hf($subject);
  $h_body=&to_html_text($body);
  $h_url=&hf($message_url);
  $h_url_text=&hf($message_url_title);
  $h_image=&hf($message_img);
  print <<EOH;
<CENTER><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>
<TR><TD>$t_name:&nbsp;</TD>
<TD ALIGN=RIGHT>&nbsp;<INPUT TYPE=TEXT NAME="name" VALUE="$h_name" SIZE=50><BR></TD>
</TR>
EOH
  print <<EOH if $acc_policy;
<TR><TD>$t_passwd:&nbsp;</TD>
<TD ALIGN=RIGHT>&nbsp;<INPUT TYPE=PASSWORD NAME="passwd" VALUE="$h_passwd" SIZE=50><BR></TD>
</TR>
EOH
  print <<EOH;
<TR><TD>$t_email:&nbsp;</TD>
<TD ALIGN=RIGHT>&nbsp;<INPUT TYPE=TEXT NAME="email" VALUE="$h_email" SIZE=50><BR></TD>
</TR>
<TR><TD>$t_subject:&nbsp;</TD>
EOH
  print "<TD ALIGN=RIGHT>&nbsp;";
  if($subject && $subject_line==1)
   { print "$h_subject";
     print "<INPUT TYPE=HIDDEN NAME=\"subject\" VALUE=\"$h_subject\">";
   } 
  else
   { print "<INPUT TYPE=TEXT NAME=\"subject\" VALUE=\"$h_subject\" SIZE=50>";
   }
  print <<EOH;
<BR></TD></TR>
<TR><TD COLSPAN=2 ALIGN=CENTER>
<TEXTAREA COLS=70 ROWS=10 NAME="body">$h_body
</TEXTAREA></BR></TD>
</TR>
EOH
  $_=($acc_url==1 && $acc_policy==1) ? "<SUP>*</SUP>" : "";
  print <<EOH if $acc_url==0 || $acc_url==1;
<TR><TD>$t_link_url:$_&nbsp;</TD>
<TD ALIGN=RIGHT>&nbsp;<INPUT TYPE=TEXT NAME="url" VALUE="$h_url" SIZE=50><BR></TD>
</TR>
<TR><TD>$t_link_text:$_&nbsp;</TD>
<TD ALIGN=RIGHT>&nbsp;<INPUT TYPE=TEXT NAME="url_title" VALUE="$h_url_text" SIZE=50><BR></TD>
</TR>
EOH
  $_=($acc_image==1 && $acc_policy==1) ? "<SUP>*</SUP>" : "";
  print <<EOH if $acc_image==0 || $acc_image==1;
<TR><TD>$t_image:$_&nbsp;</TD>
<TD ALIGN=RIGHT>&nbsp;<INPUT TYPE=TEXT NAME="img" VALUE="$h_image" SIZE=50><BR>
</TR>
EOH
  print <<EOH;
</TABLE>
<INPUT TYPE=SUBMIT VALUE="$t_post">&nbsp;&nbsp;&nbsp;<INPUT TYPE=RESET VALUE="$t_reset">
</CENTER>
</FORM>
EOH
  print <<EOH if ($acc_url==1 || $acc_image==1) && $acc_policy==1;
<TABLE WIDTH="66%" BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD COLSPAN=2><HR></TD></TR>
<TR><TD>&nbsp;&nbsp;</TD>
<TD><SUP>*</SUP>
<FONT SIZE=-1><I>$t_reg_note</I></FONT>
</TD></TR></TABLE>
EOH
  &print_html_footer unless $_[0];
}

###############################################################################
# Checking IP address -- legal or not. Prints error html and do not
# returns if not legal.
#
sub check_ip
{ local($ourip)=$_[0];
  if(open(F,$acc_ip_conf))
   { $ourip=&ip_to_bits($ourip);
     while(<F>)
      { chop if /\n$/;
        ($ip,$bl,$when,$status)=split(/:/);
        next unless $status='-';		# Only denials supported now
        &error("ip_denied") if substr($ourip,0,$bl) eq substr(&ip_to_bits($ip),0,$bl);
      }
     close(F);
   }
}

###############################################################################
# Formatting body text. Cited text and lines, that looks like
# pre-formatted leaved as is. Depends on $format_body variable.
#
sub format_text
{ return $_[0] if !$format_body;
  local(@lines)=split(/\n/,$_[0]);
  local($buf)="";
  local(@ft);
  local($_);
  foreach(@lines)
   { if(/^${cite_symbol}/ || /^\s/ || ($format_body==1 && /\s\s/) || /^\s*$/)
      { if($buf ne "")
         { push(@ft,"") if $ft[$#ft] ne "";
           push(@ft,&format_line($buf),"");
           $buf="";
         }
        push(@ft,$_) unless /^\s*$/;
      }
     else
      { $buf.=" " unless $buf eq "";
        $buf.=$_;
      }
   }
  if($buf ne "")
   { push(@ft,"") if $ft[$#ft] ne "";
     push(@ft,&format_line($buf));
   }
  shift @ft if $ft[0] eq "";
  pop @ft if $ft[$#ft] eq "";
  join("\n",@ft)."\n";
}

###############################################################################
# Formatting one long line to the given width ($format_width by default)
#
sub format_line
{ local($_)=$_[0];
  local($w)=$_[1] ? $_[1] : $format_width;
  s/\s+([.,!])([\s\w])/$1 $2/g;
  s/(\w)-\s/$1 - /g;
  s/^\s+//g;
  s/\s\s+/ /g;
  local(@words)=split;
  local(@lines);
  $line="";
  foreach(@words)
   { $_.=" ";
     if(length($_)+length($line)<=$w || (!length($line) && length($_)>$w))
      { $line.=$_;
      }
     else
      { chop($line);
        push(@lines,$line);
        $line=$_;
      }
   }
  chop($line);
  push(@lines,$line) if $line ne "";
  @lines;
}
