SourceForge.net Logo
March 3, 2009
© GPL
 
ProWikiCenter
Code /
Part3

 
sub GetHeaderCgi { #FIXME get rid of CGI, Set-Cookie: RFC2109
  my ($cookie,$result,@pars,@car);

  push(@pars,-head => "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$WikiCharset\">");
  push(@pars,-type => "text/html");
  push(@pars,-charset => $WikiCharset);
  push(@pars,-encoding => $WikiCharset);

  if(defined($PrefsCookie{cid})) {
    $cookie = "$CookieName=" . "rev&" . $PrefsCookie{rev} . "&cid&" . $PrefsCookie{cid} . "&randkey&" . $PrefsCookie{randkey};
    $cookie .= "; path=/";
    if(defined($PrefsCookie{expires})) {
      $cookie .= "; expires=" . $PrefsCookie{expires};
    }
    push(@car,$cookie);
  }
  if(defined($SessionCookie{session})) {
    $cookie = "$CookieSession=" . "rev&2" . "&username&" . $SessionCookie{username} . "&check&" . $SessionCookie{check};
    $cookie .= "; path=/;";
    push(@car,$cookie);
  }
  if($ExpirePage>0) {
    push(@pars,-expires => "+1");
  }
  if($HeaderNoCache>0 || $ExpirePage>0) {
    push(@pars,-Cache_control => 'no-cache');
    push(@pars,-pragma => 'no-cache');
  }
  if(int(@car)) {
    my $cx= [ @car ];
    push(@pars,-cookie => $cx);
  }
  $result=$cgi->header(@pars);
  return $result;
}

sub HashAddServerScriptSite {
  my ($h_hash,$script,$site)=@_;
  my ($dom,$c);

  $dom=UrlRetDomain($script);
  if(ServerHasDomain($dom)) {
    $c=chop($script);   # remove ? to make it compatible to $ScriptName
    if($c eq '?') {
      $$h_hash{$script} = $site;
    }
  }
}

sub GlobalSiteInit {
  my (%hash,$site,$script,$info,$unicode,$script2,%hslice,$dom,$c);

  if($GlobalSiteInitFlag) {
     return;
  }
  $GlobalSiteInitFlag=1;

  InterWebInit();

  HashSliceGetHash(\%Context,'interweb.',\%hslice);
  HashAddHash(\%hslice,\%InterWeb);

  %GlobalSite= ();
  while( ($site,$info) = each (%hslice) ) {
    ($script,$unicode,$script2)=InterWebSplit($info);
    HashAddServerScriptSite(\%hash,$script,$site);
    HashAddServerScriptSite(\%hash,$script2,$site);
  }
  while( ($script,$site) = each (%hash) ) {
    $GlobalSite{$site} = $script;
  }
}

sub WikiNetRetBar {
  my ($net)=@_;
  my ($ret,$key,$part,$script,$dec,$fnam);

  GlobalSiteInit();

  foreach $key (ListSplit($WikiCluster)) {
    if($key eq $WikiName) {
      $dec=$Context{'layout.net.wrap.sel'};
      $part=$key;
    } else {
      $script=$GlobalSite{$key};
      $fnam=PathRetFilename($ScriptFilename);
      $script=~ s#(\/)wiki\.cgi#$1$fnam#;
      $dec=$Context{'layout.net.wrap'};
      $part=ScriptActionLabelClassIdTargetTitleRetLink($script,'action=HomePage',$key,'net');
    }
    if($dec ne '') {
      $part=StrDecorate($part,$dec);
    } else {
      $part=StrDecorate($part,$n1.'@'.$n1);
    }
    $ret.=$part;
  }
  return $ret;
}

sub WikiRetPageBar {
  my ($pages,$id)=@_;
  my ($ret,$key,$part,$s,$dec);

  GlobalSiteInit();

  foreach $key(split(/ +/,$pages)) {
    if($key eq $id) {
      $dec=$Context{'layout.page.wrap.sel'};
      $part=$key;
    } else {
      $dec=$Context{'layout.page.wrap'};
      $part=ActionLabelClassIdTargetTitleRetLink($key,$key,'page',$key);
    }
    if($dec ne '') {
      $part=StrDecorate($part,$dec);
    } else {
      $part=StrDecorate($part,$n1.'@'.$n1);
    }
    $ret.=$part;
  }
  return $ret;
}

sub StrWrapRetStr {
  my ($s,$wrap)=@_;
  if($wrap ne '') {
    return StrDecorate($s,$wrap);
  }
  return $s;
}

