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

 
sub FileSetStr {
  my ($file, $s)=@_;
  my ($OUT);

  open ($OUT,">$file") or die ("cant write $file: $!");
  print $OUT  $s;
  close($OUT);
}

sub FileSetArray {
  my ($file,$a_tab)=@_;
  my ($line,$OUT);

  open($OUT,">$file") or die ("cant write $file: $!");
  foreach $line (@$a_tab) {
    print $OUT $line . "\n";
  }
  close($OUT);
}

sub CreatePageDir {
  my ($dir, $id)=@_;
  my $subdir;

  if(!(-d $PageDir)) {
     mkdir($PageDir,0770)
  }
  $subdir = $dir . "/" . PageRetDirectory($id);
  if(!(-d $subdir)) {
    mkdir($subdir,0770)
  }
  while($id =~ m#([^/]+)/#g) {
    $subdir = $subdir . "/" . $1;
    if(!(-d $subdir)) {
      mkdir($subdir,0770)
    }
  }
}

sub RwBold { return "'''$_[0]'''"; }
sub RwColonBold { return "'''$_[0]".LiColon()."'''"; }

sub LiSeparator { return Lu("separator|Trennlinie|séparateur|Línea divisoria"); }
sub LiHighlights { return Lu("highlights|Hervorhebungen|Emphase|Énfasis"); }
sub LiBold { return Lu("bold|fett|gras|negrita"); }
sub LiItalic { return Lu("italic|kursiv|italique|cursiva"); }
sub LiBoldAndItalic { return Lu("bold and italic|fett und kursiv|gras et italique|negrita y cursiva"); }
sub LiCamelCaseExample { return Lu("JoinedWords|VerbundeneWorte|MotsJoints|PalabrasJuntadas"); }
sub LiInterWikiExample { return Lu("AnotherWiki:WikiPage|AnderesWiki:WikiSeite|UnAutreWiki:WikiPage|OtraWiki:WikiPágina"); }
sub LiFreeLinkExample { return Lu("{{link in curly brackets}}|{{Link in geschwungenen Klammern}}|{{lien entre double-accolades}}|{{Enlace entre abrazaderas}}"); }
sub LiLists { return Lu("lists|Listen|listes|Listas"); }
sub LiItem { return Lu("item|Zeile|item|Línea"); }
sub LiNumberedLists { return Lu("numbered lists|Nummerierte Listen|listes numérotées|Lista numerada"); }
sub LiPictures { return Lu("pictures|Bilder|images|Imagen"); }
sub LiWebPages { return Lu("web pages|Webseiten|pages web|Páginas de la red"); }
sub LiBooks { return Lu("books|Bücher|livres|Libros"); }
sub LiBookCode { return Lu("code|Nummerncode|code|código"); }
sub LiTitles { return Lu("titles|Überschriften|titres|Titulos"); }
sub LiChapter { return Lu("chapter|Kapitel|Chapitre|Titulo"); }
sub LiEmail { return Lu("e-mail|e-Mail|courriel|correo"); }
sub LiEmailName { return Lu("name|name|name|nombre"); }
sub LiEmailExample { return Lu("domain.land|domäne.land|domaine.pays|dominio.país"); }
sub LiTables { return Lu("tables|Tabellen|tableaux|Tablas"); }
sub LiCdmlTable { return Lu("table|Tabelle|table|table"); }
sub LiTableBody { return Lu("lines of comma-separated columns|Zeilen mit Beistrichen zur Trennung der Spalten|lignes avec virgule séparateur de colonne|Líneas con comas para separar las columnas"); }

sub GetHelpText {
  my $h="----";

  $h.=RwColonBold(LiSeparator())."---- ; ";
  $h.=RwColonBold(LiHighlights())." ''''''".LiBold()."'''''', ''''".LiItalic()."'''', ''''''''''".LiBoldAndItalic()."''''''''''";
  $h.=";$br";

  $h.=RwColonBold(LiLinks())."".LiCamelCaseExample().", ".LiInterWikiExample()."";
  if($FreeLinks) {
    $h.=", ".LiFreeLinkExample()."";
  }
  $h.=";$br";

  $h.=RwColonBold(LiLists())."* ".LiItem()."; ** ".LiItem()."; '''".LiNumberedLists()."''': # ".LiItem()."; ## ".LiItem().";$br";

  $h.=RwColonBold(LiPictures())."http://.../file.jpg; ";
  $h.=RwColonBold(LiWebPages())."http://...html; ";
  $h.=RwColonBold(LiBooks())."ISBN: ".LiBookCode().";$br";

  $h.= RwColonBold(LiTitles())."=".LiChapter()." 1=, ==".LiChapter()." 2=, ===".LiChapter()." 3=; ";
  $h.= RwColonBold(LiEmail())."mailto:".LiEmailName()."\@".LiEmailExample().";$br";

  $h.= RwColonBold(LiTables())."[[".LiCdmlTable()."] ...".LiTableBody()."... ];''' ";
  return TextWikiRetHtml($h);
}

sub WikiRetFormEdit {
  my ($id,$collision,$oldTime,$edittext,$newtext,$preview)=@_;
  my $editRows=RetParam("editrows",$Def_editrows);
  my $editCols=RetParam("editcols",$Def_editcols);
  my $rndstamp=RetParam("rndstamp",RandomRetStamp());
  my $incoming=RetParam('incoming',$PageIncoming);
  my $section=RetParam('section','');
  my $secstamp=RetParam('secstamp','');
  my $source=RetParam("source",'');
  my $summary=RetParam("summary","*");
  my ($ret,%pg,$tlen,$h,$spam,$text1,$text2,$showtext);
  my $editCopy=($source eq 'copy');

  MetaNoIndex();

  %pg=PageRetHash($id);

  if($preview==0 && $collision==0) { # initial edit
    if($editCopy) {
      $text1=$pg{authorcopy};
    } else {
      $text1=$pg{text};
      if($section) {
        $text1=TextIndRetSection($text1,$section);
        $secstamp=StrRetHashCodeFull($text1);
      }
    }
    StrStripCR($edittext);
  }
  if($collision) {
    $text1=$pg{text};
    $text2=$edittext;
    $section='';
  } elsif($preview) {
    $text1=$edittext;
  }

  if($collision) {
    if($editRows>19) {
      $editRows -= 10;
    }
    if($collision==3) {
      $spam=" (*spam*)";
    }
    $lb1=Lu('Edit collision|Änderungskollision|Editer les collisions|Colisión mientras editando').$spam;
    $ret .= "\n<H1>$lb1!</H1>\n";
    if($collision>1) {
      $lb1=Lu('this is a new collision|Das ist eine neue Kollision|ceci est une nouvelle collision|Esto es una nueva colisión');
      $ret .= "\n<H2>($lb1)</H2>\n";
    }
    $lb1=Lu("After you started editing, someone else edited and saved this page.|Nachdem du deine Änderung begonnen hast, hat jemand eine Änderung durchgeführt und gespeichert.|Après avoir démarré l'édition, quelqu'un d'autre a édité et sauvegardé cette page.|Mientras has comenzado a editar, alguien hizo una modificación y la guardó.");
    $ret.="$br<strong>$lb1 ";
    $lb1=Lu("The first text window contains the currently stored text and only the text of this window will be stored.|Das obere Textfenster enthält den gespeicherten Text. Nur der Text im oberen Fenster wird gespeichert.|La première fenêtre de texte contient la version en cours du texte archivée et seulement le texte de cette fenêtre sera stocké.|La primera ventana del texto contiene el texto guardado. Solamente el texto de la primera ventana va a ser guardado.");
    $ret.="$lb1 </strong>$br";
    $lb1=Lu("Scroll down to see your version of the text in the second window.|Scrolle nach unten, um die von dir geänderte Version zu sehen.|Faites défilez vers le bas pour voir votre version du texte dans la seconde fenêtre.|Abajo está la versión tuya del texto.");
    $ret.="$lb1 $br";
    $lb1=Lu("The text was stored at: %TIME% (Current time: %CURRENTTIME%).|Zeitpunkt der letzten Speicherung: %TIME% (Aktuelle Uhrzeit: %CURRENTTIME%).|Le texte a été stocké à : %TIME% (horodatage actuel: %CURRENTTIME%).|Tiempo de la modificatión más reciente: %TIME% (hora actual: %CURRENTTIME%).");
    MessRepVar($lb1,"%TIME%",TimeRetText($oldTime),"%CURRENTTIME%",TimeRetText($^T));
    $ret.="$lb1 $br";
  }

  $ret.=FormStart("form_edit",$id);
  $ret.=FormNameValueHidden("incoming",$incoming) . "\n";
  $ret.=FormNameValueHidden("oldtime",$pg{'timestamp'}) . "\n";
  $ret.=FormNameValueHidden("rndstamp",$rndstamp) . "\n";
  $ret.=FormNameValueHidden("oldconflict",$collision) . "\n";
  if($section) {
    $ret.=FormNameValueHidden("section",$section) . "\n";
    $ret.=FormNameValueHidden("secstamp",$secstamp) . "\n";
  }

  if($edittext =~ /^\n/) { # editbox otherwise swallows first line
    $edittext = " " . $edittext;
  }

  $ret .= FormTextArea('text',$text1,$editRows,$editCols,1,1) . $br;

  $ret .= FormButton('Save',LiSave()) . "  \n";

  $ret .= LiSummary() . LiColon() . FormText('summary',$summary,50). $br;

  if(($RcUseLoginName>0) && ($SessionUserName ne '')) {
    $lb1=LiUsername();
    $ret .= " ($lb1: " . PageClassRetLink($SessionUserName,"body") . ") ";
  } else {
    if($UserPref ne "") {
      $lb1=LiUsername();
      $ret .= " ($lb1: " . PageClassRetLink($UserPref,"body") . ") ";
    } else {
      $lb1=Lu('set username in %PREFERENCES%|Benutzername eingeben in %PREFERENCES%|inscrivez votre nom utilisateur %PREFERENCES%|entra nombre del usuario en %PREFERENCES%');
      $lb1=~ s/ %PREFERENCES%//;
      $ret .= " ($lb1: " . PageClassRetPrefsLink($id,"body") . ") ";
    }
  }
  if($UseSmallCorrection) {
    $lb1=Lu("I'm just doing minor edits|Meine Änderungen sind kleine Korrekturen|Modifications mineures|Modificaciones minores");
    $ret .= FormCheck('minoredit',0,$lb1);
  }
  $ret.=$br;

  $ret.=FormButton('preview',Lu('Preview|Vorschau|Prévisualisation|Previsión'))."  \n";

  $lb1=Lu('page size|Seitengröße|taille de la page|talla de la página');
  $tlen=length($text1); $h="($lb1: $tlen)";
  if($tlen>30000) {
    $h=StrColorRetSpan($h,"#ffaabb");
  } elsif($tlen>20000) {
    $h=StrColorRetSpan($h,"#ffddbb");
  }
  $ret .= $h . "  \n";

  if((!$editCopy) && defined($pg{'authorcopy'}) && ($pg{'authorcopy'} ne "")) {
    $lb1=Lu("saved text of the previous author|Textsicherung des vorhergehenden Autors|texte sauvegardé de l'auteur précédent"); # FIXME: es
    $ret.=ActionLabelClassIdTargetTitleRetLink("action=edit&source=copy&id=$id",$lb1,"body",$id) . $br;
  }
  if($ShowEditHelp) {
    if(RetParam("edithelp",1)) {
      $ret.=GetHelpText();
      if($ShowEditHelpText ne '') {
        $ret.= "$br$ShowEditHelpText";
      }
    }
  }
  if($collision) {
    $ret .= "\n$br<hr><p><strong>";
    $ret .= Lu("This is your text version:|Das ist deine Textversion:|Ceci est votre version de texte :|Esto es la versión tuya del texto:");
    $ret .= " </strong>$br" . FormTextArea('newtext',$text2,$editRows,$editCols,1,1) . "</p>\n";
  }
  $ret .= FormEnd();

  if($preview) {
    $lb1=Lu('Preview|Vorschau|Prévisualisation|Previsión');
    $ret .= "<h2>$lb1:</h2>\n";
    if($collision) {
      $lb1=Lu("Note: this preview shows the saved text of the other author|Hinweis: Diese Vorschau zeigt die Version des anderen Autors|Note : cette prévisualisation montre le texte sauvegardé de l'autre auteur|Indicación: Está previsión muestra la versión de otro autor");
      $ret .= "<b>$lb1.</b><hr>\n";
    }
    $PageCur=$id;
    $PageTop=$id;
    $PageTop =~ s|/.*||;  # Only the main page name (remove subpage)
    if($collision) {
      $showtext=$text1;
    } else {
      $showtext=$newtext;
    }
    $ret.=TextWikiRetHtml($showtext)."\n";
  }

  return $ret;
}

