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

 

#!/usr/bin/perl
# ProWiki Vs. 2.0.046 (free software under GPL) (C) 2000-2006 Helmut Leitner
# Based on UseModWiki version 0.88 (October 7, 2000) (free software under GPL) (C) 2000 Clifford A. Adams
# Based on the GPLed AtisWiki 0.3 (C) 1998 Markus Denker
# Based on the LGPLed CVWiki CVS-patches (C) 1997 Peter Merel
# Based on The Original WikiWikiWeb (C) Ward Cunningham

$| = 1;    # Do not buffer output
undef $/;   # Read complete files
use strict;
no strict 'refs';

use CGI;
use CGI::Carp qw(fatalsToBrowser);
$CGI::POST_MAX=1024*1024*10;  # max post size
# $CGI::DISABLE_UPLOADS=1;  # no uploads
use Socket; # needed for host lookups

#===some perl notes
# local $/ ="\n";   # don't slurp files in this sub
# (?:...)   # regex: cluster only, not captured

#===special character repository
# äöüÄÖÜß ñíé

#===some fixes needed
# FIXME: check against infinite recursion on "Insert"
# FIXME: make DictLocks clean

use vars qw(
  $ActionCur
  $ActionPar
  %ActionHash
  $AddLetter
  $AdminNameList
  $AllowEdit
  $AllowPageType
  @AlsNodeTab
  @AlsTab
  $AlsNodeList
  $AltWordColor
  %AltWordSet
  $AltWordSource
  $AnyLetter
  $AnyLetterList
  $ArchiveMode
  $ArchiveModeThreeDelta
  $ArchiveModeThreeSec
  $ArchiveRevert
  $AutoExtLinkEmptyTarget
  $AutoFolders
  $AutoLanguageFlag
  $AutoLinkStrategies
  @AutoNewPages
  $AutoNewSelect
  $AutoNewStrategies
  $AutoSignature
  $AutoSubPageList
  $BackgroundUrl
  $BarName
  %BaseWordSet
  $BeggingColor
  $BeggingFront
  $BeggingUnderline
  $BodyTags
  $BodyTarget
  $ButtonBrowserDir
  $CategoriesListPages
  $CdmlDocumentDefaults
  $CdmlQuoteDefaults
  $CdmlTocDefaults
  $CheckEditLimit
  $ClientIP
  %CodeRetLanguage
  $CollisionDetection
  %ColorTabDe
  %ColorTabEn
  %ColorTabFr
  @ConfigFiles
  $CommonUploadDir
  $ConfigDir
  %Context
  %ContextCache
  $ContextId
  $ContextLevel
  $ContextPageName
  $ContextVarLocked
  $CookieID
  $CookieName
  $CookieSession
  $CrumbsLogFileSizeLimit
  @CrumbsLines
  @CrumbsPages
  %CrumbsUrl
  $CrumbsLogFlag
  $CrumbsInitFlag
  $CrumbsShowLimit
  $DataDir
  $DateFormatLong
  $Def_editcols
  $Def_editrows
  $Def_tzoffset
  $DefaultRights
  $DeletePageLimit
  $DocumentRoot
  $Domain
  $DomainBase
  $DomainGate
  $DomainGateAddAlways
  $DomainGateFlag
  $DomainGateTransportsLogin
  $DomainGateInput
  $DomainGateStatus
  $DomainSubDir
  $DomainUrl
  $EditByVisitorPage
  $EmailAddressWebmaster
  $ErrorStr
  $ExecutablesDir
  $ExpirePage
  $FS
  $FS1
  $FS2
  $FS3
  $FlagArchive
  $FlagDiff
  $FlagEdit
  $FlagFolders
  $FlagForum
  $FlagHelp
  $FlagIndex
  $FlagMembers
  $FlagMenuFrame
  $FlagPrefs
  $FlagProjects
  $FlagRecentChanges
  $FlagSearch
  $FlagSpellCheck
  $FlagFrontPage
  $FlagTestPage
  $FontDecSuppress
  $FootnoteCount
  @FootnoteTab
  $FormBcol
  $FormBcolAlt
  %FormData
  $FormEditId
  $FormFontDec
  $FormLinecolor
  $FormLinewidth
  $FormPadding
  $FormTextbackground
  $FormTitlebackground
  $FormUserQuota
  $FormUserStatus
  $FormWidth
  $FrageBogenFlag
  $FrageCount
  $FreeLetter
  $FreeLinks
  $FreePattern
  $FreeUsernames
  $FrontPage
  %GetCookie
  $GlobalDir
  %GlobalSite
  $GlobalSiteInitFlag
  %GlobalUserData
  $GnuplotExt
  $GrafletDir
  %GrafletFiles
  $HeadFolders
  $HeaderCount
  $HeaderNoCache
  $HeaderPattern
  $HomePage
  $HotspotDelta
  $HtmlDir
  @HtmlPairs
  @HtmlSingle
  $HtmlTags
  $ISBNPattern
  $ImageUrl
  $ImageExtensions
  $IncomingPageMissingTryLeafLink
  $IndentLimit
  $IndexAutoTalk
  $IndexAutoTalkIcon
  %InsertHash
  %InterWeb
  %InterWebSelf
  $InterWebInitFlag
  $InterWebNamePattern
  $InterWebPattern
  $InterWikiName
  $IsbnLabel2
  $IsbnLabel3
  $IsbnLink1
  $IsbnLink2
  $IsbnLink3
  $IsbnTarget
  $LabelArchive
  $LabelDiff
  $LabelEdit
  $LabelFolders
  $LabelForum
  $LabelFrontPage
  $LabelHelp
  $LabelIndex
  $LabelMembers
  $LabelPrefs
  $LabelPrint
  $LabelProjects
  $LabelSearch
  $LabelSpellCheck
  $LabelTestPage
  %LanguageRetCode
  @LanguageCount
  %LeafHash
  $LinkBarCount
  $LinkBarProjects
  $LinkBarSep
  $LinkBarSpellCheck
  $LinkSuppressCharacter
  $LinkTypeFront
  $LinkTypeIconStyle
  $LinkTypeIconDefault
  $LinkTypeIconRepSite
  $LinkTypeIcons
  $LinkRewrite
  $LinkRewriteRedirection
  @ListStack
  $LinkSuppressFilter
  $LockDir
  $LogFile
  $LogoUrl
  $LowerLetter
  $MailtoMangle
  $MatchPos
  $MetaTagAdd
  $MultiLinking
  $NameForum
  $NameHelp
  $NameIndex
  $NameRecentChanges
  $NameSearch
  $NameTestSeite
  $NameUndefinable
  %NeChrTab
  $NearLinking
  $NearLinkingWords
  $NeedStatusAdmin
  $NeedStatusAuthor
  $NeedStatusEdit
  $NeedStatusEditor
  $NeedStatusLogin
  $NeedStatusOwner
  $NeedStatusPageDel
  $NeedStatusPrefs
  $NeedStatusRead
  $NeedStatusSearch
  $NeedStatusSuper
  $NeedStatusUpload
  $NeedStatusUser
  $NewSubpageSyntax
  $NoCookieBlocking
  $NoCookieLabeledLinksChangeRangeAllowed
  $NoCookieLinksChangeRangeAllowed
  $NoCookieSizeChangeRangeAllowed
  $NoLinkSep
  $NoUnderlineLetter
  $NonEnglish
  $NotificationSystem
  $PageAutoTalk
  $PageAutoTalkIcon
  $PageBar
  %PageContext
  $PageContextFlag
  $PageCur
  $PageCurEditFlag
  $PageDir
  $PageFolders
  $PageGran
  $PageIncoming
  %PageIndex
  $PageIndexInitFlag
  $PageIsSmallFlag
  $PageLabelReduction
  $PageLeaf
  $PageLevel
  $PageMembers
  $PageParent
  $PageProjects
  $PageReferenced
  $PageSearch
  $PageTestPage
  $PageTextWiki
  $PageTitleComment
  $PageTitleStrip
  $PageTop
  $PageType
  $PageUndefinable
  $PagenameReduction
  $PagenameLengthLimit
  $PasswordCharMin
  $PasswordDigitMin
  $PlusAllowed
  $PrefsShowFunctions
  %CdmlHash
  $ProgrammerName
  $PromoteUnderline
  $ProtId
  $ProWikiVersion
  $QuizColor
  $RFCPattern
  $RawHtml
  $RcDateHeader
  $RcDateInline
  @RcDays
  $RcDefault
  $RcFile
  $RcSuppress
  $RcTop
  $RcTrim
  $RcUseLoginName
  $RedirectToProtocol
  $Referer
  $RefererFilter
  $RelTag
  $RenderUsername
  $RequestProtocol
  $RobotIpList
  $RssDescription
  $RssFlag
  $RtfBodySize
  $RtfBodyWidth
  %RtfColorHash
  @RtfColorTab
  $RtfMarginBottom
  $RtfMarginLeft
  $RtfMarginRight
  $RtfMarginTop
  $RtfMode
  $RtfPaperHeight
  $RtfPaperWidth
  %SaveUrl
  $SaveUrlIndex
  %SaveUrlNum
  $SaveUrlNumIndex
  $ScriptFilename
  $ScriptUrlPath
  $ScriptCode
  $ScriptCodeInit
  $ScriptName
  $ScriptUrl
  $SearchTextFolders
  $SearchTextMembers
  $SearchTextProjects
  $SectionEditing
  $SendMail
  $SepLetter
  $ServerDomain
  $ServerUrl
  $SessionCheck
  %SessionCookie
  %SessionCookieInput
  $SessionUserName
  %PrefsCookie
  $ShortHeader
  $ShowEditHelp
  $ShowEditHelpText
  $ShowHiddenLinks
  $ShowLinksFunction
  $ShowRTF
  $ShowSeparatePageTitleStem
  $ShowUploadLite
  $SimpleLinks
  $SisterExportFlag
  $SisterNet
  %SisterNetHash
  $SisterNetInitFlag
  $SisterNetDisplay
  $SiteBase
  $SiteName
  $SlurpBlocking
  $Sort1
  $Sort2
  $SortOrderInitFlag
  $SpaceReplacement
  $StatScale
  $StatScalePix
  %StatusInfo
  $StatusInfoChange
  @StatusTabDe
  @StatusTabEn
  $StoreAnswer
  $SubWiki
  %SymbolNames
  $TableDistance
  $TableSeparator
  $TableTextbackground
  $TableTitlebackground
  $TemplateBody
  $TemplateBodyWidth
  $TemplateDefault
  $TemplateDir
  $TemplateEdit
  $TemplateError
  $TemplateFile
  $TemplateInsertPassList
  $TemplateName
  $TemplatePrint
  $TemplateSimpleDownload
  $TemplateSimpleView
  $TemplateSimpleTest
  $TemplateWorknetsBody
  $TemplateWorknetsComments
  $TemplateWorknetsFormEdit
  $TemplateWorknetsFreeEdit
  $TemplateWorknetsFull
  $TemplateWorknetsHead
  $TemplateWorknetsMenu
  $TestVariable
  $TexExt
  $TexHeight
  $TexScale
  $TexWidth
  $TimeSummer
  $TimeZoneOffset
  $TitleColor
  $TitleFontColor
  $TitlePadding
  $TocAbstandDef
  $TocFlag
  %TocHash
  $TocMagic
  %TocParsHash
  $TocTopFlag
  $TrailName
  $TrailPage
  $TrailSection
  %TranslationHash
  $TranslationSource
  $TrustedFlag
  $TsCreatePage
  $UnderlineAutoLink
  $UploadBaseDir
  %UploadExtTab
  $UploadPattern
  $UploadUrl
  $UploadUserQuotaDefault
  $UploadUserQuotaMax
  $UploadWikiQuota
  $UpperLetter
  $UrlPattern
  $UrlProtocols
  $UrlProtocolsUsingTarget
  $UseCookieID
  $UseHtmlTitle
  $UsePageContext
  $UsePx
  $UseSmallCorrection
  $UseSmiley
  $UseSortOrder
  $UseSubpage
  %UserPrefs
  $UserDir
  $UserHost
  $UserIP
  $UserName
  $UserPref
  $UserStatus
  $UserStatusOrigin
  $UsernamePattern
  %VarLockedHash
  @Vida
  %VidaAtomHash
  $VidaAutoIntro
  $VidaCaching
  $VidaDebug
  @VidaError
  $VidaEvalPages
  $VidaExportFlag
  %VidaHashHash
  $VidaInit
  %VidaInvalid
  $VidaLevel
  $VidaOp
  $VidaRecur
  $VidaRefererFlag
  $VidaVarFilter
  $VidaVarSelect
  %VidaUsed
  $WebDir
  $WhiteSpaceType
  $WhiteSpaceWidth
  $WikiAutoLink
  $WikiAutoEditLink
  $WikiBase
  @WikiBaseChain
  %WikiBaseType
  $WikiCharset
  $WikiCluster
  $WikiCopyright
  %WikiGroup
  $WikiLanguage
  $WikiLanguageCode
  $WikiLanguageLast
  $WikiLanguageName
  $WikiLanguageParam
  $WikiLanguageN
  %WikiLanguages
  $WikiName
  $WikiNetExportFlag
  $WikiParams
  $WikiPattern
  $WikiPatternRef
  $WikiUnicode
  $WordAutoLink
  $WordAutoLower
  $WordAutoStrip
  @WordAutoStripArray
  %WordHash
  $WordHashInitFlag
  $WordPattern
  $WordPatternRef
  %WordRetLanguage
  $YesList
  $br
  $br0
  $cgi
  %dict_de
  %dict_en
  %dict_fw
  %dict_xx
  $h
  $lb1
  $lb2
  $lb3
  $n1
  $n2
  $n3
  $wls
);