sub WordRetActionLabel {
  my ($word,$wrap)=@_;
  my ($html,$act);
  my $label=ContextVarRetDefault("link.$word.label",$word);
  my $action=ContextVarRetDefault("link.$word.action",$word);

  if($action =~ /^\(/) {
    if($action eq '(edit)') {
      $action='';
      if($PageCurEditFlag) {
        $action= IdRetEditAction($PageCur);
      }
    } elsif($action eq '(diff)') {
      $action='';
      if($PageCurEditFlag) {
        $action= "action=browse&diff=4&id=$PageCur";
      }
    } elsif($action eq '(delete)') {
      $action='';
      if($PageCurEditFlag && $PageIsSmallFlag) {
        $action= "action=delete&id=$PageCur";
      }
    } elsif($action eq '(archiv)' || $action eq '(archive)') {
      $action='';
      if(($PageCurEditFlag) && ($TrustedFlag>0) && ($FlagArchive>0)) {
        $action= "action=archive&cmd=list&id=$PageCur";
      }
    } elsif($action eq '(editprefs)') {
      my $h=($PageCur ne '') ? "&oldid=$PageCur&id=$PageCur" : '';
      $action= "action=editprefs".$h;
    }
  }
  return ($action,$label);
}

sub LinkbarStrRetHtml {
  my ($var,$s)=@_;
  my @parts=split(/\s/,$s);
  my ($ret,$part,$html,$wrap,$action,$label,$class);
  $wrap=$Context{"$var.wrap"};
  $class=ContextVarRetDefault("$var.class",'nav');
  foreach $part (@parts) {
    ($action,$label)=WordRetActionLabel($part);
    if($action ne '') {
      $html=ActionLabelClassIdTargetTitleRetLink($action,$label,$class);
      $html=StrWrapRetStr($html,$wrap);
      $ret .= $html;
    }
  }
  return $ret;
}

$InsertHash{AdditionalFunctions}=\&InsertAdditionalFunctions;

sub InsertAdditionalFunctions {
  my ($id,$timestamp)=@_;
  my $ret=IdTimestampRetAddFunc($id,$timestamp);
  return $ret;
}

$InsertHash{Crumbs}=\&InsertCrumbs;

sub CrumbsInit {
  my ($fnam,%dup);
  my ($ts,$version,$ip,$dgt,$user,$action,$id,$url);
  my $limit=First($CrumbsShowLimit,5);
  my $flimit=First($CrumbsLogFileSizeLimit,7800);

  if($CrumbsInitFlag) {
    return;
  }
  $CrumbsInitFlag=1;

  @CrumbsLines=();
  @CrumbsPages=();
  if($CookieID<400) {
    return;
  }
  $fnam=UserPrefsFilename($CookieID,'.dc');
  @CrumbsLines=reverse FileRetArray($fnam);

  if(FileRetSize($fnam)>$flimit) {
    if($#CrumbsLines>16) {
      my @ar=reverse @CrumbsLines[0..$#CrumbsLines/2];
      FileSetStr($fnam,join("\n",@ar)."\n");
    }
  }

  if($PageCur) {
    $id=$PageCur;
    push(@CrumbsPages,$id);
    $dup{$id}++;
    $CrumbsUrl{$id}=$url;
  }
  foreach (@CrumbsLines) {
    ($ts,$version,$ip,$dgt,$user,$action,$id,$url)=split(/\s+/,$_);
    if($action eq 'browse') {
      $dup{$id}++;
      if($dup{$id} == 1) {
        if(int(@CrumbsPages)<$limit) {
          push(@CrumbsPages,$id);
          $CrumbsUrl{$id}=$url;
        }
      }
    }
  }
  @CrumbsPages=reverse @CrumbsPages;
}

sub InsertCrumbs {
  my ($id,$timestamp)=@_;
  my ($ret,$link);
  my $sep=' » ';

  CrumbsInit();
  foreach (@CrumbsPages) {
    $link=UrlLabelClassTitleTargetRetLink($CrumbsUrl{$_},$_);
    $ret.=$sep.$link;
  }
  if($ret eq '') {
    $ret=$sep;
  }
  return $ret;
}

$InsertHash{Login}=\&InsertLogin;
sub InsertLogin {
  my ($id,$timestamp)=@_;
  my ($ret,$loginout,$userpen,$prefslink,$datalink);

  $ret=Icon("icon_user.gif").$n1;
  if($UserName ne '') {
    $datalink.=ActionLabelClassIdTargetTitleRetLink("action=userdata".OptLang().OptId(),$UserName,'nav','','user data') . " \n";
    $ret.=$datalink.$n1;
  }
  if($UserName eq '') {
    $ret.=ActionLabelClassIdTargetTitleRetLink("action=login".OptLang().OptId(),LiLogin(),'nav','','login');
  } else {
    $ret.=ActionLabelClassIdTargetTitleRetLink("action=logout".OptLang().OptId(),LiLogout(),'nav','','logout');
  }

  if($RcUseLoginName) {
    $userpen=$UserName;
  }
  if($userpen eq '') {
    $userpen=$UserPref;
  }
  if($userpen eq '') {
    $userpen=$ClientIP;
  }
  $prefslink=PageLabelClassRetPrefsLink($id,$userpen,'nav');
  $ret.=$n2."(".Icon("icon_pen.gif").$prefslink.$n1.")";

  return $ret;
}

sub TemplateFunction {
  my ($cmd,$id,$timestamp)=@_;
  my ($raw,$f_proc);

  $f_proc=$InsertHash{$cmd};
  if($f_proc) {
    $raw = &$f_proc($id,$timestamp);
  } else {
    $raw = $cmd;
  }
  return $raw;
}

sub TemplateInsertCallee {
  my ($s,$id,$timestamp)=@_;
  my ($var,$object,$member,@par)=split(/;/,$s);
  my ($ret);

  if($var =~ m/page\.(.*)/) {
    my $ml=$MultiLinking; $MultiLinking=0;
    my $se=$SectionEditing; $SectionEditing=0;
    $ret=PageRetHtml($1,1);
    $MultiLinking=$ml;
    $SectionEditing=$se;
    return $ret;
  } elsif($var =~ m/program\.(.*)/) {
    my $cmd=$1;
    unshift(@par,$member,$object);
    my $text=PageRetTextFast($id);
    my $folders=WikiTextRetFolderTabStr($text);
    if(StrEquList("stdin=vida",@par)) {
       VidaInitPage($id);
       my $stdin=VidaRetText_SepEol(\@Vida,"=","\n");
       return CmdStdinRetText($cmd." -oHTML -p$id -f $folders",$stdin);
    }
    return CmdRetText("$cmd -oHTML -p$id -f $folders");
  } elsif($var =~ m/vida\.(.*)/) {
    return PageVarRetValDefault($PageCur,$1,$n1);
  } elsif($var =~ m/function\.(.*)/) {
    return TemplateFunction($1,$id,$timestamp);
  } elsif($var =~ m/wiki\.(.*)/) {
    return TextWikiRetHtml($1,1);
  }

  $ret=$Context{$var};
  if($member ne '') {
    if(UserHasStatus('Member')) {
      $var=$member;
    }
  }
  if($ret eq '') {
    $ret=$$var;
  }
  if($ret eq '') {
    $ret=$object;
  }
  if($var =~ /^linkbar/) {
    $ret=LinkbarStrRetHtml($var,$ret);
  } elsif ($var eq 'DateCreation') {
    $ret=TimeRetStr($^T);
  }
  return $ret;
}

sub ContextAddStr {
  my ($s)=@_;
  StrSplitContextVarSetVal($s);
}

sub SourceRetStr {
  my ($snam)=@_;
  my $ret;
  if($snam =~ m#\.#) {
    $ret=FileRetStr($snam,1);
  } else {
    $ret=PageRetTextFast($snam);
  }
  return $ret;
}

sub TemplateRetStr {
  my ($template0)=@_;
  my ($ret);
  my $template=RetParam('template','');

  if($template eq '') {
    $template=$template0;
  }
  if($template eq '') {
    $template=$TemplateFile;
  }
  if(length($template)==1) {
    if($template eq 'p') {
      $ShowHiddenLinks=1;
      $template=$TemplatePrint;
    } elsif($template eq 'b') {   
      $template=$TemplateBody;
    } elsif($template eq 'e') {
      $template=$TemplateEdit;
    } elsif($template eq 'f') {
      $template=$TemplateFile;
    } elsif($template eq 'd') {
      $template=$TemplateDefault;
    } elsif($template eq 'x') {
      $template=$TemplateError;
    }
  }
  if (length($template)<4) {    #Andrius 2009.02.22 and before
    if($template eq 'sv') {
      $template=$TemplateSimpleView;
    } elsif($template eq 'st') {
      $template=$TemplateSimpleTest;
    } elsif($template eq 'sd') {
      $template=$TemplateSimpleDownload;
    } elsif($template eq 'wb') {
      $template=$TemplateWorknetsBody;
    } elsif($template eq 'wc') {
      $template=$TemplateWorknetsComments;
    } elsif($template eq 'wfo') {
      $template=$TemplateWorknetsFormEdit;
    } elsif($template eq 'we') {
      $template=$TemplateWorknetsFreeEdit;
    } elsif($template eq 'wf') {
      $template=$TemplateWorknetsFull;
    } elsif($template eq 'wh') {
      $template=$TemplateWorknetsHead;
    } elsif($template eq 'wm') {
      $template=$TemplateWorknetsMenu;
    } 
  }
  $ret=SourceRetStr($template);
  if( !($ret=~ m/<html/i ) ) {
    $ErrorStr="<b>Template Error: template=$template</b>";
    $ret=FileRetStr($TemplateDefault);
  }
  return $ret;
}

sub HtmlRetLinks {
  my ($s,$sep,$deldup)=@_;
  my $ret;
  my (@ar,%hash);

  $s =~ s#(<a .*?</a>)#push(@ar,$1)#gse;
  foreach (@ar) {
    if($_ =~ m/href=["'][^#]/) {
      $hash{$_}++;
      if($hash{$_}<2) {
        $ret.=$_.$sep;
      }
    }
  }
  return $ret;
}

sub TemplateIdTitleHeaderTextLinkSearchRetPage {
  my ($template_def,$id,$title,$header,$text,$lflag,$sflag,$timestamp)=@_;
  my ($logo_dec,$link_bar,$edit_bar,$search_form,$buttons,$script);
  my ($script_flag,$ts,$afunc);
  my (@passes);

  my $pgflag=($id ne '');
  $PageCurEditFlag=$pgflag;

  my $ret = GetHeaderCgi();    # $ret  = "Content-type: text/html\n\n";
  $ret .= TemplateRetStr($template_def);

  $ret =~ s/{Context:([^}]*)}/&ContextAddStr($1)/ge;

  @passes=ListSplit($TemplateInsertPassList);
  foreach (@passes) {
    $ret =~ s/{$_:([^}]*)}/&TemplateInsertCallee($1,$id,$timestamp)/ge;
  }

  if($WikiCopyright eq '') {
    $WikiCopyright=" © $SiteName Community";
  }
  $ret =~ s/(<head>)/$1$MetaTagAdd/i;
  $ret =~ s/{WikiCopyright}/$WikiCopyright/g;
  $ret =~ s/{WikiName}/$SiteName/g;
  $ret =~ s/{BodyTags}/$BodyTags/;
  $ret =~ s/{ScriptName}/$ScriptName/g;
  $ret =~ s/{HomePage}/LuFirst($HomePage,$FrontPage)/ge;

  if($timestamp eq '' || $timestamp eq $TsCreatePage) {
    $ts=Lu(' (not applicable)| (keine Angabe)| (non applicable)| (no aplicable)');
  } else {
    $ts=TimeRetDay($timestamp);
  }
  $ret =~ s/{DateLastChange}/$ts/g;

  if($ret =~ m/{DateCur}/) {
    $ts=TimeRetDay($^T);
    $ret =~ s/{DateCur}/$ts/g;
  }

  $ret =~ s/{LogoFile}/$LogoUrl/g;
  $logo_dec = PageRetLogoDec($id);
  $ret =~ s/{LogoDec}/$logo_dec/g;

  if($ScriptCode ne '') {
    $ret =~ s#</head>#</head>\n<script type="text/javascript">\n$ScriptCode</script>\n#i;
  }

  if($lflag) {
    if($ret =~ m/{LinkBarTextHor}/) {
      $link_bar = IdRetLinkBarHor($id,$pgflag);
      $ret =~ s/{LinkBarTextHor}/$link_bar/g;
    }
    if($ret =~ m/{LinkBarTextVer}/) {
      $link_bar = IdRetLinkBarVer($id,$pgflag);
      $ret =~ s/{LinkBarTextVer}/$link_bar/g;
    }
  } else {
    $ret =~ s/{LinkBarTextHor}//g;
    $ret =~ s/{LinkBarTextVer}//g;
  }

  if($pgflag) {
    $edit_bar=IdTimestampRetEditBar($id,$timestamp);
  }
  $afunc=IdTimestampRetAddFunc($id,$timestamp);
  if($afunc ne '') {
    if($edit_bar ne '') {
      $edit_bar.=$br;
    }
    $edit_bar.=$afunc;
  }
  if($edit_bar eq '') {
    $edit_bar=HtmlLuft(1,1);
  }
  $ret =~ s/{EditBar}/$edit_bar/g;

  if($sflag) {
    $search_form = WikiRetFormSearchMini();
    $ret =~ s/{SearchForm}/$search_form/g;
  } else {
    $ret =~ s/{SearchForm}//g;
  }

  $ret =~ s/{PageName}/$title/g;

  $ret =~ s/{PageTitle}/$header/g;
  $ret =~ s/{PageTitleComment}/$PageTitleComment/g;
  $ret =~ s/{(WikiCluster|WikiNet)}/&WikiNetRetBar($WikiCluster)/ge;
  $ret =~ s/{PageBar}/&WikiRetPageBar($PageBar,$id)/ge;

  if($FlagMenuFrame) {
    my $section=RetParam('section');
    if($section eq '') {
      $text=HtmlRetLinks($text,$br,1);
      my $act2=$WikiParams;
      $act2 =~ s/&?target=[^&]*//;
      $act2 =~ s/&?template=[^&]*//;
      $BodyTarget='';
      $text.=$br.ScriptActionLabelClassIdTargetTitleRetLink($ScriptName,$act2,LiContinue(),'body','','_parent').$br;
    }
  }
  $ret =~ s/{PageText}/$text/;
  return $ret;
}

sub TemplateShowTitleHeaderTextPlus {
  my ($template,$title,$header,$text,$lflag,$sflag,$timestamp)=@_;
  my $ret=TemplateIdTitleHeaderTextLinkSearchRetPage($template,"",$title,$header,$text,$lflag,$sflag,$timestamp);
  PrintAnswer($ret);
}

sub TemplateShowTitleTextPlus {
  my ($template,$title,$text,$lflag,$sflag,$timestamp)=@_;
  return TemplateShowTitleHeaderTextPlus($template,$title,$title,$text,$lflag,$sflag,$timestamp);
}

sub ShowTitleTextLinkSearch {
  my ($title,$text,$lflag,$sflag,$timestamp)=@_;
  return TemplateShowTitleTextPlus($TemplateFile,$title,$text,$lflag,$sflag,$timestamp);
}

sub ShowTitleText {
  my ($title, $text)=@_;
  ShowTitleTextLinkSearch($title,$text,1,0);
}

sub StatusRetLanguageWeight {
  my ($need)=@_;
  my $ind=StatusRetWeight($need); # optimize?
  my $lang=Lu('en|de|fr|es');
  my ($info,$status);

  foreach $status (keys %StatusInfo) {
    $info=$StatusInfo{$status};
    if(int($info)==$ind) {
      if($info =~ m/$lang/) {
        return ($status,$ind);
      }
    }
  }
  return (Lu('Unknown|Unbekannt|Inconnu|Desconocido'),0);
}

sub ShowStatusMessLogin {
  my ($need_lg,$need_wt)=@_;
  my $text;

  if($need_wt>0) {
    $lb1=Lu("This feature needs special rights of a %USERSTATUS%.|Diese Funktion erfordert eine Berechtigung als %USERSTATUS%.|Cette fonctionnalité exige des droits spéciaux d'un %USERSTATUS%.|Esta función exige el derecho especial de un %USERSTATUS%.");
    MessRepVar($lb1,"%USERSTATUS%","\"$need_lg\"");
  } else {
    $lb1=Lu("This feature needs special rights.|Diese Funktion erfordert eine Berechtigung.|Cette fonctionnalité exige des droits spéciaux.|Esta función exige el derecho especial.");
  }
  $lb2=Lu("Please do your login first.|Bitte zuerst anmelden.|Merci d'insérer d'abord votre identifiant.|Por favor entrar primeramente.");

  $text = "$br<b>$lb1 $lb2</b>$br$br";
#  StrLatinCvtUnicode($text);

  $text.=WikiRetFormLogin();

  ShowTitleTextLinkSearch(Lu("Please login|Bitte anmelden|Merci d'entrer votre login|Entrar por favor"),$text,1,1);
}

sub FormStartBasic {
  return $cgi->startform("post",$ScriptName,"multipart/form-data");
}

sub FormStart {
  my ($name,$id)=@_;
  my $ret=FormStartBasic() . FormNameValueHidden($name,1) . FormNameValueHidden('action',$name) . "\n";
  $ret.=FormNameValueHidden("lang",$WikiLanguage).FormNameValueHidden("formpage",$PageCur);
  if($id eq '') {
    $id=$PageCur;
  }
  if($id eq '') {
    $id=RetPageReference();
  }
  if($PagenameReduction) {
    my $dombase=ScriptRetDomainBase();
    if($dombase ne '') {
      $id=~s#^$dombase/##;
    }
  }
  $ret.=FormNameValueHidden("id",$id);
  $ret.="\n";
  return $ret;
}

sub FormStartUrl {
  my ($url)=@_;
  return $cgi->startform("GET",$url) . "\n";
}

sub FormEnd {
  return $cgi->endform;
}

sub WikiRetFormPrefs {
  my ($oldpar,$type)=@_;
  my ($check, %labels);
  my $oldid=RetParam('oldid','');
  my $id=RetParam('id','');
  my $ret;

  if($CookieID < 400) {
    DoNewCookieLogin()
  }

  if($oldid eq '') {
    $oldid=$oldpar;
  }

  %labels=(
    1=> Lu('edit|Änderung|édition|edición'),
    2=> Lu('correction|Korrektur|correction|corrección'),
    3=> LiAuthor()
  );

  my $daz= $cgi->popup_menu(-name=>'p_defaultdiff', -values=>[1,2,3], -labels=>\%labels,-default=>RetParam("defaultdiff", 1));

  $ret .= FormStart("form_editprefs",$id);
  $ret .= FormNameValueHidden("old_plist",WikiRetParamAllStr($PageReferenced)) . "\n";
  $ret .= FormTableStart();
  if($oldid ne '') {
    $ret .= FormNameValueHidden("oldid",$oldid);
  }
  $ret .= FormNameValueHidden("type",$type);

  $ret .= HeaderColSpan( LiUser(),$FormTitlebackground,2);

  $lb1=LuNbsp('username:|Benutzername:|nom utilisateur :|nombre de usuario:');
  $lb2=LiUsernameExample();
  $ret .= Line($lb1, FormTextParam('username','',25) . $lb2) ;

 if($type ne -1) {  # Andrius 2008.12.13  added this to keep it out when adding username
  my $stim=TimeRetText($^T-$TimeZoneOffset+3600*$TimeSummer);
  $lb1=LuNbsp('timezone offset:|Unterschied der Zeitzonen:|fuseau horaire :|diferencia de la huso horario:');
  $lb2=Lu("hours (current server-time: %SERVERTIME%)|Stunden (aktuelle Server-Zeit: %SERVERTIME%)|heures (temps du serveur : %SERVERTIME%)|horas (tiempo del server: %SERVERTIME%)");
  MessRepVar($lb2,"%SERVERTIME%",$stim);
  $ret .= Line($lb1,FormTextParam('tzoffset',$Def_tzoffset,3)." $lb2");
 }   # Andrius 2008.12.13

  if($type ne 0 && $type ne -1) { # keep in sync     # Andrius 2008.12.13  added -1 switch, was  if($type) {
    $ret .= HeaderColSpan( Lu('Text edit window|Texteingabefenster|Fenêtre édition de texte|Ventana para editar el texto'),$FormTitlebackground,2);

    $lb1=LuNbsp('rows:|Zeilen:|lignes :|líneas:');
    $ret .= Line($lb1, FormTextParam('editrows',$Def_editrows,4));

    $lb1=LuNbsp('columns:|Spalten:|colonnes :|columnas:');
    $ret .= Line($lb1, FormTextParam('editcols', $Def_editcols, 4));

    $lb1=LuNbsp('maximum window width:|volle Fensterbreite:|taille max de largeur de fenêtre :|anchura máxima de la ventana:');
    $lb2=Lu('only some browsers support this option|nur manche Browser unterstützen diese Option|seuls quelques navigateurs supportent cette option|sólo algunos programas apoyan a esta opción');
    $ret .= Line($lb1, FormCheckParam('editwide',1,"($lb2)") );

    if($ShowEditHelp) {
      $lb1=LuNbsp('help text:|Hilfetext:|texte aide :|texto de ayuda:');
      $lb2=Lu('display|anzeigen|affiche|desplegar');
      $ret .= Line($lb1,FormCheckParam('edithelp',1,$lb2));
    }

    my $nrc=RetNameRecentChanges();
    $ret .= HeaderColSpan($nrc,$FormTitlebackground,2);

    $lb1=LuNbsp('contains:|zeigt:|contient :|contienen:');
    $lb2=Lu('days|Tage|jours|días');
    $ret .= Line("$nrc $lb1", FormTextParam('rcdays', $RcDefault, 2) . " $lb2");

    $lb1=LuNbsp('new contributions:|neue Beiträge:|nouvelles contributions :|nuevas contribuciones:');
    $lb2=Lu('show on top|oben anzeigen|affichées au sommet|desplegar encima');
    $ret .= Line($lb1, FormCheckParam('rcnewtop', $RcTop,$lb2));

    $lb1=LuNbsp('show difference:|Differenzanzeige:|afficher la différence :|desplegar la diferencia:');
    $lb2=Lu('(diff)-link on page|(diff)-Links auf der Seite|(diff)-lien sur la page|(diff)-enlace en la página') . " \"$nrc\"";
    $ret .= Line($lb1,FormCheckParam('diffrclink',1,$lb2));

    $lb1=LuNbsp('preselected (diff)-type:|voreingestellte Differenzart:|pre-sélection (diff)-type :|preselecto (diff)-tipo:');
    $ret .= Line($lb1,$daz);
  }

 if($type ne -1) {  # Andrius 2008.12.13  added to simplify adding the Username
  $ret .= HeaderColSpan('Cookie',$FormTitlebackground,2);
  $ret .= Line(Lu('cookie ID:|Cookie ID:|cookie ID :|Cookie ID :'),$CookieID);
  $lb2=Lu('delete data at the end of the browser session|Daten am Ende der Browser-Session löschen|efface les données à la fin de la session du navigateur|tachar los datos al cerrar el navigador');
  $ret .= Line($n1,FormCheckParam('expirecookie',0,$lb2));
  $lb2=Lu('pages expire quickly (use with some proxy servers)|Kurze Seitenverfallszeit einstellen (mit manchen Proxy-Servern verwenden)||Páginas expiran rápidamente (usar con algunos Proxy Servers)');
  $ret .= Line($n1,FormCheckParam('expirepage',0,$lb2));
 }   # Andrius 2008.12.13   


  $lb2=Lu("save preferences|Einstellungen speichern|sauvegarder préférences|guardar preferencias");
  $ret .= Line($n1, FormButton('save',$lb2));
  $ret .= FormTableEnd();

  $ret .= FormEnd();

  my $links;
  if($PrefsShowFunctions && $type) {
    $links .= ActionLabelClassIdTargetTitleRetLink("action=login&continue=action=editprefs".OptLang().OptId(),LiLogin(),"body",'','login') . " \n";

    $lb1=Lu('upload directory|Uploadverzeichnis|répertoire uploader|directorio de ficheros subidos');
    $links .= ActionLabelClassIdTargetTitleRetLink("action=upload".OptLang().OptId(),$lb1,"body",'','upload directory') . " \n";

    if(UserHasStatus('Autor')) {
      $lb1=Lu('dictionary|Wörterbuch|dictionnaire|diccionario');
      $links .= ActionLabelClassIdTargetTitleRetLink("action=dict".OptLang().OptId(),$lb1,"body") . " \n";
    }

    if(UserHasStatus($NeedStatusAdmin)) {
      $lb1=Lu("user administration|Benutzerverwaltung|administration de l'utilisateur|administración de los usuarios");
      $links .= ActionLabelClassIdTargetTitleRetLink("action=admin".OptLang().OptId(),$lb1,"body",'','user administration') . " \n";

      $lb1=Lu("statistics|Statistik|statistiques|estadística");
      $links .= ActionLabelClassIdTargetTitleRetLink("action=stat&detail=1".OptLang().OptId(),$lb1,"body",'','statistics') . " \n";

      $lb1=Lu("sessions|Sessions|sessions|sesión");
      $links .= ActionLabelClassIdTargetTitleRetLink("action=log&sum=1&names=1".OptLang().OptId(),$lb1,"body",'','sessions') . " \n";
    }
    if(UserHasStatus("Login")) {
      $lb1=Lu("user data|Benutzerdaten|user data|user data");
      $links .= ActionLabelClassIdTargetTitleRetLink("action=userdata".OptLang().OptId(),$lb1,"body",'','user data') . " \n";

      $links .= ActionLabelClassIdTargetTitleRetLink("action=logout".OptLang().OptId(),LiLogout(),"body",'','logout') . " \n";
    }
  }
  if($links) {
    $ret .= "<hr>";
    $lb1=LiAdditionalFunctions().LiColon();
    $ret .= "<b>$lb1</b> $links$br";
  }
  return $ret;
}

sub ShowStatusMessUserName {
  my ($oldpar)=@_;
  my $text=$br;
  my ($what);


  if($WikiLanguage==2) {
    $text .= "<b>Cette fonctionnalité nécessite un nom utilisateur valide. ";
    $text .= "Merci de saisir votre nom.</b>$br";
  } elsif($WikiLanguage==3) {
    $text .= "<b>Esta función exige un nombre de usuario válido. ";
    $text .= "Entra primeramente su nombre.</b>$br";
  } elsif($WikiLanguage==1) {
    $text .= "<b>Diese Funktion erfordert einen gültigen Benutzernamen. ";
    $text .= "Bitte zuerst Namen eingeben.</b>$br";
  } else {
    $text .= "<b>Please enter your full name. ";
    $text .= "Then you can edit our wiki pages!</b>$br";
  }
  $text.=$br;

  StrLatinCvtUnicode($text);

  $text.=WikiRetFormPrefs($oldpar,-1);  # Andrius 2008.12.13  simplifying Username form, was:   $text.=WikiRetFormPrefs($oldpar,0);
  ShowTitleTextLinkSearch(Lu("Username needed|Bitte Benutzername eingeben|Nom utilisateur exigé|Nombre de usuario necesario"),$text,1,1);
}

sub ShowStatusMess {
  my ($need)=@_;
  my ($need_lg,$need_wt)=StatusRetLanguageWeight($need);

  if($need_wt==200) {
    ShowStatusMessUserName(WikiRetParamAllStr());
  } else {
    ShowStatusMessLogin($need_lg,$need_wt);
  }
  exit;
}

sub CheckStatusMess {
  my ($need)=@_;
  if(UserHasStatus($need)) {
     return;
  }
  ShowStatusMess($need);
}

sub CheckStatusUpload {
  if($CommonUploadDir eq 'y') {
    CheckStatusMess($NeedStatusUpload);
  } else {
    CheckStatusMess('Login');
  }
}

sub PageNameRetWords {
  my ($name,$keepslash)=@_;
  $name =~ s/($LowerLetter)($UpperLetter)/$1__$2/g;
  if($keepslash>0) {
    $name =~ s#\/#__\/#g;
  } else {
    $name =~ s#\/#__#g;
  }
  return split(/_+/,$name);
}

sub PageNameRetWordsAndNuples {
  my ($name)=@_;
  my (@words,$n,$i);

  @words=PageNameRetWords($name,0);
  $n=@words;
  for($i=1; $i<$n; $i++) {
    push(@words,$words[$i-1].$words[$i]);
  }
  return @words;
}

sub ContextVarAllowsUserWeightRecur {
  my ($var,$uname,$uweight,$h_rhash)=@_;
  my ($val,@list,$item,$weight);
  my $allow; # 0=no 1=noinfo 2=allow
  my $ret=0;
  my ($need,$hneed);

  $val=ContextVarRetDefault($var,'');
  if($val eq '') {
    $ret=1; goto do_ret;
  }
  @list=ListSplit($val);
  foreach $item (@list) {
    if($item eq $uname) {
      $ret=2; goto do_ret;
    }
    $weight=StatusRetWeight($item);
    if($weight) {
      $need=$item;
      if($uweight>=$weight) {
        $ret=2; goto do_ret;
      }
    }
    if($item =~ m#^group\.(.*)$#) {
      if( ++$$h_rhash{$1} < 2 ) {
        ($allow,$hneed)=ContextVarAllowsUserWeightRecur("group.$1",$uname,$uweight,$h_rhash);
        if($allow==2) {
          $ret=2; goto do_ret;
        }
      }
    }
  }
do_ret:
  return ($ret,$need);
}

sub ContextVarAllowsUserWeight {
  my %rhash;
  return ContextVarAllowsUserWeightRecur(@_,\%rhash);
}

sub CheckStatusActionPage {
  my ($need,$action,$id)=@_;
  my ($wneed,@words,$word,$allow,$aneed,$leaf,$var);
  my $uname=$UserName;
  my $uweight=StatusRetWeight($UserStatus);

  if($need ne 'Supervisor') {
    $var="status.for.$action.page.$id";
    ($allow,$aneed)=ContextVarAllowsUserWeight($var,$uname,$uweight);
    if($allow==2) {
      goto do_allow;
    }
    if($allow==0) {
      $need=$aneed;
      goto do_mess;
    }

    $leaf=PageRetLeaf($id);
    $var="status.for.$action.leaf.$leaf";
    ($allow,$aneed)=ContextVarAllowsUserWeight($var,$uname,$uweight);
    if($allow==2) {
      goto do_allow;
    }
    if($allow==0) {
      $need=$aneed;
      goto do_mess;
    }

    @words=PageNameRetWordsAndNuples($id);
    foreach $word (@words) {
      $var="status.for.$action.word.$word";
      ($allow,$aneed)=ContextVarAllowsUserWeight($var,$uname,$uweight);
      if($allow==2) {
        goto do_allow;
      }
      if($allow==0) {
        $need=$aneed;
        goto do_mess;
      }
    }

    $var="status.for.$action";
    ($allow,$aneed)=ContextVarAllowsUserWeight($var,$uname,$uweight);
    if($allow==2) {
      goto do_allow;
    }
    if($allow==0) {
      $need=$aneed;
      goto do_mess;
    }
  }

  # noinfo passthrough
  if(UserHasStatus($need)) {
    $var="UserHasStatus($need)";
    goto do_allow;
  }

do_mess:
  ShowStatusMess($need);
  return;

do_allow:

if($action eq 'edit') {
MsgPrint("CSAP $^T $UserIP action=$action id=$id uname=$uname uweight=$uweight allow-because-var=$var");
}
  return;
}

sub CheckStatusAction {
  my ($need,$action)=@_;
  CheckStatusActionPage($need,$action,'');
}

sub CheckRightMess {
  my ($right)=@_;
  if(UserHasRight($right)) {
     return;
  }
  ShowStatusMess($right);
}

sub WikiRetPageTextDefault {
  return Lu('Describe the new page here.|Beschreibe hier die neue Seite.|Décrivez ici la nouvelle page.|Describe la nueva página aquí.');
}

sub PageHashCreate {
  my ($id)=@_;
  my (%page);

  $page{text} = WikiRetPageTextDefault();
  $page{timestamp} = $TsCreatePage; # Must be fixed for edit conflicts
  $page{revision} = 0;
  $page{majorcopy} = "";
  $page{authorcopy} = "";
  $page{minordiff} = "";
  $page{majordiff} = "1";
  $page{authordiff} = "1";
  $page{dbrev} = 3;
  return %page;
}

sub DataDirPageRetHash {
  my ($datadir,$id)=@_;
  my ($text,$data,%page,$IN);

  my $pnam = PageRetDirectory($id) . "/$id";
  my $bnam = $datadir . "/page/" . $pnam;
  my $fnam = "$bnam.db";
  my $wnam = "$bnam.dw";
  if(-f $fnam) {
    open($IN,"<$fnam") or die "Can't read page $fnam: $!";
      $data=<$IN>;
    close($IN);
    %page=split(/$FS3/,$data,-1);  # -1 keeps trailing null fields

    if(open($IN,"<$wnam")) {
      $text=<$IN>;
      $page{text}=$text;
      close($IN);
    }
  } else {
    %page=PageHashCreate($id);
  }
  return %page;
}

sub DataDirPageRetText {
  my ($datadir,$id)=@_;
  my %pg=DataDirPageRetHash($datadir,$id);
  my $text=$pg{text};
  return $text;
}

sub DataDirPageRetBnam {
  my ($datadir,$id)=@_;
  return $datadir."/page/".PageRetDirectory($id)."/$id";
}

sub PageRetBnam {
  my ($id)=@_;
  return DataDirPageRetBnam($DataDir,$id);
}

sub PageRetFile {
  return PageRetBnam($_[0]) . ".dw";
}

sub PageRetTime {
  return FileRetTime(PageRetFile($_[0]));
}

sub PageRetSize {
  return FileRetSize(PageRetFile($_[0]));
}

sub PageRetWordCountCharCount {
  my ($id)=@_;
  my ($words,$chars);
  my $text=PageRetTextFast($id);
  $text=TextReduceWords($text);
  $text =~ s/([A-Za-z\x80-\xff]+)/$words++;$chars+=length($1);/ge;
  return ($words,$chars);
}

sub PageRetWordCount {
  my @ar=PageRetWordCountCharCount($_[0]);
  return $ar[0];
}

sub PageRetCharCount {
  my @ar=PageRetWordCountCharCount($_[0]);
  return $ar[1];
}

sub DataDirPageRetTextFast {
  my ($datadir,$id)=@_;
  my ($text,$IN);

  my $pnam = PageRetDirectory($id) . "/$id";
  my $bnam = $datadir . "/page/" . $pnam;
  my $wnam = "$bnam.dw";
  if(open($IN,"<$wnam")) {
    $text=<$IN>;
    close($IN);
  }
  return $text;
}

sub PageRetHash {
  my ($id)=@_;
  return DataDirPageRetHash($DataDir,$id);
}

sub PageRetText {
  my ($id)=@_;
  my %page=PageRetHash($id);
  return $page{text};
}

sub PageRetTextFast {
  my ($id)=@_;
  return DataDirPageRetTextFast($DataDir,$id);
}

sub TextInsParam {
  my ($text,$param,$post)=@_;
  my (@lines,$line,@par,$var,$val,$rex,$nok,$mess,$need);

  @lines=split("\n",$param);
  foreach $line(@lines) {
    @par=split(/\|/,$line);
    if($par[0] eq "ins") {
      $mess="";
      $need=$par[1];
      $var=$par[2];
      $rex=$par[3];
      $val=RetParam($var,"");
      if(!($val =~ m/^$rex$/)) {
        $mess="<font color=red>Eingabefehler</font>";
        $nok++;
      }
      if($need>0) {
        if(StrEmpty($val)) {
          $mess="<font color=red>Eingabe fehlt</font>";
          $nok++;
        }
      }
      if($post==1 && $val eq "") {
        $val=$n1;
      }
      $text =~ s/{$var\.value}/$val/g;
      $text =~ s/{$var\.mess}/$mess/g;
    }
  }
  if($nok ne "") {
    $text =~ s/{nok}|{\/nok}//g;
    $text =~ s/{ok}.*{\/ok}//g;
  } else {
    $text =~ s/{ok}|{\/ok}//g;
    $text =~ s/{nok}.*{\/nok}//g;
  }
  return $text;
}

sub FileAppStr {
  my ($fnam,$text)=@_;
  my ($OUT);

  if(!open($OUT,">>$fnam")) {
    die "File-Open-Fehler ($fnam): $!";
  }
  print $OUT $text;
  close($OUT);
}

sub TextDoProcParam {
  my ($text,$eprog,$param,$post)=@_;

  if($eprog eq "formcheck") {
    $text=TextInsParam($text,$param,$post);
  } elsif($eprog eq "sendmail") {
    if(RetParam("b_sendmail") ne "") {
      $text=TextInsParam($text,$param,$post);
      my $sender=RetParam("p_email","");
      my $address1='leitner@hls.via.at';
      my $address2='helmut.leitner@chello.at';

      my $mtext=$text;
      $mtext =~ s/<[^<>]*>//g;
      $mtext =~ s/ //g;
      $mtext =~ s/'//g;

      SendEmail($address1,$sender,$sender,"Wiki-Bestellung",$mtext);
      SendEmail($address2,$sender,$sender,"Wiki-Bestellung",$mtext);
      FileAppStr("$GlobalDir/prot/$ProtId.txt",$mtext . "\n\n\n");
    }
  }
  return $text;
}

sub ReportError {
  my ($errmsg)=@_;

  PrintHeader();
  print "<H2>$errmsg</H2>";
  print $cgi->end_html;
}

sub ValidId {
  my ($id)=@_;
  my (@pages,$page);
  my $idlen=length($id);

  if($idlen<1) {
    goto do_error;
  }
  if($idlen>$PagenameLengthLimit) {
    $lb1=Lu("Pagename %PAGENAME% too long.|Der Seitenname %PAGENAME% ist zu lang.|%PAGENAME% nom de page trop long.|Nombre de la página %PAGENAME% es demasiado largo.");
    MessRepPagename($lb1,$id);
    ReportError($lb1);
    return 0;
  }
  if($id =~ /^$WikiPattern$/) {
    return 1;
  }
  if($FreeLinks) {
    if($id =~ /^$FreePattern$/) {
      return 1;
    }
  }
  if(PageExist($id)) {
    return 1;
  }
  if($UseSubpage) {
    @pages=split(/\//,$id);
    if(int(@pages)==0) {
      goto do_error;
    }
    foreach $page (@pages) {
      if(!($page =~ /^$FreePattern$/)) {
        goto do_error;
      }
    }
    return 1;
  }
do_error:
  $lb1=Lu("The pagename %PAGENAME% is invalid.|Der Seitenname %PAGENAME% ist ungültig.|L\'%PAGENAME% du nom de page est invalide.|Nombre de la página %PAGENAME% es inválido.");
  MessRepPagename($lb1,$id);
  MessNormalTitleText(LiError(),$lb1);
  return 0;
}

sub ShowEol {
  my ($s)=@_;
  my $h;
  my $ret=$s;
  $h=NameStyleRetImageGif("0Dsmall");
  $ret =~ s#\r#$h#gs;
  $h=NameStyleRetImageGif("0Asmall");
  $ret =~ s#\n#$h#gs;
  $ret .= $s;
  return $ret;
}

sub DomainRetServerDomainDir {
  my ($dom)=@_;
  return $Context{"domain.$dom"};
}

sub ScriptFileRetPathUnicode {
  my ($script,$file)=@_;
  my ($path,$cfg_file,$cfg_dir,$s,$unicode);
  my $dom=UrlRetDomain($script);
  my $domdir=DomainRetServerDomainDir($dom);

  $cfg_file=FileSetExtRet($script,".cfg");
  if($domdir ne '') {
    $cfg_file =~ s/$dom/$domdir/;
  }
  $cfg_file =~ s#$ServerUrl#$WebDir#;
  $cfg_file =~ s#$DomainUrl#$WebDir/$DomainSubDir#;
  $cfg_dir= FileRetDir($cfg_file);
  $s=FileRetStr($cfg_file);
  if($s =~ m/DataDir=(.*)\n/ ) { # FIXME: use better config structure
    $path=$1;
    StrStripBrackets($path,'"','"');
    ValCvtDir($path,$cfg_dir);
    $path.=$file;
  }
  if($s =~ m/WikiUnicode=(.*)\n/ ) {
    $unicode=$1;
  }
  return ($path,$unicode);
}

sub TabAddRcFileRetArGetTimeLastErr {
  my ($a_tab,$fnam,$p_lastts,$p_nofile,$adds,$select,$filter)=@_;
  my ($line,$pushflag,$IN);
  my $lastts=0;
  my $nofile=0;

  local $/ ="\n";
  if(!open($IN,"<$fnam")) {
    $nofile=1;
    goto do_ret;
  }
  while($line = <$IN>) {
    $line =~ s/^9/09/gm; #Korrekur ts overflow
    $pushflag=1;
    if($select ne '') {
      if(!($line =~ m/$select/)) {
        $pushflag=0;
      }
    }
    if($filter ne '') {
      if($line =~ m/$filter/) {
        $pushflag=0;
      }
    }
    if($pushflag) {
      chomp($line);
      push(@$a_tab,$line.$adds);
    }
  }
  close($IN);

  if(@$a_tab > 0) {  # Only false if no lines in file
    ($lastts) = split(/$FS3/,$$a_tab[$#$a_tab],1);
    if(($^T - $lastts) > 5) { # Skip last unless very recent
      $lastts++;
    }
  }

do_ret:
  $$p_nofile=$nofile;
  $$p_lastts=$lastts;
}

sub InterWebInit {
  my ($data,$cmd,$site,$info,$dom,$IN);

  if($InterWebInitFlag==0) {
    my $fnam="$GlobalDir/interweb.txt";
    $InterWebInitFlag=1;
    open($IN,"<$fnam") or return;
      $data=<$IN>;
    close($IN);
    foreach (split(/\n/,$data)) {
      ($site,$info)=split(/\s+/,$_,2);
      $InterWeb{$site}=$info;
    }
    $cmd="$ScriptUrl?";
    $InterWebSelf{'DiesesWiki'}=$cmd; # FIXME: es
    $InterWebSelf{'ThisWiki'}=$cmd;
    $InterWebSelf{'CeWiki'}=$cmd;

    $dom=$Context{"link.rewrite.*"};
    if($dom ne '') {
      $dom =~ s/^domain\.//;
      $cmd="http://$dom".$cmd;
    }
# MsgPrint("InterWebInit dom=$dom cmd=$cmd");
    $InterWebSelf{'Top'}=$cmd;

    $InterWeb{'Upload'}="$UploadUrl/";
  }
}

sub HashSliceGetHash {
  my ($h_context,$slice,$h_hash)=@_;
  my ($key,$val);

  while( ($key,$val) = each(%$h_context) ) {
    if($key =~ m/^$slice(.*)/) {
      $$h_hash{$1}=$val;
    }
  }
}

sub HashAddHash {
  my ($h_d,$h_s)=@_;
  my ($key,$val);

  while( ($key,$val) = each(%$h_s) ) {
    $$h_d{$key}=$val;
  }
}

sub HashAddArray {
  my ($h_d,@ar)=@_;
  my $i;

  for($i=0; $i<=$#ar; $i+=2) {
    $$h_d{$ar[$i]}=$ar[$i+1];
  }
}

sub HashAddValKeys {
  my ($h_d,$val,@ar)=@_;
  foreach (@ar) {
    $$h_d{$_}=$val;
  }
}

sub ServerHasDomain {
  my ($dom)=@_;
  if($dom eq $ServerDomain || $dom eq $Domain || DomainRetServerDomainDir($dom) ne '') {
    return 1;
  }
  return 0;
}

sub RetParamWiki {
  my $wiki;
  if(UserHasStatus($NeedStatusSuper)) {
    $wiki=RetParam('wiki','');
  }
  return $wiki;
}

sub SiteScriptRetAuthorLink {
  my ($site,$script,$host,$username,$uid,$unicode)=@_;
  my ($html,$label,$title);

  if(!($username =~ /^$UsernamePattern$/)) {  # Invalid under current rules
    $username = "";  # Just pretend it isn't there.
  }
  $html  = ". . . . . ";  # Later optional
  if(($uid > 0) && ($username ne "")) {
    $site=ContextVarRetDefault('cluster.user.site',$site);
    $script=ContextVarRetDefault('cluster.user.script',$script);
    if($RenderUsername) {
      $label=PageRetLabel($username);
    } else {
      $label=$username;
    }
    if($unicode!=$WikiUnicode) {
      StrUnicodeCvtUnicode($label,$unicode,$WikiUnicode);
    }
    if(defined($site)) {
      $label="$site:$label";
    }
    if($UserPref ne '') {
      $title="ID $uid von $host";
    }
    $html .= ScriptActionLabelClassIdTargetTitleRetLink($script,$username,$label,'body',$username,'',$title);
  } else {
    $html .= $host;
  }
  return $html;
}

sub IdRenderParts {
  my ($id)=@_;
  $id =~ s#\/# \/ #g;
  return $id;
}

sub RcLineSplitPlus {
  my ($rcline,$trim)=@_;
  my ($pagehost,$name,$uid,$rev,$shost,$stime);
  my ($ts,$id,$summary,$isEdit,$host,$kind,$extraTemp,$site,$script,$unicode) = split(/$FS3/, $rcline);
  my %extra=split(/$FS2/,$extraTemp,-1);

  PageNormalize($id);

  $name=$extra{name};
  $uid=$extra{id};
  $rev=$extra{rev};

  $shost=$host;
  if($trim==1) {
    if($name ne "") {
      $shost=$name;
    }
  } if($trim>=2) {
    $shost='';
  }
  $stime= ($trim>=3) ? '' : TimeRetDayEnglish($ts);
  $pagehost=$id."=".$shost."=".$stime;
  return ($ts,$id,$summary,$isEdit,$host,$kind,$site,$script,$unicode,$name,$pagehost,$uid,$rev);
}

sub WikiRetLanguage639_1 {
  if($WikiLanguage==1) {
    return "de";
  }
  if($WikiLanguage==2) {
    return "fr";
  }
  if($WikiLanguage==3) {
    return "es";
  }
  return "en";
}

sub RcRetRss {
  my @outrc = @_;
  my ($rcline,$ts,$summary,$isEdit,$host,$kind,$site,$script,$pagehost,$uid,$rev,$unicode);
  my (@rtab,@itab,$h,$cmd,$stime,$pagename,$pagename_link,$name,$name_link);
  my (%changetime,%pagecount);
  my $trim=RetParam('trim',$RcTrim);
  my $showedit=RetParam("edits",0);
  my $lang=WikiRetLanguage639_1();

my $ret= <<'#END_OF_RSS';
<?xml version="1.0" encoding="ISO-8859-1"?>
<rdf:RDF
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns="http://purl.org/rss/1.0/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wiki="http://purl.org/rss/1.0/modules/wiki/"
>
  <channel rdf:about="{ScriptName}?action=rss">
    <title>{SiteName}</title>
    <link>{ScriptName}?RecentChanges</link>
    <description>{RssDescription}</description>
    <wiki:interwiki>
      <rdf:Description link="{ScriptName}"><rdf:value>{SiteName}</rdf:value></rdf:Description>
    </wiki:interwiki>
    <items><rdf:Seq>
{RTAB}
    </rdf:Seq></items>
  </channel>
{ITAB}
</rdf:RDF>
#END_OF_RSS

  my $sc="$DomainUrl$ScriptUrlPath/$ScriptName";
  foreach $rcline (@outrc) {
    ($ts,$pagename,$summary,$isEdit,$host,$kind,$site,$script,$unicode,$name,$pagehost,$uid,$rev)=RcLineSplitPlus($rcline,$trim);
    if(ShowEdit($showedit,$isEdit)==0) {
      next;
    }
    $pagecount{$pagehost}++;
    $changetime{$pagehost} = $ts;
  }
  @outrc=reverse @outrc;
  foreach $rcline (@outrc) {
    ($ts,$pagename,$summary,$isEdit,$host,$kind,$site,$script,$unicode,$name,$pagehost,$uid,$rev)=RcLineSplitPlus($rcline,$trim);
    if(ShowEdit($showedit,$isEdit)==0) {
      next;
    }
    if($ts<$changetime{$pagehost}) {
      next;
    }
    $pagename_link=StrRetNecEsc($pagename);
    $pagename=StrRetNecHtml($pagename);
    $name_link=StrRetNecHtml($name);
    $name=StrRetNecHtml($name);
    $summary=~ s/&/&/g;
    $summary=~ s/</</g;
    $summary=~ s/</>/g;
    $summary=StrRetNecHtml($summary);

    $cmd="$sc?action=browse&id=$pagename_link&revision=$rev";
    $h="      <rdf:li rdf:resource=\"$cmd\"/>";
    push(@rtab,$h);

    $stime=TimeRetRssTime($ts); # 2004-03-15T12:20:18+00:00

    $h=
"   <item rdf:about=\"$cmd\">\n" .
"     <title>$pagename</title>\n" .
"     <link>$sc?action=browse&id=$pagename_link&diff=3</link>\n" .
"     <description>$summary</description>\n" .
"     <dc:date>$stime</dc:date>\n" .
"     <dc:language>$lang</dc:language>\n" .

"     <dc:creator>$name</dc:creator>\n" .

#nok "     <dc:creator link=\"$sc?$name\">$name</dc:creator>\n" .

#nok
#"     <dc:creator>\n" .
#"       <rdf:Description link=\"$sc?$name_link\">\n" .
#"         <rdf:value>$name</rdf:value>\n" .
#"       </rdf:Description>\n" .
#"     </dc:creator>\n" .

"     <dc:contributor>\n" .
"       <rdf:Description link=\"$sc?$name_link\">\n" .
"         <rdf:value>$name</rdf:value>\n" .
"       </rdf:Description>\n" .
"     </dc:contributor>\n" .

"     <wiki:status>updated</wiki:status>\n" .
"     <wiki:importance>major</wiki:importance>\n" .
"     <wiki:diff>$sc?action=browse&id=$pagename_link&diff=4</wiki:diff>\n" .
"     <wiki:version>$rev</wiki:version>\n" .
"     <wiki:history>$sc?action=archive&id=$pagename_link</wiki:history>\n" .
"   </item>\n";

    push(@itab,$h);
  }
  $ret =~ s#{ScriptName}#$sc#g;
  $ret =~ s#{SiteName}#$SiteName#g;
  $ret =~ s#{RssDescription}#$RssDescription#g;
  $ret =~ s#{RTAB}#join("\n",@rtab)#ge;
  $ret =~ s#{ITAB}#join("\n",@itab)#ge;

  return $ret;
}

sub ShowEdit {
  my ($show,$edit)=@_;
  if($show==1) {
    return 1;
  }
  if($show==0) {
    if($edit==0) {
      return 1;
    }
  } else { # $show==2
    if($edit) {
      return 1;
    }
  }
  return 0;
}

sub RcRetHtml {
  my @outrc = @_;
  my ($html,$date,$sdate,$sum,$edit,$count,$newtop,$author);
  my ($inlist,$link,$all,$idOnly,$text,$line,$label);
  my ($rcline,$ts,$pagename,$summary,$isEdit,$host,$kind,$site,$script,$unicode,$name,$pagehost,$uid,$rev);
  my (%changetime,%pagecount);
  my $chtext=Lu('changes|Änderungen|modifications|modificaciones');
  my $trim=RetParam('trim',$RcTrim);
  my $showedit=RetParam("edits",0);
  my $dheader=RetParam("dh",$RcDateHeader);
  my $dinline=RetParam("di",$RcDateInline);

  $all = RetParam("rcall", 0);
  $all = RetParam("all", $all);
  $newtop = RetParam("rcnewtop", $RcTop);
  $newtop = RetParam("newtop", $newtop);
  $idOnly = RetParam("rcidonly",'');

  foreach $rcline (@outrc) {
    ($ts,$pagename,$summary,$isEdit,$host,$kind,$site,$script,$unicode,$name,$pagehost,$uid,$rev)=RcLineSplitPlus($rcline,$trim);
    if(ShowEdit($showedit,$isEdit)==0) {
      next;
    }
    $pagecount{$pagehost}++;
    $changetime{$pagehost}=$ts;
  }
  $date = "";
  $inlist = 0;
  $html = "";

  if($newtop) {
    @outrc=reverse @outrc;
  }
  foreach $rcline (@outrc) {
    ($ts,$pagename,$summary,$isEdit,$host,$kind,$site,$script,$unicode,$name,$pagehost,$uid,$rev)=RcLineSplitPlus($rcline,$trim);
    if(ShowEdit($showedit,$isEdit)==0) {
      next;
    }
    if((!$all) && ($ts < $changetime{$pagehost})) {
      next;
    }
    if(($idOnly ne "") && ($idOnly ne $pagename)) {
      next;
    }
    if($date ne TimeRetDayGerman($ts)) {
      $date = TimeRetDayGerman($ts);
      $sdate = TimeRetDay($ts);
      if($dheader) {
        if($inlist) {
          $html .= "</ul>\n";
          $inlist=0;
        }
        $html.="<p><strong>$sdate</strong></p>\n";
      }
    }
    if($inlist==0) {
      $html .= "<ul>\n";
      $inlist = 1;
    }
    if(!defined($script)) {
       $script=$ScriptName;
    }

    $host=QuoteHtml($host);
    if(defined($name) && defined($uid)) {
      $author = SiteScriptRetAuthorLink($site,$script,$host,$name,$uid,$unicode);
    } else {
      $author = SiteScriptRetAuthorLink($site,$script,$host,"",0);
    }

    $sum = "";
    if(($summary ne "") && ($summary ne "*")) {
      if($site ne '') {
        if($unicode!=$WikiUnicode) {
          StrUnicodeCvtUnicode($summary,$unicode,$WikiUnicode);
        }
      }
      $summary = QuoteHtml($summary);
      $sum = "<strong>[$summary]</strong> ";
    }

    $edit = "";
    if($isEdit) {
      $edit = "<em>(" . Lu('minor edits|Korrektur|modifications mineures|modificaciones menores') .")</em> ";
    }

    $count = "";
    if((!$all) && ($pagecount{$pagehost} > 1)) {
      $count = "($pagecount{$pagehost} $chtext) ";
    }

    NoFollow();
    $link=ScriptDiffPageTextClassRetLink($script,4,$pagename,"(diff)","body") . "  ";

    $label=IdRenderParts(LabelStripBase(PageRetLabel($pagename)));
    if($site ne '') {
      if($unicode!=$WikiUnicode) {
        StrUnicodeCvtUnicode($label,$unicode,$WikiUnicode);
      }
    }
    if(defined($site)) {
      $label="$site:$label";
    }
    $link.=ScriptPageRefLabelClassCompleteRetLink($script,$pagename,'',$label,"body",1);
    if($dinline) {
      $link.=" $sdate";
    }

    $line="$link " . TimeRetHour($ts) . " $count$edit$sum$author";
    $html .= "<li>$line</li>";
    $html .= "\n";
  }
  if($inlist) {
    $html .= "</ul>\n";
  }
  return $html;
}

sub WikiGroupInit {
  my $group=RetParam('group','');
  my $var=RetParam('var','');
  my ($val,@wg,$wiki);

  GlobalSiteInit();

  if($var ne '') {
    $val=$$var;
  } else {
    $val=$GlobalUserData{'WikiGroup'.$group};
  }
  @wg=ListSplit($val);
  foreach $wiki (@wg) {
    if($GlobalSite{$wiki}) {
      $WikiGroup{$wiki}='ok';
    }
  }
}

sub StrCmpWikiGroup {
  my ($site)=@_;
  if($WikiGroup{$site} ne '') {
     return 0;
  }
  return 1;
}

sub StrCmpFilter {
  my ($s,$filter)=@_;
  if($filter eq '') {
    return 0;
  }
  if($s eq $filter) {
    return 0;
  }
  return 1;
}

sub TextDays {
  my ($i)=@_;
  my $ret;
  if($i==1) {
    $ret=Lu("1 day|1 Tag|1 jour|1 día");
  } else {
    $ret=Lu("%COUNT% days|%COUNT% Tage|%COUNT% jours|%COUNT% días");
    MessRepVar($ret,"%COUNT%",$i);
  }
  return $ret;
}

sub NowDaysRetTsecLabel {
  my ($ts2,$daysago)=@_;
  my ($ts1,$lb1);
  $ts1 = $ts2 - 86400*$daysago;
  if($daysago!=1) {
    $lb1=Lu("Contributions of the last %DAYCOUNT% days|Beiträge der letzten %DAYCOUNT% Tage|Contribution des %DAYCOUNT% derniers jours|Contribuciones de los últimos %DAYCOUNT% días");
    MessRepVar($lb1,"%DAYCOUNT%",$daysago);
  } else {
    $lb1=Lu("Contributions of the last 24 hours|Beiträge der letzten 24 Stunden|Contributions des dernières 24 heures|Contribuciones de las últimas 24 horas");
  }
  return ($ts1,$lb1);
}

sub ShowRcGlobalRetText {
  my ($global,$action)= @_;
  my ($head,$rcline,$i,$daysago,$ts,$ts1,$ts2,$idOnly,@files,$file,$unicode);
  my ($last,$lastts,@fullrc,$answer,$a2,$nofile,$site,$script,$rcfile,$rcpage);
  my $showbar=0;
  my $wiki=RetParamWiki();
  my $select=RetParam('select','');
  my $filter=RetParam('filter','');

  if($select ne '' || $filter ne '') {
    if($select ne '') {
      $PageTitleComment.="select=$select ";
    }
    if($filter ne '') {
      $PageTitleComment.="filter=$filter ";
    }
    $PageTitleComment="( $PageTitleComment)";
  }

  $ts2=$^T;

  if(RetParam("from", 0)) {
    $ts1 = RetParam("from", 0);
    $lb1=Lu('Contributions since|Beiträge seit|Contribution des|Contribuciones desde');
    $head="<h2>$lb1 " . TimeRetText($ts1) . "</h2>\n";
  } else {
    $daysago=RetParam("days", 0);
    if($daysago==0) {
      $daysago=RetParam("rcdays", 0)
    }
#    if($action eq 'rss') {
#      if($daysago>3) {
#        $daysago=3;
#      }
#    }
    if($daysago) {
      ($ts1,$lb1)=NowDaysRetTsecLabel($ts2,$daysago);
      $head="<h2>$lb1</h2>\n";
    }
  }
  if($ts1==0) {
    ($ts1,$lb1)=NowDaysRetTsecLabel($ts2,$RcDefault);
    $head ="<h2>$lb1</h2>\n";
  }

  if($global) {
    WikiGroupInit();

    while( ($site,$script)=each(%GlobalSite) ) {
      if(StrCmpFilter($site,$wiki)) {
        next;
      }
      if($global==1 && StrCmpWikiGroup($site)) {
        next;
      }
      ($rcfile,$unicode)=ScriptFileRetPathUnicode($script,"/rclog");
      if($rcfile ne '') {
        @files=NameTsRangeRetFiles($rcfile,$ts1,$ts2);
        foreach $file (@files) {
          TabAddRcFileRetArGetTimeLastErr(\@fullrc,$file,\$last,\$nofile,"$FS3$site$FS3$script$FS3$unicode",$select,$filter);
        }
      }
    }
    if($global==2 && ($wiki =~ m#^/.*/$#)) {
      $script=$ServerUrl.$wiki."wiki.cgi";
      $site=$wiki;
      ($rcfile,$unicode)=ScriptFileRetPathUnicode($script,"/rclog");
      if($rcfile ne '') {
        @files=NameTsRangeRetFiles($rcfile,$ts1,$ts2);
        foreach $file (@files) {
          TabAddRcFileRetArGetTimeLastErr(\@fullrc,$file,\$last,\$nofile,"$FS3$site$FS3$script$FS3$unicode",$select,$filter);
        }
      }
    }
    @fullrc=sort @fullrc;
  } else {
    my $rcf=$RcFile;
    if($WikiBase ne '') {
      $rcf=PageRetPath($WikiBase)."/rclog";
    }
    @files=NameTsRangeRetFiles($rcf,$ts1,$ts2);
    foreach $file (@files) {
      TabAddRcFileRetArGetTimeLastErr(\@fullrc,$file,\$last,\$nofile,'',$select,$filter);
    }
    if($nofile) {
      if($WikiLanguage==2) {
        $a2.="$br<strong>Erreur lors de l'ouverture du fichier : </strong>$rcf$br";
        $a2.="Erreur: <strong>$!</strong>$br$br";
        $a2.="Note : ils n'y a d'erreur, tant que c'est un nouveau wiki ne contenant aucune pages.$br";
      } elsif($WikiLanguage==1) {
        $a2.="$br<strong>Fehler beim Öffnen von File: </strong>$rcf$br";
        $a2.="Fehler: <strong>$!</strong>$br$br";
        $a2.="Hinweis: Dieser Fehler ist normal, solange bei einem neuen Wiki noch keine Seiten angelegt sind.$br";
      } elsif($WikiLanguage==3) {
        $a2.="$br<strong>Error abriendo fichero: </strong>$rcf$br";
        $a2.="Error: <strong>$!</strong>$br$br";
        $a2.="Indicación: Este error es normal, mientras que ya no hay páginas en un nuevo wiki.$br";
      } else {
        $a2.="$br<strong>Error opening file: </strong>$rcf$br";
        $a2.="Error: <strong>$!</strong>$br$br";
        $a2.="Note: this is no error, as long as this is a new wiki containing no pages.$br";
      }
      $answer.=Su($a2);
      return $answer;
    }
  }

  if($last>$lastts) {
    $lastts=$last;
  }

  $answer .= $head;

  $idOnly = RetParam("rcidonly","");
  if($idOnly ne "") {
    $answer .= "<b>(nur Beiträge von " . ActionLabelClassIdTargetTitleRetLink($idOnly, $idOnly,"body") . ")</b>$br";
  }

  $rcpage=PreBase()."RecentChanges";
  foreach $i (@RcDays) {
    if($showbar) {
      $answer .= $LinkBarSep;
    } else {
      $showbar = 1;
    }
    $answer .= ActionLabelClassIdTargetTitleRetLink("action=browse&id=$rcpage&days=$i",TextDays($i),"body",$rcpage);
  }

  $lb1=Lu('Contributions starting with|Liste der Beiträge beginnend mit|Contributions a partir du|Contribuciones a partir del');
  my $contrib = $br . ActionLabelClassIdTargetTitleRetLink("action=browse&id=$rcpage&from=$lastts",$lb1,"body",$rcpage) . " " . TimeRetText($lastts);

  if($RssFlag) {
    $i=1;
    $rcpage=PreBase()."RecentChangesRss";
    $answer .= $LinkBarSep . ActionLabelClassIdTargetTitleRetLink("action=browse&id=$rcpage&days=$i",TextDays($i)." RSS","body",$rcpage);
  }

  $answer .= $contrib.$br;

  $i = 0;
  while($i < @fullrc) {  # Optimization: skip old entries quickly, consider a binary search?
    ($ts)=split(/$FS3/,$fullrc[$i],1);
    if($ts>=$ts1) {
      if($i>0) {
        $i-=1000;
      }
      last;
    }
    $i+=1000;
  }
  if(($i > 0) && ($i >= @fullrc)) {
    $i-=1000;
  }
  for (; $i < @fullrc ; $i++) {
    ($ts)=split(/$FS3/,$fullrc[$i],1);
    last if($ts>=$ts1);
  }

  if($action eq 'rss') {
    if($i == @fullrc) {
      @fullrc=();
    } else {
      splice(@fullrc, 0, $i);  # Remove items before index $i
    }
    return RcRetRss(@fullrc);
  } else {
    if($i == @fullrc) {
      $lb1=Lu('No contributions since|Keine Änderungen seit|Pas de contributions depuis|Ningunas contribuciones desde');
      $answer .= "$br<strong>$lb1 " . TimeRetText($ts1) . "</strong>$br";
    } else {
      splice(@fullrc, 0, $i);  # Remove items before index $i
      $answer .= RcRetHtml(@fullrc);
    }
  }
  $lb1=Lu('Page created on|Seite erzeugt am|Page créée le|Página creada el');
  $answer .= "$lb1 " . TimeRetText($^T) . $br;
  return $answer;
}

sub PageIndexInit {
  if($PageIndexInitFlag<1) {
    LogFileGetHash_Type("$DataDir/pagelog",\%PageIndex);
    $PageIndexInitFlag=1;
  }
}

sub StrFindWord {
  if($_[0] =~ m/(^|\W)$_[1](\W|$)/) {
    return 1;
  }
  return 0;
}

sub StrDelWord {
  $_[0] =~ s/(^|\W)$_[1](\W|$)\s*/ /;
}