sub ShowFormEdit {
  my ($id0,$collision,$oldTime,$edittext,$newtext,$preview,$timestamp)=@_;
  my ($title,$header,$lba);
  my $editCopy=(RetParam('source') eq 'copy');
  my $id=QuoteHtml($id0);

  $lba=Lu('Edit|Ändern von Seite:|Editer|Editar');
  $header="$lba $id";
  if($editCopy) {
    $header=Lu('Edit an old version of %PAGENAME%|Ändern einer alten Version von %PAGENAME%|Editer une ancienne version de %PAGENAME%|Editar una versión vieja de %PAGENAME%');
    MessRepPagename($header,$id);
  }
  $title=$header;
  my $text=WikiRetFormEdit($id,$collision,$oldTime,$edittext,$newtext,$preview);
  if($ShowSeparatePageTitleStem) {
    $lba="<span style='background: white;'>$lba </span>".PageRetStem($id);
    $header="<span class='titlestem'>$lba<br></span>".PageRetLeaf($id);
  }
  $FormEditId=$id0;
  TemplateShowTitleHeaderTextPlus($TemplateEdit,$title,$header,$text,1,0,$timestamp);
}

sub CreateUserDir {
  my ($n, $subdir);

  if(!(-d "$UserDir/0")) {
    if(!(-d $UserDir)) {
      mkdir($UserDir,0770);
    }
    foreach $n (0..9) {
      $subdir = "$UserDir/$n";
      if(!(-d $subdir)) {
        mkdir($subdir,0770);
      }
    }
  }
}

sub PrefsCookieExpires {
  $PrefsCookie{expires}="Fri, 08-Sep-2015 19:48:24 GMT";
}

sub DoNewCookieLogin { # create new cookie / user file
  # Later consider warning if cookie already exists
  # (maybe use "replace=1" parameter)
  CreateUserDir();

  # The cookie will be transmitted in the next header
  $PrefsCookie{cid}=GetNewUserCookieId();
  $PrefsCookie{randkey}=RandomRetStamp();
  $PrefsCookie{rev}=1;
  PrefsCookieExpires();

  %GetCookie=%PrefsCookie;

  $CookieID=$PrefsCookie{cid};
  %UserPrefs=%GetCookie;
  $UserPrefs{createtime} = $^T;
  $UserPrefs{createip} = $ClientIP;
  SaveUserPrefs();
}

sub ShowFormPrefs {
  my $type=RetParam('type',1);
  my $text=WikiRetFormPrefs('',$type);
  ShowTitleTextLinkSearch(Lu('Edit preferences|Ändern der Einstellungen|Editer préférences|Editar preferencias'),$text,1,0);
}

sub UserNameIsLegal {
  my ($username)=@_;
  if($username =~ /^$WikiPattern$/) {
    return 1;
  }
  return 0;
}

sub UpdatePrefCheckbox {
  my ($param)=@_;
  my $temp = RetParam("p_$param","*");

  # It is possible to skip updating by using another value, like "2"
  if($temp eq "on") {
    $UserPrefs{$param}=1;
  }
  if($temp eq "*") {
    $UserPrefs{$param} = 0;
  }
}

sub UpdatePrefNumber {
  my ($param, $integer, $min, $max)=@_;
  my $temp = RetParam("p_$param","*");

  return  if($temp eq "*");
  $temp =~ s/[^-\d\.]//g;
  $temp =~ s/\..*//  if($integer);
  return  if($temp eq "");
  return  if(($temp < $min) || ($temp > $max));
  $UserPrefs{$param} = $temp;
  # Later consider returning status?
}

sub PasswordCheckRetErr {
  my ($pw1,$pw2)=@_;
  my $ret;

  if( !($pw1 =~ m/^$AnyLetter*$/) ) {
    $ret .= Lu("The password contains illegal characters (only letters and digits are allowed).|Illegale Zeichen im Passwort (erlaubt sind nur Buchstaben und Ziffern).|Le mot de passse contient des caractères illégaux (seuls les lettres et les chiffres sont permis).|La contraseña contiene signos inválidos (sólo letras y cifras estan permitidas).");
  } elsif(length($pw1) < $PasswordCharMin) {
    $ret .= Lu("The password is too short.|Das Passwort ist zu kurz.|Le mot de passe est trop court.|La contraseña es demasiada corta.");
  } elsif(StrRetDigitCount($pw1) < $PasswordDigitMin) {
    $ret .= Lu("The password must contain at least %COUNT% digits.|Das Passwort muss mindestens %COUNT% Ziffern enthalten.|Le mot de passe doit contenir au moin %COUNT% chiffres.|La contraseña tiene que contener por lo menos %COUNT% cifras.");
    MessRepVar($ret,"%COUNT%",$PasswordDigitMin);
  } elsif($pw1 ne $pw2) {
    $ret .= Lu("The two passwords entered differ.|Kontrolleingabe des Passwortes nicht identisch.|Les deux mots de passes saisis diffèrent. |Las dos contraseñas son diferentes.");
  }
  if($ret ne '') {
    $ret .= ' ';
  }
  return $ret;
}

sub OldPlistBlockRetAction {
  my ($block)=@_;
  my ($action,$plist);

  $plist=RetParam("old_plist");
  $plist =~ s/$block(&|&)continue=//;
  if(($plist =~ m/$block/) || ($plist eq '')) {
    $action=RetIdDefault();
  } else {
    $action=$plist;
  }
  return $action;
}

sub ShowFormPasswordAnswer {
  my ($username,$pw1,$pw2,$text,$err);

  $pw1 = RetParam("p_password1",  "");
  $pw2 = RetParam("p_password2",  "");

  $err=PasswordCheckRetErr($pw1,$pw2);
  if($err ne '') {
    $text .= $err . Lu(" The password wasn't changed.| Das Passwort wurde nicht geändert.| Le mot de passe n'a pas été modifié.|La contraseña no fue cambiado.");
    goto do_err;
  }
  $GlobalUserData{'Password'}=$pw1;
  UserSetGlobalInfo($UserName,\%GlobalUserData);
  $text .=  Lu("The password was changed.| Das Passwort wurde geändert.| Le mot de passe a été modifié.|La contraseña fue cambiado.");
do_err:
  ShowTitleTextLinkSearch(Lu("Changing the password|Ändern des Passworts|Modification du mot de passe en cours|Modificación de la contraseña"),$text,1,1);
}