$TestVariable = "Labas";

$cgi = new CGI;

$ProWikiVersion="2.0.046";
$CookieSession="ProWikiSession"; # tmp cookie for login

#===automatic configuration from environment
$Domain=$ENV{HTTP_HOST}; # becomes www.wikiservice.at or 213.133.103.173 or tolkienwiki.org
$DomainUrl="http://$Domain"; # external access
$UploadUrl="$DomainUrl/upload"; # used in html pages
$ImageUrl="$DomainUrl/image"; # used in html pages
$Referer=$ENV{HTTP_REFERER};
$DocumentRoot=$ENV{DOCUMENT_ROOT};
$ClientIP=$ENV{REMOTE_ADDR}; # basically the client IP
$RequestProtocol=RequestRetProtocol();

#===for all servers, variables go to standards
sub GlobalCfgAfter {
  # currently no processing needed
}

#===for all wikis on a server, should be defined in server.cfg
$ServerDomain="www.xyz.org"; # main domain
$GlobalDir="/usr/home/wikise/wiki"; # administrative information
$WebDir="/usr/home/wikise/website"; # htdocs directory or equivalent
$ExecutablesDir="/usr/home/wikise/bin"; # path for calling diff, rcs ...
$EmailAddressWebmaster='webmaster@wikiserver.org'; # for error messages
$SendMail="/usr/sbin/sendmail"; # absolute path to sendmail executable
$SlurpBlocking=0; # blocking/unblocking high access rates, cron-script cooperation
$NotificationSystem=0; # Email notification, cron-script cooperation
$ProgrammerName="DefineInServerCfg"; # for special debug output

sub ServerCfgAfter {
  $ServerUrl="http://$ServerDomain";
  $UploadBaseDir="$WebDir/upload";
  $TemplateFile="$WebDir/image/classic_template.txt";
  $TemplatePrint="$WebDir/image/print_template.txt";
  $TemplateBody="$WebDir/image/body_template.txt";
  $TemplateDefault="$WebDir/image/default_template.txt";
  $TemplateError="$WebDir/image/error_template.txt";
  $TemplateSimpleView="$WebDir/image/simple_view_template.txt";
  $TemplateSimpleTest="$WebDir/image/simple_test_template.txt";
  $TemplateSimpleDownload="$WebDir/image/simple_download_template.txt";
  $TemplateWorknetsBody="$WebDir/software/template/worknets_body_template.txt";
  $TemplateWorknetsComments="$WebDir/software/template/worknets_comments_template.txt";
  $TemplateWorknetsFormEdit="$WebDir/software/template/worknets_formedit_template.txt";
  $TemplateWorknetsFreeEdit="$WebDir/software/template/worknets_freeedit_template.txt";
  $TemplateWorknetsFull="$WebDir/software/template/worknets_full_template.txt";
  $TemplateWorknetsHead="$WebDir/software/template/worknets_head_template.txt";
  $TemplateWorknetsMenu="$WebDir/software/template/worknets_menu_template.txt";
  $ENV{PATH}=$ExecutablesDir; # path used to find "diff"
  $DataDir=$ConfigDir; # main wiki data directory
}

