From: fox_two <> Date: Wed, 21 Feb 2001 10:38:08 +0000 (+0000) Subject: Initial release X-Git-Tag: start~1 X-Git-Url: https://git.p6c8.net/selfforum.git/commitdiff_plain/ba659b53059e637777865e646f0f2a6fb7f2988e?hp=504ff3f8ee5e277c2b1bf12a7a630098eaf55f0a Initial release --- diff --git a/selfforum-cgi/shared/Conf.pm b/selfforum-cgi/shared/Conf.pm new file mode 100644 index 0000000..1fa97b2 --- /dev/null +++ b/selfforum-cgi/shared/Conf.pm @@ -0,0 +1,163 @@ +# Conf.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-05 +# lm : n.d.p. / 2001-02-02 +# ==================================================== +# Funktion: +# Einlesen der Scriptkonfiguration +# ==================================================== + +use strict; + +package Conf; + +use vars qw(@ISA @EXPORT); + +use XML::DOM; + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(read_script_conf); + +################################ +# sub read_script_conf +# +# Scriptkonf. lesen +################################ + +sub read_script_conf ($$$) { + my ($Bin, $Shared, $Script) = @_; + + $Script =~ s/^(.*)\..*$/$1/; # Vornamen extrahieren + my $common = "$Shared/common.xml"; # gemeinsame Konf-datei + my $group = "$Bin/config/common.xml"; # gemeinsame (Gruppen-)Konf-datei + my $special = "$Bin/config/$Script.xml"; # spezielle Konf-datei + my %conf=(); # conf-Hash + + &parse_script_conf ($common , \%conf, $Script); # und los... + &parse_script_conf ($group, \%conf, $Script); + &parse_script_conf ($special, \%conf, $Script); + + # Rueckgabe + \%conf; +} + +# ==================================================== +# Private Funktionen +# ==================================================== + +sub parse_script_conf ($$$) { + my ($filename, $conf, $Script) = @_; + + if (-f $filename) { + # XML parsen + my $xml = new XML::DOM::Parser -> parsefile ($filename); + my $config = $xml -> getElementsByTagName ('Config',0) -> item (0); + + foreach ($config -> getElementsByTagName ('Constant', 0)) {&add_data ($_, $conf)} + foreach ($config -> getElementsByTagName ('Property', 0)) {&add_prop ($_, $conf)} + foreach ($config -> getElementsByTagName ('Limit', 0)) {&add_limit ($_, $conf, $Script)}} + + return; +} + +sub add_data ($$) { + my ($node, $conf) = @_; + my $name = $node -> getAttribute ('name'); + + die "element '".$node -> getNodeName."' requires attribute 'name' - aborted" unless (length ($name) and defined ($name)); + die "double defined name '$name' - aborted" if ( exists ( $conf -> {$name} ) ); + + # Wert eintragen + $conf -> {$name} = ($node -> hasChildNodes)?$node -> getFirstChild -> getData:undef; + + return; +} + +sub add_prop ($$) { + my ($node, $conf) = @_; + + my $name = $node -> getAttribute ('name'); + + die "element 'Property' requires attribute 'name' - aborted" unless (length ($name)); + + my @props = $node -> getElementsByTagName ('Property', 0); + my @vars = $node -> getElementsByTagName ('Variable', 0); + my @lists = $node -> getElementsByTagName ('List', 0); + + # Properties + if (@props) { + for (@props) { + my $hash = (defined $conf -> {$name})?$conf -> {$name}:{}; + + die "name '$name' is defined for 'Property' and 'Variable' - aborted" unless (ref $hash eq 'HASH'); + + &add_prop ($_, $hash); + $conf -> {$name} = $hash;}} + + # Array + if (@lists) { + for (@lists) { + my $lname = $_ -> getAttribute ('name'); + + die "element 'List' requires attribute 'name' - aborted" unless (length ($lname) and defined ($lname)); + die "double defined name '$lname' - aborted" if ( exists ( $conf -> {$name} -> {$lname} ) ); + + $conf -> {$name} -> {$lname} = [map {($_ -> hasChildNodes)?$_ -> getFirstChild -> getData:undef} $_ -> getElementsByTagName ('ListItem', 0)];}} + + # Hash + if (@vars) { + for (@vars) { + my $vname = $_ -> getAttribute ('name'); + + die "element 'Variable' requires attribute 'name' - aborted" unless (length ($vname) and defined ($vname)); + die "double defined name '$vname' - aborted" if ( exists ( $conf -> {$name} -> {$vname} ) ); + + $conf -> {$name} -> {$vname} = ($_ -> hasChildNodes)?$_ -> getFirstChild -> getData:undef;}} + + return; +} + +sub add_limit ($$$) { + my ($node, $conf, $Script) = @_; + + my %apps = map {($_ -> getFirstChild -> getData => 1)} + $node -> getElementsByTagName ('Application',0) -> item (0) + -> getElementsByTagName ('Script',0); + + if ($apps {$Script}) { + foreach ($node -> getElementsByTagName ('Constant', 0)) {&add_data ($_, $conf)} + foreach ($node -> getElementsByTagName ('Property', 0)) {&add_prop ($_, $conf)}} + + return; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Conf +# ==================================================== + +package Conf::Test;sub show{print"Content-type: text/plain\n\n";&hash($_[ +0],'')}sub hash{my($ref,$string)=@_;foreach(sort keys%$ref){my$val=$ref-> +{$_};unless(ref($val)){print$string,$_,' = ',$val,"\n";next;}else{if(ref( +$val)eq 'HASH'){&hash($val,"$string$_ -> ");}else{if(ref($val)eq'ARRAY'){ +&array($val,"$string$_ -> ");}}}}}sub array {my($ref,$string)=@_;my $i=0; +foreach (@$ref){unless(ref($_)){print$string,"[$i] = ", $_,"\n";}else{if( +ref($_)eq 'HASH'){&hash($_,"$string\[$i] -> ")}else{if(ref($_)eq'ARRAY'){ +&array($_,"$string\[$i] -> ");}}}$i++;}}# n.d.p./2001-01-05/lm:2001-01-19 +# FUNCTION: printing the configuration, USAGE: &Conf::Test::show ($conf); + +# ==================================================== +# 'real' end of Conf .-)) +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Conf/Admin.pm b/selfforum-cgi/shared/Conf/Admin.pm new file mode 100644 index 0000000..cf4fa13 --- /dev/null +++ b/selfforum-cgi/shared/Conf/Admin.pm @@ -0,0 +1,150 @@ +# Admin.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-05 +# lm : n.d.p. / 2001-02-02 +# ==================================================== +# Funktion: +# Einlesen der Admindefaultkonfiguration +# ==================================================== + +use strict; + +package Conf::Admin; + +use vars qw(@ISA @EXPORT); + +use Lock qw(:READ); + +use XML::DOM; + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(read_admin_conf); + +################################ +# sub read_admin_conf +# +# Default-Admin-Konf. lesen +################################ + +sub read_admin_conf ($) { + my $filename=shift; + my %conf; + + if (-f $filename) { # gibts die Datei ueberhaupt? + if (lock_file ($filename)) { # sperren... + my $xml = new XML::DOM::Parser -> parsefile ($filename); # ...einlesen und parsen... + violent_unlock_file ($filename) unless (unlock_file ($filename)); # ...freigeben + + # ================================= + # jetzt Daten in den Hash schreiben + + my $forum = $xml -> getElementsByTagName ('Forum',0) -> item (0); + + # View + my $forum_view = $forum -> getElementsByTagName ('ForumView', 0) -> item (0); + my $thread_view = $forum_view -> getElementsByTagName ('ThreadView', 0) -> item (0); + my $show_thread = $thread_view -> getElementsByTagName ('ShowThread', 0) -> item (0); + my $show_how = $show_thread -> getElementsByTagName ('*', 0) -> item (0); + my $how_name = $show_how -> getTagName; + my $message_view = $forum_view -> getElementsByTagName ('MessageView', 0) -> item (0); + my $flags = $forum_view -> getElementsByTagName ('Flags', 0) -> item (0); + my $quoting = $forum_view -> getElementsByTagName ('Quoting', 0) -> item (0); + my $char = $quoting -> getElementsByTagName ('Chars', 0) -> item (0); + + $conf {View} = {threadOpen => $thread_view -> getAttribute ('threadOpen'), + countMessages => $thread_view -> getAttribute ('countMessages'), + sortThreads => $thread_view -> getAttribute ('sortThreads'), + sortMessages => $thread_view -> getAttribute ('sortMessages'), + showThread => (($how_name eq 'showAll')?undef: + (($how_name eq 'showNone')?1: + ($show_how -> getFirstChild -> getData))), + showPreview => $message_view -> getAttribute ('previewON'), + showNA => $flags -> getAttribute ('showNA'), + showHQ => $flags -> getAttribute ('showHQ'), + quoting => $quoting -> getAttribute ('quotingON'), + quoteChars => $char?$char -> getFirstChild -> getData:undef}; + + # Severance + $conf {Severance} = &get_severance ($forum -> getElementsByTagName ('Severance', 0) -> item (0)); + + # Messaging + my $messaging = $forum -> getElementsByTagName ('Messaging', 0) -> item (0); + my $call_by_user = $messaging -> getElementsByTagName ('CallByUser', 0) -> item (0); + + $conf {Messaging} = {userAnswer => $messaging -> getAttribute ('callUserAnswer'), + thread => $messaging -> getAttribute ('callAdminThread'), + na => $messaging -> getAttribute ('callAdminNA'), + hq => $messaging -> getAttribute ('callAdminHQ'), + voting => $messaging -> getAttribute ('callAdminVoting'), + archiving => $messaging -> getAttribute ('callAdminArchiving'), + byUser => $messaging -> getAttribute ('callUserAnswer'), + callByName => [map {$_ -> getFirstChild -> getData} $call_by_user -> getElementsByTagName ('Name', 0)], + callByMail => [map {$_ -> getFirstChild -> getData} $call_by_user -> getElementsByTagName ('Email', 0)], + callByIP => [map {$_ -> getFirstChild -> getData} $call_by_user -> getElementsByTagName ('IpAddress', 0)]}; + + # Instant + my $instant = $forum -> getElementsByTagName ('InstantJob', 0) -> item (0); + my $job = $instant -> getElementsByTagName ('*',0) -> item (0); + my $job_name = $job -> getTagName; + $job_name = $job -> getAttribute ('reason') if ($job_name ne 'Severance'); + + $conf {Instant} = {execute => $instant -> getAttribute ('executeJob'), + description => $job_name, + url => (($job_name ne 'Severance')?$job -> getElementsByTagName ('FileUrl', 0) -> item (0) -> getFirstChild -> getData:undef), + Severance => (($job_name eq 'Severance')?&get_severance ($job):undef)}; + + # User + my $user = $forum -> getElementsByTagName ('UserManagement', 0) -> item (0); + + $conf {User} = {deleteAfterDays => $user -> getElementsByTagName ('DeleteUser', 0) -> item (0) + -> getElementsByTagName ('AfterDays', 0) -> item (0) + -> getFirstChild -> getData}; + } + + else { + violent_unlock_file ($filename);}} + + # Rueckgabe + \%conf; +} + +# ==================================================== +# Private Funktionen +# ==================================================== + +sub get_severance ($) { + my $severance = shift; + + my $after_byte = $severance -> getElementsByTagName ('AfterByte', 0) -> item (0); + my $after_message = $severance -> getElementsByTagName ('AfterMessage', 0) -> item (0); + my $after_thread = $severance -> getElementsByTagName ('AfterThread', 0) -> item (0); + my $last_posting = $severance -> getElementsByTagName ('AfterLastPosting', 0) -> item (0); + + my %conf =( exArchiving => $severance -> getAttribute ('executeArchiving'), + archiving => $severance -> getElementsByTagName ('Archiving', 0) -> item (0) + -> getElementsByTagName ('*', 0) -> item (0) -> getTagName, + severance => $severance -> getAttribute ('executeSeverance'), + afterByte => ($after_byte?$after_byte -> getFirstChild -> getData:undef), + afterThread => ($after_thread?$after_thread -> getFirstChild -> getData:undef), + afterMessage => ($after_message?$after_message -> getFirstChild -> getData:undef), + lastPosting => ($last_posting?$last_posting -> getFirstChild -> getData:undef)); + + \%conf; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Conf::Admin +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Encode/Plain.pm b/selfforum-cgi/shared/Encode/Plain.pm new file mode 100644 index 0000000..cf7ef06 --- /dev/null +++ b/selfforum-cgi/shared/Encode/Plain.pm @@ -0,0 +1,402 @@ +# Encode/Plain.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-07 +# lm : n.d.p. / 2001-02-06 +# ==================================================== +# Funktion: +# Codierung von non-ASCII-Zeichen fuer +# HTML +# ==================================================== + +use strict; + +package Encode::Plain; + +require 5.6.0; + +use vars qw(@ISA @EXPORT %sonder %unimap $utf8); + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(plain multiline toUTF8); + +################################ +# sub plain +# +# einfache Sonderzeichen -> +# Entity-Codierung +################################ + +sub plain ($;$) { + my ($old,$ref)=@_; + my $exreg; + + return \'' unless (defined $old); + + my $new=(ref ($old))?$$old:$old;; + $ref=($ref or {}); + + # Ausnahmen + my $except=exists($ref->{-except}); + if ($except) { + + # Referenz, also Liste uebergeben -> umwandeln in Regex + if (ref ($ref -> {-except})) { + $exreg = join ('|',map {quotemeta $_} @{$ref -> {-except}});} + + # keine Referenz, also Regex angegeben + else { + $exreg = $ref -> {-except}; + $exreg =~ s/\//\\\//g;}} # LTS :-) + + if (lc($ref->{-amp}) eq 'soft') { + + if ($except) { + $new=~s/($exreg)|(?:\&(?!(?:#[Xx][\da-fA-F]+|#\d+|[a-zA-Z]+);))/(length($1))?$1:'&'/eg;} + + else { + $new=~s/\&(?!(?:#[Xx][\da-fA-F]+|#\d+|[a-zA-Z]+);)/&/g;}} + + elsif (lc($ref->{-amp}) ne 'no') { + + if ($except) { + $new=~s/($exreg)|\&/(length($1))?$1:'&'/eg;} + + else { + $new=~s/\&/&/g;}} + + # Weitere Zeichen + if ($except) { + $new =~ s/($exreg)|/(length($1))?$1:'>'/eg; + $new =~ s/($exreg)|\|/(length($1))?$1:'|'/eg; # nich wahr + $new =~ s/($exreg)|"/(length($1))?$1:'"'/eg; # Diese Zeile wird den Bannerklickern + # zu schaffen machen, sowas aber auch... + + # Der grosse Hash + if ($utf8 or $ref -> {-utf8}) { + my $x; + $new =~ s/($exreg)|([\300-\337][\200-\277]|[\340-\357][\200-\277][\200-\277])/ + length($1)?$1:(exists($unimap{$x = unpack('U',$2)})?$unimap{$x}:"&#$x;")/eg;} + + $new =~ s/($exreg)|([\177-\377])/(length($1))?$1:$sonder{$2}/eg;} + + else { + $new =~ s//>/g; + $new =~ s/\|/|/g; + $new =~ s/"/"/g; + + # Der grosse Hash + if ($utf8 or $ref -> {-utf8}) { + my $x; + $new =~ s/([\300-\337][\200-\277]|[\340-\357][\200-\277][\200-\277])/ + exists($unimap{$x = unpack('U',$1)})?$unimap{$x}:"&#$x;"/eg;} + + $new =~ s/([\177-\377])/$sonder{$1}/g;} + + # Zeichen <= 31 + $new=~s/([\001-\010\013\014\016-\037])/'&#'.ord($1).';'/eg; + $new=~s/\000/ /g; + + # Rueckgabe + ref($old)?\$new:$new; +} + +################################ +# sub multiline +# +# Whitespacecodierung +# fuer Leerzeilen +################################ + +sub multiline { + my $old=shift; + my $string=(ref ($old))?$$old:$old; + + # Zeilenumbrueche normalisieren + $string=~s/\015\012|\015|\012/\n/g; + + # Zeilenumbrueche in
umwandeln + $string=~s/\n/
/g; + + # mehr als ein aufeinanderfolgendes + # Leerzeichen in feste Leerzeichen umwandeln + $string=~s/(\s\s+)/(' ' x (length($1)-1)) . ' '/eg; + + # Leerzeichen nach einem
in feste + # Spaces umwandeln + $string=~s/(?:^|(
))\s/$1 /g; + + # Rueckgabe + \$string; +} + +sub toUTF8 ($) { + my $ref = shift; + my $string = ref($ref)?$$ref:$ref; + no warnings 'utf8'; + + $string =~ tr/\x80-\xff//CU; + + ref($ref)?\$string:$string; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +BEGIN { + # Latin 1 + geraten + %sonder=("\177" => '', # Delete-Zeichen + "\200" => '€', # Euro-Zeichen + "\201" => 'ü', # ue - DOS-Zeichensatz + "\202" => '‚', # einfaches Anfuehrungszeichen unten + "\203" => 'ƒ', # forte + "\204" => '„', # doppelte Anfuehrungszeichen unten + "\205" => '…', # drei punkte + "\206" => '†', # dagger + "\207" => '‡', # Dagger + "\210" => 'ˆ', # circ + "\211" => '‰', # Promille + "\212" => 'Š', # so ein S mit Haken drueber :-) + "\213" => '‹', # lsaquo + "\214" => 'Œ', # OE (so verhakelt - daenisch?) wer weiss das schon + "\215" => 'ì', # Codepage 850; + "\216" => 'Ž', # Z mit Haken drueber (Latin Extended B) + "\217" => 'Å', # Codepage 850 (Win) + "\220" => 'ü', # ue - Mac-Zeichensatz + "\221" => "'", # einfache Anfuehrungszeichen oben + "\222" => "'", # dito + "\223" => '“', # doppelte Anfuehrungszeichen oben + "\224" => '“', # dito + "\225" => '•', # Bullet + "\226" => '-', # Bindestrich + "\227" => '-', # dito + "\230" => '˜', # tilde...? + "\231" => '™', # Trade-Mark + "\232" => 'š', # kleines s mit Haken drueber + "\233" => '›', # rsaquo; + "\234" => 'œ', # oe verhakelt + "\235" => 'Ø', # Codepage 850 (Win) + "\236" => '×', # Codepage 850 (Win) + "\237" => 'Ÿ', # Y mit Punkten drueber + "\240" => ' ', # nbsp; + "\241" => '¡', # umgedrehtes ! + "\242" => '¢', # cent-Zeichen + "\243" => '£', # (engl.)Pfund-Zeichen + "\244" => '¤', # Waehrungszeichen + "\245" => '¥', # Yen halt :-) + "\246" => '¦', # eigentlich soll es wohl ein | sein .-) + "\247" => '§', # Paragraph + "\250" => '¨', # zwei Punkte oben + "\251" => '©', # (C) + "\252" => 'ª', # hochgestelltes unterstrichenes a + "\253" => '«', # left-pointing double angle quotation mark (besser koennte ichs auch nicht beschreiben...) + "\254" => '¬', # Negationszeichen + "\255" => '-', # Bindestrich + "\256" => '®', # (R) + "\257" => 'ß', # sz, was auch immer fuern Zeichensatz (DOS?) + "\260" => '°', # Grad-Zeichen + "\261" => '±', # Plusminus + "\262" => '²', # hoch 2 + "\263" => '³', # hoch 3 + "\264" => '‚', # einf. anfuehrungszeichen unten + "\265" => 'µ', # my-Zeichen (griech) + "\266" => '¶', # Absatzzeichen + "\267" => '·', # Mal-Zeichen + "\270" => '¸', + "\271" => '¹', # hoch 1 + "\272" => 'º', # masculine ordinal indicator (spanish) + "\273" => '»', # right-pointing double angle quotation mark + "\274" => '¼', # 1/4 + "\275" => '½', # 1/2 + "\276" => '¾', # 3/4 + "\277" => '¿', # umgedrehtes ? + "\300" => 'À', + "\301" => 'Á', + "\302" => 'Â', + "\303" => 'Ã', + "\304" => 'Ä', + "\305" => 'Å', + "\306" => 'Æ', + "\307" => 'Ç', + "\310" => 'È', + "\311" => 'É', + "\312" => 'Ê', + "\313" => 'Ë', + "\314" => 'Ì', + "\315" => 'Í', + "\316" => 'Î', + "\317" => 'Ï', + "\320" => 'Ð', # keine Ahnung, was das wohl sein soll, auf jeden Fall was islaendisches... + "\321" => 'Ñ', + "\322" => 'Ò', + "\323" => 'Ó', + "\324" => 'Ô', + "\325" => 'Õ', + "\326" => 'Ö', + "\327" => '×', # eigentlich × funzt afaik aber nicht aufm Mac (ob das hier funktioniert, weiss ich nicht) + "\330" => 'Ø', + "\331" => 'Ù', + "\332" => 'Ú', + "\333" => 'Û', + "\334" => 'Ü', + "\335" => 'Ý', + "\336" => 'Þ', + "\337" => 'ß', + "\340" => 'à', + "\341" => 'á', + "\342" => 'â', + "\343" => 'ã', + "\344" => 'ä', + "\345" => 'å', + "\346" => 'æ', + "\347" => 'ç', + "\350" => 'è', + "\351" => 'é', + "\352" => 'ê', + "\353" => 'ë', + "\354" => 'ì', + "\355" => 'í', + "\356" => 'î', + "\357" => 'ï', + "\360" => 'ð', + "\361" => 'ñ', + "\362" => 'ò', + "\363" => 'ó', + "\364" => 'ô', + "\365" => 'õ', + "\366" => 'ö', + "\367" => '÷', + "\370" => 'ø', + "\371" => 'ù', + "\372" => 'ú', + "\373" => 'û', + "\374" => 'ü', + "\375" => 'ý', + "\376" => 'þ', + "\377" => 'ÿ'); + + # Unicode-Mapping + %unimap=(128 => '€', + 129 => 'ü', + 130 => '‚', + 131 => 'ƒ', + 132 => '„', + 133 => '…', + 134 => '†', + 135 => '‡', + 136 => 'ˆ', + 137 => '‰', + 138 => 'Š', + 139 => '‹', + 140 => 'Œ', + 141 => 'ì', + 142 => 'Ž', + 143 => 'Å', + 144 => 'ü', + 145 => "'", + 146 => "'", + 147 => '“', + 148 => '“', + 149 => '•', + 150 => '-', + 151 => '-', + 152 => '˜', + 153 => '™', + 154 => 'š', + 155 => '›', + 156 => 'œ', + 157 => 'Ø', + 158 => '×', + 159 => 'Ÿ', + 160 => ' ', + 163 => '£', + 165 => '¥', + 167 => '§', + 169 => '©', + 171 => '«', + 173 => '-', + 174 => '®', + 175 => 'ß', + 180 => '‚', + 184 => '¸', + 185 => '¹', + 187 => '»', + 192 => 'À', + 193 => 'Á', + 194 => 'Â', + 195 => 'Ã', + 196 => 'Ä', + 197 => 'Å', + 198 => 'Æ', + 199 => 'Ç', + 200 => 'È', + 201 => 'É', + 202 => 'Ê', + 203 => 'Ë', + 204 => 'Ì', + 205 => 'Í', + 206 => 'Î', + 207 => 'Ï', + 208 => 'Ð', + 209 => 'Ñ', + 210 => 'Ò', + 211 => 'Ó', + 212 => 'Ô', + 213 => 'Õ', + 214 => 'Ö', + 216 => 'Ø', + 217 => 'Ù', + 218 => 'Ú', + 219 => 'Û', + 220 => 'Ü', + 221 => 'Ý', + 222 => 'Þ', + 223 => 'ß', + 224 => 'à', + 225 => 'á', + 226 => 'â', + 227 => 'ã', + 228 => 'ä', + 229 => 'å', + 230 => 'æ', + 231 => 'ç', + 232 => 'è', + 233 => 'é', + 234 => 'ê', + 235 => 'ë', + 236 => 'ì', + 237 => 'í', + 238 => 'î', + 239 => 'ï', + 240 => 'ð', + 241 => 'ñ', + 242 => 'ò', + 243 => 'ó', + 244 => 'ô', + 245 => 'õ', + 246 => 'ö', + 247 => '÷', + 248 => 'ø', + 249 => 'ù', + 250 => 'ú', + 251 => 'û', + 252 => 'ü', + 253 => 'ý', + 254 => 'þ', + 255 => 'ÿ'); +} + +# making require happy +1; + +# ==================================================== +# end of Encode::Plain +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Encode/Posting.pm b/selfforum-cgi/shared/Encode/Posting.pm new file mode 100644 index 0000000..b12420f --- /dev/null +++ b/selfforum-cgi/shared/Encode/Posting.pm @@ -0,0 +1,231 @@ +# Posting.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-07 +# lm : n.d.p. / 2001-01-08 +# ==================================================== +# Funktion: +# Spezielle Codierung eines Postingtextes +# ==================================================== + +use strict; + +package Encode::Posting; + +use vars qw(@ISA @EXPORT); +use Encode::Plain; $Encode::Plain::utf8 = 1; + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(encoded_body answer_field message_field); + +################################ +# sub encoded_body +# +# Nachrichtentext in gueltiges +# HTML konvertieren +################################ + +sub encoded_body ($;$) { + my $posting = ${+shift}; + my $params = shift; + + $posting =~ s/[ \t]$//gm; # Whitespaces am Zeilenende entfernen + $posting =~s /\s+$//; # Whitespaces am Stringende entfernen + $posting = ${plain (\$posting)}; # Sonderzeichen maskieren + + # Quotingzeichen normalisieren (\177) + my $quote = plain($params -> {quoteChars}); + my $qquote = quotemeta $quote; + my $len = length ($quote); + $posting =~ s!^((?:$qquote)+)(.*)$!"\177" x (length($1)/$len) .$2!gem if (length ($qquote)); + + # Multine + $posting = ${multiline (\$posting)}; + + # normaler Link + $posting =~ s{\[link:\s* + ((?:ftp:// # hier beginnt $1 + | https?:// + | about: + | view-source: + | gopher:// + | mailto: + | news: + | nntp:// + | telnet:// + | wais:// + | prospero:// + | \.\.?/ # relativ auf dem server + | / # absolut auf dem server + | (?:[a-zA-Z.\d]+)?\?? # im forum + ) [^\s<'()\[\]]+ # auf jeden Fall kein \s und kein ] etc. + ) # hier ist $1 zuende + \s*(?:\]|(\s|\(|\)|
)) # der Begrenzer (\s, ] oder Zeilenende) + } + {$1$2}gix; # und der Link + + # javascript-links extra + my $klammer1='\((?:[^)])*\)'; + my $klammer2="\\((?:$klammer1|(?:[^)])*)\\)"; + my $klammer3="\\((?:$klammer2|(?:[^)])*)\\)"; + my $klammer4="\\((?:$klammer3|(?:[^)])*)\\)"; + + $posting =~ s{\[link:\s* + (javascript: # hier beginnt $1 + (?: + $klammer4 # Klammern bis Verschachtelungstiefe 4 (sollte reichen?) + | '[^\'\\]*(?:\\.[^\'\\]*)*' # mit ' quotierter String, J.F. sei gedankt + # im String sind Escapes zugelassen (also auch \') + # damit werden (korrekt gesetzte) Javascript-Links moeglich + | [^\s<()'\]]+)+ # auf jeden Fall kein \s und kein ] (ausser im String) + ) # hier ist $1 zuende + \s*(?:\s|\]|(\(|\)|
)) # der Begrenzer (\s, ] oder Zeilenende) + } + {$1$2}gix; # und der Link + + # images + $posting =~ s{\[image:\s* + ((?:https?:// + | \.\.?/ # relativ auf dem server + | / # absolut auf dem server + | (?:[a-zA-Z.\d]+)?\?? # im forum + ) [^\s<'()\[\]]+ # auf jeden Fall kein \s und kein ] etc. + ) # hier ist $1 zuende + \s*(?:\]|(\s|\(|\)|
)) # der Begrenzer (\s, ] oder Zeilenende) + } + {$2}gix; # und das Bild + + # iframe + $posting =~ s{\[iframe:\s* + ((?:ftp:// + | https?:// + | about: + | view-source: + | gopher:// + | mailto: + | news: + | nntp:// + | telnet:// + | wais:// + | prospero:// + | \.\.?/ # relativ auf dem server + | / # absolut auf dem server + | [a-zA-Z\d]+(?:\.html?|/) # im forum (koennen eh nur threads oder verweise + # auf tiefere verzeichnisse sein) + )[^\s<'()\]]+ # auf jeden Fall kein \s und kein ] etc. (s.o.) + ) # hier ist $1 zuende + \s*(?:\]|(\s|\(|\)|
)) # der Begrenzer (\s, ] oder Zeilenende) + } + {$2}gix; + + # [msg...] + $params -> {messages} = {} unless (defined $params -> {messages}); + my %msg = %{$params -> {messages}}; + foreach (keys %msg) { + $posting =~ s/\[msg:\s*$_(?:\s*\]|\s)/''.plain($msg{$_}->{alt}).''/gei;} + + # Rueckgabe + \$posting; +} + +################################ +# sub answer_field +# +# Antwort HTML einer Message +# erzeugen +################################ + +sub answer_field ($$) { + my $posting = shift; + my $params = shift; + $params = {} unless (defined $params); + + # ================ + # Antwortfeld + # ================ + my $area = $$posting; + + my $qchar = $params -> {quoteChars}; + + $area =~ s/(?:^|(
))(?!
)/$1\177/g if ($params -> {quoteArea}); # Antwortfeld quoten?! + $area =~ s/\177/$qchar/g; # normalisierte Quotes jedenfalls in Chars umsetzen + + # HTML-Zeug zurueckuebersetzen + + $params -> {messages} = {} unless (defined $params -> {messages}); # um Fehlermeldungen auszuschliessen... + my %msg = map {($params -> {messages} -> {$_} -> {src} => $_)} keys %{$params -> {messages}}; + + $area =~ s{]+>.*?|]+>|]*>|.*?} + {if (defined $1) {"[iframe: $1]"} + elsif (defined $2) {"[msg: $msg{$2}]"} + elsif (defined $3) {"[image: $3]"} + elsif (defined $4) {"[link: $4]"}}eg; + $area =~ s/
/\n/g; + $area =~ s/&(?:#160|nbsp);/ /g; + + # Rueckgabe + \$area; +} + +################################ +# sub message_field +# +# HTML eines Postingtextes +# erzeugen +################################ + +sub message_field ($$) { + my $posting = ${+shift}; + my $params = shift; + $params = {} unless (defined $params); + + # ================ + # Postingtext + # ================ + my $qchar = $params -> {quoteChars}; + + if ($params -> {quoting}) { # Quotes bekommen eine extra Klasse? + # ueberfluessige Abstaende entfernen, + # sie werden eh wieder auseinandergezogen... + $posting =~ s/(\177(?:[^<]|<(?!br>))*
)
(?=\177)/$1/g; + $posting =~ s/(\177(?:[^<]|<(?!br>))*
)
(?!\177)/$1/g; + + my ($last_level, $level, $line, $q, @new)=(-1,0); + + foreach $line (split (/
/,$posting)) { # Zeilenweise gucken, + ($q) = ($line =~ /^(\177+)/g); # wieviele + $level = length ($q); # Quotingchars am Anfang stehen + if ($level != $last_level) { # wenn sich was verandert... + # ... dann TU ETWAS! + + if ($last_level <= 0 and $level > 0) {$last_level = $level; $line='
'.$params -> {startCite} . $line} + elsif ($level > 0) {$last_level = $level; $line=$params -> {endCite} . '
' . $params -> {startCite} . $line} + elsif ($level == 0 and $last_level > 0) {$last_level = -1; $line = $params -> {endCite} . '
' . $line}} + + push @new,$line} + + $new[0] =~ s/^
//; + $posting = (join '
',@new) . (($last_level > 0)?$params -> {endCite}:'');} + + $posting =~ s/\177/$qchar/g; # normalisierte Quotes in Chars umsetzen + + # Rueckgabe + \$posting; +} + + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Encode::Posting +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Id.pm b/selfforum-cgi/shared/Id.pm new file mode 100644 index 0000000..33c0c83 --- /dev/null +++ b/selfforum-cgi/shared/Id.pm @@ -0,0 +1,73 @@ +# Id.pm + +############################################## +# # +# Autor: n.d.p. / nd@o3media.de # +# # +# Letze Aenderung: n.d.p. / 2001-01-28 # +# # +# ========================================== # +# # +# Funktion: # +# # +# Bereitsstellen einer einmaligen ID # +# # +############################################## + +use strict; + +package Id; +require 5.000; + +##################### +# Funktionsexport +##################### + +require Exporter; +@Id::ISA = qw(Exporter); +@Id::EXPORT = qw(unique_id); + +use vars qw(@table); + +########################################## +# EXPORT # +# # +# sub &unique_id # +# # +# Funktion: # +# Rueckgabe der ID # +########################################## + +sub unique_id { + my $id; + + my $ip=$ENV{'REMOTE_ADDR'}; + my $time=time(); + my $port=$ENV{'REMOTE_PORT'}; + my $rand=int(rand(time())); + $ip = hex(join ('',map {sprintf ('%02X',$_)} split (/\./,$ip))); + + join '',map {to_base64 ($_)} (substr ($time,-9), $port, $ip, $rand, $$); +} + +sub to_base64 ($) { + my $x = shift; + my $y = $table[$x % 64]; + + while ($x = int ($x/64)) {$y = $table[$x % 64] . $y} + + # Rueckgabe + $y; +} + +BEGIN { + srand(time()^$$); + @table = ('a'..'z','-','0'..'9','A'..'Z','_'); +} + +# making 'require' happy +1; + +##################### +# end of Id +##################### \ No newline at end of file diff --git a/selfforum-cgi/shared/Lock.pm b/selfforum-cgi/shared/Lock.pm new file mode 100644 index 0000000..1d2c929 --- /dev/null +++ b/selfforum-cgi/shared/Lock.pm @@ -0,0 +1,608 @@ +# Lock.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-04 +# lm : n.d.p. / 2000-01-05 +# ==================================================== +# Funktion: +# Sperren einer Datei +# ==================================================== + +use strict; + +package Lock; + +use vars qw(@ISA @EXPORT_OK %EXPORT_TAGS $Timeout $violentTimeout $masterTimeout $iAmMaster); + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); + +@EXPORT_OK = qw(lock_file unlock_file write_lock_file write_unlock_file + violent_unlock_file set_master_lock release_file); + +%EXPORT_TAGS = (READ => [qw(lock_file unlock_file violent_unlock_file)], + WRITE => [qw(write_lock_file write_unlock_file violent_unlock_file)], + ALL => [qw(lock_file unlock_file write_lock_file write_unlock_file + violent_unlock_file set_master_lock release_file)]); + +# ==================================================== +# Windows section (no symlinks) +# ==================================================== + +################################ +# sub w_lock_file +# +# Schreibsperre setzen +################################ + +sub w_lock_file ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + my $i; + + if (-f &masterlockfile($filename)) { + + for ($i=0 ; $i<=$timeout ; $i++) { + # Referenzzaehler um eins erhoehen + &set_ref($filename,1,$timeout) and return 1; + sleep (1);}} + + else { + # Mastersperre + return undef;} + + 0; # Mist +} + +################################ +# sub w_unlock_file +# +# Schreibsperre aufheben +################################ + +sub w_unlock_file ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + + if (-f &masterlockfile($filename)) { + # Referenzzaehler um eins erniedrigen + &set_ref($filename,-1,$timeout) and return 1;} + + 0; # Mist +} + +################################ +# sub w_write_lock_file +# +# Lese- und Schreibsperre +# setzen +################################ + +sub w_write_lock_file ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + + if (-f &masterlockfile($filename) or $iAmMaster) { + # bevorstehenden Schreibzugriff anmelden + &simple_lock ($filename,$timeout) or return 0; + + my $i; + for ($i=0 ; $i<=$timeout ; $i++) { + # Referenzdatei sperren + &simple_lock (&reffile($filename),$timeout) or (return &simple_unlock($filename,$timeout) and 0); + + # Referenzzaehler = 0 ? => okay + return 1 if (&get_ref ($filename) == 0); + + # Referenzdatei wieder freigeben + &simple_unlock (&reffile($filename),$timeout) or (return &simple_unlock($filename,$timeout) and 0); + sleep(1);} + + &simple_unlock ($filename);} + + else { + # Mastersperre gesetzt + return undef;} + + 0; # Mist +} + +################################ +# sub w_write_unlock_file +# +# Lese- und Schreibsperre +# aufheben +################################ + +sub w_write_unlock_file ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + + if (-f &masterlockfile($filename) or $iAmMaster) { + &simple_unlock (&reffile($filename),$timeout) or return 0; # Referenzdatei freigeben + &simple_unlock ($filename,$timeout) or return 0;} # Lesesperre aufheben + + 1; # jawoll! +} + +################################ +# sub w_violent_unlock_file +# +# Sperre brutal aufheben +################################ + +sub w_violent_unlock_file ($) { + my $filename=shift; + + if (-f &masterlockfile($filename)) { + + # Zeit der letzten Modifikation feststellen + # und abbrechen, wenn meine Zeit noch nicht gekommen ist + my $reffile; + if (-f ($reffile = $filename) or -f ($reffile = &lockfile($filename))) { + my $time = (stat $reffile)[9]; + return if ((time - $time) < $violentTimeout);} + + write_lock_file ($filename,1); # letzter Versuch, exklusiven Zugriff zu bekommen + unlink (&reffile($filename)); # Referenzzaehler auf null + simple_unlock (&reffile($filename)); # Referenzdatei freigeben + simple_unlock ($filename);} # Datei freigeben (Lesesperre aufheben) +} + +################################ +# sub w_set_master_lock +# +# Mastersperre setzen +################################ + +sub w_set_master_lock ($;$) { + my $filename=shift; + my $timeout=(shift @_ or $masterTimeout); + + # exklusiven Zugriff erlangen...oder abbrechen + return 0 unless (&write_lock_file ($filename,$timeout)); + + # Mastersperre setzen und Erfolg melden + unlink &masterlockfile($filename) and return 1; + + 0; # Mist +} + +################################ +# sub w_release_file +# +# Alle Sperren inkl. Master- +# sperre aufheben +################################ + +sub w_release_file ($) { + my $filename=shift; + + unlink (&reffile($filename)); # Referenzzaehler auf null + return 0 if (-f &reffile($filename)); # wirklich? + return 0 unless (simple_unlock (&reffile($filename))); # Referenzzaehler freigeben + return 0 unless (&simple_unlock ($filename)); # Datei selbst freigeben (Lesesperre) + return 0 unless (&simple_unlock (&masterfile($filename))); # Mastersperre aufheben + + 1; # jup +} + +# ==================================================== +# *n*x section (symlinks possible) +# ==================================================== + +################################ +# sub x_lock_file +# +# Schreibsperre setzen +################################ + +sub x_lock_file ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + my $i; + + unless (-l &masterlockfile($filename)) { + + for ($i=0 ; $i<=$timeout ; $i++) { + # Referenzzaehler um eins erhoehen + &set_ref($filename,1,$timeout) and return 1; + sleep (1);}} + + else { + # Mastersperre + return undef;} + + 0; # Mist +} + +################################ +# sub x_unlock_file +# +# Schreibsperre aufheben +################################ + +sub x_unlock_file ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + + unless (-l &masterlockfile($filename)) { + # Referenzzaehler um eins erniedrigen + &set_ref($filename,-1,$timeout) and return 1;} + + 0; # Mist +} + +################################ +# sub x_write_lock_file +# +# Lese- und Schreibsperre +# setzen +################################ + +sub x_write_lock_file ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + + unless (-l &masterlockfile($filename) and not $iAmMaster) { + # bevorstehenden Schreibzugriff anmelden + &simple_lock ($filename,$timeout) or return 0; + + my $i; + for ($i=0 ; $i<=$timeout ; $i++) { + # Referenzdatei sperren + &simple_lock (&reffile($filename),$timeout) or (return &simple_unlock($filename,$timeout) and 0); + + # Referenzzaehler = 0 ? => okay + return 1 if (&get_ref ($filename) == 0); + + # Referenzdatei wieder freigeben + &simple_unlock (&reffile($filename),$timeout) or (return &simple_unlock($filename,$timeout) and 0); + sleep(1);} + + &simple_unlock ($filename);} + + else { + # Mastersperre gesetzt + return undef;} + + 0; # Mist +} + +################################ +# sub x_write_unlock_file +# +# Lese- und Schreibsperre +# aufheben +################################ + +sub x_write_unlock_file ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + + unless (-l &masterlockfile($filename) and not $iAmMaster) { + &simple_unlock (&reffile($filename),$timeout) or return 0; # Referenzdatei freigeben + &simple_unlock ($filename,$timeout) or return 0;} # Lesesperre aufheben + + 1; # jawoll! +} + +################################ +# sub x_violent_unlock_file +# +# Sperre brutal aufheben +################################ + +sub x_violent_unlock_file ($) { + my $filename=shift; + + unless (-l &masterlockfile($filename)) { + + # Zeit der letzten Modifikation feststellen + # und abbrechen, wenn meine Zeit noch nicht gekommen ist + my ($reffile,$time); + + if (-f ($reffile = $filename)) { + $time = (stat $reffile)[9];} + + elsif (-l ($reffile = &lockfile($filename))) { + $time = (lstat $reffile)[9];} + + if ($reffile) { + return if ((time - $time) < $violentTimeout);} + + write_lock_file ($filename,1); # letzter Versuch, exklusiven Zugriff zu bekommen + unlink (&reffile($filename)); # Referenzzaehler auf null + simple_unlock (&reffile($filename)); # Referenzdatei freigeben + simple_unlock ($filename);} # Datei freigeben (Lesesperre aufheben) +} + +################################ +# sub x_set_master_lock +# +# Mastersperre setzen +################################ + +sub x_set_master_lock ($;$) { + my $filename=shift; + my $timeout=(shift @_ or $masterTimeout); + + # exklusiven Zugriff erlangen...oder abbrechen + return 0 unless (&write_lock_file ($filename,$timeout)); + + # Mastersperre setzen und Erfolg melden + symlink $filename, &masterlockfile($filename) and return 1; + + 0; # Mist +} + +################################ +# sub x_release_file +# +# Alle Sperren inkl. Master- +# sperre aufheben +################################ + +sub x_release_file ($) { + my $filename=shift; + + unlink (&reffile($filename)); # Referenzzaehler auf null + return 0 if (-f &reffile($filename)); # wirklich? + return 0 unless (simple_unlock (&reffile($filename))); # Referenzzaehler freigeben + return 0 unless (&simple_unlock ($filename)); # Datei selbst freigeben (Lesesperre) + return 0 unless (&simple_unlock (&masterfile($filename))); # Mastersperre aufheben + + 1; # jup +} + +# ==================================================== +# private subs +# ==================================================== + +################################ +# Dateinamen +################################ + +sub reffile ($) { + "$_[0].lock.ref"; +} +sub lockfile ($) { + "$_[0].lock"; +} +sub masterlockfile ($) { + &lockfile(&masterfile($_[0])); +} +sub masterfile ($) { + "$_[0].master"; +} + +################################ +# einfaches Sperren/Entsperren +# Windows +# +# (Lockdatei loeschen) +################################ + +sub w_simple_lock ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + my $lockfile=&lockfile($filename); + + my $i; + for ($i=$timeout; $i>=0; $i--) { + unlink("$lockfile") and return 1; + sleep(1);} + + 0; # Mist +} + +sub w_simple_unlock ($) { + my $filename=shift; + my $lockfile=&lockfile($filename); + my $flag=1; + local *LF; + + open(LF, ">$lockfile") or $flag=0; + close(LF) or $flag=0; + + # Rueckgabe + $flag; +} + +################################ +# einfaches Sperren/Entsperren +# *n*x +# +# (symlink setzen) +################################ + +sub x_simple_lock ($;$) { + my $filename=shift; + my ($timeout)=(shift (@_) or $Timeout); + my $lockfile=&lockfile($filename); + + my $i; + for ($i=$timeout; $i>=0; $i--) { + symlink $filename,$lockfile and return 1; + sleep(1);} + + 0; # Mist +} + +sub x_simple_unlock ($) { + my $filename=shift; + + unlink (&lockfile($filename)) and return 1; + + 0; # hmmm... +} + +################################ +# sub w_set_ref +# Windows +# +# Referenzzaehler um $_[1] +# erhoehen +# (kann auch negativ sein...) +################################ + +sub w_set_ref ($$$) { + my ($filename,$z)=@_; + my $timeout=(shift @_ or $Timeout); + my $old; + my $reffile=&reffile($filename); + local *REF; + + + # runterzaehlen - ja, neue Leseversuche - nein + if ($z > 0) { + return 0 unless(-e &lockfile($filename));} + + # Referenzdatei locken + return 0 unless(&simple_lock ($reffile,$timeout)); + + # Referenzdatei auslesen + unless (open REF,"<$reffile") { + $old=0;} + else { + $old=; + chomp $old; + close REF or return 0;} + + # Neuen Referenzwert schreiben + $old+=$z; + $old=0 if ($old < 0); + open REF,">$reffile" or return 0; + print REF $old; + close REF or return 0; + + # wieder entsperren + return 0 unless(&simple_unlock($reffile)); + + 1; +} + +################################ +# sub x_set_ref +# *n*x +# +# Referenzzaehler um $_[1] +# erhoehen +# (kann auch negativ sein...) +################################ + +sub x_set_ref ($$$) { + my ($filename,$z)=@_; + my $timeout=(shift @_ or $Timeout); + my $old; + my $reffile=&reffile($filename); + local *REF; + + + # runterzaehlen - ja, neue Leseversuche - nein + if ($z > 0) { + return 0 if(-l &lockfile($filename));} + + # Referenzdatei locken + return 0 unless(&simple_lock ($reffile,$timeout)); + + # Referenzdatei auslesen + unless (open REF,"<$reffile") { + $old=0;} + else { + $old=; + chomp $old; + close REF or return 0;} + + # Neuen Referenzwert schreiben + $old += $z; + $old = 0 if ($old < 0); + open REF,">$reffile" or return 0; + print REF $old; + close REF or return 0; + + # wieder entsperren + return 0 unless(&simple_unlock($reffile)); + + 1; +} + +################################ +# sub get_ref +# +# Referenzzaehler auslesen +# +# Das Locking muss an +# anderer Stelle ausgefuehrt +# werden! +################################ + +sub get_ref ($$) { + my $filename=shift; + my $reffile=&reffile($filename); + my $old; + local *REF; + + unless (open REF,"<$reffile") { + $old=0;} + else { + $old=; + chomp $old; + close REF or return 0;} + + # Rueckgabe + $old; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +BEGIN { + # Globale Variablen (Zeiten in Sekunden) + $Timeout = 10; # normaler Timeout + $violentTimeout = 600; # zum gewaltsamen Entsperren (10 Minuten) + $masterTimeout = 20; # fuer die Mastersperre + + $iAmMaster = 0; # erstmal bin ich kein Master :-) + + # wirkliche Funktionen ihren Bezeichnern zuweisen + # (perldoc -f symlink) + + if ( eval {local $SIG{__DIE__}; symlink('',''); 1 } ) { + *lock_file = \&x_lock_file; + *unlock_file = \&x_unlock_file; + *write_lock_file = \&x_write_lock_file; + *write_unlock_file = \&x_write_unlock_file; + *violent_unlock_file = \&x_violent_unlock_file; + *set_master_lock = \&x_set_master_lock; + *release_file = \&x_release_file; + + *simple_lock = \&x_simple_lock; + *simple_unlock = \&x_simple_unlock; + *set_ref = \&x_set_ref;} + + else { + *lock_file = \&w_lock_file; + *unlock_file = \&w_unlock_file; + *write_lock_file = \&w_write_lock_file; + *write_unlock_file = \&w_write_unlock_file; + *violent_unlock_file = \&w_violent_unlock_file; + *set_master_lock = \&w_set_master_lock; + *release_file = \&w_release_file; + + *simple_lock = \&w_simple_lock; + *simple_unlock = \&w_simple_unlock; + *set_ref = \&w_set_ref;} +} + +# making require happy +1; + +# ==================================================== +# end of Lock +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Mail.pm b/selfforum-cgi/shared/Mail.pm new file mode 100644 index 0000000..e46a81c --- /dev/null +++ b/selfforum-cgi/shared/Mail.pm @@ -0,0 +1,294 @@ +# Mail.pm + +############################################## +# # +# Autor: n.d.p. nd@o3media.de # +# # +# Letze Aenderung: n.d.p. / 2001-01-03 # +# # +# ========================================== # +# # +# Funktion: # +# ganz simples Formatieren und Senden # +# einer Mail im text/plain, qp-Format # +# # +############################################## + +use strict; + +package Mail; + +use vars qw($mailbox $mailprog @ISA @EXPORT); + +# =================== +# Funktionsexport +# =================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(is_mail_address send_mail); + +######################################## +# EXPORT +# sub is_mail_address +# +# Funktion: +# Ueberpruefen der Syntax einer +# Email-Adresse +# +# Rueckgabe +# true/false +######################################## + +sub is_mail_address ($) { + return ($_[0] =~ /$mailbox/); +} + +######################################## +# EXPORT +# sub send_mail +# +# Funktion: +# Senden der Nachricht +# ueber open-print-close +# $Mail::mailprog enthaelt +# den vollstaendigen string fuer +# open, dass heisst, es kann +# auch ein Dateiname sein. +# +# Rueckgabe: +# true/false +######################################## + +sub send_mail { + my $param=shift; + local *MAIL; + + open MAIL,$mailprog or return 0; + print MAIL &as_string ($param); + close MAIL and return 1; + + # Hier muss irgendwas schiefgelaufen sein + 0; +} + +########################################## +# PRIVAT +# sub as_string +# +# Funktion: +# Bereitstellung der gesamten Mail +# als String. +# +# Rueckgabe: +# String +########################################## + +sub as_string { + my $param=shift; + + my $header=&header_as_string ($param); + my $body=&body_as_string ($param); + + # Rueckgabe + "$header\n$body\n"; +} + +########################################## +# PRIVAT +# sub body_as_string +# +# Funktion: +# Bereitstellung des Bodys +# als (qp-codierten) String. +# +# Rueckgabe: +# String +########################################## + +sub body_as_string { + my $param=shift; + + &encode_qp($param->{body}); +} + +########################################## +# PRIVAT +# sub header_as_string +# +# Funktion: +# Bereitstellung des Headers +# als String. +# +# Rueckgabe: +# String +########################################## + +sub header_as_string { + my $param=shift; + + my $string="Content-Disposition: inline\n"; + $string.="MIME-Version: 1.0\n"; + $string.="Content-Transfer-Encoding: quoted-printable\n"; + $string.="Content-Type: text/plain\n"; + $string.="Date: ".&rfc822_date(time)."\n"; + $string.="From: ".$param->{'from'}."\n"; + $string.=&get_list('To',$param->{'to'}); + $string.=&get_list('Cc',$param->{'cc'}); + $string.=&get_list('Bcc',$param->{'bcc'}); + $string.="Subject: ".encode_qp($param->{'subject'})."\n"; + + # Rueckgabe + $string; +} + +####################################### +# PRIVAT +# sub encode_qp +# +# C&P aus dem Modul MIME::QuotedPrint +# Thanx for that +####################################### + +sub encode_qp ($) +{ + my $res = shift; + $res =~ s/([^ \t\n!-<>-~])/sprintf("=%02X", ord($1))/eg; # rule #2,#3 + $res =~ s/([ \t]+)$/ + join('', map { sprintf("=%02X", ord($_)) } + split('', $1) + )/egm; # rule #3 (encode whitespace at eol) + + # rule #5 (lines must be shorter than 76 chars, but we are not allowed + # to break =XX escapes. This makes things complicated :-( ) + my $brokenlines = ""; + $brokenlines .= "$1=\n" + while $res =~ s/(.*?^[^\n]{73} (?: + [^=\n]{2} (?! [^=\n]{0,1} $) # 75 not followed by .?\n + |[^=\n] (?! [^=\n]{0,2} $) # 74 not followed by .?.?\n + | (?! [^=\n]{0,3} $) # 73 not followed by .?.?.?\n + ))//xsm; + + "$brokenlines$res"; +} + +############################################## +# PRIVAT +# sub get_list +# +# Funktion: +# Aufbereitung einer Liste oder eines +# Strings fuer den Header (To, Cc, Bcc) +# +# Rueckgabe: +# Ergebnis oder nichts +############################################## + +sub get_list ($$) { + my ($start,$list)=splice @_; + my $string=""; + + return "" unless (length($list)); + if (ref($list)) { + return "" unless (@$list); + foreach (@$list) { + $string.="$start: $_\n";}} + else { + $string="$start: $list\n";} + + # Rueckgabe + $string; +} + +############################################## +# PRIVAT +# sub rfc822_date +# +# Funktion: +# Bereitstellung eines RFC-konformen +# Datumstrings +# +# Rueckgabe: +# Datumstring +############################################## + +sub rfc822_date ($) { + my ($sek, $min, $std, $mtag, $mon, $jahr, $wtag) = gmtime (+shift); + + sprintf ('%s, %02d %s %04d %02d:%02d:%02d GMT', + (qw(Sun Mon Tue Wed Thu Fri Sat))[$wtag], + $mtag, + (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$mon], + $jahr+1900, $std, $min, $sek); +} + +############################################## +# Modulinitialisierung +# BEGIN +# +# Funktion: +# Bereitstellung des Regexps und des +# Mailprogs +############################################## + +BEGIN { + # Standard-Mailprogramm + + # Dieser String wird so, wie er ist, an die open-Anweisung geschickt, + # -t = tainted(?),der Header (=alles bis zur ersten Leerzeile) + # wird nach To:, Cc: und evtl. Bcc: abgesucht. + # -oi = damit wird verhindert, dass sendmail, ein Zeile, wo nur ein + # Punkt drinsteht, als Mailende erkennt( waere Standard ). + # =================================================================== + + $mailprog = '|/usr/lib/sendmail -t -oi'; + + # Thanx to J. Friedl for this regex: + + my ($address,$route_addr,$phrase,$addr_spec,$X,$phrase_char,$quoted_str,$comment,$word,$phrase_ctrl,$NonASCII, + $CloseBR,$OpenBR,$esc,$route,$domain,$local_part,$Period,$sub_domain,$domain_lit,$domain_ref,$quoted_pair, + $dtext,$atom,$qtext,$atom_char,$ctrl,$space,$tab,$CloseParen,$ctext,$Cnested,$OpenParen,$CRlist); + + $esc = '\\\\'; + $Period = '\.'; + $space = '\040'; + $tab = '\t'; + $OpenBR = '\['; + $CloseBR = '\]'; + $OpenParen = '\('; + $CloseParen = '\)'; + $NonASCII = '\x80-\xff'; + $ctrl = '\000-\037'; + $CRlist = '\n\015'; + $qtext = qq/[^$esc$NonASCII$CRlist\"]/; + $dtext = qq/[^$esc$NonASCII$CRlist$OpenBR$CloseBR]/; + $quoted_pair = qq< $esc [^$NonASCII] >; + $ctext = qq< [^$esc$NonASCII$CRlist()] >; + $Cnested = qq< $OpenParen $ctext* (?: $quoted_pair $ctext* )* $CloseParen >; + $comment = qq< $OpenParen $ctext* (?: (?: $quoted_pair | $Cnested ) $ctext* )* $CloseParen >; + $X = qq< [$space$tab]* (?: $comment [$space$tab]* )* >; + $atom_char = qq/[^($space)<>\@,;:\".$esc$OpenBR$CloseBR$ctrl$NonASCII]/; + $atom = qq< $atom_char+ (?!$atom_char) >; + $quoted_str = qq< \" $qtext * (?: $quoted_pair $qtext * )* \" >; + $word = qq< (?: $atom | $quoted_str ) >; + $domain_ref = $atom; + $domain_lit = qq< $OpenBR (?: $dtext | $quoted_pair )* $CloseBR >; + $sub_domain = qq< (?: $domain_ref | $domain_lit ) $X >; + $domain = qq< $sub_domain (?: $Period $X $sub_domain )* >; + $route = qq< \@ $X $domain (?: , $X \@ $X $domain )* : $X >; + $local_part = qq< $word $X (?: $Period $X $word $X )* >; + $addr_spec = qq< $local_part \@ $X $domain >; + $route_addr = qq[ < $X (?: $route )? $addr_spec > ]; + $phrase_ctrl = '\000-\010\012-\037'; + $phrase_char = qq/[^()<>\@,;:\".$esc$OpenBR$CloseBR$NonASCII$phrase_ctrl]/; + $phrase = qq< $word $phrase_char * (?: (?: $comment | $quoted_str ) $phrase_char * )* >; + $mailbox = qq< $X (?: $addr_spec | $phrase $route_addr ) >; + $mailbox = qr ~^$mailbox$~x; +} + +# making 'require' happy +1; + +##################### +# end of Mail +##################### \ No newline at end of file diff --git a/selfforum-cgi/shared/Posting/Write.pm b/selfforum-cgi/shared/Posting/Write.pm new file mode 100644 index 0000000..d2444df --- /dev/null +++ b/selfforum-cgi/shared/Posting/Write.pm @@ -0,0 +1,280 @@ +# Posting/Write.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-29 +# lm : n.d.p. / 2001-01-29 +# ==================================================== +# Funktion: +# Speicherung eines Postings +# ==================================================== + +use strict; + +package Posting::Write; + +use vars qw(@ISA @EXPORT); + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(write_posting); + +use Encode::Plain; $Encode::Plain::utf8 = 1; +use Encode::Posting; +use Lock qw(:WRITE release_file); +use Posting::_lib qw(get_message_node get_message_header create_forum_xml_string save_file); + +use XML::DOM; + +################################ +# sub write_posting +# +# Neues Posting speichern +################################ + +sub write_posting ($) { + my $param = shift; + my ($thread,$tid); + my $mid = 'm'.($param -> {lastMessage} + 1); + + my $pars = {quoteChars => $param -> {quoteChars}, + messages => $param -> {messages}}; + + my %error = (threadWrite => '1 could not write thread file', + forumWrite => '2 could not write forum file', + threadFile => '3 could not load thread file', + noParent => '4 could not find parent message'); + + # neue Nachricht + unless ($param -> {parentMessage}) { + $tid = 't'.($param -> {lastThread} + 1); + $thread = create_new_thread ({msg => $mid, + ip => $param -> {ip}, + name => $param -> {author}, + email => $param -> {email}, + home => $param -> {homepage}, + image => $param -> {image}, + category => $param -> {category}, + subject => $param -> {subject}, + time => $param -> {time}, + dtd => $param -> {dtd}, + thread => $tid, + body => $param -> {body}, + pars => $pars}); + + save_file ($param -> {messagePath}.$tid.'.xml',\($thread -> toString)) or return $error{threadWrite}; + + # Thread eintragen + $param -> {parsedThreads} + -> {$param -> {lastThread} + 1} = [{mid => $param -> {lastMessage} + 1, + unid => $param -> {uniqueID}, + name => plain($param -> {author}), + cat => plain(length($param -> {category})?$param->{category}:''), + subject => plain($param -> {subject}), + time => plain($param -> {time})}]; + + my $forum = create_forum_xml_string ($param -> {parsedThreads}, + {dtd => $param -> {dtd}, + lastMessage => $mid, + lastThread => $tid}); + + save_file ($param -> {forumFile}, $forum) or return $error{forumWrite}; + release_file ($param -> {messagePath}.$tid.'.xml'); + return (0, $thread, $mid);} + + # Reply + else { + $tid = 't'.($param -> {thread}); + my $tfile = $param -> {messagePath}.$tid.'.xml'; + my $xml; + + unless (write_lock_file ($tfile)) { + violent_unlock_file ($tfile); + return $error{threadFile};} + + else { + $xml = eval {local $SIG{__DIE__}; new XML::DOM::Parser (KeepCDATA => 1) -> parsefile ($tfile);}; + + if ($@) { + violent_unlock_file ($tfile) unless (write_unlock_file ($tfile)); + return $error{threadFile};} + + my $mnode = get_message_node ($xml, $tid, 'm'.$param -> {parentMessage}); + + unless (defined $mnode) { + violent_unlock_file ($tfile) unless (write_unlock_file ($tfile)); + return $error{noParent};} + + my $pheader = get_message_header ($mnode); + + my $message = create_message ($xml, + {msg => $mid, + ip => $param -> {ip}, + name => $param -> {author}, + email => $param -> {email}, + home => $param -> {homepage}, + image => $param -> {image}, + category => length($param -> {category})?$param -> {category}:$pheader -> {category}, + subject => length($param -> {subject})?$param -> {subject}:$pheader -> {subject}, + time => $param -> {time}, + pars => $pars}); + + $mnode -> appendChild ($message); + + my $mcontent = $xml -> createElement ('MessageContent'); + $mcontent -> setAttribute ('mid', $mid); + $mcontent -> appendChild ($xml -> createCDATASection (${encoded_body(\($param -> {body}), $pars)})); + + my $content = $xml -> getElementsByTagName ('ContentList', 1) -> item (0); + $content -> appendChild ($mcontent); + + unless (save_file ($tfile, \($xml -> toString))) { + violent_unlock_file ($tfile) unless (write_unlock_file ($tfile)); + return $error{threadWrite};} + + violent_unlock_file ($tfile) unless (write_unlock_file ($tfile)); + + $thread = $xml; + + # Message eintragen + # ACHTUNG! danach kann der Threadbaum nicht mehr fuer die visuelle + # Ausgabe genutzt werden, da die answers nicht angepasst werden + # (und somit nicht mehr stimmen...) + + my $i=1; + my $cat = length($param -> {category})?$param -> {category}:$pheader -> {category}; + my $subj = length($param -> {subject})?$param -> {subject}:$pheader -> {subject}; + + for (@{$param -> {parsedThreads} -> {$param -> {thread}}}) { + if ($_ -> {mid} == $param -> {parentMessage}) { + splice @{$param -> {parsedThreads} -> {$param -> {thread}}},$i,0, + {mid => $param -> {lastMessage} + 1, + unid => $param -> {uniqueID}, + name => plain ($param -> {author}), + cat => plain(length($cat)?$cat:''), + subject => plain(length($subj)?$subj:''), + level => $_ -> {level} + 1, + time => plain ($param -> {time})}; + last;} + $i++;} + + my $forum = create_forum_xml_string ($param -> {parsedThreads}, + {dtd => $param -> {dtd}, + lastMessage => $mid, + lastThread => 't'.$param -> {lastThread}}); + + save_file ($param -> {forumFile}, $forum) or return $error{forumWrite};} + + return (0, $thread, $mid);} +} + +# ==================================================== +# Private Funktionen +# ==================================================== + +sub create_message ($$) { + my ($xml,$par) = @_; + + my $message = $xml -> createElement ('Message'); + $message -> setAttribute ('id', $par -> {msg}); + $message -> setAttribute ('ip', $par -> {ip}); + + # Header erzeugen + my $header = $xml -> createElement ('Header'); + + # alles inside of 'Header' + my $author = $xml -> createElement ('Author'); + my $name = $xml -> createElement ('Name'); + $name -> addText ($par -> {name}); + $author -> appendChild ($name); + + my $email = $xml -> createElement ('Email'); + $email -> addText ($par -> {email}); + $author -> appendChild ($email); + + if (length ($par -> {home})) { + my $home = $xml -> createElement ('HomepageUrl'); + $home -> addText ($par -> {home}); + $author -> appendChild ($home);} + + if (length ($par -> {image})) { + my $image = $xml -> createElement ('ImageUrl'); + $image -> addText ($par -> {image}); + $author -> appendChild ($image);} + + my $category = $xml -> createElement ('Category'); + $category -> addText ($par -> {category}); + + my $subject = $xml -> createElement ('Subject'); + $subject -> addText ($par -> {subject}); + + my $date = $xml -> createElement ('Date'); + $date -> setAttribute ('longSec', $par -> {time}); + + $header -> appendChild ($author); + $header -> appendChild ($category); + $header -> appendChild ($subject); + $header -> appendChild ($date); + $message -> appendChild ($header); + + $message; +} + +sub create_new_thread ($) { + my $par = shift; + + # neues Dokument + my $xml = new XML::DOM::Document; + + # XML-declaration + my $decl = new XML::DOM::XMLDecl; + $decl -> setVersion ('1.0'); + $decl -> setEncoding ('UTF-8'); + $xml -> setXMLDecl ($decl); + + # Doctype + my $dtd = $xml -> createDocumentType ('Forum', $par -> {dtd}, undef, undef); + $xml -> setDoctype ($dtd); + + # Root erzeugen + my $forum = $xml -> createElement ('Forum'); + + # Thread erzeugen + my $thread = $xml -> createElement ('Thread'); + $thread -> setAttribute ('id', $par -> {thread}); + + # Message erzeugen + my $message = create_message ($xml,$par); + + # Contentlist + my $content = $xml -> createElement ('ContentList'); + my $mcontent = $xml -> createElement ('MessageContent'); + $mcontent -> setAttribute ('mid', $par -> {msg}); + $mcontent -> appendChild ($xml -> createCDATASection (${encoded_body(\($par -> {body}), $par -> {pars} )})); + + # die ganzen Nodes verknuepfen + $thread -> appendChild ($message); + $forum -> appendChild ($thread); + + $content -> appendChild ($mcontent); + $forum -> appendChild ($content); + + $xml -> appendChild ($forum); + + # und fertiges Dokument zurueckgeben + $xml; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Posting::Write +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Posting/_lib.pm b/selfforum-cgi/shared/Posting/_lib.pm new file mode 100644 index 0000000..fea4097 --- /dev/null +++ b/selfforum-cgi/shared/Posting/_lib.pm @@ -0,0 +1,509 @@ +# Posting/_lib.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-07 +# lm : n.d.p. / 2001-01-08 +# ==================================================== +# Funktion: +# * Schnittstellen fuer den Zugriff auf Messages +# * Zeitdarstellung +# ==================================================== + +use strict; + +package Posting::_lib; + +use vars qw(@ISA @EXPORT_OK); + +use Encode::Plain; $Encode::Plain::utf8 = 1; + +use XML::DOM; + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT_OK = qw(get_message_header get_message_body get_message_node parse_single_thread + hr_time short_hr_time long_hr_time + get_all_threads + create_forum_xml_string + save_file); + +# ==================================================== +# Zugriff uebers DOM +# ==================================================== + +########################### +# sub get_message_header +# +# Messageheader auslesen +########################### + +sub get_message_header ($) { + my $node = shift; + my %conf; + + my $header = $node -> getElementsByTagName ('Header', 0) -> item (0); + my $author = $header -> getElementsByTagName ('Author', 0) -> item (0); + my $name = $author -> getElementsByTagName ('Name', 0) -> item (0); + my $email = $author -> getElementsByTagName ('Email', 0) -> item (0); + my $home = $author -> getElementsByTagName ('HomepageUrl', 0) -> item (0); + my $image = $author -> getElementsByTagName ('ImageUrl', 0) -> item (0); + my $cat = $header -> getElementsByTagName ('Category', 0) -> item (0); + my $subject = $header -> getElementsByTagName ('Subject', 0) -> item (0); + my $date = $header -> getElementsByTagName ('Date', 0) -> item (0); + + %conf = (name => ($name -> hasChildNodes)?$name -> getFirstChild -> getData:undef, + category => ($cat -> hasChildNodes)?$cat -> getFirstChild -> getData:undef, + subject => ($subject -> hasChildNodes)?$subject -> getFirstChild -> getData:undef, + email => (defined ($email) and $email -> hasChildNodes)?$email -> getFirstChild -> getData:undef, + home => (defined ($home) and $home -> hasChildNodes)?$home -> getFirstChild -> getData:undef, + image => (defined ($image) and $image -> hasChildNodes)?$image -> getFirstChild -> getData:undef, + time => $date -> getAttribute ('longSec')); + \%conf; +} + +########################### +# sub get_message_header +# +# Messagebody auslesen +########################### + +sub get_message_body ($$) { + my ($xml,$mid) = @_; + my $body; + + foreach ($xml -> getElementsByTagName ('ContentList', 1) -> item (0) -> getElementsByTagName ('MessageContent', 0)) { + if ($_ -> getAttribute ('mid') eq $mid) { + $body = ($_ -> hasChildNodes)?$_ -> getFirstChild -> getData:''; + last;}} + + \$body; +} + +########################### +# sub get_message_header +# +# Messagenode bestimmen +########################### + +sub get_message_node ($$$) { + my ($xml,$tid,$mid) = @_; + my ($mnode,$tnode); + + for ( $xml -> getElementsByTagName ('Thread')) { + if ($_ -> getAttribute ('id') eq $tid) { + $tnode = $_; + for ($tnode -> getElementsByTagName ('Message')) { + if ($_ -> getAttribute ('id') eq $mid) { + $mnode = $_; + last;}} + last;}} + + wantarray?($mnode, $tnode):$mnode; +} + +########################### +# sub parse_single_thread +# +# einzelne Threaddatei +# parsen +########################### + +sub parse_single_thread ($$;$) { + my ($tnode, $deleted, $sorted) = @_; + my ($header, @msg, %mno); + + for ($tnode -> getElementsByTagName ('Message')) { + $header = get_message_header ($_); + + push @msg,{mid => ($_ -> getAttribute ('id') =~ /(\d+)/)[0], + ip => $_ -> getAttribute ('ip'), + kids => [$_ -> getElementsByTagName ('Message', 0)], + answers => $_ -> getElementsByTagName ('Message') -> getLength, + deleted => ($_ -> getAttribute ('flag') eq 'deleted')?1:0, + name => plain($header -> {name}), + cat => plain($header -> {category} or ''), + subject => plain($header -> {subject}), + time => plain($header -> {time})}; + $mno{$_} = $#msg;} + + # Eintraege ergaenzen und korrigieren + my $level; + $msg[0] -> {level} = 0; + for (@msg) { + $level = $_ -> {level} + 1; + @{$_ -> {kids}} = map {$msg[$mno{$_}] -> {level} = $level; $mno{$_}} @{$_ -> {kids}};} + + # ============ + # Sortieren und bei Bedarf + # geloeschte Messages entfernen + + my $smsg = sort_thread (\@msg, $sorted); + delete_messages ($smsg) unless ($deleted); + + $smsg; +} + +########################### +# sub create_message_xml +# +# Message-XML-String +# erzeugen +########################### + +sub create_message_xml ($$$) { + my ($xml, $msges, $num) = @_; + + my $msg = $msges -> [$num]; + + my $message = $xml -> createElement ('Message'); + $message -> setAttribute ('id', 'm'.$msg -> {mid}); + $message -> setAttribute ('flag', 'deleted') if ($msg -> {deleted}); + + # Header erzeugen + my $header = $xml -> createElement ('Header'); + + # alles inside of 'Header' + my $author = $xml -> createElement ('Author'); + my $name = $xml -> createElement ('Name'); + $name -> addText (toUTF8($msg -> {name})); + + my $email = $xml -> createElement ('Email'); + + my $category = $xml -> createElement ('Category'); + $category -> addText (toUTF8($msg -> {cat})); + + my $subject = $xml -> createElement ('Subject'); + $subject -> addText (toUTF8($msg -> {subject})); + + my $date = $xml -> createElement ('Date'); + $date -> setAttribute ('longSec', $msg -> {time}); + + $author -> appendChild ($name); + $author -> appendChild ($email); + $header -> appendChild ($author); + $header -> appendChild ($category); + $header -> appendChild ($subject); + $header -> appendChild ($date); + $message -> appendChild ($header); + + if ($msg -> {kids}) { + for (@{$msg -> {kids}}) { + $message -> appendChild (&create_message_xml ($xml, $msges, $_));}} + + $message; +} + +# ==================================================== +# XML-Parsen von Hand +# ==================================================== + +########################### +# sub sort_thread +# +# Messages eines +# Threads sortieren +########################### + +sub sort_thread ($$) { + my ($msg, $sorted) = @_; + + my ($z, %mhash) = (0); + + if ($sorted) { # aelteste zuerst + for (@$msg) { + @$msg[@{$_ -> {kids}}] = sort {$a -> {mid} <=> $b -> {mid}} @$msg[@{$_ -> {kids}}] if (@{$_ -> {kids}} > 1); + $mhash{$_ -> {mid}} = [@$msg[@{$_ -> {kids}}]];}} + + else { # juengste zuerst + for (@$msg) { + @$msg[@{$_ -> {kids}}] = sort {$b -> {mid} <=> $a -> {mid}} @$msg[@{$_ -> {kids}}] if (@{$_ -> {kids}} > 1); + $mhash{$_ -> {mid}} = [@$msg[@{$_ -> {kids}}]];}} + + # Kinder wieder richtig einsortieren + my @smsg = ($msg -> [0]); + for (@smsg) { + ++$z; + splice @smsg,$z,0,@{$mhash{$_ -> {mid}}} if ($_ -> {answers}); + delete $_ -> {kids};} + + \@smsg; +} + +########################### +# sub delete_messages +# +# geoeschte Nachrichten +# herausfiltern +########################### + +sub delete_messages ($) { + my $smsg = shift; + + my ($z, $oldlevel, @path) = (0,0,0); + + for (@$smsg) { + if ($_ -> {deleted}) { + my $n = $_ -> {answers}+1; + for (@path) {$smsg -> [$_] -> {answers} -= $n;} + splice @$smsg,$z,$n;} + + else { + if ($_ -> {level} > $oldlevel) { + push @path,$z; + $oldlevel = $_ -> {level};} + + elsif ($_ -> {level} < $oldlevel) { + splice @path,$_ -> {level}-$oldlevel; + $oldlevel = $_ -> {level};} + + else { $path[-1] = $z; } + + $z++;}} + + return; +} + +########################### +# sub get_all_threads +# +# Hauptdatei laden und +# parsen +########################### + +sub get_all_threads ($$;$) { + my ($file, $deleted, $sorted) = @_; + my ($last_thread, $last_message, @unids, %threads); + local *FILE; + + open FILE, $file or return undef; + my $xml = join '', ; + close(FILE) or return undef; + + if (wantarray) { + ($last_thread) = map {/(\d+)/} $xml =~ /]*>/; + ($last_message) = map {/(\d+)/} $xml =~ /]*>/;} + + my $reg_msg = qr~(?: + |]*>\s* +
[^<]*(?:<(?!Name>)[^<]*)* + ([^<]+)[^<]*(?:<(?!Category>)[^<]*)* + ([^<]*)\s* + ([^<]+)\s* + ]*>\s* +
\s*(?:(<)/Message>|(?=(<)Message\s*)))~sx; + + while ($xml =~ /([^<]*(?:<(?!\/Thread>)[^<]*)*)<\/Thread>/g) { + + my ($tid, $thread) = ($1, $2); + my ($level, $cmno, @msg, @stack) = (0); + + while ($thread =~ m;$reg_msg;g) { + + if (defined($9)) { + push @stack,$cmno if (defined $cmno); + push @msg, {}; + + if (defined $cmno) { + push @{$msg[$cmno] -> {kids}} => $#msg; + push @{$msg[$cmno] -> {unids}} => $2;} + else { + push @unids => $2;} + + for (@stack) {$msg[$_] -> {answers}++} + + $cmno=$#msg; + + ($msg[-1] -> {mid}, + $msg[-1] -> {unid}, + $msg[-1] -> {name}, + $msg[-1] -> {cat}, + $msg[-1] -> {subject}, + $msg[-1] -> {time}) = ($1, $2, $4, $5, $6, $7); + + $msg[-1] -> {deleted} = ($3 eq 'deleted')?1:undef; + + $msg[-1] -> {name} =~ s/&/&/g; + $msg[-1] -> {cat} =~ s/&/&/g; + $msg[-1] -> {subject} =~ s/&/&/g; + + $msg[-1] -> {unids} = []; + $msg[-1] -> {kids} = []; + $msg[-1] -> {answers} = 0; + $msg[-1] -> {level} = $level++;} + + elsif (defined ($8)) { + push @msg, {}; + + if (defined $cmno) { + push @{$msg[$cmno] -> {kids}} => $#msg; + push @{$msg[$cmno] -> {unids}} => $2; + $msg[$cmno] -> {answers}++;} + else { + push @unids => $2;} + + for (@stack) {$msg[$_] -> {answers}++} + + ($msg[-1] -> {mid}, + $msg[-1] -> {unid}, + $msg[-1] -> {name}, + $msg[-1] -> {cat}, + $msg[-1] -> {subject}, + $msg[-1] -> {time}) = ($1, $2, $4, $5, $6, $7); + + $msg[-1] -> {deleted} = ($3 eq 'deleted')?1:undef; + + $msg[-1] -> {name} =~ s/&/&/g; + $msg[-1] -> {cat} =~ s/&/&/g; + $msg[-1] -> {subject} =~ s/&/&/g; + + $msg[-1] -> {level} = $level; + $msg[-1] -> {unids} = []; + $msg[-1] -> {kids} = []; + $msg[-1] -> {answers} = 0;} + + else { + $cmno = pop @stack; $level--;}} + + # ============ + # Sortieren und bei Bedarf + # geloeschte Messages entfernen + + my $smsg = sort_thread (\@msg, $sorted); + delete_messages ($smsg) unless ($deleted); + + $threads{$tid} = $smsg if (@$smsg); + } + + wantarray?(\%threads, $last_thread, $last_message, \@unids): \%threads; +} + +########################### +# sub create_forum_xml_string +# +# Forumshauptdatei erzeugen +########################### + +sub create_forum_xml_string ($$) { + my ($threads, $param) = @_; + my ($level, $thread, $msg); + + my $xml = ''."\n" + .' {dtd}.'">'."\n" + .''; + + foreach $thread (sort {$b <=> $a} keys %$threads) { + $xml .= ''; + $level = -1; + + foreach $msg (@{$threads -> {$thread}}) { + $xml .= '' x ($level - $msg -> {level} + 1) if ($msg -> {level} <= $level); + $level = $msg -> {level}; + $xml .= ' {deleted})?' flag="deleted"':'') + .'>' + .'
' + .'' + .'' + .plain($msg -> {name}) + .'' + .'' + .'' + .'' + .((length $msg -> {cat})?plain($msg -> {cat}):'') + .'' + .'' + .plain($msg -> {subject}) + .'' + .'' + .'
';} + + $xml .= '
' x ($level + 1); + $xml .= '
';} + + $xml.='
'; + + \$xml; +} + +########################### +# sub save_file +# +# Datei speichern +########################### + +sub save_file ($$) { + my ($filename,$content) = @_; + local *FILE; + + open FILE,">$filename.temp" or return; + + unless (print FILE $$content) { + close FILE; + return;}; + + close FILE or return; + + rename "$filename.temp", $filename or return; + + 1; +} + +# ==================================================== +# Zeitdarstellung +# ==================================================== + +########################### +# sub hr_time +# 02. Januar 2001, 12:02 Uhr +# +# sub short_hr_time +# 02. 01. 2001, 12:02 Uhr +# +# sub long_hr_time +# Dienstag, 02. Januar 2001, 12:02:01 Uhr +# +# formatierte Zeitangabe +########################### + +sub hr_time ($) { + my @month = qw(Januar Februar M\303\244rz April Mail Juni Juli August September Oktober November Dezember); + # ^^^^^^^^ - UTF8 # + + my (undef, $min, $hour, $day, $mon, $year) = localtime ($_[0]); + + sprintf ('%02d. %s %04d, %02d:%02d Uhr', $day, $month[$mon], $year+1900, $hour, $min); +} + +sub short_hr_time ($) { + my (undef, $min, $hour, $day, $mon, $year) = localtime ($_[0]); + + sprintf ('%02d. %02d. %04d, %02d:%02d Uhr', $day, $mon+1, $year+1900, $hour, $min); +} + +sub long_hr_time ($) { + my @month = qw(Januar Februar M\303\244rz April Mail Juni Juli August September Oktober November Dezember); + # ^^^^^^^^ - UTF8 # + + my @wday = qw(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag); + my ($sek, $min, $hour, $day, $mon, $year, $wday) = localtime ($_[0]); + + sprintf ('%s, %02d. %s %04d, %02d:%02d:%02d Uhr', $wday[$wday], $day, $month[$mon], $year+1900, $hour, $min, $sek); +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Posting::_lib +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Template.pm b/selfforum-cgi/shared/Template.pm new file mode 100644 index 0000000..74626d9 --- /dev/null +++ b/selfforum-cgi/shared/Template.pm @@ -0,0 +1,228 @@ +# Template.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-06 +# lm : n.d.p. / 2001-01-25 +# ==================================================== +# Funktion: +# Ausfuellen von Templates +# ==================================================== + +use strict; + +package Template; + +use XML::DOM; + +# ==================================================== +# Methoden +# ==================================================== + +################################ +# sub new +# +# Konstruktor +################################ + +sub new { + my $instance=shift; + my $class=(ref($instance) or $instance); + + my $self = {}; + $self = bless $self,$class; + + $self -> file (+shift); + + # Rueckgabe + $self; +} + +################################ +# sub file +# +# Datei zuweisen und parsen +################################ + +sub file { + my $self = shift; + my $old = $self -> {file}; + my $new = shift; + + $self -> {file} = $new if (defined $new); + $self -> parse_file; + + $old; +} + +################################ +# sub insert +# +# Bezeichner in Metazeichen +# eingeschlossen zurueckgeben +################################ + +sub insert { + my $self=shift; + die "no template file specified" unless (defined $self -> {file}); + + my $name=shift; + + # Rueckgabe + $self -> {metaon} . $name . $self -> {metaoff}; +} + +################################ +# sub list +# +# komplette Liste einsetzen +################################ + +sub list { + my $self=shift; + my $name=shift; + + die "no template file specified" unless (defined $self->{file}); + + my $list = join '', map { ${ $self -> scrap ($name, $_) } } @{ +shift }; + + # Rueckgabe + \$list; +} + +################################ +# sub scrap +# +# Schnipsel ausfuellen +################################ + +sub scrap { + my $self=shift; + my $name=shift; + + die "no template file specified" unless (defined $self->{file}); + + my %params; + + # Parameter holen + # Als Values werden nur die Referenzen gespeichert + %params = map { my $ref = $_; map { ($_ => ( (ref ($ref -> {$_} ) )?$ref -> {$_}: \($ref -> {$_} ) ) ) } keys %$ref } splice @_; + + # und einsetzen + my $scrap=$self->{parsed}->{$name}; + my $qmon=quotemeta $self->{metaon}; + my $qmoff=quotemeta $self->{metaoff}; + + # und zwar solange, bis nichts mehr da ist + while ($scrap =~ s<$qmon\s*([_a-zA-Z]\S*)\s*$qmoff>[ + my $x=''; + if ( exists ( $params{$1} ) ) { $x = ${$params{$1}} } + elsif (exists ( $self -> {parsed} -> {$1} ) ) { $x = $self -> {parsed} -> {$1}} + $x;]geo ){}; + + $self -> parse_if (\$scrap,\%params); + + # Rueckgabe + \$scrap; +} + +# ==================================================== +# Private Funktionen/Methoden +# ==================================================== + +################################ +# sub parse_file +# +# Template einlesen & parsen +################################ + +sub parse_file { + my $self = shift; + + if (-f $self -> {file}) { + my $filename = $self -> {file}; + my $xml = new XML::DOM::Parser -> parsefile ($filename); + my $template = $xml -> getElementsByTagName ('Template', 0) -> item (0); + + # Metas bestimmen + $self -> {metaon} = $template -> getAttribute ('metaon'); + $self -> {metaoff} = $template -> getAttribute ('metaoff'); + + die "missing meta defintion(s) in template file '$filename'." unless ($self -> {metaon} and $self -> {metaoff}); + + $self -> {parsed} = {}; + foreach ($template -> getElementsByTagName ('Scrap', 0)) { + my $name = $_ -> getAttribute ('id'); + + die "Element 'Scrap' requires attribute 'id' in template file '$filename'." unless (length ($name)); + die "double defined id '$name' in template file '$filename'." if (exists ($self -> {parsed} -> {$name})); + die "use '/^[_a-zA-Z]\\S*\$/' for 'Scrap'-ids in template file '$filename' (wrong: '$name')." unless ($name =~ /^[_a-zA-Z]\S*$/); + + $self -> {parsed} -> {$name} = $_ -> getFirstChild -> getData; + $self -> {parsed} -> {$name} =~ s/^\s+|\s+$//g;} + + return 1; # alles klar + } + + 0; +} + +################################ +# sub parse_if +# +# %IF - Anweisungen parsen +################################ + +sub parse_if { + my $self = shift; + my ($scrap,$params) = @_; + + my $qmon = quotemeta $self -> {metaon}; + my $qmoff = quotemeta $self -> {metaoff}; + + # der folgende Regex ist ein bisschen fies ... + # ... aber er funktioniert :-) + # + # pfff - rekursive Strukturen iterativ parsen ist nicht wirklich witzig + while ($$scrap=~s[ ($qmon\s*%(?:IF|ELSE)\s+.+?\s*$qmoff.*?) # Wenn IF oder ELSE von + (?=$qmon\s*%IF\s+.+?\s*$qmoff) # IF gefolgt werden, soll + # dieses Stueck uebersprungen + # werden und erstmal mit der + # naechsten Ebene weitergemacht + # werden. + + |( # hier beginnt $2 + $qmon\s*%IF\s+(.+?)\s*$qmoff # IF + (.*?) # $4 + (?: + $qmon\s*%ENDIF\s*$qmoff # gefolgt von ENDIF + | # oder + $qmon\s*%ELSE\s*$qmoff # von ELSE... ($4 ELSE $5) $5 $6 + (.*?) + $qmon\s*%ENDIF\s*$qmoff # und ENDIF + ) + ) + ] + [my $ret; + if ($2) { + my ($t4,$t5,$t6) = ($4,$5,$6); + my $flag=0; + foreach (split /\s+/,$3) { + if (exists($params->{$_}) and length(${$params->{$_}})) {$ret = $t4; $flag=1;last;}} + $ret = $t5 unless ($flag);} + else {$ret=$1;} + $ret; + ]gosex) {}; + + return; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Template +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Template/Forum.pm b/selfforum-cgi/shared/Template/Forum.pm new file mode 100644 index 0000000..ab853ae --- /dev/null +++ b/selfforum-cgi/shared/Template/Forum.pm @@ -0,0 +1,96 @@ +# Template/Forum.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-12 +# lm : n.d.p. / 2001-01-12 +# ==================================================== +# Funktion: +# Erzeugung der HTML-Ausgabe der +# Forumshauptdatei +# ==================================================== + +use strict; + +package Template::Forum; + +use vars qw(@ISA @EXPORT); + +use Lock qw(:READ); +use Encode::Plain; $Encode::Plain::utf8 = 1; +use Posting::_lib qw(get_all_threads long_hr_time); +use Template; +use Template::_conf; +use Template::_thread; + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(print_forum_as_HTML); + +################################ +# sub print_forum_as_HTML +# +# HTML erstellen +################################ + +sub print_forum_as_HTML ($$$) { + my ($mainfile, $tempfile, $param) = @_; + my $assign = $param -> {assign}; + + my $template = new Template $tempfile; + + my ($threads, $stat); + + unless ($stat = lock_file ($mainfile)) { + if ($stat == 0) { + violent_unlock_file ($mainfile); + # ueberlastet + } + + else { + # Mastersperre... + }} + + else { + my $view = get_view_params ({adminDefault => $param -> {adminDefault} + }); + + $threads = get_all_threads ($mainfile, $param -> {showDeleted}, $view -> {sortedMsg}); + violent_unlock_file ($mainfile) unless (unlock_file ($mainfile)); + + print ${$template -> scrap ($assign -> {mainDocStart}, + {$assign -> {loadingTime} => plain (long_hr_time (time)) } )},"\n
"; + + my $tpar = {template => $param -> {tree}, + cgi => $param -> {cgi}, + start => -1}; + + my @threads; + + unless ($view -> {sortedThreads}) { + @threads = sort {$b <=> $a} keys %$threads;} + else { + @threads = sort {$a <=> $b} keys %$threads;} + + for (@threads) { + $tpar -> {thread} = "$_"; + print ${html_thread ($threads -> {$_}, $template, $tpar)},"\n",'
 
',"\n";} + + print "
\n",${$template -> scrap ($assign -> {mainDocEnd})};} + + return; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Template::Forum +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Template/Posting.pm b/selfforum-cgi/shared/Template/Posting.pm new file mode 100644 index 0000000..d10d105 --- /dev/null +++ b/selfforum-cgi/shared/Template/Posting.pm @@ -0,0 +1,147 @@ +# Template/Posting.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-14 +# lm : n.d.p. / 2001-01-14 +# ==================================================== +# Funktion: +# HTML-Darstellung eines Postings +# ==================================================== + +use strict; + +package Template::Posting; + +use vars qw(@ISA @EXPORT); + +use Encode::Posting; +use Encode::Plain; $Encode::Plain::utf8 = 1; +use Id; +use Lock qw(:WRITE); +use Posting::_lib qw(get_message_node get_message_header get_message_body parse_single_thread hr_time); +use Template; +use Template::_query; +use Template::_thread; + +use XML::DOM; + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(print_posting_as_HTML message_as_HTML); + +################################ +# sub print_posting_as_HTML +# +# HTML erzeugen +################################ + +sub print_posting_as_HTML ($$$) { + my ($threadpath, $tempfile, $param) = @_; + + my $template = new Template $tempfile; + + # Datei sperren... (eigentlich) + my $xml=new XML::DOM::Parser -> parsefile ($threadpath.'t'.$param -> {thread}.'.xml'); + + my ($mnode, $tnode) = get_message_node ($xml, 't'.$param -> {thread}, 'm'.$param -> {posting}); + my $pnode = $mnode -> getParentNode; + my $header = get_message_header ($mnode); + my $msg = parse_single_thread ($tnode, 0, 0); + my $pheader = ($pnode -> getNodeName eq 'Message')?get_message_header ($pnode):{}; + + my $assign = $param -> {assign}; + my $formdata = $param -> {form} -> {data}; + my $formact = $param -> {form} -> {action}; + + my $body = get_message_body ($xml, 'm'.$param -> {posting}); + + my $text = message_field ($body, + {quoteChars => '»» ', + quoting => 1, + startCite => ${$template -> scrap ($assign -> {startCite})}, + endCite => ${$template -> scrap ($assign -> {endCite})} + }); + + my $area = answer_field ($body, + {quoteArea => 1, + quoteChars => '»» ', + messages => $param -> {messages} + }); + + my $pars = {}; + + for (qw(posterBody uniqueID followUp quoteChar userID posterName posterEmail posterURL posterImage)) { + $pars -> {$formdata -> {$_} -> {assign} -> {name}} = plain($formdata -> {$_} -> {name});} + + my $cgi = $param -> {cgi}; + + my $tpar = {thread => $param -> {thread}, + template => $param -> {tree}, + start => $param -> {posting}, + cgi => $cgi}; + + my $plink = %$pheader?(query_string ({$cgi -> {thread} => $param -> {thread}, $cgi -> {posting} => ($pnode -> getAttribute ('id') =~ /(\d+)/)[0]})):''; + + print ${$template -> scrap ($assign->{mainDoc}, + {$assign->{name} => plain($header->{name}), + $assign->{email} => plain($header->{email}), + $assign->{home} => plain($header->{home}), + $assign->{image} => plain($header->{image}), + $assign->{time} => plain(hr_time($header->{time})), + $assign->{message} => $text, + $assign->{messageTitle} => plain($header->{subject}), + $assign->{parentTitle} => plain($pheader->{subject}), + $assign->{messageCat} => plain($header->{category}), + $assign->{parentCat} => plain($pheader->{category}), + $assign->{parentName} => plain($pheader->{name}), + $assign->{parentLink} => $plink, + $assign->{parentTime} => plain(hr_time($pheader->{time})), + $param->{tree}->{main} => html_thread ($msg, $template, $tpar), + $formact->{post}->{assign} => $formact->{post}->{url}, + $formact->{vote}->{assign} => $formact->{vote}->{url}, + $formdata->{posterBody}->{assign}->{value} => $area, + $formdata->{uniqueID} ->{assign}->{value} => plain(unique_id), + $formdata->{followUp} ->{assign}->{value} => plain($param -> {thread}.';'.$param -> {posting}), + $formdata->{quoteChar} ->{assign}->{value} => "ÿ".plain('»» '), + $formdata->{userID} ->{assign}->{value} => '', + }, $pars)}; + +} + +################################ +# sub message_as_HTML +# +# HTML erzeugen +################################ + +sub message_as_HTML ($$$) { + my ($xml, $template, $param) = @_; + + my $assign = $param -> {assign}; + my $body = get_message_body ($xml, $param -> {posting}); + + my $text = message_field ($body, + {quoteChars => '»» ', + quoting => 1, + startCite => ${$template -> scrap ($assign -> {startCite})}, + endCite => ${$template -> scrap ($assign -> {endCite})} + }); + + # Rueckgabe + $text; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Template::Posting +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Template/_conf.pm b/selfforum-cgi/shared/Template/_conf.pm new file mode 100644 index 0000000..b94d01d --- /dev/null +++ b/selfforum-cgi/shared/Template/_conf.pm @@ -0,0 +1,54 @@ +# Template/_conf.pm + +# ==================================================== +# Autor: n.d.p. / 2001-02-20 +# lm : n.d.p. / 2001-02-20 +# ==================================================== +# Funktion: +# Bereitstellung der Ausgabeparameter +# durch Kombination von User und Adminkonf. +# ==================================================== + +use strict; + +package Template::_conf; + +use vars qw(@ISA @EXPORT); + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(get_view_params); + +################################ +# sub get_view_params +# +# Ausgabeparameter bestimmen +################################ + +sub get_view_params ($) { + my $param = shift; + my $default = $param -> {adminDefault}; + my %hash; + + %hash = (quoteChars => $default -> {View} -> {quoteChars}, + sortedMsg => $default -> {View} -> {sortMessages}, + sortedThreads => $default -> {View} -> {sortThreads} + ); + + \%hash; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Template::_conf +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Template/_query.pm b/selfforum-cgi/shared/Template/_query.pm new file mode 100644 index 0000000..606f4f3 --- /dev/null +++ b/selfforum-cgi/shared/Template/_query.pm @@ -0,0 +1,71 @@ +# Template/_query.pm + +# ==================================================== +# Autor: n.d.p. / 2000-12-30 +# lm : n.d.p. / 2001-02-04 +# ==================================================== +# Funktion: +# Erzeugen eines Querystrings +# ==================================================== + +use strict; + +package Template::_query; + +use vars qw(@ISA @EXPORT); + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(query_string); + +################################ +# sub query_string +# +# Querystring erzeugen +################################ + +sub query_string ($) { + my $parlist=shift; + + my $string = '?'.join ('&', + map {(ref)?map{&url_encode ($_).'='.&url_encode ($parlist -> {$_})} @{$parlist -> {$_}}: + &url_encode ($_).'='.&url_encode ($parlist -> {$_})} + keys %$parlist); + + # return + $string; +} + +# ==================================================== +# Private Funktionen +# ==================================================== + +################################ +# sub url_encode +# +# URL-Codierung +# (mehr oder weniger aus +# CGI.pm geklaut...) +################################ + +sub url_encode ($) { + my $string = shift; + $string=~s/([^a-zA-Z\d_.-])/uc sprintf('%%%02x',ord($1))/eg; + + $string; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Template::_query +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/Template/_thread.pm b/selfforum-cgi/shared/Template/_thread.pm new file mode 100644 index 0000000..8c3cbbb --- /dev/null +++ b/selfforum-cgi/shared/Template/_thread.pm @@ -0,0 +1,136 @@ +# Template/_thread.pm + +# ==================================================== +# Autor: n.d.p. / 2001-01-11 +# lm : n.d.p. / 2001-01-11 +# ==================================================== +# Funktion: +# HTML-Darstellung eines Threads +# ==================================================== + +use strict; + +package Template::_thread; + +use vars qw(@ISA @EXPORT); + +use Encode::Plain; $Encode::Plain::utf8 = 1; +use Posting::_lib qw(short_hr_time); +use Template; +use Template::_query; + +# ==================================================== +# Funktionsexport +# ==================================================== + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(html_thread); + +################################ +# sub html_thread +# +# Thread erzeugen +################################ + +sub html_thread ($$$) { + my ($msg, $template, $par) = @_; + + return \'' unless @$msg; + + my $temp = $par -> {template}; + my $i = $par -> {cgi} -> {user}; + my $t = $par -> {cgi} -> {thread}; + my $p = $par -> {cgi} -> {posting}; + my $c = $par -> {cgi} -> {command}; + my $tid = $par -> {thread}; + my $html=''; + my $startlevel=0; + my $oldlevel=0; + my @indexes; + + # ganzer Thread + if ($par -> {start} == -1) { + $_ = $msg -> [0]; + @indexes = (1..$_ -> {answers}); + + if ($_ -> {answers}) { + $html = '
' + .${$template -> scrap ($temp -> {(length $_ -> {cat})?'start':'startNC'}, + {$temp -> {name} => $_ -> {name}, + $temp -> {subject} => $_ -> {subject}, + $temp -> {cat} => $_ -> {cat}, + $temp -> {time} => plain(short_hr_time ($_ -> {time})), + $temp -> {link} => query_string({$t => $tid, $p => $_ -> {mid}})}, + $par -> {addParam})} + .'
';} + + else { + $html = '
' + .${$template -> scrap ($temp -> {(length $_ -> {cat})?'start':'startNC'}, + {$temp -> {name} => $_ -> {name}, + $temp -> {subject} => $_ -> {subject}, + $temp -> {cat} => $_ -> {cat}, + $temp -> {time} => plain(short_hr_time ($_ -> {time})), + $temp -> {link} => query_string({$t => $tid, $p => $_ -> {mid}})}, + $par -> {addParam})} + .'
'; + + return \$html;}} + + # Teilthread + else { + my $start=-1; + for (@$msg) {$start++; last if ($_ -> {mid} == $par -> {start});} + my $end = $start + $msg -> [$start] -> {answers}; + $start++; + @indexes = ($start..$end); + $oldlevel = $startlevel = $msg -> [$par -> {start}] -> {level};} + + # HTML erzeugen + for (@$msg[@indexes]) { + + if ($_ -> {level} < $oldlevel) { + $html.='
' x ($oldlevel - $_ -> {level});} + + $oldlevel = $_ -> {level}; + + if ($_ -> {answers}) { + $html.='
' + .${$template -> scrap ($temp -> {(length $_ -> {cat})?'line':'lineNC'}, + {$temp -> {name} => $_ -> {name}, + $temp -> {subject} => $_ -> {subject}, + $temp -> {cat} => $_ -> {cat}, + $temp -> {time} => plain(short_hr_time ($_ -> {time})), + $temp -> {link} => query_string({$t => $tid, $p => $_ -> {mid}})}, + $par -> {addParam})} + .'
'; + } + else { + $html.='
' + .${$template -> scrap ($temp -> {(length $_ -> {cat})?'line':'lineNC'}, + {$temp -> {name} => $_ -> {name}, + $temp -> {subject} => $_ -> {subject}, + $temp -> {cat} => $_ -> {cat}, + $temp -> {time} => plain(short_hr_time ($_ -> {time})), + $temp -> {link} => query_string({$t => $tid, $p => $_ -> {mid}})}, + $par -> {addParam})} + .'
'; + } + } + + $html.='
' x ($oldlevel - $startlevel); + + \$html; +} + +# ==================================================== +# Modulinitialisierung +# ==================================================== + +# making require happy +1; + +# ==================================================== +# end of Template::_thread +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/shared/common.xml b/selfforum-cgi/shared/common.xml new file mode 100644 index 0000000..b534444 --- /dev/null +++ b/selfforum-cgi/shared/common.xml @@ -0,0 +1,9 @@ + + + + C:/Server/teamone + C:/Server/teamone/cgi-local + teamone + + + diff --git a/selfforum-cgi/user/config/answer.tmp.xml b/selfforum-cgi/user/config/answer.tmp.xml new file mode 100644 index 0000000..8da9959 --- /dev/null +++ b/selfforum-cgi/user/config/answer.tmp.xml @@ -0,0 +1,236 @@ + + + diff --git a/selfforum-cgi/user/config/common.xml b/selfforum-cgi/user/config/common.xml new file mode 100644 index 0000000..f0496b0 --- /dev/null +++ b/selfforum-cgi/user/config/common.xml @@ -0,0 +1,72 @@ + + + + + /selfaktuell/forum/messages/ + /selfaktuell/forum/messages/selfforum.xml + config/fo_admin_default.xml + + + + + + + /selfaktuell/forum/images/01.gif + 419 + 119 + Für dein Problem gibt es nur eine Lösung: SELFmade von Selbermachen. + + + /selfaktuell/forum/images/02.gif + 302 + 119 + Die Antwort auf deine Frage findest du im Archiv. + + + /selfaktuell/forum/images/03.gif + 248 + 119 + Was willst du jetzt eigentlich wissen? + + + /selfaktuell/forum/images/04.gif + 428 + 119 + Schau mal in SELFHTML nach, um eine Antwort auf deine Frage zu finden! + + + /selfaktuell/forum/images/05.gif + 158 + 119 + Jetzt reicht's aber! + + + /selfaktuell/forum/images/06.gif + 462 + 119 + Erstmal selber probieren, dann bei Problemen: SELFHTML, danach: dieses Forum. + + + /selfaktuell/forum/images/07.gif + 275 + 119 + Stopp! So etwas hat hier nichts zu suchen. + + + /selfaktuell/forum/images/08.gif + 213 + 100 + Schau mal unter folgenden Links nach: + + + /selfaktuell/forum/images/10.gif + 224 + 119 + ??!%${ + + + + + + + \ No newline at end of file diff --git a/selfforum-cgi/user/config/fo_admin_default.dtd b/selfforum-cgi/user/config/fo_admin_default.dtd new file mode 100644 index 0000000..b066b07 --- /dev/null +++ b/selfforum-cgi/user/config/fo_admin_default.dtd @@ -0,0 +1,296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/selfforum-cgi/user/config/fo_admin_default.xml b/selfforum-cgi/user/config/fo_admin_default.xml new file mode 100644 index 0000000..bbdfa57 --- /dev/null +++ b/selfforum-cgi/user/config/fo_admin_default.xml @@ -0,0 +1,44 @@ + + + + + + + 10 + + + + + + »» + + + + 400 + 100 + 70 + + + + + + a9105535@unet.univie.ac.at + selfhtml@teamone.de + Wowbagger + 123.456.789 + + + + + 300 + + + + + + + + 45 + + + \ No newline at end of file diff --git a/selfforum-cgi/user/config/fo_admin_default.xml.lock b/selfforum-cgi/user/config/fo_admin_default.xml.lock new file mode 100644 index 0000000..e69de29 diff --git a/selfforum-cgi/user/config/fo_admin_default.xml.lock.ref b/selfforum-cgi/user/config/fo_admin_default.xml.lock.ref new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/selfforum-cgi/user/config/fo_admin_default.xml.lock.ref @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/selfforum-cgi/user/config/fo_admin_default.xml.lock.ref.lock b/selfforum-cgi/user/config/fo_admin_default.xml.lock.ref.lock new file mode 100644 index 0000000..e69de29 diff --git a/selfforum-cgi/user/config/fo_admin_default.xml.master.lock b/selfforum-cgi/user/config/fo_admin_default.xml.master.lock new file mode 100644 index 0000000..e69de29 diff --git a/selfforum-cgi/user/config/fo_posting.xml b/selfforum-cgi/user/config/fo_posting.xml new file mode 100644 index 0000000..0616273 --- /dev/null +++ b/selfforum-cgi/user/config/fo_posting.xml @@ -0,0 +1,260 @@ + + + + + + config/answer.tmp.xml + + + DOC_OPENING + DOC_THANKYOU + + DOC_OPENING + DOC_FATAL + _ERR_MESS + _NUM + _MANIPULATED + _ENCODING + _OCCUPIED + _NOREPLY + _DUPE + _UNKNOWN + + _CSS_FILE + + OPTION + _OPTVAL + _SELECTED + + _MESSAGE + + CITE_START + CITE_END + + + + _NAME + _MAIL + _TIME + _BODY + _CATEGORY + _TITLE + _HOME + _IMAGE + + + + + + /cgi-local/user/fo_posting.pl + _FORM_ACTION + + + + + + uniqueID + quoteChar + posterName + posterEmail + posterCategory + posterSubject + posterBody + + + + followUp + uniqueID + quoteChar + posterName + posterEmail + posterBody + + + + + + + _FORM_FUP_NAME + _FORM_FUP_VALUE + _MANIPULATED + + + fup + 20 + fatal + + + + + _FORM_UID_NAME + _FORM_UID_VALUE + _MANIPULATED + + + userid + 40 + fatal + + + + + _FORM_UNID_NAME + _FORM_UNID_VALUE + _MANIPULATED + + + unid + 40 + fatal + + + + + _FORM_QCHAR_NAME + _FORM_QCHAR_VALUE + _MANIPULATED + + + qchar + 20 + fatal + + + + + _FORM_NAME_NAME + _FORM_NAME_VALUE + _NAME_TOO_LONG + _NAME_TOO_SHORT + + + name + 60 + 2 + repeat + + + + + _FORM_MAIL_NAME + _FORM_MAIL_VALUE + _MAIL_TOO_LONG + _MAIL_TOO_SHORT + _MAIL_WRONG + + + email + 60 + 7 + email + repeat + + + + + _FORM_CAT_NAME + _CATLIST + _CAT_WRONG + _CAT_WRONG + _CAT_WRONG + + + category + 18 + 3 + repeat + + ASP + BROWSER + CGI + CSS + DATENBANK + DESIGN + DHTML + E_MAIL + FTP + GRAFIK + HTML + HTTP + INTERNET-ANBINDUNG + JAVA + JAVASCRIPT + MEINUNG + MENSCHELEI + PERL + PHP + PROGRAMMIERTECHNIK + PROJEKTVERWALTUNG + PROVIDER + RECHT + SERVER + SOFTWARE + VBSCRIPT + XML + XML-DERIVAT + XSL + ZUR INFO + ZU DIESEM FORUM + + + + + + _FORM_SUBJECT_NAME + _FORM_SUBJECT_VALUE + _SUB_TOO_LONG + _SUB_TOO_SHORT + + subject + 64 + 4 + repeat + + + + + _FORM_BODY_NAME + _FORM_BODY_VALUE + _BODY_TOO_LONG + _BODY_TOO_SHORT + + body + 12288 + 10 + repeat + + + + _FORM_SIGN_VALUE + + + + + _FORM_URL_NAME + _FORM_URL_VALUE + _URL_TOO_LONG + + url + 1024 + repeat + + + + + _FORM_IMG_NAME + _FORM_IMG_VALUE + _IMG_TOO_LONG + + image + 1024 + repeat + + + + + + + + + \ No newline at end of file diff --git a/selfforum-cgi/user/config/fo_view.xml b/selfforum-cgi/user/config/fo_view.xml new file mode 100644 index 0000000..c5995c7 --- /dev/null +++ b/selfforum-cgi/user/config/fo_view.xml @@ -0,0 +1,182 @@ + + + + + + + + + i + t + m + c + + + + _THREAD + TREE_START + TREE_LINE + TREE_CLOSED + TREE_START_NC + TREE_LINE_NC + TREE_CLOSED_NC + _LINK + _NAME + _COMMAND + _TITLE + _CATEGORY + _TIME + + + + + + config/forum.tmp.xml + + + DOC_FORUM_START + DOC_FORUM_END + _LOAD_TIME + _CSS_FILE + + + + + + config/posting.tmp.xml + + + DOC_POSTING + _CSS_FILE + _MESSAGE + _BEF_NAME + _BEF_MAIL + _BEF_TIME + _BEF_HOME + _BEF_IMAGE + _BEF_TITLE + _REF_CATEGORY + _BEF_CATEGORY + _REF_TITLE + _REF_NAME + _REF_TIME + _REF_LINK + CITE_START + CITE_END + + + + + + /cgi-local/user/fo_posting.pl + _FORM_ACTION + + + + /cgi-local/user/fo_voting.pl + _VOTE_ACTION + + + + + + + _FORM_FUP_NAME + _FORM_FUP_VALUE + + + fup + 20 + + + + + _FORM_UID_NAME + _FORM_UID_VALUE + + + userid + 25 + + + + + _FORM_UNID_NAME + _FORM_UNID_VALUE + + + unid + 25 + + + + + _FORM_QCHAR_NAME + _FORM_QCHAR_VALUE + + + qchar + 5 + + + + + _FORM_NAME_NAME + _FORM_NAME_VALUE + + + name + 60 + 2 + + + + + _FORM_MAIL_NAME + _FORM_MAIL_VALUE + + + email + 60 + 7 + + + + + _FORM_BODY_NAME + _FORM_BODY_VALUE + + body + 12288 + 10 + + + + _FORM_SIGN_VALUE + + + + + _FORM_URL_NAME + _FORM_URL_VALUE + + url + 1024 + + + + + _FORM_IMG_NAME + _FORM_IMG_VALUE + + image + 1024 + + + + + + + + + \ No newline at end of file diff --git a/selfforum-cgi/user/config/forum.tmp.xml b/selfforum-cgi/user/config/forum.tmp.xml new file mode 100644 index 0000000..89c7e56 --- /dev/null +++ b/selfforum-cgi/user/config/forum.tmp.xml @@ -0,0 +1,142 @@ + + diff --git a/selfforum-cgi/user/config/posting.tmp.xml b/selfforum-cgi/user/config/posting.tmp.xml new file mode 100644 index 0000000..f37c575 --- /dev/null +++ b/selfforum-cgi/user/config/posting.tmp.xml @@ -0,0 +1,130 @@ + + + diff --git a/selfforum-cgi/user/fo_posting.pl b/selfforum-cgi/user/fo_posting.pl new file mode 100644 index 0000000..fc8b182 --- /dev/null +++ b/selfforum-cgi/user/fo_posting.pl @@ -0,0 +1,523 @@ +#!/usr/bin/perl + +# ==================================================== +# Autor: n.d.p. / 2001-01-23 +# lm : n.d.p. / 2001-01-25 +# ==================================================== +# Funktion: +# Entgegennahme von Postings und +# Darstellung der "Neue Nachricht"-Seite +# ==================================================== + +use strict; +use vars qw($Bin $Shared $Script %subhash $httpurl $flocked); + +BEGIN { + ($Bin) = ($0 =~ /^(.*)\/.*$/)? $1 : '.'; + $Shared = "$Bin/../shared"; + ($Script) = ($0 =~ /^.*\/(.*)$/)? $1 : $0;} + +use CGI::Carp qw(fatalsToBrowser); + +use lib "$Shared"; +use Conf; +use Encode::Plain; $Encode::Plain::utf8 = 1; +use Encode::Posting; +use Id; +use Lock qw(:ALL); +use Mail; +use Posting::_lib qw(get_all_threads get_message_node get_message_header hr_time); +use Posting::Write; +use Template; +use Template::Posting; + +use CGI qw(param header); + +use XML::DOM; + +print header (-type => 'text/html'); + +our $conf = read_script_conf ($Bin, $Shared, $Script); + +our $show_posting = $conf -> {show} -> {Posting}; +our $assign = $show_posting -> {assign}; +our $formmust = $show_posting -> {form} -> {must}; +our $formdata = $show_posting -> {form} -> {data}; +our $formact = $show_posting -> {form} -> {action}; +our $template = new Template "$Bin/".$show_posting -> {templateFile}; +our $pars = {}; +our ($failed, %dparam, $threads, $last_thread, $last_message, $ftid, $fmid, $flocked); + +sub forum_filename () {$conf -> {wwwRoot} . $conf -> {files} -> {forum};} +sub message_path () {$conf -> {wwwRoot} . $conf -> {files} -> {messagePath};} + +################################ + +# Formfelder ausfuellen (Namen) +for (qw(posterBody uniqueID followUp quoteChar userID posterName posterEmail posterCategory posterSubject posterURL posterImage)) { + $pars -> {$formdata -> {$_} -> {assign} -> {name}} = plain($formdata -> {$_} -> {name});} + +my $checked = &check_param; + +unless (exists ($subhash {$checked})) { + &print_fatal ($assign -> {unknownError});} + +else { + unless ($checked eq 'newThread') { + $checked = &check_reply_dupe() || $checked;} + + unless (exists ($subhash {$checked})) { + &print_fatal ($assign -> {unknownError});} + else { + &{$subhash {$checked}};} + + if ($flocked) { + violent_unlock_file (forum_filename) unless (write_unlock_file (forum_filename));}} + +# ==================================================== +# end of main / Funktionen +# ==================================================== + +################################ +# sub check_reply_dupe +# +# Reply moeglich? +# Doppelposting? +################################ + +sub check_reply_dupe () { + my $stat; + + unless ($stat = write_lock_file (forum_filename)) { + if ($stat == 0) { + # ueberlastet oder so + violent_unlock_file (forum_filename); + return 'Occupied';} + + else { + return 'masterLock';}} + + else { + my ($i, %msg, %unids); + + $flocked = 1; + + ($threads, $last_thread, $last_message, my $unids) = get_all_threads (forum_filename, 1, 0); + ($ftid,$fmid) = split /;/,$dparam{$formdata -> {followUp} -> {name}},2; + + # Thread existiert nicht + if (exists($dparam{$formdata -> {followUp} -> {name}})) { + return 'noReply' unless (exists($threads -> {$ftid})); + + # nur nicht geloeschte Messages beachten + for ($i=0; $i < @{$threads -> {$ftid}}; $i++) { + if ($threads -> {$ftid} -> [$i] -> {deleted}) { + $+=$threads -> {$ftid} -> [$i] -> {answers};} + + else { + $msg{$threads -> {$ftid} -> [$i] -> {mid}}=$i;}} + + # Message existiert nicht + if (exists($dparam{$formdata -> {followUp} -> {name}})) { + return 'noReply' unless (exists($msg{$fmid}));} + + %unids = map {$_ => 1} @{$threads -> {$ftid} -> [$msg{$fmid}] -> {unids}};} + + else { + %unids = map {$_ => 1} @$unids;} + + # jetzt endlich + return 'Dupe' if (exists ($unids{$dparam{$formdata -> {uniqueID} -> {name}}}));} + + return; +} + +################################ +# sub got_new +# +# Eroeffnungsposting speichern +################################ + +sub got_new () { + + my $time = time; + my $pars = {author => $dparam {$formdata -> {posterName} -> {name}}, + email => $dparam {$formdata -> {posterEmail} -> {name}}, + category => $dparam {$formdata -> {posterCategory} -> {name}}, + subject => $dparam {$formdata -> {posterSubject} -> {name}}, + body => $dparam {$formdata -> {posterBody} -> {name}}, + homepage => $dparam {$formdata -> {posterURL} -> {name}}, + image => $dparam {$formdata -> {posterImage} -> {name}}, + time => $time, + uniqueID => $dparam {$formdata -> {uniqueID} -> {name}}, + ip => $ENV{REMOTE_ADDR}, + forumFile => forum_filename, + messagePath => message_path, + lastThread => $last_thread, + lastMessage => $last_message, + parsedThreads => $threads, + dtd => 'forum.dtd', + quoteChars => toUTF8('»» '), + messages => $conf -> {template} -> {messages}}; + + my ($stat, $xml, $mid) = write_posting ($pars); + violent_unlock_file (forum_filename) unless (write_unlock_file (forum_filename)); + $flocked = undef; + + if ($stat) { + print "Och noe...: $stat";} + + else { + my $thx = $show_posting -> {thanx}; + + print ${$template -> scrap ($assign -> {docThx}, + {$thx -> {author} => plain ($dparam {$formdata -> {posterName} -> {name}}), + $thx -> {email} => plain ($dparam {$formdata -> {posterEmail} -> {name}}), + $thx -> {time} => plain (hr_time($time)), + $thx -> {body} => message_as_HTML ($xml, $template, + {posting => $mid, + assign => $assign}), + $thx -> {category} => plain ($dparam {$formdata -> {posterCategory} -> {name}}), + $thx -> {home} => plain ($dparam {$formdata -> {posterURL} -> {name}}), + $thx -> {image} => plain ($dparam {$formdata -> {posterImage} -> {name}}), + $thx -> {subject} => plain ($dparam {$formdata -> {posterSubject} -> {name}})})};} + return; +} + +################################ +# sub got_reply +# +# Antwortposting speichern +################################ + +sub got_reply () { + my $stat; + + my $time = time; + my $pars = {author => $dparam {$formdata -> {posterName} -> {name}}, + email => $dparam {$formdata -> {posterEmail} -> {name}}, + category => $dparam {$formdata -> {posterCategory} -> {name}}, + subject => $dparam {$formdata -> {posterSubject} -> {name}}, + body => $dparam {$formdata -> {posterBody} -> {name}}, + homepage => $dparam {$formdata -> {posterURL} -> {name}}, + image => $dparam {$formdata -> {posterImage} -> {name}}, + time => $time, + uniqueID => $dparam {$formdata -> {uniqueID} -> {name}}, + ip => $ENV{REMOTE_ADDR}, + parentMessage => $fmid, + thread => $ftid, + forumFile => forum_filename, + messagePath => message_path, + lastThread => $last_thread, + lastMessage => $last_message, + parsedThreads => $threads, + dtd => 'forum.dtd', + quoteChars => toUTF8('»» '), + messages => $conf -> {template} -> {messages}}; + + ($stat, my $xml, my $mid) = write_posting ($pars); + violent_unlock_file (forum_filename) unless (write_unlock_file (forum_filename)); + $flocked = undef; + + if ($stat) { + print "Och noe...: $stat";} + + else { + my $thx = $show_posting -> {thanx}; + + print ${$template -> scrap ($assign -> {docThx}, + {$thx -> {author} => plain ($dparam {$formdata -> {posterName} -> {name}}), + $thx -> {email} => plain ($dparam {$formdata -> {posterEmail} -> {name}}), + $thx -> {time} => plain (hr_time($time)), + $thx -> {body} => message_as_HTML ($xml, $template, + {posting => $mid, + assign => $assign}), + $thx -> {category} => plain ($dparam {$formdata -> {posterCategory} -> {name}}), + $thx -> {home} => plain ($dparam {$formdata -> {posterURL} -> {name}}), + $thx -> {image} => plain ($dparam {$formdata -> {posterImage} -> {name}}), + $thx -> {subject} => plain ($dparam {$formdata -> {posterSubject} -> {name}})})};} +} + +################################ +# sub new_thread +# +# HTML fuer Eroeffnungsposting +################################ + +sub new_thread () { + my $list = [map {{$assign -> {optval} => plain($_)}} @{$formdata -> {posterCategory} -> {values}}]; + + # spaeter kommen noch userspezifische Daten dazu... + print ${$template -> scrap ($assign -> {docNew}, + {$formdata->{uniqueID} ->{assign}->{value} => plain(unique_id), + $formdata->{quoteChar} ->{assign}->{value} => 'ÿ'.plain(toUTF8('»» ')), + $formact->{post}->{assign} => $formact->{post}->{url}, + $formdata->{posterCategory}->{assign}->{value} => $template->list ($assign -> {option}, $list) + },$pars)}; +} + +################################ +# diverse subs +# +# Fehlermeldungen +################################ + +sub no_reply () {&print_fatal ($assign -> {noReply});} +sub dupe_posting () {&print_fatal ($assign -> {dupe});} +sub missing_key () {&print_fatal ($assign -> {wrongPar});} +sub unexpected_key () {&print_fatal ($assign -> {wrongPar});} +sub unknown_encoding () {&print_fatal ($assign -> {wrongCode});} +sub too_short () { + if ($formdata -> {$failed} -> {errorType} eq 'repeat') { + &print_error ($formdata -> {$failed} -> {assign} -> {tooShort}, + $formdata -> {$failed} -> {minlength});} + + else { + &print_fatal ($formdata -> {$failed} -> {assign} -> {tooShort});} +} + +sub too_long () { + if ($formdata -> {$failed} -> {errorType} eq 'repeat') { + &print_error ($formdata -> {$failed} -> {assign} -> {tooLong}, + $formdata -> {$failed} -> {maxlength});} + + else { + &print_fatal ($formdata -> {$failed} -> {assign} -> {tooLong});} +} + +sub wrong_mail () {print_error ($formdata -> {$failed} -> {assign} -> {wrong});} +sub occupied () {print_error ($assign -> {occupied});} + +################################ +# sub print_fatal +# +# fatale Fehlerausgabe +################################ + +sub print_fatal ($) { + print ${$template -> scrap ($assign -> {docFatal}, + {$assign -> {errorMessage} => $template -> insert ($_[0]) + },$pars)}; +} + +################################ +# sub print_error +# +# Fehlerausgabe, Moeglichkeit +# zur Korrektur +################################ + +sub print_error ($;$) { + &fillin; + print ${$template -> scrap ($assign -> {docError}, + {$assign -> {errorMessage} => $template -> insert ($_[0]), + $assign -> {charNum} => $_[1] + },$pars)}; +} + +################################ +# sub fetch_subject +# +# Subject und Category besorgen +# (wenn noch nicht vorhanden) +################################ + +sub fetch_subject () { + unless (exists ($dparam{$formdata -> {posterCategory} -> {name}}) and + exists ($dparam{$formdata -> {posterSubject} -> {name}})) { + + my $filename = message_path.'t'.$ftid.'.xml'; + + if (lock_file ($filename)) { + my $xml = new XML::DOM::Parser -> parsefile ($filename); + violent_unlock_file($filename) unless unlock_file ($filename); + + my $mnode = get_message_node ($xml, "t$ftid", "m$fmid"); + my $header = get_message_header ($mnode); + + $dparam{$formdata -> {posterCategory} -> {name}} = $header -> {category}; + $dparam{$formdata -> {posterSubject} -> {name}} = $header -> {subject};}} +} + +################################ +# sub fillin +# +# Fuellen von $pars +# (bereits vorhandene Formdaten) +################################ + +sub fillin () { + fetch_subject; + + my $list = [map {{$assign -> {optval} => plain($_), + (($_ eq $dparam{$formdata -> {posterCategory} -> {name}})?($assign -> {optsel} => 1):())}} + @{$formdata -> {posterCategory} -> {values}}]; + + $pars -> {$formdata->{posterCategory}->{assign}->{value}} = $template->list ($assign -> {option}, $list); + $pars -> {$formact ->{post}->{assign}} = $formact->{post}->{url}; + $pars -> {$formdata->{quoteChar}->{assign}->{value}} = 'ÿ'.plain($dparam {$formdata -> {quoteChar} -> {name}} or ''); + + # Formfelder ausfuellen (Werte) + for (qw(uniqueID userID followUp posterName posterEmail posterSubject posterBody posterURL posterImage)) { + $pars -> {$formdata->{$_}->{assign}->{value}} = plain($dparam {$formdata -> {$_} -> {name}});} +} + +################################ +# sub decode_param +# +# CGI-Parameter decodieren +# (rudimentaerer UTF8-support) +################################ + +sub decode_param () { + my $code = param ($formdata -> {quoteChar} -> {name}); + my @array; + + # UTF-8 ([hoechst-]wahrscheinlich) + if ($code =~ /^\303\277/) { + + foreach (param) { + @array=param ($_); + + if (@array == 1) { + $dparam{$_} = $array[0];} + + else { + $dparam{$_} = \@array;}}} + + # Latin 1 (hoffentlich - eigentlich ist es gar keine Codierung...) + elsif ($code =~ /^\377/) { + foreach (param) { + @array=param ($_); + + if (@array == 1) { + $dparam{$_} = toUTF8($array[0]);} + + else { + $dparam{$_} = [map {toUTF8($_)} @array];}}} + + # unbekannte Codierung + else { + return;} + + # ersten beiden Zeichen der Quotechars loeschen (Indikator [ÿ (als UTF8)]) + $dparam {$formdata -> {quoteChar} -> {name}} = ($dparam {$formdata -> {quoteChar} -> {name}} =~ /..(.*)/)[0]; + + delete $dparam {$formdata -> {posterURL} -> {name}} + unless ($dparam {$formdata -> {posterURL} -> {name}} =~ /$httpurl/); + + delete $dparam {$formdata -> {posterImage} -> {name}} + unless ($dparam {$formdata -> {posterImage} -> {name}} =~ /$httpurl/); + + # Codierung erkannt, alles klar + 1; +} + +################################ +# sub check_param +# +# CGI-Parameter pruefen +################################ + +sub check_param () { + my %gotKeys = map {($_ => 1)} param; + my $numGotKeys = keys %gotKeys; + + # Threaderoeffnung, Ersteingabe (leere Seite) + return 'newThread' if ($numGotKeys == 0 or + (($numGotKeys == 1) and ($gotKeys {$formdata -> {userID} -> {name}}))); + + # ======================================================= + # ab hier steht fest, wir haben ein ausgefuelltes + # Formular bekommen + # + # 1. Umrechnungshash bauen (CGI-Key => Identifier) + # 2. alle must-keys vorhanden? + # 3. zuviele Parameter uebermittelt? + # 4. entsprechen die Daten den Anforderungen? + # (alle, nicht nur die must-Daten) + + # 1 + # === + my %name = map {($formdata -> {$_} -> {name} => $_)} keys %$formdata; + + # 2 + # === + $failed=1; + foreach (@{$formmust -> {$gotKeys {$formdata -> {followUp} -> {name}}?'reply':'new'}}) { + return 'missingKey' unless ($gotKeys {$formdata -> {$_} -> {name}});} + + # 3 + # === + foreach (param) { + $failed = $name {$_}; + return 'unexpectedKey' unless (exists ($name {$_}));} + + # 4 + # === + return 'unknownEncoding' unless (decode_param); + + foreach (keys %dparam) { + $failed = $name {$_}; + + return 'tooLong' if (length($dparam{$_}) > $formdata -> {$name {$_}} -> {maxlength}); + return 'tooShort' if (@{[$dparam{$_} =~ /(\S)/g]} < $formdata -> {$name {$_}} -> {minlength}); + return 'wrongMail' if ($formdata -> {$name{$_}} -> {type} eq 'email' and length ($dparam{$_}) and not is_mail_address ($dparam{$_})); + } + + $failed=0; + return $gotKeys {$formdata -> {followUp} -> {name}}?'gotReply':'gotNew'; +} + +# ==================================================== +# Initialisierung +# ==================================================== + +BEGIN { + %subhash = (newThread => \&new_thread, + missingKey => \&missing_key, + unexpectedKey => \&unexpected_key, + unknownEncoding => \&unknown_encoding, + tooShort => \&too_short, + tooLong => \&too_long, + wrongMail => \&wrong_mail, + Occupied => \&occupied, + Dupe => \&dupe_posting, + noReply => \&no_reply, + gotReply => \&got_reply, + gotNew => \&got_new + ); + + # Die RFC-gerechte URL-Erkennung ist aus dem Forum + # (thx2Cheatah - wo auch immer er sie (in der Form) her hat :-) + my $lowalpha = '(?:[a-z])'; + my $hialpha = '(?:[A-Z])'; + my $alpha = "(?:$lowalpha|$hialpha)"; + my $digit = '(?:\d)'; + my $safe = '(?:[$_.+-])'; + my $hex = '(?:[\dA-Fa-f])'; + my $escape = "(?:%$hex$hex)"; + my $digits = '(?:\d+)'; + my $alphadigit = "(?:$alpha|\\d)"; + + # URL schemeparts for ip based protocols: + my $port = "(?:$digits)"; + my $hostnumber = "(?:$digits\\.$digits\\.$digits\\.$digits)"; + my $toplabel = "(?:(?:$alpha(?:$alphadigit|-)*$alphadigit)|$alpha)"; + my $domainlabel = "(?:(?:$alphadigit(?:$alphadigit|-)*$alphadigit)|$alphadigit)"; + my $hostname = "(?:(?:$domainlabel\\.)*$toplabel)"; + my $host = "(?:(?:$hostname)|(?:$hostnumber))"; + my $hostport = "(?:(?:$host)(?::$port)?)"; + + my $httpuchar = "(?:(?:$alpha|$digit|$safe|(?:[!*\',]))|$escape)"; + my $hsegment = "(?:(?:$httpuchar|[;:\@&=~])*)"; + my $search = "(?:(?:$httpuchar|[;:\@&=~])*)"; + my $hpath = "(?:$hsegment(?:/$hsegment)*)"; + + # das alles ergibt eine gueltige URL :-) + $httpurl = "^(?:https?://$hostport(?:/$hpath(?:\\?$search)?)?)\$"; +} + +# ==================================================== +# end of fo_posting.pl +# ==================================================== \ No newline at end of file diff --git a/selfforum-cgi/user/fo_view.pl b/selfforum-cgi/user/fo_view.pl new file mode 100644 index 0000000..5d7d529 --- /dev/null +++ b/selfforum-cgi/user/fo_view.pl @@ -0,0 +1,63 @@ +#!/usr/bin/perl + +use strict; + +use vars qw($Bin $Shared $Script $t0); + +BEGIN { + ($Bin) = ($0 =~ /^(.*)\/.*$/)? $1 : '.'; + $Shared = "$Bin/../shared"; + ($Script) = ($0 =~ /^.*\/(.*)$/)? $1 : $0;} + +use lib "$Shared"; +#use CGI::Carp qw(fatalsToBrowser); + +use Conf; +use Conf::Admin; +use Template::Forum; +use Template::Posting; + +use CGI qw(param header); + +print header(-type => 'text/html'); + +my $conf = read_script_conf ($Bin, $Shared, $Script); + +$conf -> {wwwRoot} = 'i:/i_selfhtml/htdocs' unless ($ENV{GATEWAY_INTERFACE} =~ /CGI/); + +my $show = $conf -> {show}; +my $show_forum = $show -> {Forum}; +my $show_posting = $show -> {Posting}; +my $cgi = $show -> {assign} -> {cgi}; +my $tree = $show -> {assign} -> {thread}; +my $adminDefault = read_admin_conf ("$Bin/".$conf -> {files} -> {adminDefault}); + +my $forum_file = $conf -> {wwwRoot}.$conf -> {files} -> {forum}; +my $message_path = $conf -> {wwwRoot}.$conf -> {files} -> {messagePath}; + +#use Lock qw(:ALL);release_file(forum_file);die; + +my ($tid, $mid) = (param ($cgi -> {thread}), param ($cgi -> {posting})); + +if (defined ($tid) and defined ($mid)) { + print_posting_as_HTML ($message_path, + "$Bin/".$show_posting -> {templateFile}, + {assign => $show_posting -> {assign}, + thread => $tid, + posting => $mid, + messages => $show_posting -> {messages}, + form => $show_posting -> {form}, + cgi => $cgi, + tree => $tree + });} + +else { + print_forum_as_HTML ($forum_file, + "$Bin/".$show_forum -> {templateFile}, + {assign => $show_forum -> {assign}, + adminDefault => $adminDefault, + cgi => $cgi, + tree => $tree + });} + +# eos \ No newline at end of file diff --git a/selfforum-data/.htaccess b/selfforum-data/.htaccess new file mode 100644 index 0000000..374a763 --- /dev/null +++ b/selfforum-data/.htaccess @@ -0,0 +1,4 @@ +DirectoryIndex index.shtml +Options +Includes +AddHandler server-parsed shtml + \ No newline at end of file diff --git a/selfforum-data/images/01.gif b/selfforum-data/images/01.gif new file mode 100644 index 0000000..1050b8f Binary files /dev/null and b/selfforum-data/images/01.gif differ diff --git a/selfforum-data/images/02.gif b/selfforum-data/images/02.gif new file mode 100644 index 0000000..e7a39cf Binary files /dev/null and b/selfforum-data/images/02.gif differ diff --git a/selfforum-data/images/03.gif b/selfforum-data/images/03.gif new file mode 100644 index 0000000..431cdaf Binary files /dev/null and b/selfforum-data/images/03.gif differ diff --git a/selfforum-data/images/04.gif b/selfforum-data/images/04.gif new file mode 100644 index 0000000..eb6aa5b Binary files /dev/null and b/selfforum-data/images/04.gif differ diff --git a/selfforum-data/images/05.gif b/selfforum-data/images/05.gif new file mode 100644 index 0000000..14c1157 Binary files /dev/null and b/selfforum-data/images/05.gif differ diff --git a/selfforum-data/images/06.gif b/selfforum-data/images/06.gif new file mode 100644 index 0000000..505b2ac Binary files /dev/null and b/selfforum-data/images/06.gif differ diff --git a/selfforum-data/images/07.gif b/selfforum-data/images/07.gif new file mode 100644 index 0000000..d33e968 Binary files /dev/null and b/selfforum-data/images/07.gif differ diff --git a/selfforum-data/images/08.gif b/selfforum-data/images/08.gif new file mode 100644 index 0000000..95dcc0f Binary files /dev/null and b/selfforum-data/images/08.gif differ diff --git a/selfforum-data/images/09.gif b/selfforum-data/images/09.gif new file mode 100644 index 0000000..36a798f Binary files /dev/null and b/selfforum-data/images/09.gif differ diff --git a/selfforum-data/images/10.gif b/selfforum-data/images/10.gif new file mode 100644 index 0000000..67e5911 Binary files /dev/null and b/selfforum-data/images/10.gif differ diff --git a/selfforum-data/index.shtml b/selfforum-data/index.shtml new file mode 100644 index 0000000..2a7f9ef --- /dev/null +++ b/selfforum-data/index.shtml @@ -0,0 +1 @@ + diff --git a/selfforum-data/messages/forum.dtd b/selfforum-data/messages/forum.dtd new file mode 100644 index 0000000..46cb440 --- /dev/null +++ b/selfforum-data/messages/forum.dtd @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/selfforum-data/messages/selfforum.xml.lock b/selfforum-data/messages/selfforum.xml.lock new file mode 100644 index 0000000..e69de29 diff --git a/selfforum-data/messages/selfforum.xml.lock.ref b/selfforum-data/messages/selfforum.xml.lock.ref new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/selfforum-data/messages/selfforum.xml.lock.ref @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/selfforum-data/messages/selfforum.xml.lock.ref.lock b/selfforum-data/messages/selfforum.xml.lock.ref.lock new file mode 100644 index 0000000..e69de29 diff --git a/selfforum-data/messages/selfforum.xml.master.lock b/selfforum-data/messages/selfforum.xml.master.lock new file mode 100644 index 0000000..e69de29 diff --git a/selfforum-data/neu.shtml b/selfforum-data/neu.shtml new file mode 100644 index 0000000..4623889 --- /dev/null +++ b/selfforum-data/neu.shtml @@ -0,0 +1 @@ +