sub WikiRetFormPrefsAnswer {
  my ($username,$password,$answer,$ecookie,$action);
  my $type=RetParam('type',0);

  UpdatePrefCheckbox("toplinkbar"); # redundant intensionally
  UpdatePrefCheckbox("linkrandom");

  $answer.=$br;
  if($CookieID < 1001) {
    $lb1=Lu("Invalid CookieID, preferences not saved.|Ungültiges Cookie, die Einstellungen wurden nicht gespeichert.|CookieID invalide, préférences non sauvegardées.|Cookie inválido. Las preferencias no fueron guardadas.");
    $answer .= "<b>$lb1 (#$CookieID)</b>";
    if($CookieID == 111) {
      $lb1=Lu("No Cookie available. Please activate Cookies in your browser software.|Kein Cookie vorhanden. Bitte im Browserprogramm Cookies aktivieren.|Pas de Cookie disponible. Merci d'activers les Cookies dans votre logiciel navigateur.|No cookie disponible. Por favor activar los cookies en el navegador.");
      $answer .= "$br$br<b>$lb1</b>$br$br";
    }
    return $answer;
  }
  $username = RetParam("p_username",  "");
  $username =~ s/["]//g;
  if($PromoteUnderline) {
    $username =~ s/\s+/_/g;
  } else {
    $username =~ s/\s+//g;
  }
  if($username eq '') {
    $lb1=Lu('username deleted.|Benutzername entfernt.|nom utilisateur effacé.|Nombre de usuario tachado.');
    $answer .= "$lb1$br";
    undef $UserPrefs{username};
  } elsif(!($username =~ /^$UsernamePattern$/)) {  # Currently invalid
    $lb1=Lu("Invalid username %USERNAME% not stored.|Ungültiger Benutzername %USERNAME% nicht gespeichert.|Nom utilisateur erroné %USERNAME% non reconnu.|Nombre de usuario inválido %USERNAME% no tachado.");
    MessRepVar($lb1,"%USERNAME%",$username);
    $answer .= "$lb1$br";
  } elsif(length($username) > 50) {  # Too long
    $lb1=Lu('Username must not exceed 50 characters (not stored).|Benutzername darf 50 Zeichen nicht überschreiten (nicht gespeichert).|Le nom utilisateur ne doit pas exécéder 50 caractères (non reconnu).|Nombre de usuario no debe exceder 50 caracteres (no guardado).');
    $answer .= "$lb1$br";
  } else {
    $answer=LuNbsp('Username %USERNAME% stored.|Benutzername %USERNAME% gespeichert.|nom utilisateur %USERNAME% enregistré.|Nombre de usuario %USERNAME% guardado.');
    MessRepVar($answer,"%USERNAME%","<b>$username</b>");
    $answer.=" $br";
    $UserPrefs{username}=$username;
  }

  UpdatePrefNumber("tzoffset", 0, -999, 999);
  if($type) { # keep in sync
    UpdatePrefNumber("editrows", 1, 1, 999);
    UpdatePrefNumber("editcols", 1, 1, 999);
    UpdatePrefCheckbox("editwide");
    UpdatePrefCheckbox("edithelp");
    UpdatePrefNumber("rcdays", 0, 0, 999999);
    UpdatePrefCheckbox("rcnewtop");
    UpdatePrefCheckbox("rcall");
    UpdatePrefCheckbox("norcdiff");
    UpdatePrefCheckbox("diffrclink");
    UpdatePrefCheckbox("alldiff");
    UpdatePrefNumber("defaultdiff", 1, 1, 3);
  }
  UpdatePrefCheckbox("expirecookie");
  UpdatePrefCheckbox("expirepage");

  $ecookie=RetParam("expirecookie",0);
  %PrefsCookie=%GetCookie;
  if($ecookie>0) {
    delete $PrefsCookie{expires};
  } else {
    PrefsCookieExpires();
  }

  $lb1=Lu('server time: %CLOCKTIME%|Server Zeit: %CLOCKTIME%|heure serveur : %CLOCKTIME%|hora server: %CLOCKTIME%');
  MessRepVar($lb1,"%CLOCKTIME%",TimeRetText($^T-$TimeZoneOffset+3600*$TimeSummer));
  $answer .= $lb1 . $br0;

  $TimeZoneOffset = (RetParam("tzoffset", $Def_tzoffset) + $TimeSummer)* 3600;

  $lb1=Lu('local time: %CLOCKTIME%|Lokale Zeit: %CLOCKTIME%|heure locale : %CLOCKTIME%|hora local : %CLOCKTIME%');
  MessRepVar($lb1,"%CLOCKTIME%",TimeRetText($^T));
  $answer .= $lb1 . $br0;

  SaveUserPrefs();
  $lb1=Lu('The preferences have been saved.|Die Einstellungen wurden gespeichert.|Les préférences ont été enregistrées.|Las preferencias fueron guardadas.');
  $answer .= "<b>$lb1</b>$br$br";
  $UserPref=$username;   # partial, just for display


  $action=OldPlistBlockRetAction("action=editprefs");
  $answer.=ActionLabelClassIdTargetTitleRetLink($action,LiContinue(),'body','').$br.$br;
  return $answer;
}

sub ShowFormPrefsAnswer {
  # All link bar settings should be updated before printing the header
  UpdatePrefCheckbox("toplinkbar");
  UpdatePrefCheckbox("linkrandom");

  my $text = WikiRetFormPrefsAnswer();
  ShowTitleTextLinkSearch(Lu("Storing the preferences|Speichern der Einstellungen|Enregistrement des Préférences en cours|Modificación de las preferencias"),$text,1,1);
}

sub ShowLogoutAnswer {
  my ($answer);

  SessionCookieLogout();
  $UserName='';   # partial, just for display
  my $id=$PageReferenced;
  if($id eq '') {
    $id=RetPageDefault();
  }
  $answer .= $br . Lu('Logout completed.|Logout durchgeführt.|Déconnexion terminée.|Deconexión terminado.') . $n3;
  $answer .= ActionLabelClassIdTargetTitleRetLink($id,LiContinue(),'body',$id).$br.$br;
  ShowTitleTextLinkSearch(Lu("Logout"),$answer,1,1);
}

sub ArraySort {
  my (@ar)=@_;
  my ($key,$val,%hash,$i);

  if($UseSortOrder<1) {
    @ar = sort @ar;
    goto do_return;
  }
  $i=1000000;
  foreach (@ar) {
    $key=$_;
    $key =~ tr/a-zÀÁÂÃÄÅÆàáâãäåæÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖòóôõöÙÚÛÜùúûüß/A-ZAAAAAAAAAAAAAAEEEEEEEEIIIIIIIIOOOOOOOOOOUUUUUUUUS/;
    $key .= " $i";
    $hash{$key}=$_;
    $_=$key;
    $i++;
  }
  @ar=sort @ar;
  foreach (@ar) {
    $_=$hash{$_};
  }
do_return:
  return @ar;
}

sub ArrayAddFilesDirSpec {
  my ($a_file,$dir,$spec)=@_;
  my ($file,@dirs,$DIR);

  opendir($DIR,"$dir/.");
  while($file = readdir($DIR)) {
    if($file eq '.' || $file eq '..') {
      next;
    }
    $file = "$dir/$file";
    if(-d $file) {
      push(@dirs,$file);
    } elsif(-f $file) {
      if($file =~ m#$spec#) {
        push(@$a_file,$1);
      }
    }
  }
  closedir($DIR);

  foreach (@dirs) {
    ArrayAddFilesDirSpec($a_file,$_,$spec);
  }
}

sub DataDirRetAllPagesList {
  my ($datadir)=@_;
  my (%hash);
  LogFileGetHash_Type("$datadir/pagelog",\%hash);
  return sort keys %hash;
}

sub DataDirRetAllPagesListOld {
  my ($datadir,$ext)=@_;
  my (@pages,@dirs,$dir);

  $ext=First($ext,'dw');

  @dirs = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z other);
  foreach (@dirs) {
    $dir="$datadir/page/$_";
    ArrayAddFilesDirSpec(\@pages,$dir,"^$dir/(.*)\.$ext\$");
  }
  @pages=ArraySort(@pages);
  return @pages;
}

sub WikiRetPageList {
  my ($ext)=@_;
  return DataDirRetAllPagesList($DataDir,$ext);
}

sub WikiRetPageListOld {
  my ($ext)=@_;
  return DataDirRetAllPagesListOld($DataDir,$ext);
}

sub DataDirPageRetGroupList {
  my ($datadir,$id)= @_;
  my $pagedir=$datadir."/page";
  my $dir = PageRetDirectory($id);
  my (@pages,$subdir);

  while(<$pagedir/$dir/$id.dw>) {
    m|$pagedir/$dir/(.*).dw|;
    push(@pages,$1);
  }
  $subdir="$pagedir/$dir/$id";
  ArrayAddFilesDirSpec(\@pages,$subdir,"^$pagedir/$dir/(.*)\.dw\$");
  @pages=ArraySort(@pages);
  return @pages;
}