#===wiki setup parameters (must be set in wiki.cfg)
$SiteName="Wiki";   # Name of site (used for titles)
$CookieName="Wiki";   # Name for this wiki (for multi-wiki sites)
$DomainSubDir=""; # if domain is defined, relative to server dir
$UseCookieID=0; # add cookie # to IP for identification
$WikiUnicode=0;
$WikiCharset="iso-8859-1"; # don't set this directly

sub WikiCfgAfter {
  $LockDir="$DataDir/lock";
  $HtmlDir="$DataDir/html";
  $PageDir="$DataDir/page";

  $RcFile="$DataDir/rclog";
  $LogFile="$DataDir/log";

  if($UserDir eq '') {
    $UserDir = "$DataDir/user";
  }
  if($WikiUnicode) {
    $WikiCharset="utf-8";
  }
}

$ButtonBrowserDir="/vorlagen/";
$PageUndefinable="ExampleOfAnUndefinedPage|BeispielEinerUndefiniertenSeite|ExempleDePageNonDéfinie|EjemploDeUnaPáginaIndefinida";
$NameUndefinable=''; # alias
$NoLinkSep="Š"; # alt-0166 FIXME: not working with utf-8
$IndentLimit=20; # Maximum depth of nested lists
$TimeSummer= -8; # offset in hours
$Def_tzoffset=8;
$CheckEditLimit=0; # no check
$WhiteSpaceType=0;
$WhiteSpaceWidth=10;
$WikiLanguage=1;
$WikiLanguageLast=999;
$TranslationSource="Admin/Translations/TranslationMap_{lang}";
$UseSortOrder=0;
$RcSuppress=0;
$CollisionDetection=1;
$DomainGate=0;

#===spam defense parameters
$NoCookieBlocking=1;
$NoCookieLabeledLinksChangeRangeAllowed="0;0";
$NoCookieLinksChangeRangeAllowed="0;0";
$NoCookieSizeChangeRangeAllowed="-5;5000";
$MailtoMangle=1;


#===wiki config parameters (typically)
$TemplateInsertPassList="Insert";
$TemplateName=""; # prefix für icons
$FrontPage="FrontPage|StartSeite|PageAccueil|PáginaDelTítulo";
$HomePage=''; # alias for FrontPage
$LogoUrl="";
$BackgroundUrl="";
$BodyTags="";
$CdmlQuoteDefaults='';
$CdmlDocumentDefaults='';
$CdmlTocDefaults='';
$UseSubpage=0;
$UseSmiley=0;
$ArchiveMode=3; $ArchiveModeThreeSec=4*3600; $ArchiveModeThreeDelta=1000;
$RssFlag=1;
$RawHtml=0;  # 1=allow <HTML> tag, 0=no raw HTML in pages
$HtmlTags=0;  # 1 = "unsafe" HTML tags, 0 = only minimal tags
$SimpleLinks=0;  # 1=only letters, 0=allow _ and numbers
$NonEnglish=1;  # 1=foreign chars allowed, 0=only A-Za-z chars
$FreeLinks=0;
$WordAutoLink=0;
$WikiAutoLink=1;
$WikiAutoEditLink=1;
$AutoSignature=1;
$AutoLinkStrategies='T';
$AutoNewStrategies='T';
@AlsTab=("T");
$HeaderNoCache=0;
$TitleColor="#ccccff";
$TitlePadding=2;
$QuizColor='#ccccff';
$TitleFontColor="#000000";
$TableTitlebackground="#9999ff";
$TableTextbackground="#eeeeee";
$TableSeparator=",";
$FormBcol="#eeeeee";
$FormBcolAlt="#cccccc";
$FormLinecolor="#ffffff";
$FormLinewidth=1;
$FormPadding=3;
$FormTextbackground="#e2e2e2";
$FormTitlebackground="#ccffcc";
$FormWidth="90%";
$LinkBarSep=" | ";
$StatScale=3;
$StatScalePix=500;
$BeggingFront=0;
$BeggingUnderline=0;
$FlagFrontPage=1;
$FlagRecentChanges=1;
$FlagTestPage=1;
$FlagForum=0;
$FlagMembers=1;
$FlagFolders=1;
$FlagProjects=1;
$FlagIndex=1;
$FlagHelp=0;
$CategoriesListPages=1;
$ShowLinksFunction=1;

$DateFormatLong="%MONTH% %DAY%, %YEAR%|%DAY%. %MONTH% %YEAR%|%DAY% %MONTH%, %YEAR%|%DAY% de %MONTH% de %YEAR%";

$NameRecentChanges="RecentChanges|AktuelleBeiträge|DernièresModifs|CambiosRecientes";
$PageTestPage="SandBox|TestSeite|BacASable|CuadroDeArena";
$LabelTestPage="SandBox|TestSeite|BacASable|CuadroDeArena";
$NameForum="Forum|Forum|Forum|Foro";
$LabelForum="Forum|Forum|Forum|Foro";
$LabelMembers="Members|Teilnehmer|Membres|Miembros";
$LabelPrint='Print|zum Drucken|Imprimer|Imprimir';
$PageMembers="FolderMembers|KategorieHomePage|DossierMembres|CategoríaMiembros";
$PageFolders="FolderFolders|KategorieKategorie|DossierDossiers|CategoríaCategorías";
$PageProjects="FolderProjects|KategorieProjekt|DossierProjets|CategoríaProyectos";
$HeadFolders="Folder|Kategorie|Dossier|Categoría";
$LabelFolders="Folders|Kategorien|Dossiers|Categorías";
$LabelProjects="Projects|Projekte|Projets|Proyectos";
$LabelIndex="Index|Index|Index|Índice";
$NameIndex=''; # alias
$NameHelp="Help|Hilfe|Aide|Ayuda";
$LabelHelp="Help|Hilfe|Aide|Ayuda";
$FlagSpellCheck=0;
$LabelSpellCheck="SpChk|RSK|VérOrth"; # FIXME: es
$LinkBarSpellCheck=0;
$FlagSearch=0;
$NameSearch="SearchPage|SuchSeite|Chercher|Buscar";
$LabelSearch="Search|Suchen|Chercher|Buscar";
$FlagDiff=0;
$LabelDiff="Difference|Differenz|Différence|Diferencia";
$FlagPrefs=1;
$LabelPrefs="Preferences|Einstellungen|Préférences|Preferencias";
$FlagArchive=3;
$LabelArchive="Archive|Archiv|Archives|Archivo";
$FlagEdit=1; $AllowEdit=1;
$LabelEdit="Edit|Ändern|Editer|Editar";

$NeedStatusRead="";
$NeedStatusEdit="";
$NeedStatusSearch="";
$NeedStatusPrefs="";
$NeedStatusLogin="";
$NeedStatusUpload="Login";

$NeedStatusUser="User";
$NeedStatusAdmin="Admin";
$NeedStatusAuthor="Author";
$NeedStatusPageDel="Admin";
$NeedStatusOwner="Owner";
$NeedStatusSuper="Supervisor";
$NeedStatusEditor="Editor";

$LinkTypeIconStyle="vertical-align: -4px;";
$PagenameLengthLimit=120;
$DefaultRights="";
$ShortHeader=1;
$HeaderPattern="(\\=+)\\s*([^\\n]+?)\\s*(\\=*)\\s*";
$ShowEditHelp=1;
$AutoExtLinkEmptyTarget=0;
$HotspotDelta=1200;
$IsbnTarget='isbn';
$GnuplotExt='gif';
$TexExt='gif';
$TexWidth=6.0;
$TexHeight=1.5;
$TexScale=0.5;
$PasswordCharMin=6;
$PasswordDigitMin=2;
$SpaceReplacement="__";
$SectionEditing=1;

#===wiki internal parameters (rarely changed)
@RcDays=qw(1 2 3 7 14 30);
$RcDefault=30;
$RcTop=1; # 1=recent on top
$RcTrim=1; # rc-Anzeige 0=alle Änderungen 1=je Autor 2=je Dokument
$RcDateHeader=1;
$RcDateInline=0;
$Def_editcols=65;
$Def_editrows=20;
$DeletePageLimit=64;
$TsCreatePage=943410730;
$VidaCaching=0;
$VidaExportFlag=0;
$VidaOp=':=';
$VidaAutoIntro='';

#===wiki internal variables
$UserStatus="Visitor";
$UserStatusOrigin="Script";
$SiteBase="";  # complete URL for <BASE> header
$PrefsShowFunctions=1;
$ProtId="0815";

$FrageCount=0;
$FrageBogenFlag=0;
$PageCur="";
$FormUserStatus="";
$FormUserQuota="";

$ContextPageName='';
%Context=();

%StatusInfo=( # FIXME: es
  "Nobody"       =>"999 en",
  "Niemand"      =>"999 de",
  "Supervisor"   =>"800 en de",
  "Superviseur"  =>"800 fr",
  "Owner"        =>"700 en",
  "Eigentümer"   =>"700 de",
  "Propriétaire" =>"700 fr",
  "Admin"        =>"600 en",
  "Administrator"=>"600 de",
  "Admistrateur" =>"600 fr",
  "Redakteur"    =>"550 de",
  "Editor"       =>"550 en",
  "Author"       =>"500 en",
  "Autor"        =>"500 de",
  "Auteur"       =>"500 fr",
  "Reader"       =>"400 en",
  "Leser"        =>"400 de",
  "Lecteur"      =>"400 fr",
  "Member"       =>"300 en",
  "Mitglied"     =>"300 de",
  "Membre"       =>"300 fr",
  "Login"        =>"250 en de",
  "Identifiant"  =>"250 fr",
  "User"         =>"200 en",
  "Benutzer"     =>"200 de",
  "Utilisateur"  =>"200 fr",
  "Surfer"       =>"100 en de",
  "Visitor"      =>"100 en de",
  "Visiteur"     =>"100 fr",
  "Robot"        =>"050 en de fr xx"
);

# can't be redefined after wiki.cfg
%VarLockedHash=(
  'CookieName' => 'n',
  'ContextPageName' => 'n',
  'DataDir' => 'n',
  'ExecutablesDir' => 'n',
  'GlobalDir' => 'n',
  'WebDir' => 'n',
  'WikiCharset' => 'n',
  'WikiBase' => 'n',
  'UserName' => 'n',
  'DefaultRights' => 'n',
  'AllowEdit' => 'n',
  'PageLimit' => 'n',
  'DateLimit' => 'n',
  'TemplateInsertPassList' => 'n',
  'ScriptFile' => 'n'
);

$WikiLanguageN=3;

@LanguageCount=qw(0 0 0 0 0 0 0);

%LanguageRetCode=(
  "en" => 0, "English" => 0,
  "de" => 1, "German"  => 1,
  "fr" => 2, "French"  => 2,
  "es" => 3, "Spanish" => 3
);


%CodeRetLanguage=(
  "0" => "en",
  "1" => "de",
  "2" => "fr",
  "3" => "es"
);

%WordRetLanguage=(
  "of" => 0, "to" => 0, "the" => 0, "that" => 0, "and" => 0, "a" => 0, "is" => 0, "for" => 0, "you" => 0,
  "der" => 1, "die" => 1, "das", =>1, "den", =>1, "von", =>1, "zu", =>1, "und" => 1, "mit", =>1,
  "de" => 2, "la" =>2, "le" => 2, "et" => 2, "les" => 2, "des" => 2, "en" => 2, "un" => 2, "du" => 2, "une" => 2
);
#===fr: la,le,et,les,des,un,du,une,que,est   (not implemented)
#===nl: van,een,het,dat,op,te,zijn,voor,met   (not implemented)

$StatusInfoChange=""; # separator ,

sub StatusRetWeight {
  my ($status)=@_;
  return int($StatusInfo{$status});
}

sub WikiRetStatusTab {
  my $lang=Lu('en|de|fr|es');
  my ($info,$ind,%h,@ar);

  foreach (keys %StatusInfo) {
    $info=$StatusInfo{$_};
    $ind=int($info);
    if(100<=$ind && $ind<=600) {
      if($info =~ m/$lang/) {
        $h{$info.$_}=$_;
      }
    }
  }
  foreach (sort keys %h) {
    push(@ar,$h{$_});
  }
  return @ar;
}

$UseSmallCorrection=1;
%UploadExtTab= (
  '.bz2' => 'ok', '.c'   => 'ok', '.cpp' => 'ok', '.css' => 'ok', '.csv' => 'ok', '.cty' => 'ok',
  '.d'   => 'ok', '.dll' => 'ok', '.doc' => 'ok',
  '.exe' => 'ok', '.gif' => 'ok', '.gz'  => 'ok',
  '.h'   => 'ok', '.java'=> 'ok', '.jpg' => 'ok', '.JPG' => 'ok', '.lib' => 'ok', '.mov' => 'ok',
  '.pl'  => 'ok', '.pdf' => 'ok', '.png' => 'ok', '.ppt' => 'ok', '.pps' => 'ok', '.ps'  => 'ok',
  '.rtf' => 'ok', '.swf' => 'ok', '.tgz' => 'ok', '.gz'  => 'ok', '.txt' => 'ok',
  '.xls' => 'ok', '.xul' => 'ok', '.zip' => 'ok', '.amr' => 'ok', '.mp3' => 'ok', '.odt' => 'ok',
  '.htm' => 'ok', '.nb' => 'ok', '.3gp' => 'ok'
);
$UploadUserQuotaDefault=500*1024;
$UploadUserQuotaMax=2*1024*1024;
$UploadWikiQuota=20*1024*1024;

%ColorTabDe= ( # keep p_xxxxx.gif in sync
  'dunkelrot' => '#bb0000',
  'rot' => '#ff0000',
  'hellrot' => '#ffcccc',
  'rosa' => 'ffcccc',
  'dunkelblau' => '#0011bb',
  'blau' => '#0066ff',
  'hellblau' => '#aaddff',
  'dunkelgrün' => '#009900', Unicode('dunkelgrün') => '#009900',
  'grün' => '#00cc00', Unicode('grün') => '#00cc00',
  'hellgrün' => '#aaffaa', Unicode('hellgrün') => '#aaffaa',
  'gelb' => '#ffff00',
  'hellgelb' => '#ffffcc',
  'orange' => '#ffcc00',
  'hellorange' => '#ffdd99',
  'braun' => '#996600',
  'hellbraun' => '#cc9933',
  'pink' => '#ff00ff',
  'hellpink' => '#ffccff',
  'violett' => '#9922dd',
  'hellviolett' => '#bb99ee',
  'schwarz' => '#000000',
  'weiß' => '#ffffff', Unicode('weiß') => '#ffffff',
  'graublau' => '#6699aa',
  'graugrün' => '#66aa99', Unicode('graugrün') => '#66aa99',
  'dunkelgrau' => '#aaaaaa',
  'grau' => '#cccccc',
  'hellgrau' => '#eeeeee',
  'gold' => '#ffcc00',
  'keine' => ''
);

%ColorTabEn= ( # keep p_xxxxx.gif in sync
  'darkred' => '#bb0000',
  'red' => '#ff0000',
  'lightred' => '#ffcccc',
  'rosered' => 'ffcccc',
  'darkblue' => '#0011bb',
  'blue' => '#0066ff',
  'lightblue' => '#aaddff',
  'darkgreen' => '#009900',
  'green' => '#00cc00',
  'lightgreen' => '#aaffaa',
  'yellow' => '#ffff00',
  'lightyellow' => '#ffffcc',
  'orange' => '#ffcc00',
  'lightorange' => '#ffdd99',
  'brown' => '#996600',
  'lightbrown' => '#cc9933',
  'pink' => '#ff00ff',
  'lightpink' => '#ffccff',
  'violet' => '#9922dd',
  'lightviolet' => '#bb99ee',
  'black' => '#000000',
  'white' => '#ffffff',
  'grayblue' => '#6699aa','greyblue' => '#6699aa',
  'graygreen' => '#66aa99','greygreen' => '#66aa99',
  'darkgray' => '#aaaaaa','darkgrey' => '#aaaaaa',
  'gray' => '#cccccc','grey' => '#cccccc',
  'lightgray' => '#eeeeee','lightgrey' => '#eeeeee',
  'golden' => '#ffcc00',
  'none' => ''
);

%ColorTabFr= ( # keep p_xxxxx.gif in sync
  "rougefoncé" => '#bb0000', Unicode("rougefoncé") => '#bb0000',
  'rouge' => '#ff0000',
  'rougeclair' => '#ffcccc',
  "bleufoncé" => '#0011bb', Unicode("bleufoncé") => '#0011bb',
  'bleu' => '#0066ff',
  'bleuclair' => '#aaddff',
  'vertfoncé' => '#009900', Unicode('vertfoncé') => '#009900',
  'vert' => '#00cc00',
  'vertclair' => '#aaffaa',
  'jaune' => '#ffff00',
  'jauneclair' => '#ffffcc',
  'orange' => '#ffcc00',
  'orangeclair' => '#ffdd99',
  'marron' => '#996600',
  'marronclair' => '#cc9933',
  'rose' => '#ff00ff',
  'roseclair' => '#ffccff',
  'violet' => '#9922dd',
  'violetclair' => '#bb99ee',
  'grisbleu' => '#6699aa',
  'grisvert' => '#66aa99',
  "grisfoncé" => '#aaaaaa', Unicode("grisfoncé") => '#aaaaaa',
  'gris' => '#cccccc',
  'grisclair' => '#eeeeee',
  'noir' => '#000000',
  'blanc' => '#ffffff',
  'or' => '#ffcc00'
#  'none' => ''
);