sub DataDirPageRetGroupSize {
  my ($datadir,$id)= @_;
  my @pages=DataDirPageRetGroupList($datadir,$id);
  return 1+$#pages;
}

sub PageRetGroupSize {
  my ($id)= @_;
  return DataDirPageRetGroupSize($DataDir,$id);
}

sub PageRetGroupList {
  my ($id)= @_;
  return DataDirPageRetGroupList($DataDir,$id);
}

sub GlobalFileRetUserStatus {
   my ($fnam)= @_;
   my $s=FileRetStr($fnam);
   my ($state,$state2,$h);

   $s =~ s#\{UserStatus(.*):(.*)\}#{
        if($1 eq "[$CookieName]") {
          $state = " <b>$CookieName.$2</b>";
        } elsif($1 eq "") {
          $state2 = " <b>*.$2</b>" . $state2;
        } else {
          $h=$1;
          StrStripBrackets($h,'[',']');
          $state2 .= " $h.$2";
        }
      }#ge ;
   $state .= $state2;
   return $state;
}

sub DirRetUserList {
  my ($dir,$flag,$all)=@_;
  my (@list,@dirs,$entry,$subdir,$fnam,$state);

  @dirs = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z other);
  foreach $subdir (@dirs) {
    while(<$dir/$subdir/*.xu>) {
      $fnam=$_;
      m#/([^/]*).xu#;
      $entry = $1;
      if($flag) {
        $state = GlobalFileRetUserStatus($fnam);
        if($state =~ m/<b>/ ) {
          $entry="<b>" . $entry . "</b>";
        }
        $entry .= $state;
      }
      if($all || ($entry =~ m/$CookieName/)) {
        push(@list, $entry);
      }
    }
  }
  return sort(@list);
}

sub DirRetFiles {
  my ($dir)=@_;
  my (@ret);

  while( <$dir/*.*> ) {
    push(@ret,$_);
  }
  return @ret;
}

sub DirRetFileListGetSize {
  my ($dir, $p_totsize)=@_;
  my (@ret, $elm, $file, $fnam, $sum, $size, @info, $ftim);

  $sum=0;
  while( <$dir/*.*> ) {
    $file=$_;
    m#$dir/(.*)#;
    $fnam = $1;

    @info=stat($file);
    $size=$info[7];
    $ftim=$info[9];
    $sum += $size;

    $elm = join(';',$fnam,$size,$ftim);
    push(@ret, $elm);
  }
  $$p_totsize=$sum;
  return sort(@ret);
}

sub PageListLoHiSizeRetHtml {
  my ($lo,$hi,@allpages)=@_;
  my ($pagename,$ret,$size,$anz);

  foreach $pagename (@allpages) {
    my %pg = PageRetHash($pagename);
    $size=length($pg{text});
    if($lo<=$size && $size<=$hi) {
       $ret .= PageClassRetLink($pagename,"body") . " ($size)$br";
       $anz++;
    }
  }
  $lb1=LiFound();
  return "<h2>" . SiteAnzRetSeiten('',$anz,$lb1) . "</h2>\n".$ret.$br;
}

sub ShowPagesSize {
  my ($title,$lo,$hi)=@_;
  my $text=PageListLoHiSizeRetHtml($lo,$hi,WikiRetPageList());
  ShowTitleTextLinkSearch($title,$text,1,1);
}

sub WikiShowKill { #FIXME: improve dups, dels
  my $ip=RetParam('ip');
  my $comment=RetParam('comment',"spam");
  my (undef,$ip2,undef)=IpRetParts($ip);
  my ($dir,$killfile,$text);
  if($ip2 eq '') {
    goto do_show;
  }
  $dir="$GlobalDir/kill";
  DirCreate($dir);
  $killfile="$dir/kill.$ip2.cfg";
  FileAppStr($killfile,"kill.ip.$ip=$comment\n");
  $text=FileRetStr($killfile);
  $text=~ s#\n#$br#g;
do_show:
  ShowTitleTextLinkSearch(Lu("List of killed IPs within $ip2.*"),$text,1,1);
}

sub ShowIndex {
  my @pages=WikiRetPageList();
  my $text=PageListRetHtml('',$ScriptName,\@pages,undef,LiFound(),'',0,'',0,undef,0,0,undef,undef,1);
  ShowTitleTextLinkSearch(Lu("List of all pages|Index aller Seiten|Liste de toutes les pages|Índice de todas las páginas"),$text,1,1);
}

sub InterWikiName {
  return First($InterWikiName,$SiteName);
}

sub WikiNetExportPage {
  my ($op,$page)=@_;
  my $name=InterWikiName().':'.$page;
  if($WikiUnicode==0) {
    StrCvtUnicode($name);
  }
  FileAppStr($GlobalDir.'/wikinet/export/page.log',$^T.$op.$name."\n");
}

sub WikiNetExportPageVarVal {
  my ($op,$page,$var,$val)=@_;
  my $wiki=InterWikiName();
  if($WikiUnicode==0) {
    StrCvtUnicode($wiki);
    StrCvtUnicode($var);
    StrCvtUnicode($page);
    StrCvtUnicode($val);
  }
  FileAppStr($GlobalDir.'/wikinet/export/vida.log',$^T."$op$wiki:$page $var=$val\n");
}

sub VidaCacheRetVars {
  my @vars;
  ArrayAddFilesDirSpec(\@vars,"$DataDir/vida","^$DataDir/vida/(.*)\.lvd\$");
  return @vars;
}

sub WikiRetPageListContext {
  my @pages=WikiRetPageList();
  @pages= grep { /(^|\/)$ContextPageName/ } @pages;
  return @pages;
}

sub MsgPrintTitleHash {
  my ($title,$h_hash)=@_;
  my ($key,$val);

  MsgPrint($title);
  foreach $key (keys %$h_hash) {
    $val=$$h_hash{$key};
    MsgPrint(" $key => $val");
  }
  MsgPrint('');
}

sub ContextCacheInit {
  my @pages=WikiRetPageListContext();
  my ($fnam,$text);
  my ($page,%vida,$var,$val,%hash);

  foreach $fnam (@ConfigFiles) {
    $text=FileRetStr($fnam);
    $text=~ s/(^|\n)/$1\*/g;
    %vida=();
    VidaAppTextVar(undef,\%vida,$page,'','','',0,'=','',0,1,$text);
    foreach $var (keys %vida) {
      $val=$vida{$var};
      ValStrip($val);
      $ContextCache{$var}{'*'}=$val;
    }
  }

  foreach $page (@pages) {
    %vida=();
    VidaAppPageVar(undef,\%vida,$page,'','','',0,'=','',0,1);
    foreach $var (keys %vida) {
      $val=$vida{$var};
      ValStrip($val);
      $page =~ s#/$ContextPageName$##;
      if($page eq $ContextPageName) {
        $ContextCache{$var}{'*'}=$val;
      } else {
        $ContextCache{$var}{$page}=$val;
      }
    }
  }
  $var='AutoFolders';
  %hash=%{$ContextCache{$var}};
# MsgPrintTitleHash("ContextCache {$var} hash",\%hash);
}

sub ContextCachePageVarRetVal {
  my ($id,$var)=@_;
  my ($val,$stem,$ret);

  $ret=$ContextCache{$var}{'*'};
  foreach $stem (PageRetStemArray($id)) {
    $val=$ContextCache{$var}{$stem};
    if($val ne '') {
# MsgPrint("CCPVRV var=$var stem=$stem val=$val");
      $ret=$val;
    }
  }
  return $ret;
}

sub ShowBuildPageIndex {
  my ($page,$s,$w,$n,$text,$cs,$title,%vida,$leaf,@vfiles,$var,%vars,@ar,$fnam,$val);
  my %arrays; # sorry for hash of arrays
  my @pages=WikiRetPageListOld();

  ContextCacheInit();

  $n=$#pages+1;
  foreach $page (@pages) {
    $text=PageRetText($page);
    TextStripNoLink(\$text);
    $AutoFolders=ContextCachePageVarRetVal($page,'AutoFolders');
    $cs=WikiTextRetFolderTabStr($text);
    $s .= "+$page $cs\n";
    if($page =~ m/^$WordPattern$/) {
      $w .= "+$page\n";
    }
    if($SisterExportFlag) {
      SisterExportPage('+',$page);
    }
    if($WikiNetExportFlag) {
      WikiNetExportPage('=',$page);
    }
    if($VidaCaching) {
      InterWebInit();
      $leaf=PageRetLeaf($page);
      if($leaf ne $ContextPageName) {
        %vida=();
        VidaAppPageVar(undef,\%vida,$page,'','','',0,$VidaOp,'',0,1);
        foreach $var (keys %vida) {
          if($vars{$var}++ ==0) {
            $arrays{$var} = ();
          }
          $val=$vida{$var};
          push(@{$arrays{$var}},"=$page $val");
          if($VidaExportFlag) {
            WikiNetExportPageVarVal('=',$page,$var,$val);
          }
        }
      }
    }
  }
  FileSetStr("$DataDir/pagelog",$s);
  FileSetStr("$DataDir/wordlog",$w);

  if($VidaCaching) {
    DirCreateRecur("$DataDir/vida",0770);
    ArrayAddFilesDirSpec(\@vfiles,"$DataDir/vida","^$DataDir/vida/(.*)\.lvd\$");
    foreach $var (keys %vars) {
      @ar=@{$arrays{$var}};
      FileSetStr("$DataDir/vida/$var.lvd",join("\n",@ar)."\n");
    }
    foreach $var (@vfiles) {
      if(!defined($vars{$var})) {
        $fnam="$DataDir/vida/$var.lvd";
        FileDel($fnam);
      }
    }
  }

  $title=Lu("%PAGEINDEX% built|%PAGEINDEX% erzeugt|%PAGEINDEX% construit|%PAGEINDEX% creado");
  MessRepVar($title,"%PAGEINDEX%","PageIndex");
  $lb2=Lu("%PAGECOUNT% pages|%PAGECOUNT% Seiten|%PAGECOUNT% pages|%PAGECOUNT% páginas");
  MessRepVar($lb2,"%PAGECOUNT%",$n);
  ShowTitleTextLinkSearch($title,$lb2,1,1);
}