$RtfMode=0;

$RtfPaperHeight=16834;
$RtfPaperWidth=11909;
$RtfMarginLeft=1200;
$RtfMarginTop=1000;
$RtfMarginRight=1000;
$RtfMarginBottom=1000;

$RtfBodySize=22;
$RtfBodyWidth=9000;

$TocMagic='xA71qzFP13';
$TocAbstandDef=40;

# HTML tag lists, enabled if $HtmlTags is set.
# Scripting is currently possible with these tags, so they are *not* particularly "safe".
# Tags that must be in <tag> ... </tag> pairs:

@HtmlPairs = qw(b i u font big small sub sup h1 h2 h3 h4 h5 h6 cite code em s strike strong tt var div center blockquote ol ul dl caption);
@HtmlSingle = qw(br p hr li dt dd tr); # Single tags (no closing /tag)
@HtmlPairs = (@HtmlPairs, @HtmlSingle);  # All singles can also be pairs

$n1=' ';
$n2='  ';
$n3='   ';
$br="<br />\n";
$br0="<br />";

$FormFontDec="<font size=3 face='arial,helvetica'><b>@</b></font>";

sub CmdRetText {
  my ($cmd)=@_;
  return `$cmd`;
}

sub CmdStdinRetText {
  my ($cmd,$s)=@_;
  my $fnam="$DataDir/".RandomRetInt().".tmp";
  my $out;
  FileSetStr($fnam,$s);
  $out=CmdRetText("$cmd <$fnam");
  FileDel($fnam);
  return $out;
}

sub DirCreatePermission {
  my ($dir,$mod)=@_;

  if($dir eq '') {
    return;
  }
  if(-d $dir) {
    return;
  }
  mkdir($dir,$mod)
}

sub DirCreate {
  my ($dir)=@_;
  DirCreatePermission($dir,0770);
}

sub DirCreateRecur {   #FIXME: unify to DirCreate, mkdir may not be available
  my ($dir,$mode)=@_;
  my ($cmd,$out);

  $cmd="mkdir -p $dir";
  $out=CmdRetText($cmd);
}

sub StrRetHashCodeFull {
   my ($s)=@_;
   my $hash=0;
   my ($c,$i);
   my $slen=length($s);

   for($i=0; $i<$slen; $i++) {
     $c=substr($s,$i,1);
     $hash=($hash*33+ord($c)) & 0xFFFFFF;
   }
   return $hash;
}

sub StrRetHashCodeQuick {
   my ($s)=@_;
   my $hash=0;
   my ($c,$i);
   my $slen=length($s);

   for($i=0; $i<$slen; $i++) {
     $c=substr($s,$i,1);
     if($c ne ' ') {
       $hash=($hash*33+ord($c)) & 0xFFFFFF;
     }
   }
   return $hash;
}

sub FileDel {
  unlink($_[0]);
}

sub FileRetSize {
  my ($fnam)=@_;
  my @info=stat($fnam);
  return $info[7];
}

sub FileRetTime {
  my ($fnam)=@_;
  my @info=stat($fnam);
  return $info[9];
}

sub RandomChrLower {
  return chr(97+rand(26));
}

sub RandomRetInt {
  my ($n)=@_;
  if($n==0) {
    $n=1000000000;
  }
  return int(rand($n));
}

sub RandomRetStamp {
  return int(rand(1000000000));
}

sub IsYes {
  my($s)=@_;
  my $c=StrRetLower(substr($s,0,1));
  my $ret=0;
  if($c eq 'y') {
    $ret=1;
  } elsif($c eq 'j') {
    $ret=1;
  } elsif($c eq 'q') {
    $ret=1;
  } elsif($c eq 's') {
    $ret=1;
  } elsif($s>0) {
    $ret=1;
  }
  return $ret;
}

sub QuoteHtml {
  my ($html)=@_;

  $html =~ s/&/&/g;
  $html =~ s/</</g;
  $html =~ s/>/>/g;
#  $html =~ s/&([a-zA-Z]{2,6});/&$1;/g;  # only non-numerical
  $html =~ s/&([#a-zA-Z0-9]{2,6});/&$1;/g;  # Allow character references

  return $html;
}

sub UnquoteHtml {
  my ($html)=@_;

  $html =~ s/&/&/g;
  $html =~ s/</</g;
  $html =~ s/>/>/g;

  return $html;
}

sub First {
  foreach (@_) {
    if($_ ne '') {
      return $_;
    }
  }
  return '';
}

# temporary helper
sub LuFirst {
  foreach (@_) {
    if($_ ne '') {
      return Lu($_);
    }
  }
  return '';
}

sub SaveUrlClear {
  %SaveUrl = ();
  %SaveUrlNum = ();
  $SaveUrlIndex = 0;
  $SaveUrlNumIndex = 0;
}

&SaveUrlClear();

sub StrCvtUnicode {
  $_[0] =~ s/([\x80-\xff])/chr(0xC0|(ord($1)>>6)).chr(0x80|(ord($1)&0x3F))/ge;
}

sub UnicodeCvtStr {
  $_[0] =~ s/([\xc0-\xff])([\x80-\xff])/chr( ( 0x80 | (ord($1) & 0x01) << 6) | (ord($2) & 0xBF) )/ge;
}

sub StrLatinCvtUnicode {
  if($WikiUnicode) {
    $_[0] =~ s/([\x80-\xff])/chr(0xC0|(ord($1)>>6)).chr(0x80|(ord($1)&0x3F))/ge;
  }
}

sub Unicode { # StrRetUnicode, used for String constants
  my $s=shift;
  $s =~ s/([\x80-\xff])/chr(0xC0|(ord($1)>>6)).chr(0x80|(ord($1)&0x3F))/ge;
  return $s;
}

sub Su { # StrRetUnicode, if wiki is Unicode
  my $s=shift;
  if($WikiUnicode) {
    StrLatinCvtUnicode($s);
  }
  return $s;
}

sub ValStrip {
  StrStripBoth($_[0]);
  my $c=substr($_[0],0,1);
  if($c eq "'" or $c eq '"') {
    StrStripBrackets($_[0],$c,$c);
  }
}

sub TranslationHashLoadSource {
  my ($snam)=@_;
  my ($text,$line,$str,$var,$val,$c,$slen,$s2);

# MsgPrint("THL page=$page lang=$WikiLanguageName code=$WikiLanguageCode WikiLanguage=$WikiLanguage");
  $text=SourceRetStr($snam);
  if(!StrEmpty($text)) {
    foreach $line (split(/\n/,$text)) {
      if($line =~ m/^(\*+)\s*([^#]*)/ ) {
        $slen=length($1);
        $s2=$2;
        $s2=~ s/\s+$//;
        if($slen==1) {
          $var=$s2;
        } elsif($slen==2) {
          $val=$s2;
          StrStripBoth($var);
          ValStrip($val);
          $TranslationHash{$var}=$val;
        }
      }
    }
  }
}

sub En {
  my ($ret)=split('\|',$_[0],2);
  return $ret;
}

sub LuLang {
  my @ar=split('\|',$_[0]);
  my ($hval,$sval,$key,$ret);
  $ret=$key=$ar[0];

  $hval=$TranslationHash{$key};
  if($hval ne '') {
    $ret=$hval;
    goto do_ret;
  }
  $sval=$ar[$_[1]];
  if($sval ne '') {
    $ret=$sval;
  }
  if($WikiUnicode) {
    StrLatinCvtUnicode($ret);
  }
do_ret:
# MsgPrint("LuLang $key => $ret");
  return $ret;
}

sub Lu {
  my $snam;

  if($WikiLanguage ne $WikiLanguageLast) {
    $snam=$TranslationSource;
    $WikiLanguageLast=$WikiLanguage;
    if($WikiLanguage =~ m/^\d*$/) {
      $WikiLanguageCode=$WikiLanguage;
      $WikiLanguageName=$CodeRetLanguage{$WikiLanguageCode};
    } else {
      $WikiLanguageName=$WikiLanguage;
      $WikiLanguageCode=$LanguageRetCode{$WikiLanguageName};
    }
    if($WikiLanguage==101) {
      $WikiLanguageCode=0;
      $snam="TranslationMap";
    }
    $snam=~ s/\{lang\}/$WikiLanguageName/;
    TranslationHashLoadSource($snam);
  }
  return LuLang($_[0],$WikiLanguageCode);
}

sub LuNbsp {
  my $ret=Lu($_[0]);
  $ret =~ s/ / /g;
  return $ret;
}

sub LiAdditionalFunctions { return Lu('Additional functions|Zusatzfunktionen|Fonctions additionnelles|Funciones adicionales'); }
sub LiAuthor { return Lu('Author|Autor|Auteur|Autor'); }
sub LiContinue { return Lu('continue|Fortsetzen|Continuer|Continuar'); }
sub LiColon { return Lu(': |: | : |: '); }
sub LiFullstop { return Lu('. |. | . |. '); }
sub LiCreatedOn { return Lu('created on|erzeugt am|créée le|creado el'); }
sub LiEdit { return Lu($LabelEdit); }
sub LiError { return Lu("Error|Fehler|Erreur|Error"); }
sub LiErrorBold { return "<b>".LiError()."</b>"; }
sub LiForminput { Lu("Form Input|Formulareingabe"); }
sub LiFound { return Lu(" found| gefunden| trouvées| encontrados"); }
sub LiLinks { return Lu("Links|Links|Liens|Enlaces"); }
sub LiLogin { return Lu('login|Anmelden|login|Entrar'); }
sub LiLogout { return Lu("logout|Abmelden|déconnexion|desconexión"); }
sub LiNote { return Lu("Note|Hinweis|Information|Indicación"); }
sub LiPages { return Lu("Pages|Seiten"); } # FIXME: fr,es,multi
sub LiProject { return Lu("Project|Projekt|Projet|Projecto"); }
sub LiPublish { return Lu("Publish|Veröffentlichen|Publier"); } # FIXME: es
sub LiResults { return Lu("Results|Resultate|Résultats|Resultados"); }
sub LiSave { return Lu('Save|Speichern|Sauvegarder|Guardar'); }
sub LiSummary { return Lu('Summary|Zusammenfassung|Résumé|Resumen'); }
sub LiUpload { return Lu("Upload|Upload|Uploader|Subir"); }
sub LiUser { return Lu("User|Benutzer|Utilisateur|Usuario"); }
sub LiUsername { return LuNbsp('username|Benutzername|nom utilisateur |nombre del usuario'); }

sub LiSvgMissing {
  return "<b>". LiError() . LiColon(). Lu("SVG-Plugin missing - please install|SVG-Plugin fehlt - bitte installieren|Plugin-SVG manquant - installez-le SVP") . "</b>"; # FIXME: es
}

sub LiUsernameExample {
  my $ret=LuNbsp(" such as FredKayiwa| z. B. Peter_Müller| par ex. Peter_Smith| por ejemplo Pedro_Herrera");
  if($PromoteUnderline==0) {
    $ret=~s/_//g;
  }
  return $ret;
}

sub StrEquList {
  my $s=shift;

  foreach(@_) {
    if($s eq $_) {
      return 1;
    }
  }
  return 0;
}

sub StrEquExist {
  my ($s1,$s2)=@_;
  if($s1 eq '' && $s2 eq '') {
    return 0;
  }
  return ($s1 eq $s2);
}


sub StrRetUpper {
  my ($s)=@_;
  $s =~ tr/a-z\xe0-\xfd/A-Z\xc0-\xdd/;
  return $s;
}

sub StrRetLower {
  my ($s)=@_;
  $s =~ tr/A-Z\xc0-\xdd/a-z\xe0-\xfd/;
  return $s;
}

sub HexRetChr {
  my ($code)=@_;
  return chr(hex($code));
}

sub HexRetChrSave {
  my ($code)=@_;
  my $c=chr(hex($code));
  if($c eq '<') {
    $c="<";
  } elsif($c eq '>') {
    $c=">";
  }
  return $c;
}

sub HexRetInt {
  my ($code)=@_;
  return hex($code);
}

sub StrHexCvtText {
  $_[0] =~ s/%([0-9A-Fa-f]{2})/&HexRetChr($1)/ge;
}

sub StrHexCvtTextSave {
  $_[0] =~ s/%([0-9A-Fa-f]{2})/&HexRetChrSave($1)/ge;
}

sub StrCvtNoRegex {
  $_[0] =~ s/([.+*?(){}\[\]\|])/\\$1/g;
}

sub ChrRetHex {
  my ($c)=@_;
  return sprintf("%02lx",$c);
}

sub StrExistApp {
  if($_[0] ne '') {
    $_[0].=$_[1];
  }
}

sub StrRetHex {
  my ($s)=@_;
  $s =~ s/(.)/&ChrRetHex($1)/ge;
  return $s;
}

sub StrStripStrFront {
  my $sslen=length($_[1]);
  if($sslen) {
    if(substr($_[0],0,$sslen) eq $_[1]) {
      substr($_[0],0,$sslen)='';
    }
  }
}

sub StrStripFront {
  $_[0] =~ s/^\s+//;
}

sub StrStripBoth {
  $_[0] =~ s/^\s+//;
  $_[0] =~ s/\s+$//;
}

sub StrStripCR {
  $_[0] =~ s/\r//g;
}

sub StrStripHtml {
  $_[0] =~ s/<[^<>]*>//g;
}

sub StrStripStem {
  $_[0] =~ s#^[^/]+/+##g;
}

sub ListSplit {
  return split(/[\s,;]+/,$_[0]);
}

sub ListSplitHash {
  my @ret;
  foreach (ListSplit($_[0])) {
    push(@ret,$_,1);
  }
  return @ret;
}

sub StrStripStr {
  $_[0] =~ s/$_[1]$//;
}

sub StrStripChrBoth {
  $_[0] =~ s/$_[1]+$//;
  $_[0] =~ s/^$_[1]+//;
}

sub StrFindStrRetCount {
  my ($s,$c)=@_;
  my $count=0;
  $s =~ s/$c/{$count++;}/ge;
  return $count;
}

sub StrRetDigitCount {
  my ($s)=@_;
  $s =~ s/[^0-9]//g;
  return length($s);
}

sub ArrayRetSize {
#  my($a_ar)=@_;
#  return int(@$a_ar);
  return int(@{$_[0]});
}

sub ArrayRetText {
  my($a_ar)=@_;
  return join("\n",@$a_ar)."\n";
}

sub ArrayStrFilterRegex {
  my ($a_ar,$s,$filterflag,$regex)=@_;
  my (@ar,$val);

  if($regex<1) {
    StrCvtNoRegex($s);
  }

  foreach $val (@$a_ar) {
    if($val =~ m/$s/) {
      if($filterflag==0) {
        push(@ar,$val);
      }
    } else {
      if($filterflag) {
        push(@ar,$val);
      }
    }
  }
  return @ar;
}

sub HashPtrHeadMidTailFilterRetStr {
  my ($p_hash,$head,$mid,$tail,$filter)=@_;
  my ($ret,$key,$val,$show);
  foreach $key (sort(keys(%$p_hash))) {
    $val=$$p_hash{$key};
    $show=1;
    if($filter ne '') {
      if($val =~ m/$filter/) {
        $show=0;
      }
    }
    if($show) {
      $ret .= $head.$key.$mid.$val.$tail;
    }
  }
  return $ret;
}

sub FileExist {
  my ($fnam)=@_;
  if(-f $fnam) {
    return 1;
  }
  return 0;
}

sub FileRetDir {
  my ($fnam)=@_;
  $fnam =~ s#/[^/]*$##;
  return $fnam;
}

sub PathRetDir {
  my $path = shift;
  my $dir;
  $path =~ m#(.*[\\:\/])[^\\:\/]+$# ;
  if($1 ne "") {
    $dir = $1;
  }
  return $dir;
}

sub PathRetFilename {
  my ($path)=@_;
  $path =~ s#\?.*$##;  # del ?...
  $path =~ s#^.*\/##;  # del .../
  return $path;
}

sub PathStripParams {
  my ($path)=@_;
  $path =~ s#\?.*$##;  # del ?...
  return $path;
}

sub PathRetFile {
  my $path = shift;
  my $file;
  $path =~ m#[\\:\/]([^\\:\/]+)$# ;
  if($1 eq "") {
    $file = $path;
  } else {
    $file = $1;
  }
  return $file;
}

sub PathRetExt {
  my $file = shift;
  $file =~ m#(\.[a-zA-Z0-9]*)$# ;
  return $1;
}

sub PathRetExtPure {
  my $file = shift;
  $file =~ m#\.([a-zA-Z0-9]*)$# ;
  return $1;
}

sub PathRetProtocol {
  my $file = shift;
  $file =~ m#^([a-z]+):# ;
  return $1;
}

sub FileCpy {
  my ($dest,$src)= @_;
  my ($size,$buffer,$bytes,$OUT);
  open($OUT,">$dest");
  while($bytes = read($src, $buffer, 1024)) {
    print $OUT $buffer;
    $size += $bytes;
  }
  close($OUT);
  return $size;
}

sub WordTogCase {
  my ($s)=@_;
  my $ret=substr($s,0,1);
  if($s =~ m/^$UpperLetter/) {
    $ret=StrRetLower($ret);
  } else {
    $ret=StrRetUpper($ret);
  }
  $ret .= substr($s,1);
  return $ret;
}

sub HashRetTabSortedStr { # hash contains sortable string
  my ($h_hash,$rev)=@_;
  my (@tab,@stab,$val,$key,$line);

  foreach $key (keys %$h_hash) {
    push(@stab,"$$h_hash{$key}$FS1$key");
  }
  foreach $line (sort @stab) {
    ($val,$key)=split($FS1,$line);
    push(@tab,$key);
  }
  if($rev) {
    return reverse @tab;
  }
  return @tab;
}

sub HashRetTabSorted { # hash contains count
  my ($h_hash)=@_;
  my (@tab,@stab,$key,$count,$line,$n);

  foreach $key (keys %$h_hash) {
    $count=$$h_hash{$key};
    if($count>0) {
      $n=100000-$count;
      push(@stab, sprintf("%06d",$n) . "$FS1$key$FS1$count");
    }
  }
  foreach $line (sort @stab) {
    ($n,$key,$count)=split($FS1,$line);
    push(@tab,$key,$count);
  }
  return @tab;
}

sub ShowHtmlPage {
  my ($html)=@_;
  print "Content-type: text/html\n\n";
  print $html;
}

sub ShowHtml {
  my ($html)=@_;
  print "Content-type: text/html\n\n";
  if(!($html =~ m#</body>#i)) {
    $html="<body>\n$html</body>";
  }
  if(!($html =~ m#</head>#i)) {
    $html="<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$WikiCharset\">\n"
      . "<title>$SiteName: $PageCur</title>\n</head>\n"
      . $html;
  }
  if(!($html =~ m#</html>#i)) {
    $html="<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n<html>\n$html\n</html>\n";
  }
  print $html;
}

sub ShowText {
  my ($text)=@_;
  print "Content-type: text/plain\n\n";
  print $text;
}

sub ShowFile {
  my ($fnam)=@_;
  my $text=FileRetStr($fnam);
  ShowText($text);
}

sub YearRetLongCount {
  my ($year)=@_;
  $year--;
  my $h=1; $h+=int($year/4); $h-=int($year/100); $h+=int($year/400);
  return $h;
}

sub YearRetLongFlag {
  my ($year)=@_;
  return (!($year%4)-!($year%100)+!($year%400));
}

my @MonthLenDefault=(31,28,31,30,31,30,31,31,30,31,30,31);

sub YearMonthRetLen {
  my ($year,$month)=@_;
  if($month==2) {
    return 28+YearRetLongFlag($year);
  }
  return $MonthLenDefault[$month-1];
}

sub TimeAllRetTimeSec { # month 1..12, year+-1900
  my ($year,$month,$day,$hour,$min,$sec)=@_;
  my @MonthLen=(31,28,31,30,31,30,31,31,30,31,30,31);
  my $date=0;
  my $i;

  if($year>1900) {
    $year-=1900;
  }

  $MonthLen[1]=28+YearRetLongFlag($year);
  $month--;
  if($month<0 || $month>11 || $day<1 || $day>$MonthLen[$month] || $year<0) {
     return '';
  }
  my $sj=YearRetLongCount(1900+$year)-YearRetLongCount(1970);

  $date=($year-70)*365 + $sj + ($day-1);
  for($i=0; $i<$month; $i++) {
     $date+=$MonthLen[$i];
  }
  $date*=86400;
  $date+=$sec+$min*60+$hour*3600;
  $date+= -3600; # correction
  return $date;
}

sub TimeRetTimeClient {
  my ($ts)=@_;
  $ts += $TimeZoneOffset;
  return localtime($ts);
}

sub SecRetHhMm {
  my ($ts)=@_;
  my $mm=int($ts/60);
  my $hh=int($mm/60);
  return sprintf("%d:%02d",$hh,$mm%60);
}

sub DateStripTime {
  my ($ts)=@_;
  my ($sec,$min,$hour) = TimeRetTimeClient($ts);
  return $ts-$sec-$min*60-$hour*3600;
}

sub TimeRetLogSpec {
  my ($ts)=@_;
  my ($sec,$min,$hour,$mday,$mon,$year) = localtime($ts);
  return sprintf("%02d%02d",$year-100,$mon+1);
}

sub TimeRetLog {
  my ($ts)=@_;
  my ($sec,$min,$hour,$mday,$mon,$year) = localtime($ts);
  return sprintf("%04d%02d%02d-%02d:%02d.%02d",1900+$year,$mon+1,$mday,$hour,$min,$sec);
}

my @MonthNameLong=(
  "January|Januar|Janvier|Enero",
  "February|Februar|Février|Febrero",
  "March|März|Mars|Marzo",
  "April|April|Avril|Abril",
  "May|Mai|Mai|Mayo",
  "June|Juni|Juin|Junio",
  "July|Juli|Juillet|Julio",
  "August|August|Août|Agosto",
  "September|September|Septembre|Septiembre",
  "October|Oktober|Octobre|Octubre",
  "November|November|Novembre|Noviembre",
  "December|Dezember|Décembre|Diciembre"
);

sub MonthName {
  my ($ind)=@_;
  return Lu($MonthNameLong[$ind%12]);
}

sub MessRepVar {
  my $i=1;
  while ($_[$i] ne '') {
    $_[0]=~s/$_[$i]/$_[$i+1]/;
    $i+=2;
  }
}

sub MessRepPagename {
  my $idq=QuoteHtml($_[1]);
  MessRepVar($_[0],"%PAGENAME%","\"$idq\"");
}

sub TimeLangRetDay {
  my ($ts,$lang)=@_;
  my $ret=LuLang($DateFormatLong,$lang);
  my ($sec,$min,$hour,$mday,$mon,$year) = TimeRetTimeClient($ts);
  $mon=LuLang($MonthNameLong[$mon],$lang);
  $year+=1900;
  MessRepVar($ret,"%DAY%",$mday,"%MONTH%",$mon,"%YEAR%",$year);
  return $ret;
}

sub TimeRetDayEnglish {
  my ($ts)=@_;
  return TimeLangRetDay($ts,0);
}

sub TimeRetDayGerman {
  my ($ts)=@_;
  return TimeLangRetDay($ts,1);
}

sub TimeRetDayFrench {
  my ($ts)=@_;
  return TimeLangRetDay($ts,2);
}

sub TimeRetDaySpanish {
  my ($ts)=@_;
  return TimeLangRetDay($ts,3);
}

sub TimeRetDay {
  my ($ts)=@_;
  return TimeLangRetDay($ts,$WikiLanguage);
}

sub TimeRetRssTime {
  my ($ts)=@_;
  my ($sec,$min,$hour,$mday,$mon,$year) = localtime($ts);
  return sprintf("%04d-%02d-%02dT%02d:%02d:%02d+01:00",$year+1900,$mon+1,$mday,$hour,$min,$sec);
}

sub TimeRetStr {
  my ($ts)=@_;

  my ($sec, $min, $hour, $mday, $month, $year) = TimeRetTimeClient($ts);
  $month++;
  return sprintf("%04d_%02d_%02d %02d:%02d.%02d",1900+$year,$month,$mday,$hour,$min,$sec);
}

sub TimeSpanRetStrLog {
  my ($ts1,$ts2)=@_;

  my ($sec, $min, $hour, $mday, $month, $year) = TimeRetTimeClient($ts1);
  $month++;
  my $ret=sprintf("%02d.%02d+%02d:%02d",$mday,$month,$hour,$min);
  ($sec, $min, $hour, $mday, $month, $year) = TimeRetTimeClient($ts2);
  $ret .= sprintf("_%02d:%02d",$hour,$min);
  return $ret;
}

sub TimeRetHour {
  my ($ts)=@_;
  my ($sec, $min, $hour, $mday, $mon, $year) = TimeRetTimeClient($ts);
  $min = "0" . $min   if ($min<10);
  return $hour . ":" . $min;
}

sub TimeRetDaySort {
  my ($ts)=@_;
  my ($sec, $min, $hour, $mday, $mon, $year) = TimeRetTimeClient($ts);
  return sprintf("%04d_%02d_%02d",$year+1900,$mon+1,$mday);
}

my @DayNameShortTab=(
  "Su|So|Di|Do",
  "Mo|Mo|Lu|Lu",
  "Tu|Di|Ma|Ma",
  "We|Mi|Me|Mi",
  "Th|Do|Je|Ju",
  "Fr|Fr|Ve|Vi",
  "Sa|Sa|Sa|Sá"
);

sub DayNameShort {
  my ($ind)=@_;
  return Lu($DayNameShortTab[$ind%7]);
}

sub TimeRetWeekdayInd {
  my ($ts)=@_;
  my ($sec,$min,$hour,$mday,$mon,$year,$wday)=TimeRetTimeClient($ts);
  return $wday;
}

sub TimeRetWeekday {
  my ($ts)=@_;
  my $wdind=TimeRetWeekdayInd($ts);
  return DayNameShort($wdind);
}

sub TimeRetTextEnglish {
  my ($ts)=@_;
  return TimeRetDayEnglish($ts) . " " . TimeRetHour($ts);
}

sub TimeRetTextGerman {
  my ($ts)=@_;
  return TimeRetDayGerman($ts) . " " . TimeRetHour($ts);
}

sub TimeRetTextFrench {
  my ($ts)=@_;
  return TimeRetDayFrench($ts) . " " . TimeRetHour($ts);
}

sub TimeRetTextSpanish {
  my ($ts)=@_;
  return TimeRetDaySpanish($ts) . " " . TimeRetHour($ts);
}

sub TimeRetText {
  my ($ts)=@_;
  if($WikiLanguage==1) {
    return TimeRetTextGerman($ts);
  } elsif($WikiLanguage==2) {
    return TimeRetTextFrench($ts);
  } elsif($WikiLanguage==3) {
    return TimeRetTextSpanish($ts);
  }
  return TimeRetTextEnglish($ts);
}

sub FileSetExtRet {
  my($file,$ext)=@_;
  if( $file =~ s#[\.][a-zA-Z]*$#$ext#g ) {
  } else {
    $file .= $ext;
  }
  return $file;
}

sub FileSetNameRet {
  my($file,$name)=@_;
  if( $file =~ s#/[^/]*$#/$name# ) {
  } else {
    $file = $name;
  }
  return $file;
}

sub PrintHeader { #uni
        print $cgi->header(
                -type => "text/html",
                -charset => $WikiCharset,
                -head => "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$WikiCharset\">",
                -encoding => $WikiCharset
        );
}

sub PrintStartHtml { #uni
        print $cgi->start_html(
                -encoding => $WikiCharset,
#                -head => meta( { -http_equiv => 'Content-Type', -content    => "text/html; charset=$WikiCharset"}),
                -title => "Some sample characters ($WikiCharset)"
        );
}

sub MessAbort {
  my $func=shift;
  my $text=shift;
  my ($package, $filename, $line)=caller;

  PrintHeader();
  PrintStartHtml();

  $lb1=Lu("Program error:|Programmfehler:|Erreur Programme :|Error del programa:");
  print $br,ParamsRetStr_h3($lb1),$br;

  print ParamsRetStr_h1($text);

  print ParamsRetStr_h3("Script= ",$ScriptFilename);
  print ParamsRetStr_h3("Function= ",$func," Line= ",$line);
  print @_;

  print $cgi->end_html;
  exit;
}

sub FileRetLineFirst {
  my ($file)=@_;
  my ($ret,$IN);

  local $/ ="\n";
  if(open($IN,"<$file")) {
    $ret=<$IN>;
    close($IN);
  }
  return $ret;
}

sub FileRetStr {
  my ($file,$tolerant)=@_;
  my ($ret,$IN);

  if(open($IN,"<$file")) {
    $ret=<$IN>;
    close($IN);
  } elsif($tolerant==0) {
    $lb1=Lu('Error opening file|Fehler beim Öffnen von File|Erreur ouverture fichier|Error abriendo fichero');
    MessAbort("FileRetStr","$lb1 $file: $!");
  }

  return $ret;
}

sub FileSepRetArray {
  my ($file,$sep)=@_;
  my $s=FileRetStr($file,1);
  return split($sep,$s);
}

sub FileRetArray {
  return FileSepRetArray($_[0],"\n");
}

sub StrHasBrackets {
  my ($s)=@_;
  my $ret=0;
  my $c;

  if(length($s)<2) {
    goto do_ret;
  }
  $c=substr($s,0,1);
  if(substr($s,-1,1) eq $c) {
    if($c eq "\"" || $c eq "\'") {
      $ret=1;
    }
  }
do_ret:
  return $ret;
}

sub StrStripBrackets { # my($s,$cl,$cr)=@;
  my $slen=length($_[0]);
  if($slen<2) {
    return;
  }
  if(substr($_[0],0,1) eq $_[1]) {
    if(substr($_[0],-1,1) eq $_[2]) {
      $_[0]=substr($_[0],1,$slen-2);
    }
  }
}

sub ValCvtDir {
  if($_[0] =~ m/^@/ ) {
    $_[0] =~ s#^\@CONFIGDIR@(\/|$)#$_[1]$1#;
    $_[0] =~ s#^\@WEBDIR@\/#$WebDir\/#;
    $_[0] =~ s#^\@GLOBALDIR@(\/|$)#$GlobalDir$1#;
    $_[0] =~ s#^@@(\/|$)#$_[1]$1#;
    $_[0] =~ s#^@\/#$WebDir\/#;
  }
}

sub ContextVarSetVal {
  my($var,$val)=@_;
  if($ContextVarLocked>0) {
    if($VarLockedHash{$var} ne '') {
      return;
    }
  }
  if($var =~ /\./) {
    $Context{$var}=$val;
  } else {
    ValCvtDir($val,$ConfigDir);
    $$var=$val;
  }
}

sub ReflectVarVal {
  my($var,$val)=@_;
  my $setflag=1;
  my ($head,$tail)=split(/\./,$var,2);

do_restart:
# MsgPrint("reflect var=$var val=$val");
  if($head eq "PageSetDomain") {
    if($tail ne '*') {
      ContextVarSetVal("pagename.reduction.$val",$tail);
    }
    ContextVarSetVal("link.rewrite.$tail",$val);
    goto do_ret;
  } elsif ($head eq "script2") {
    if($ScriptName =~ m/2/) {
      ContextVarSetVal($tail,$val);
    }
  }

do_ret:
  return $setflag;
}

sub StrSplitContextVarSetVal {
  my($s)=@_;
  my($var,$val,$line,$c,$cl1,$cl2,$setflag);

LOOP_LINE:
  foreach $line (split("\n",$s)) {
    chomp($line);
    if($line =~ m/=/) {
      $var = $`;
      $val = $';
      StrStripBoth($var);
      ValStrip($val);
      $setflag=1;

      if($var =~ m/^(\d+)[\.\-](.*)/ ) { # e.g. 1.var=val
        $cl1=$cl2=$1;
        $var=$2;
        if($var =~ m/^(\d+)[\.\-](.*)/ ) { # e.g. 1-3.var=val
          $cl2=$1;
          $var=$2;
        }
        if($PageLevel+1<$ContextLevel+$cl1) {
          $setflag=0;
        } elsif($PageLevel+1>$ContextLevel+$cl2) {
          $setflag=0;
        }
      } elsif($var =~ m/reflect\.(.*)/) {
        $setflag=ReflectVarVal($1,$val);
      }
      if($setflag) {
        ContextVarSetVal($var,$val);
      }
    }
  }
}

sub ConfigFileLoad {
  my($fnam,$push)=@_;
  my $s=FileRetStr($fnam);
  StrSplitContextVarSetVal($s);
  if($push) {
    push(@ConfigFiles,$fnam);
  }
}

sub PrintAnswer { # prints page completely
  my($ret)=shift;

  if($StoreAnswer) {
    if(($UserName eq $ProgrammerName) || $Context{"store.answer.$ClientIP"}) {
      my $fnam="$DataDir/answer.txt";
      FileAppStr($fnam,"=====314=====".$Domain.WikiRetAction()."\n");
      FileAppStr($fnam,$ret);
      FileAppStr($fnam,"\n\n\n\n\n");
    }
  }
  print $ret;
}