sub WikiDw2Db {
  my (%hash,$id,$text,$title);
  my $count=0;
  my @arw=WikiRetPageList('dw');
  my @arb=WikiRetPageList('db');
  HashAddValKeys(\%hash,1,@arb);
  foreach $id (@arw) {
    if($hash{$id}==0) {
      PageHashCreate();
      $text=PageRetTextFast($id);
      PageSetTextLogSummary($id,$text,0,'');
      $count++;
    }
  }
  $title=Lu("%PAGEINDEX% built|%PAGEINDEX% erzeugt|%PAGEINDEX% construit|%PAGEINDEX% creado"); # FIXME: fr
  MessRepVar($title,"%PAGEINDEX%","dw => db");
  $lb2=Lu("%PAGECOUNT% pages|%PAGECOUNT% Seiten|%PAGECOUNT% pages|%PAGECOUNT% páginas"); # FIXME: fr
  MessRepVar($lb2,"%PAGECOUNT%",$count);
  ShowTitleTextLinkSearch($title,$lb2,1,1);
}

sub WikiShowPageIndexTitleSelect {
  my ($title,$select,$showcount,$group)=@_;
  my (@pages,$page,$cat,$cats,$count,%pinfo);
  my $showsource=RetParam('source',0);
  my $showheader=RetParam('header',1);

  PageIndexInit();
  foreach $page (keys %PageIndex) {
    if($group ne '') {
      if(!($page =~ m#^$group/#)) {
        next;
      }
    }
    if($WikiBase ne '') {
      if(!($page =~ m#^$WikiBase/#)) {
        next;
      }
    }
    $cats=$PageIndex{$page};
    if(($select eq '') || ($cats =~ m/(^|\W)$select(\W|$)/)) {
      push(@pages,$page);
    }
    if($showcount) {
      foreach $cat (split(' ',$cats)) {
        $pinfo{$cat}++;
      }
    }
  }
  @pages=ArraySort(@pages);
  if($showcount) {
    foreach $page (@pages) {
      $pinfo{$page}=" ($pinfo{$page})";
    }
  }
  my $text=PageListRetHtml('',$ScriptName,\@pages,\%pinfo,LiFound(),'',0,'',0,undef,0,$showheader,undef,undef,1);
  ShowTitleTextLinkSearch($title,$text,1,1);
}

sub WikiNetShowPageIndexTitleSelect {
  my ($title)=@_;
  my (@pages,$page,$cat,$cats,$count,%pinfo,%horder,%hlabel,%hlink);
  my ($fnam,$site,$script,%pindex,$hpage,$spage,$label,$lb1,$unicode);
  my $showheader=RetParam('header',1);

  WikiGroupInit();

  while( ($site,$script)=each (%GlobalSite) ) {
    if(StrCmpWikiGroup($site)) {
      next;
    }
    ($fnam,$unicode)=ScriptFileRetPathUnicode($script,"/pagelog");
    LogFileGetHash_Type($fnam,\%pindex);

    foreach $page (keys %pindex) {
      $hpage=$page;
      if($WikiUnicode!=$unicode) {
        StrUnicodeCvtUnicode($hpage,$unicode,$WikiUnicode);
      }
      $lb1=PageRetLabel($hpage);
      $spage="$hpage.$site";
      $label="$lb1 ($site)";
      $hlabel{$spage}=$label;
      $horder{$spage}="$hpage.$site";
      $hlink{$spage}=ScriptPageRefLabelClassCompleteRetLink($script,$page,'',$label,"body",1);
      push(@pages,$spage);
    }
  }
  my $text=PageListRetHtml('',$ScriptName,\@pages,\%pinfo,LiFound(),'',0,'',0,\%horder,0,$showheader,\%hlabel,\%hlink,0);
  ShowTitleTextLinkSearch($title,$text,1,1);
}

sub WikiShowWordIndexTitleSelect {
  my ($title,$select,$showcount)=@_;
  my (%links,$word,%words,$page,$part,@parts,$text,$nparts,$i,$start,%double);
  my $maxparts=RetParam('parts',3);
  my $count=RetParam('count',3);

  PageIndexInit();
  foreach $page (keys %PageIndex) {
    @parts=PageNameRetWords($page,0);
    $nparts=@parts;
    $start=$nparts-3;
    if($start<0) {
      $start=0;
    }
    %double=(); # word twice in a page
    for ($i=$start; $i<$nparts; $i++) {
      $part=$parts[$i];
      if(++$double{$part}==1) {
        $words{$part}++;
        $links{$part} .= PageClassRetLink($page,'body') . "   ";
      }
    }
  }
  foreach $word (sort keys %words) {
    if($words{$word}<$count) {
      next;
    }
    $text .= "$br<b>$word($words{$word})</b>$br$links{$word}$br";
  }
  $lb1=Lu("count >= %COUNT%|Vorkommen >= %COUNT%|compteur >= %COUNT%|cantidad >= %COUNT%");
  MessRepVar($lb1,"%COUNT%",$count);
  ShowTitleTextLinkSearch("$title ($lb1)",$text,1,1);
}

sub ShowIndexGroup {
  my ($id)=@_;
  my @pages=PageRetGroupList($id);
  my $text=PageListRetHtml('',$ScriptName,\@pages,undef,LiFound(),'',0,'',0,undef,0,0,undef,undef,1);
  ShowTitleTextLinkSearch(Lu("Index of page group|Index der Seitengruppe|Index du groupe de page|Índice de grupo de páginas"),$text,1,1);
}

sub ApRetAction {
  my ($action)=@_;
  if($action =~ m/\?/) {
    $action =~ s/^.*\?//;
  } else {
    $action = LuFirst($HomePage,$FrontPage);
  }
  $action =~ s/^keywords=//;
  return $action;
}

sub HashAddLogFileTsRange {
  my ($h_hash,$fnam,$action_flag,$ts1,$ts2)=@_;
  my ($line,%pars,$act,$action,$ts,$IN);
  my $zugriffe=0;

  local $/ ="\n";
  open($IN,"<$fnam") or die "Can't open $fnam: $!";

LOOP:
  while($line=<$IN>) {
    if($line =~ m/^#DONE2/) {
      %pars=split(/\|/,$line);

      $ts=$pars{'TS'};
      if($ts<$ts1 || $ts>$ts2) {
        next LOOP;
      }

      $zugriffe++;
      $action = ApRetAction($pars{'ACTION'});
      if($action_flag<1) {
        if($action =~ m/=/) {
          if($action =~ m/&id=($WikiPattern)/) {
            $action=$1;
          } else {
            $action="";
          }
        }
      }
      if($action ne "") {
        $$h_hash{$action}++;
      }
    }
  }
  close($IN);
  return $zugriffe;
}

sub FileRetLineCount {
  my ($fnam)=@_;
  my $count=0;
  my ($line,$IN);

  local $/ ="\n";
  open($IN,"<$fnam");
  while($line=<$IN>) {
    $count++;
  }
  close($IN);
  return $count;
}

sub TabAddLogFile {
  my ($a_tab,$fnam,$site,$ts1,$ts2,$strip,$select,$invert)=@_;
  my ($line,%pars,$ip,$action,$ts,$alter,$page,$user,$name,$add,$count,$IN);

  local $/ ="\n";
  open($IN,"<$fnam") or die "Can't open $fnam: $!";

LOOP:
  while($line=<$IN>) {
    chomp($line);
    $count++;
    if($line =~ m/^#DONE2/) {
      %pars=split(/\|/,$line);
      $ts=$pars{'TS'};
      if($ts<$ts1 || $ts2<$ts) {
        next LOOP;
      }
      $action = ApRetAction($pars{'ACTION'});
      if($action =~ m/action=edit/) { # attention: action&edit=special treatment
        $page='edit';
      } elsif($action =~ m/form_edit=1/) {
        $page='edit';
      } elsif($action =~ m/=/) {
        $page='action';
      } else {
        $page=$action; # page
        if($site ne "") {
          $page = "$site:$page";
        }
      }
      $ip=$pars{'IP'};
      $user=$pars{'USER'};
      $name=$pars{'NAME'};
      if($strip>0) {
        $ip =~ s/\d+$/xxx/;
      }
      $add=1;
      if($select ne '') {
        $add=$invert;
        if(($ip =~ m/$select/) || ($user =~ m/$select/) || ($name =~ m/$select/) || ($page =~ m/$select/)) {
           $add=1-$invert;
        }
      }
      if($add>0) {
        $ts =~ s/^9/09/; # correcting ts overflow in old files
        push(@$a_tab,"$ip|$ts|$user|$name|$page")
      }
    }
  }
  close($IN);
}

sub HashLogRetText {
  my ($h_hash)=@_;
  my ($text,$key);

  foreach $key (keys %$h_hash) {
     $text .= $key . " " . $$h_hash{$key} . $br;
  }
  return $text;
}

sub GlobalHashSessionRetUserPages {
  my ($global,@tab)=@_;
  my ($users,$pages,$i,$user,$ind,$page);
  my $tabn=$#tab;

  for($i=0; $i<=$tabn; $i+=2) {
    $page=$tab[$i];
    if($global>0) {
      $page=InterWikiPageRetLink($page);
    } else {
      if(($page ne 'action') && ($page ne 'edit')) {
        $page=PageClassRetLink($page,'body');
      }
    }
    $ind=$tab[$i+1];
    if($ind>0) {
      $pages .= "$page($ind) ";
    } else {
      if($users ne '') {
        $users .= ' ';
      }
      $user=$tab[$i];
      $user=~s/#$//;
      $users.=$user;
    }
  }
  return ($users, $pages);
}

sub CountsAddPages {
  my ($p_pcnt,$p_acnt,$p_ecnt,$p_single,$pages)=@_;
  my ($name,$n,$count);

  foreach (split(" ",$pages)) {
    ($name) = $_ =~ m/([^\(]+)/;
    ($n) = $_ =~ m/\((\d+)\)/;
    if($name eq 'edit') {
      $$p_ecnt+=$n;
    } elsif($name eq 'action') {
      $$p_acnt+=$n;
    } else {
      $$p_pcnt+=$n;
    }
    $count+=$n;
  }
  if($count==1) {
    $$p_single++;
  }
  return $count;
}

sub HclassCreate {
  my ($robots,$admins)=@_;
  my (%hclass,$key,$val,$c);

  foreach $key (keys %Context) {
    $val=$Context{$key};
    if($key =~ s/^stat\.type\.//) {
      $c=StrRetLower(substr($val,0,1));
      $hclass{$key}=$c;
    }
  }
  return %hclass;
}

sub NameTsRangeRetFiles {
  my ($fnam,$ts1,$ts2,$all)=@_;
  my (@files,$file,$i,$month);

  my $ls1=TimeRetLogSpec($ts1);
  my $ls2=TimeRetLogSpec($ts2);
  for($i=$ls1; $i<=$ls2; $i++) {
    $month=$i%100;
    if(1<=$month && $month<=12) {
      $file=sprintf("%s_%04d",$fnam,$i);
      if($all || FileExist($file)) {
        push(@files,$file);
      }
    }
  }
  return @files;
}

sub DaysRetParamTsRange {
  my ($days,$strip)=@_;
  my ($ts1,$ts2);

  $ts2=GetParamTimeSecHost('to',$^T);
  $ts1=$ts2 - $days*86400;
  if($strip>0) {
     $ts1=DateStripTime($ts1);
  }
  $ts1=GetParamTimeSecHost('from',$ts1);

  return ($ts1,$ts2);
}

sub HotspotHashesAddLogFile {
  my ($h_read,$h_write,$fnam,$ts1,$ts2)=@_;

  my ($line,%pars,$action,$ts,$alter,$re,$page,$rcount,$wcount,$inc,$winc,$IN);
  my $span=$ts2-$ts1;
  my $a2=$span/2;
  my $a4=$span/4;

  local $/ ="\n";
  open($IN,"<$fnam") or die "Can't open $fnam: $!";

LOOP:
  while($line=<$IN>) {
    if($line =~ m/^#DONE2/) {
      %pars=split(/\|/,$line);
      $ts=$pars{'TS'};
      if($ts<$ts1 || $ts2<$ts) {
        next LOOP;
      }
      $alter=$ts2-$ts;
      if($alter<$a4) {
        $inc=4; $winc=4;
      } elsif($alter<$a2) {
        $inc=2; $winc=2;
      } else {
        $inc=1; $winc=0;
      }

      $action = ApRetAction($pars{'ACTION'});
      $re=0; $page='';
      if($action =~ m/action=edit&/ ) {
        $re=2;
        ($page) = ($action =~ m/id=([^&]*)/ );
      } elsif($action =~ m/[^_]edit=/) {
        $re=2;
        ($page) = ($action =~ m/edit=([^&]*)/ );
      } elsif($action =~ m/=/) {
        #
      } else {
        $re=1;
        $page=$action;
      }
      if($re==1) {
        $$h_read{$page}+=$inc; $rcount++;
      } elsif($re==2) {
        $$h_write{$page}+=$winc; $wcount++;
      }
    }
  }
  close($IN);
  return ($rcount,$wcount);
}

sub WikiCreate {
  my $dir=RetParam('dir','');
  my $name=RetParam('name','');
  my $title='Create Wiki';
  my $source=RetParam('source','projekt/default');
  my ($text,$cmd,$out,$s,$fnam);
  my $sdir="$WebDir/$source";
  my $ddir="$WebDir/$dir";
  my $wlink=UrlLabelTypeRetLink("$ServerUrl/$dir/$ScriptName",$name);

  if(($dir eq '') or ($name eq '')) {
    $text=Lu('illegal parameters.|Illegale Parameter.|paramètres illégaux.|Parámetros ilegales.');
    goto do_mess;
  }
  if(!(-d $sdir)) {
    $text=Lu("source wiki doesn't exist.|Ursprungs-Wiki fehlt.|le source wiki n'existe pas.|El wiki origen no existe.");
    goto do_mess;
  }
  if(-d $ddir) {
    $text=Lu("%WIKINAME% already exists.|%WIKINAME% existiert bereits.|%WIKINAME% existe déjà.|%WIKINAME% ya existe.");
    MessRepVar($text,"%WIKINAME%",$wlink);
    goto do_mess;
  }
  $cmd="cp -R $sdir $ddir";
  $out .= CmdRetText($cmd);
  $cmd="rm $ddir/log_*";
  $out .= CmdRetText($cmd);
  $cmd="rm $ddir/rclog_*";
  $out .= CmdRetText($cmd);

  $fnam="$ddir/wiki.cfg";
  $s=FileRetStr($fnam);
  $s=~ s/DefaultWikiName/$name/g;
  FileSetStr($fnam,$s);

  $text=Lu('%WIKINAME% was created.|%WIKINAME% wurde angelegt.|%WIKINAME% était créé.|%WIKINAME% fue creado.');
  MessRepVar($text,"%WIKINAME%",$wlink);
  $text.= " $out";

  ShowTitleTextLinkSearch($title,$text,1,1);
  return;

do_mess:
  MessNormalTitleText($title,$text);
}

sub WikiBuildHotspotFile {
  my ($answer)=@_;
  my $days=RetParam('days',8);
  my ($ts1,$ts2)=DaysRetParamTsRange($days,0);
  my @files=NameTsRangeRetFiles($LogFile,$ts1,$ts2);
  my ($file,%rhash,%whash,@tab,$tabn,$i,$ii,$page,$count,$fnam,$rc,$wc,$wcount,$key,$fac);
  my ($OUT);

  foreach $file (@files) {
    ($rc,$wc)=HotspotHashesAddLogFile(\%rhash,\%whash,$file,$ts1,$ts2);
  }

  undef $rhash{LuFirst($HomePage,$FrontPage)};
  undef $rhash{'TopFünfzig'};
  undef $rhash{'RecentChanges'};
  undef $rhash{'TestSeite'};
  undef $rhash{'SuchSeite'};

  foreach $key (%rhash) {
    $fac=$Context{"hotspots.fac.$key"};
    if(defined $fac) {
      $rhash{$key} *= $fac;
    }
  }

  $fnam="$DataDir/hotspots";
  if(!open($OUT,">$fnam")) {
    die "File-Fehler (File=$fnam): $!";
  }
  print $OUT "$^T\n";

  @tab=HashRetTabSorted(\%rhash);
  $tabn=$#tab;
  for($i=0,$ii=1; $i<$tabn; $i+=2) {
    $page=shift(@tab);
    $count=shift(@tab);
    $wcount=$whash{$page};
    if($wcount<1) {
      $wcount=0;
    }
    if(PageExist($page)) {
      print $OUT "$page,$count,$wcount\n";
      $ii++;
    }
    if($ii>=50) {
      goto do_cont;
    }
  }
do_cont:
  close($OUT);

  if($answer) {
    $lb1=Lu("Hotspots-file built.|Hotspot-File erzeugt.|fichier Hotspots construit.| Fichero Hotspots creado.");
    $lb2=Lu("From %READCOUNT% read and %WRITECOUNT% write accesses.|Aus %READCOUNT% Lese- und %WRITECOUNT% Schreibzugriffen.|De %READCOUNT% lit et $wc écrit des accès.|De %READCOUNT% accesos para leer y %WRITECOUNT% accesos para escribir.");
    MessRepVar($lb2,"%READCOUNT%",$rc,"%WRITECOUNT%",$wc);
    ShowTitleTextLinkSearch($lb1,$lb2,1,1);
  }
}

sub IpRetParts {
  $_[0] =~ m/(((\d+)\.(\d+))\.(\d+))/;
  return ($1,$2,$3);
}

sub ShowReferer {
  my $days=RetParam('days',7);
  my $detail=RetParam('detail',0);
  my ($ts1,$ts2)=DaysRetParamTsRange($days,0);
  my $rfile="$DataDir/refer";
  my @files=NameTsRangeRetFiles($rfile,$ts1,$ts2);
  my ($file,$line,%hash,%thash,$text,@tab,$key,$count,$i,$target,$source,$text2,$ts,$tcount);
  my $dsep=$FS3;
  my $sep="!!";

  foreach $file (@files) {
    $text=FileRetStr($file);
LOOP_LINE:
    foreach $line (split(/\n/,$text)) {
      ($ts,$target,$source)=split(/\|/,$line,3);
      if($ts<$ts1 || $ts>$ts2) {
        next LOOP_LINE;
      }
      if($source =~ m/www.google/) {
        $source="google";
      }
      $hash{$source}++;
      if($detail>0) {
        $thash{"$source$dsep$target"}++;
      }
      $tcount++;
    }
  }
  $text=$br;

  $text.="
";
$text.="Count$sep Source\n";
 
for($i=0; $i<=$#tab; $i+=2) {
$key=$tab[$i];
$count=$tab[$i+1];
$text.="$count$sep$key\n";
}
$text.="$tcount$sep (Total)\n";
$text.="
$br0"; if($detail>0) { $text.="
";
$text.="Count$sep Source$sep Target\n";
 
for($i=0; $i<=$#tab; $i+=2) {
$key=$tab[$i];
($source,$target)=split(/$dsep/,$key,2);
$count=$tab[$i+1];
$text.="$count$sep$source$sep$target\n";
}
$text.="
$br0"; } ShowTitleTextLinkSearch(Lu("Referer"),TextWikiRetHtml($text),1,1); } sub ShowLogGlobal { my ($global)=@_; my (%hash,@tab,@tab2,$text,$i,$user,$name,$page,$count,$show); my ($ip_old,$ip,$ip3,$ts_old,$users,$pages,%hip,$nips,@files,$file); my ($ts,$ts_min,$ts_max,$ts_sum,$tsh,$pcnt,$acnt,$ecnt,$scnt,$single,@har,%names); my $strip=RetParam('strip',0); my $lines=RetParam('lines',1); my $more=RetParam('more',1); my $select=RetParam('select',''); my $filter=RetParam('filter',''); my $radef=(UserHasStatus($NeedStatusSuper)) ? 0 : 1; my $robots=RetParam('robots',$radef); my $admins=RetParam('admins',$radef); my $names=RetParam('names',''); my $singles=RetParam('singles','1'); my $sum=RetParam('sum',0); my $invert=0; my $ts_gap=RetParam('gap',20)*60; my ($script,$site,$log_file); my $wiki=RetParamWiki(); my %hclass=HclassCreate($robots,$admins); my $days=RetParam('days',1); my ($ts1,$ts2)=DaysRetParamTsRange($days,0); my $unicode; if($filter ne '') { $select=$filter; $invert=1; } if($global>0) { WikiGroupInit(); while( ($site,$script)=each(%GlobalSite) ) { if(StrCmpFilter($site,$wiki)) { next; } if($global==1 && StrCmpWikiGroup($site)) { next; } ($log_file,$unicode)=ScriptFileRetPathUnicode($script,"/log"); if($log_file ne '') { @files=NameTsRangeRetFiles($log_file,$ts1,$ts2); foreach $file (@files) { TabAddLogFile(\@tab,$file,$site,$ts1,$ts2,$strip,$select,$invert); } } } if(($global==2) && ($wiki =~ m#^/.*/$#)) { ($log_file,$unicode)=ScriptFileRetPathUnicode($ServerUrl.$wiki."wiki.cgi","/log"); $site=$wiki; if($log_file ne '') { @files=NameTsRangeRetFiles($log_file,$ts1,$ts2); foreach $file (@files) { TabAddLogFile(\@tab,$file,$site,$ts1,$ts2,$strip,$select,$invert); } } } } else { @files=NameTsRangeRetFiles($LogFile,$ts1,$ts2); foreach $file (@files) { TabAddLogFile(\@tab,$file,"",$ts1,$ts2,$strip,$select,$invert); } } @tab=sort(@tab); my $tabn=@tab; for($i=0; $i<$tabn; $i++) { ($ip,$ts,$user,$name,$page) = split(/\|/,$tab[$i]); if($i==0) { %hash=(); $count=0; $ip_old=$ip; $ts_old=$ts; $ts_min=$ts; } if(($ip ne $ip_old) || ($ts-$ts_old>$ts_gap)) { ($users,$pages) = GlobalHashSessionRetUserPages($global,%hash); push(@tab2,"$ts_min|$ts_max|$ip_old|$users|$pages"); %hash=(); $count=0; $ts_min=$ts; } $hash{$page}++; $hash{$user.'#'}='u'; $hash{$name.'#'}='n'; $ts_max=$ts; $count++; $ip_old=$ip; $ts_old=$ts; } if($count>0) { # FIXME: ($users,$pages) = GlobalHashSessionRetUserPages($global,%hash); push(@tab2,"$ts_min|$ts_max|$ip_old|$users|$pages"); } $text .= FormTableStart(); $lb1=LiUser(); $lb2=Lu("Activities|Aktivitäten|Activités|Actividades"); $text .= LineLsLsLmCol(Lu("Time|Zeitraum|Temps|Tiempo"),$lb1,$lb2,"#ccffcc"); @tab2=reverse sort(@tab2); $tabn=@tab2; for($i=0; $i<$tabn; $i++) { ($ts_min,$ts_max,$ip,$users,$pages)=split(/\|/,$tab2[$i]); $tsh=TimeSpanRetStrLog($ts_min,$ts_max); $ip =~ m/((\d+)\.(\d+)\.(\d+))/; $ip3 = $1; $nips= ($users ne '') ? $users : $ip3; $show=1; if($robots==0) { if($hclass{$ip} eq 'r') { $show=0; } if($hclass{$ip3} eq 'r') { $show=0; } } if($admins==0) { if($hclass{$users} eq 'a') { $show=0; } } if($show>0) { $ts_sum+=($ts_max-$ts_min+10); # avg assumption $hip{$nips}++; $count=CountsAddPages(\$pcnt,\$acnt,\$ecnt,\$single,$pages); $scnt++; if($lines>0) { if($singles==0 && $count==1) { # nop } else { $pages =~ s/\(1\)//g; $text .= LineLsLsLm($tsh,"$ip $users",$pages); } } } if($names) { foreach (split(' ',$users)) { $names{$_}++; } } } if($sum) { my @tab=keys %hip; my $nip=@tab; my $nip2; foreach (keys %hip) { if($hip{$_}>$more) { $nip2++; } } my $xcnt=$acnt+$ecnt+$pcnt; my $xps=($scnt>0) ? sprintf(" XPS=%.1lf SECPS=%.1f",$xcnt/$scnt,$ts_sum/$scnt) : ''; my $spx=($xcnt>0) ? sprintf(" SECPX=%.1f",$ts_sum/$xcnt) : ''; $text .= LineLsLsLmCol("Hsum=".&SecRetHhMm($ts_sum),"NIPs=$nip NIPmore=$nip2","Sessions=$scnt Singles=$single Pages=$pcnt Edits=$ecnt Actions=$acnt".$xps.$spx,"#bbbbbb"); } if($names) { @har=sort keys %names; my $ncount=@har; $text .= LineLsLsLmCol($n1,"NIPname=$ncount",join(' ',@har),"#bbbbbb"); } $text .= FormTableEnd(); $lb1=Lu('Sessions|Sitzungen|Sessions|Sesiones'); ShowTitleTextLinkSearch("$lb1 $wiki",$text,1,1); } sub StatAddLogFileTsRange { my ($h_stat,$h_name,$h_core,$h_rob,$h_vis,$fnam,$ts1,$ts2)=@_; my (%hstat,%hname,%hcore,%hrob,%hvis); my ($IN,$line,%pars,$tsh,$ts,$name,$ip,$ip3,$inc,$data,$fversion,$vok); my $robots=RetParam('robots',1); my $usecache=RetParam('usecache',1); my $fnam2="$fnam.cache"; my $version='1'; # support cache structure change my $exist=FileExist($fnam); my $exist2=FileExist($fnam2); if($exist2==0) { $usecache=0; } elsif($exist) { my $ftime=FileRetTime($fnam); my $ftime2=FileRetTime($fnam2); if($ftime2<$ftime) { # outdated if($^T-$ftime2>300) { # not new enough $usecache=0; } } } if($usecache==0) { goto do_buildcache; } # read cache $data=FileRetStr($fnam2); foreach $line (split(/\n/,$data)) { $tsh=KnowStrVarRetVal($line,'day'); $$h_stat{$tsh}+=KnowStrVarRetVal($line,'stat'); $$h_name{$tsh}+=KnowStrVarRetVal($line,'name'); $$h_core{$tsh}+=KnowStrVarRetVal($line,'core'); $$h_rob{$tsh}+=KnowStrVarRetVal($line,'rob'); $$h_vis{$tsh}+=KnowStrVarRetVal($line,'vis'); $fversion=KnowStrVarRetVal($line,'version'); if($fversion ne '') { if($fversion ne $version) { goto do_buildcache; } } } return; do_buildcache: if($exist==0) { # avoid delete cache on missing return; } local $/ ="\n"; open($IN,"<$fnam") or die "Can't open $fnam: $!"; while($line=<$IN>) { if($line =~ m/^#DONE2/) { %pars=split(/\|/,$line); $ts=$pars{'TS'}; if($ts>0) { # safety against multi-line log entries $tsh=TimeRetDaySort($ts); $inc=1; $name=$pars{'NAME'}; if($name ne '') { if($Context{"stat.type.$name"} eq 'admin') { $$h_core{$tsh}++; $hcore{$tsh}++; } else { $$h_name{$tsh}++; $hname{$tsh}++; } } else { $ip=$pars{'IP'}; $ip =~ m/((\d+)\.(\d+)\.(\d+))/; $ip3 = $1; if(($Context{"stat.type.$ip"} eq 'robot') || ($Context{"stat.type.$ip3"} eq 'robot')) { if($robots==0) { $inc=0; } $$h_rob{$tsh}+=$inc; $hrob{$tsh}+=$inc; } else { $$h_vis{$tsh}++; $hvis{$tsh}++; } } $$h_stat{$tsh}+=$inc; $hstat{$tsh}+=$inc; } } } close($IN); foreach $tsh (sort keys %hstat) { $data.="{day:$tsh}{stat:$hstat{$tsh}}{name:$hname{$tsh}}{core:$hcore{$tsh}}{rob:$hrob{$tsh}}{vis:$hvis{$tsh}}{version:$version}\n"; } FileSetStr($fnam2,$data); } sub StatCreatePlus { my ($global,$legend,$months,$days,$detail)=@_; my (%hash,%hname,%hcore,%hrob,%hvis,%htot,$tsm); my ($text,$script,$site,$log_file,$key,@keys,$img,$h,$bcol,$wday,@files,$file,$hscale,$imgw); my ($val,$anz,$anz1,$anz2,$anz3,$anz4,$anz5,@sar,%hsite,@colar,%hline,$gif,$ind,$leg); my $scale=RetParam('scale',$StatScale); my $strip=RetParam('strip',1); my $scalepix=RetParam('scalepix',$StatScalePix); my ($ts1,$ts2)=DaysRetParamTsRange($days,1); my %wd=(); my $wiki=RetParamWiki(); my $unicode; my @sctab=( '#003399', '#990000', '#66cc99', '#ff9900', '#006600', '#6699cc', '#ffcccc', '#cc66ff', '#999933', '#ff0000', '#99ccff', '#ffcc00', '#00cc33', '#336699', '#cc0033', '#cc99ff', '#663333', '#cc6633', '#0066ff', '#99ff99', '#cccc00', '#996600', '#ff99ff', '#99cccc', ); my $ncolar=@sctab; for($h=$ts1; $h<=$ts2+86400; $h+=86400) { $wd{&TimeRetDaySort($h)}=TimeRetWeekdayInd($h); } if($detail==2 || $detail==3) { foreach $gif (@sctab) { if(!($gif =~ /#(.)\1{5}/)) { $gif =~ s/^#/p_/; push(@colar,"/pixel/$gif.gif"); } } } if($global>0) { WikiGroupInit(); $ind=0; foreach $site (sort keys %GlobalSite) { $script=$GlobalSite{$site}; if(StrCmpFilter($site,$wiki)) { next; } if($global==1 && StrCmpWikiGroup($site)) { next; } ($log_file,$unicode)=ScriptFileRetPathUnicode($script,"/log"); if($log_file ne '') { @files=NameTsRangeRetFiles($log_file,$ts1,$ts2,1); foreach $file (@files) { StatAddLogFileTsRange(\%hash,\%hname,\%hcore,\%hrob,\%hvis,$file,$ts1,$ts2); } if($detail==2 || $detail==3) { push(@sar,$site); $gif=$colar[$#sar % $ncolar]; $leg .= ScriptPageRefLabelClassCompleteRetLink($script,'RecentChanges','',$site,'body',1); $leg .= ": " . ImageRetHtmlBar($gif,24,12) . "  "; if(++$ind>=5) { $leg.=$br0; $ind=0; } $leg .= "\n"; foreach $key (keys %hash) { $htot{$key}+=$hash{$key}; $hsite{$key}.="$site|$hash{$key}|"; $hash{$key}=0; } } } } %hash=%htot; if($global==2) { if($wiki =~ m#^/.*/$#) { ($log_file,$unicode)=ScriptFileRetPathUnicode($ServerUrl.$wiki."wiki.cgi","/log"); if($log_file ne '') { @files=NameTsRangeRetFiles($log_file,$ts1,$ts2,1); foreach $file (@files) { StatAddLogFileTsRange(\%hash,\%hname,\%hcore,\%hrob,\%hvis,$file,$ts1,$ts2); } } } } } else { @files=NameTsRangeRetFiles($LogFile,$ts1,$ts2,1); foreach $file (@files) { StatAddLogFileTsRange(\%hash,\%hname,\%hcore,\%hrob,\%hvis,$file,$ts1,$ts2); } } my $tsh1=TimeRetDaySort($ts1); my $tsh2=TimeRetDaySort($ts2); foreach (keys %hash) { if($_ lt $tsh1) { delete $hash{$_}; } if($_ gt $tsh2) { delete $hash{$_}; } } if($months) { foreach (keys %hash) { $tsm=substr($_,0,7); $hash{$tsm}+=$hash{$_}; delete $hash{$_}; $hname{$tsm}+=$hname{$_}; delete $hname{$_}; $hcore{$tsm}+=$hcore{$_}; delete $hcore{$_}; $hrob{$tsm}+=$hrob{$_}; delete $hrob{$_}; $hvis{$tsm}+=$hvis{$_}; delete $hvis{$_}; } } if($scalepix>10) { my $max=HashRetMax(\%hash); $scale=$max*1.0/$scalepix; } if($scale==0) { $scale=1; } @keys=sort keys %hash; if($strip) { pop(@keys); } $text.=FormTableStart(); foreach $key (@keys) { $wday=$wd{$key}; if($wday==0 || $wday eq 6) { $bcol=$FormBcolAlt; } else { $bcol=$FormBcol; } $img=''; $imgw=''; if($detail==2 || $detail==3) { $val=$hsite{$key}; %hline=split(/\|/,$val); $ind=0; $anz=0; foreach $site (@sar) { $val=$hline{$site}; $gif=$colar[$ind % $ncolar]; $imgw.=ImageRetHtmlBar($gif,int(1+$val/$scale),12); $ind++; $anz+=$val; } } if($detail!=2) { $anz=$hash{$key}; $anz2=$hname{$key}; $anz3=$hcore{$key}; $anz4=$hrob{$key}; $anz1=$hvis{$key}; $hscale=$scale; if($detail==3) { $hscale=$anz/75; } if($hscale==0) { $hscale=1; } if($detail>0 && $hscale>0) { if($anz3>0) { $img.=ImageRetHtmlBar('/pixel/p1gruen.gif',int(1+$anz3/$hscale),12); } if($anz2>0) { $img.=ImageRetHtmlBar('/pixel/p1blau.gif',int(1+$anz2/$hscale),12); } } if($detail==0) { if($anz>0) { $img.=ImageRetHtmlBar('/pixel/p1rot.gif',int(1+($anz)/$hscale),12); } } else { if($anz1>0) { $img.=ImageRetHtmlBar('/pixel/p1rot.gif',int(1+($anz1)/$hscale),12); } } if($detail>0 && $hscale>0) { if($anz4>0) { $img.=ImageRetHtmlBar('/pixel/p1pink.gif',int(1+$anz4/$hscale),12); } } if($img eq '') { $img=$n1; } } if($detail==3) { $text .= LineLsRsLsLmCol($key,$anz,$img,$imgw,$bcol); } elsif($detail==2) { $text .= LineLsRsLmCol($key,$anz,$imgw,$bcol); } else { $text .= LineLsRsLmCol($key,$anz,$img,$bcol); } } if($legend>0) { $lb1=Lu('Legend|Legende|Légende|Leyenda'); if($detail==1) { $leg=ImageRetHtmlBar('/pixel/p1gruen.gif',18,12)." admins".$n3; $leg.=ImageRetHtmlBar('/pixel/p1blau.gif',18,12)." users".$n3; $leg.=ImageRetHtmlBar('/pixel/p1rot.gif',18,12)." visitors".$n3; $leg.=ImageRetHtmlBar('/pixel/p1pink.gif',18,12)." robots".$n3; $text.=LineLsRsLmCol($lb1,$n1,"\n".$leg,'ivory'); } elsif($detail==2) { $text.=LineLsRsLmCol($lb1,$n1,"\n".$leg,'ivory'); } elsif($detail==3) { $text.=LineLsRsLsLmCol($lb1,$n1,$n1,"\n".$leg,'ivory'); } elsif($detail==0) { $leg=ImageRetHtmlBar('/pixel/p1rot.gif',18,12)." access (hits)".$n3; $text.=LineLsRsLmCol($lb1,$n1,"\n".$leg,'ivory'); } } $text .= FormTableEnd(); return $text; } sub ShowStatGlobal { my ($global)=@_; my $wiki=RetParamWiki(); my $legend=RetParam('legend',1); my $months=RetParam('months',0); my $detail=RetParam('detail',0); my $days=RetParam('days',21); my $text=StatCreatePlus($global,$legend,$months,$days,$detail); $lb1=Lu("Statistics|Statistik|Statistiques|Estadística"); ShowTitleTextLinkSearch("$lb1 $wiki",$text,1,1); }