Import of the current version of www.zeitungsliste.de
authorJoey Schulze <joey@infodrom.org>
Mon, 23 Jun 2008 17:13:23 +0000 (17:13 +0000)
committerJoey Schulze <joey@infodrom.org>
Mon, 23 Jun 2008 17:13:23 +0000 (17:13 +0000)
63 files changed:
bin/zeitungen-checkrobots [new file with mode: 0755]
bin/zeitungen-rdf [new file with mode: 0755]
bin/zeitungen-tidy [new file with mode: 0755]
lib/ajax.inc [new file with mode: 0644]
lib/board.inc [new file with mode: 0644]
lib/bookmarks.inc [new file with mode: 0644]
lib/core.inc [new file with mode: 0644]
lib/extern/apache-log-parser.php [new file with mode: 0644]
lib/extern/rfc822.php [new file with mode: 0644]
lib/footer.inc [new file with mode: 0644]
lib/functions.inc [new file with mode: 0644]
lib/info.inc [new file with mode: 0644]
lib/layout.inc [new file with mode: 0644]
lib/login.inc [new file with mode: 0644]
lib/search.inc [new file with mode: 0644]
lib/session.inc [new file with mode: 0644]
lib/tags.inc [new file with mode: 0644]
lib/zeitung.inc [new file with mode: 0644]
templates/addsense.js [new file with mode: 0644]
templates/bookmarks.js [new file with mode: 0644]
templates/contact.html [new file with mode: 0644]
templates/contact.js [new file with mode: 0644]
templates/login.html [new file with mode: 0644]
templates/login_new.html [new file with mode: 0644]
templates/main.html [new file with mode: 0644]
templates/options.html [new file with mode: 0644]
templates/options.js [new file with mode: 0644]
templates/passwd.html [new file with mode: 0644]
templates/passwd.js [new file with mode: 0644]
templates/reply.html [new file with mode: 0644]
templates/reply.js [new file with mode: 0644]
templates/searchform.html [new file with mode: 0644]
templates/searchform.js [new file with mode: 0644]
templates/signature [new file with mode: 0644]
templates/tags.html [new file with mode: 0644]
templates/tags.js [new file with mode: 0644]
templates/topic.html [new file with mode: 0644]
templates/topic.js [new file with mode: 0644]
templates/zeitung.html [new file with mode: 0644]
templates/zeitung.js [new file with mode: 0644]
templates/zeitung_new.html [new file with mode: 0644]
www/achtung.gif [new file with mode: 0644]
www/add.gif [new file with mode: 0644]
www/ajax.php [new file with mode: 0644]
www/antworten.gif [new file with mode: 0644]
www/archive.gif [new file with mode: 0644]
www/bookmarks.gif [new file with mode: 0644]
www/config.php [new file with mode: 0644]
www/delete.gif [new file with mode: 0644]
www/down.png [new file with mode: 0644]
www/edit.gif [new file with mode: 0644]
www/favicon.ico [new file with mode: 0644]
www/index.php [new file with mode: 0644]
www/information.gif [new file with mode: 0644]
www/listitem.gif [new file with mode: 0644]
www/main.css [new file with mode: 0644]
www/newspaper.gif [new file with mode: 0644]
www/newtopic.gif [new file with mode: 0644]
www/passwd.gif [new file with mode: 0644]
www/tag.gif [new file with mode: 0644]
www/up.png [new file with mode: 0644]
www/zlist.js [new file with mode: 0644]
www/zlist.png [new file with mode: 0644]

diff --git a/bin/zeitungen-checkrobots b/bin/zeitungen-checkrobots
new file mode 100755 (executable)
index 0000000..6191748
--- /dev/null
@@ -0,0 +1,49 @@
+#! /usr/bin/php
+<?php
+
+include_once('/org/zeitungsliste.de/lib/core.inc');
+include_once('/org/zeitungsliste.de/lib/extern/apache-log-parser.php');
+
+$log = '/var/log/apache2/www.zeitungsliste.de/combined.log.0';
+
+$notfound = array();
+
+$logparser = new apache_log_parser();
+if ($logparser->open_log_file($log)) {
+  while ($line = $logparser->get_line()) {
+
+    if (strpos($line, "GET /robots.txt HTTP/") !== false) {
+      $parts = $logparser->format_line($line);
+
+      $_SERVER['HTTP_USER_AGENT'] = $parts['agent'];
+
+      if (!is_spider())
+       $notfound[] = $parts['agent'];
+    }
+  }
+  $logparser->close_log_file();
+} else {
+  echo "Cannot open $log\n";
+  exit(1);
+}
+
+if (count($notfound)) {
+  $header[] = 'From: Zeitungsliste <master@zeitungsliste.de>';
+  $header[] = 'To: Joey Schulze <joey@infodrom.org>';
+  $header[] = 'MIME-Version: 1.0';
+  $header[] = 'Content-type: text/plain; charset=utf-8';
+  $header[] = 'Content-Disposition: inline';
+  $header[] = 'Content-Transfer-Encoding: 8bit';
+
+  $to = 'joey@infodrom.org';
+  $subject = 'Spider nicht erkannt';
+  $body = "Die folgenden Spider wurden nicht anhand ihres UserAgent-Kennung\n".
+    "erkannt:\n\n";
+
+  foreach ($notfound as $agent)
+    $body .= "  " . $agent . "\n";
+
+  mail ($to, $subject, $body, implode("\n", $header));
+}
+
+?>
\ No newline at end of file
diff --git a/bin/zeitungen-rdf b/bin/zeitungen-rdf
new file mode 100755 (executable)
index 0000000..ceb080d
--- /dev/null
@@ -0,0 +1,84 @@
+#! /usr/bin/perl
+
+# zeitungen-rdf - Build RDF file for www.zeitungsliste.de
+# Copyright (c) 2008  Joey Schulze <joey@infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+
+use strict;
+use warnings;
+
+use DBI;
+use XML::RSS;
+use Algorithm::Diff;
+
+my %cfg = ('home' => 'http://www.zeitungsliste.de/',
+          'webdir' => '/var/www/www.zeitungsliste.de');
+
+my $dsn = 'dbi:Pg:dbname=zlist';
+
+my $dbh = DBI->connect('dbi:Pg:dbname=zlist') or die "Can't connect to database\n";
+
+sub fetchnew
+{
+    my $query = q{SELECT id,name,description FROM zeitungen
+                 WHERE deleted IS false AND changed > now() - interval'3 months'
+                 ORDER BY changed DESC};
+
+    my $sth = $dbh->prepare ($query) or die "Can't prepare Query: $DBI::errstr\n";
+    my $rv = $sth->execute or die "Can't execute query: $DBI::errstr\n";
+
+    my @ret = ();
+    push @ret, [$_->{id},$_->{name},$_->{description}] while ($_ = $sth->fetchrow_hashref);
+
+    return \@ret;
+}
+
+sub rdf_new
+{
+    my $fname = shift;
+    my $papers = fetchnew();
+
+    my $rss = new XML::RSS (version => '1.0', encoding => 'utf-8');
+    $rss->channel (
+       title          => 'Zeitungsliste',
+       description    => 'Zeitungen im Netz',
+       link           => $cfg{'home'},
+       );
+
+    foreach my $paper (@$papers) {
+       # printf "%d: %s\n%s\n", $paper->[0], $paper->[1], $paper->[2];
+
+       $rss->add_item (
+           title       => $paper->[1],
+           description => $paper->[2],
+           link        => sprintf('%szeitung/%d.html', $cfg{'home'}, $paper->[0]),
+           );
+    }
+
+    if (-e $fname) {
+       my @new = split (/\n/, $rss->as_string);
+       open (F, $fname);
+       chomp(my @old = <F>);
+       close (F);
+
+       my @diff = Algorithm::Diff::diff (\@old, \@new);
+       $rss->save ($fname) if (@diff);
+    } else {
+       $rss->save ($fname);
+    }
+}
+
+rdf_new($cfg{webdir} . '/zeitungen.rdf');
diff --git a/bin/zeitungen-tidy b/bin/zeitungen-tidy
new file mode 100755 (executable)
index 0000000..51f98f3
--- /dev/null
@@ -0,0 +1,82 @@
+#! /usr/bin/perl
+
+# zeitungen-tidy - Daily Tidy run for www.zeitungsliste.de
+# Copyright (c) 2008  Joey Schulze <joey@infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+
+use strict;
+use warnings;
+
+use DBI;
+
+my $dsn = 'dbi:Pg:dbname=zlist';
+
+my $dbh = DBI->connect('dbi:Pg:dbname=zlist') or die "Can't connect to database\n";
+
+sub tidy_online
+{
+    my $query = q{SELECT uid FROM online WHERE activity < now() - interval'12 hours'};
+
+    my $sth = $dbh->prepare ($query) or die "Can't prepare Query: $DBI::errstr\n";
+    my $rv = $sth->execute or die "Can't execute query: $DBI::errstr\n";
+
+    my @uids = ();
+    push @uids, $_->{uid} while ($_ = $sth->fetchrow_hashref);
+
+    if ($#uids > -1) {
+       $query = sprintf('DELETE FROM online WHERE uid in (%s)',
+                        join(',', @uids));
+       $dbh->do($query);
+    }
+}
+
+sub archive_topics
+{
+    my $query = q{SELECT id FROM topics WHERE archived IS false AND modified < now() - interval'2 weeks'};
+
+    my $sth = $dbh->prepare ($query) or die "Can't prepare Query: $DBI::errstr\n";
+    my $rv = $sth->execute or die "Can't execute query: $DBI::errstr\n";
+
+    my @ids = ();
+    push @ids, $_->{id} while ($_ = $sth->fetchrow_hashref);
+
+    if ($#ids > -1) {
+       $query = sprintf('UPDATE topics SET archived=true WHERE id in (%s)',
+                        join(',', @ids));
+       $dbh->do($query);
+    }
+}
+
+sub tidy_tags
+{
+    my $query = q{SELECT id FROM tags WHERE id NOT IN (SELECT DISTINCT tag FROM zeitung_tags)};
+
+    my $sth = $dbh->prepare ($query) or die "Can't prepare Query: $DBI::errstr\n";
+    my $rv = $sth->execute or die "Can't execute query: $DBI::errstr\n";
+
+    my @ids = ();
+    push @ids, $_->{id} while ($_ = $sth->fetchrow_hashref);
+
+    if ($#ids > -1) {
+       $query = sprintf('DELETE FROM SET tags WHERE id in (%s)',
+                        join(',', @ids));
+       $dbh->do($query);
+    }
+}
+
+tidy_online;
+archive_topics;
+# tidy_tags;
diff --git a/lib/ajax.inc b/lib/ajax.inc
new file mode 100644 (file)
index 0000000..2c0e495
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+
+$functions = array('search_check' => array('lib' => 'search.inc',
+                                          'func' => 'ajax_search_check'),
+                  'passwd_check' => array('lib' => 'login.inc',
+                                          'func' => 'ajax_passwd_check'),
+                  'nickname_check' => array('lib' => 'login.inc',
+                                            'func' => 'ajax_nickname_check'),
+                  'tag_add' => array('lib' => 'tags.inc',
+                                     'func' => 'ajax_tag_add'),
+                  'tag_del' => array('lib' => 'tags.inc',
+                                     'func' => 'ajax_tag_del'),
+                  'tag_new' => array('lib' => 'tags.inc',
+                                     'func' => 'ajax_tag_new'),
+                  'tag_exists' => array('lib' => 'tags.inc',
+                                        'func' => 'ajax_tag_exists'),
+                  'bookmark_up' => array('lib' => 'bookmarks.inc',
+                                         'func' => 'ajax_bookmark_up'),
+                  'bookmark_down' => array('lib' => 'bookmarks.inc',
+                                           'func' => 'ajax_bookmark_down'),
+                  'bookmark_del' => array('lib' => 'bookmarks.inc',
+                                          'func' => 'ajax_bookmark_del'),
+                  'bookmark_add' => array('lib' => 'bookmarks.inc',
+                                          'func' => 'ajax_bookmark_add'),
+                  'zeitung_check_url' => array('lib' => 'zeitung.inc',
+                                          'func' => 'ajax_zeitung_check_url'),
+                  );
+
+function dumpinfo()
+{
+  global $_SERVER;
+  global $_POST;
+  global $_GET;
+
+  $info = "\$_SERVER = " . var_export($_SERVER, true);
+  $info .= "\n\$_POST = " . var_export($_POST, true);
+  $info .= "\n\$_GET = " . var_export($_GET, true);
+
+  $f = fopen("/tmp/zlist.dump", "w");
+  fwrite($f, $info);
+  fclose($f);
+}
+
+function ajax_process()
+{
+  global $functions;
+  global $_POST;
+
+  dumpinfo();
+
+  if (strlen($_POST['function']) && array_key_exists($_POST['function'], $functions)) {
+      if (array_key_exists('lib', $functions[$_POST['function']]))
+       include_once($functions[$_POST['function']]['lib']);
+      if (array_key_exists('func', $functions[$_POST['function']])) {
+       if (function_exists($functions[$_POST['function']]['func']))
+         return $functions[$_POST['function']]['func']();
+       else
+         return false;
+      }
+  }
+
+  return false;
+}
+
+?>
\ No newline at end of file
diff --git a/lib/board.inc b/lib/board.inc
new file mode 100644 (file)
index 0000000..61b70fb
--- /dev/null
@@ -0,0 +1,149 @@
+<?php
+
+// Precondition: $body is already sanitised
+function article_add($topic, $body)
+{
+  global $_SESSION;
+  global $_SERVER;
+
+  $query = sprintf("INSERT INTO article (topic,uid,status,body,created,remote_addr) ".
+                  "VALUES (%d,%d,%d,'%s',now(),'%s')",
+                  $topic,  $_SESSION['uid'], 1, pg_escape_string($body),
+                  $_SERVER['REMOTE_ADDR']);
+
+  $sth = db_query($query);
+  if ($sth === false)
+    return false;
+
+  return true;
+}
+
+function topic_add($zid, $topic, $body)
+{
+  db_query('BEGIN TRANSACTION');
+
+  $query = sprintf("INSERT INTO topics (zeitung,topic,created,modified) ".
+                  "VALUES (%d,'%s',now(),now())",
+                  $zid, $topic);
+
+  $sth = db_query($query);
+  if ($sth === false) {
+    db_query('ROLLBACK');
+    return false;
+  }
+
+  $id = db_last_id('topics', 'id');
+  if ($id === false) {
+    db_query('ROLLBACK');
+    return false;
+  }
+
+  if (article_add($id, $body) === false) {
+    db_query('ROLLBACK');
+    return false;
+  }
+
+  db_query('COMMIT');
+
+  return $id;
+}
+
+function process_topic()
+{
+  global $cfg;
+  global $zlist;
+  global $_POST;
+  global $_GET;
+
+  if (isset($_GET['zeitung']) && is_numeric($_GET['zeitung']))
+    $zid = $_GET['zeitung'];
+  elseif (isset($_POST['zeitung']) && is_numeric($_POST['zeitung']))
+    $zid = $_POST['zeitung'];
+  else
+    $ret = warning('Keine Zeitung oder Magazin gefunden!');
+
+  if (isset($zid)) {
+    $try = format_newspaper($zid, true);
+    if ($try === false) {
+      $ret .= warning('Keine Zeitung oder Magazin gefunden!');
+      unset($zid);
+    } else
+      $ret .= $try;
+  }
+
+  if (isset($zid)) {
+    if (!isset($_SESSION['uid']))
+      $ret .= warning('Um eine neue Diskussion zu beginnen, müssen Sie angemeldet sein.');
+    else {
+      $replace = array('zeitung' => $zid);
+      if (!isset($_POST['zeitung'])) {
+       $ret .= information('Sie beginnen eine neue Diskussion im Forum.');
+      } else {
+       $replace['topic'] = htmlspecialchars($_POST['topic']);
+       $replace['body'] = string_sanitise($_POST['body']);
+
+       if (strlen($_POST['topic'])) {
+         if (strlen($_POST['body'])) {
+           if (($tid = topic_add($zid, $replace['topic'], $replace['body'])) !== false) {
+             header(sprintf('Location: %stopic/%d.html', $cfg['home'], $tid));
+           } else
+             $ret .= warning('Es ist ein Datenbankfehler aufgetreten.');
+         } else
+           $ret .= warning('Sie haben keinen Text für die Diskussion angegeben!');
+       } else
+         $ret .= warning('Sie haben keinen Titel für die Diskussion angegeben!');
+      }
+
+      $ret .= load_javascript('topic.js') . load_template('topic.html', $replace);
+    }
+  }
+
+  return $ret;
+}
+
+// Sideeffect: May set $zlist['redirect']
+function process_reply()
+{
+  global $cfg;
+  global $zlist;
+  global $_GET;
+  global $_POST;
+
+  if (isset($_GET['topic']) && is_numeric($_GET['topic']))
+    $topic = $_GET['topic'];
+  elseif (isset($_POST['topic']) && is_numeric($_POST['topic']))
+    $topic = $_POST['topic'];
+  else
+    $ret = warning('Keine passende Diskussion gefunden!');
+
+  if (isset($topic)) {
+    $discussion = format_topic($topic);
+    if (isset($zlist['zid'])) {
+      $ret .= format_newspaper($zlist['zid'], true);
+
+      if (isset($_POST['body'])) {
+       if (article_add($topic, string_sanitise($_POST['body'])) === true) {
+         $ret .= information('Danke für Ihren Beitrag.  Sie werden automatisch zur Diskussion weitergeleitet.');
+         header(sprintf('Location: %stopic/%d.html', $cfg['home'], $topic));
+       } else {
+         $ret .= warning('Ihr Beitrag konnte nicht aufgenommen werden.');
+         $ret .= $discussion;
+         $replace = array('topic' => $topic,
+                          'title' => $zlist['topic'],
+                          'body' => htmlspecialchars($_POST['body']));
+         $ret .= load_javascript('reply.js') . load_template('reply.html', $replace);
+       }
+      } else {
+       $ret .= $discussion;
+       $replace = array('topic' => $topic,
+                        'title' => $zlist['topic']);
+       $ret .= load_javascript('reply.js') . load_template('reply.html', $replace);
+      }
+    } else
+      $ret .= $discussion;
+  }
+
+  return $ret;
+}
+
+?>
\ No newline at end of file
diff --git a/lib/bookmarks.inc b/lib/bookmarks.inc
new file mode 100644 (file)
index 0000000..842db68
--- /dev/null
@@ -0,0 +1,215 @@
+<?php
+
+function bookmark_add($zid, $uid)
+{
+  $query = sprintf("INSERT INTO bookmarks (uid,zeitung) VALUES (%d,%d)",
+                  $uid, $zid);
+
+  # Ignore potentially existing bookmark
+  db_query($query);
+}
+
+function bookmark_delete($zid, $uid)
+{
+  $query = sprintf("DELETE FROM bookmarks " .
+                  "WHERE uid = %d AND zeitung = %d",
+                  $uid, $zid);
+
+  # Ignore potentially non-existing bookmark
+  db_query($query);
+}
+
+function bookmark_up($zid, $uid)
+{
+  $query = sprintf("UPDATE bookmarks SET priority = priority - 1 " .
+                  "WHERE uid = %d AND zeitung = %d",
+                  $uid, $zid);
+
+  # Ignore potentially non-existing bookmark
+  db_query($query);
+}
+
+function bookmark_down($zid, $uid)
+{
+  $query = sprintf("UPDATE bookmarks SET priority = priority + 1 " .
+                  "WHERE uid = %d AND zeitung = %d",
+                  $uid, $zid);
+
+  # Ignore potentially non-existing bookmark
+  db_query($query);
+}
+
+function format_bookmarks()
+{
+  global $_SESSION;
+
+  if (!isset($_SESSION['uid']))
+    return;
+
+  $query = sprintf("SELECT zeitung,name,priority FROM bookmarks " .
+                  "JOIN zeitungen ON zeitungen.id = zeitung " .
+                  "WHERE uid = %d " .
+                  "ORDER BY priority,name LIMIT 20",
+                  $_SESSION['uid']);
+
+  $sth = db_query($query);
+
+  if ($sth === false || pg_NumRows ($sth) == 0)
+    return '&nbsp;';
+
+$rowf = '<tr>
+<td width="85">
+<a %s><img src="up.png" width="16" height="16" alt="up" title="Nach oben schieben" border="0"></a>
+<strong>%d</strong>
+<a %s><img src="down.png" width="16" height="16" alt="up" title="Nach unten schieben" border="0"></a>
+<a %s><img src="delete.gif" width="16" height="16" alt="delete" title="Lesezeichen löschen" border="0"></a>
+</td>
+<td>
+<a href="zeitung/%d.html">%s</a></td>
+</tr>';
+
+  $ret .= '<table class="bookmarks" width="100%", alt=¨">';
+  for ($n=0; $n < pg_NumRows ($sth); $n++) {
+    $row = pg_fetch_array ($sth, $n);
+
+    if (javascript_ok()) {
+      $link_up = sprintf('href="bookmark.html" onclick="return bookmark_action(\'up\',%d);"', $row['zeitung']);
+      $link_down = sprintf('href="bookmark.html" onclick="return bookmark_action(\'down\',%d);"', $row['zeitung']);
+      $link_del = sprintf('href="bookmark.html" onclick="return bookmark_action(\'del\',%d);"', $row['zeitung']);
+    } else {
+      $link_up = sprintf('href="bookmark.html?zeitung=%d&action=up"', $row['zeitung']);
+      $link_down = sprintf('href="bookmark.html?zeitung=%d&action=down"', $row['zeitung']);
+      $link_del = sprintf('href="bookmark.html?zeitung=%d&action=delete"', $row['zeitung']);
+    }
+
+    $ret .= sprintf($rowf,
+                   $link_up, $row['priority'], $link_down, $link_del,
+                   $row['zeitung'], $row['name']);
+  }
+  $ret .= '</table>';
+
+
+  return $ret;
+}
+
+function bookmarks_manage()
+{
+  global $_SESSION;
+
+  if (!isset($_SESSION['uid']))
+    return notfound();
+
+  $ret = '<h3>Verwaltung der persönlichen Lesezeichen</h3>';
+
+  $ret .= '<div id="bookmarks">';
+  $ret .= load_javascript('bookmarks.js');
+  $ret .= format_bookmarks();
+  $ret .= '</div>';
+
+  return $ret;
+}
+
+function process_bookmark()
+{
+  global $_SESSION;
+  global $_SERVER;
+  global $_GET;
+  global $zlist;
+  global $cfg;
+
+  if (!isset($_SESSION['uid']))
+    return notfound();
+
+  if (empty($_SERVER['QUERY_STRING'])) {
+    return bookmarks_manage();
+  } elseif (!isset($_GET['zeitung']) || !is_numeric($_GET['zeitung'])) {
+    if (isset($_SERVER['HTTP_REFERER']))
+      $zlist['redirect'] = substr($_SERVER['HTTP_REFERER'], strlen($zlist['home']));
+    return warning('Keine Zeitung oder Magazin gefunden.');
+  } elseif (isset($_GET['action'])) {
+    if ($_GET['action'] == 'up')
+      bookmark_up($_GET['zeitung'], $_SESSION['uid']);
+    elseif ($_GET['action'] == 'down')
+      bookmark_down($_GET['zeitung'], $_SESSION['uid']);
+    elseif ($_GET['action'] == 'delete')
+      bookmark_delete($_GET['zeitung'], $_SESSION['uid']);
+    else
+      return notfound();
+    header('Location: ' . $cfg['home'] . 'bookmark.html');
+    exit;
+  } else {
+    bookmark_add($_GET['zeitung'], $_SESSION['uid']);
+    if (isset($_SERVER['HTTP_REFERER'])) {
+      header('Location: ' . $_SERVER['HTTP_REFERER']);
+      exit;
+    } else
+      return information('Ihr Lesezeichen wurde hinzugefügt');
+  }
+}
+
+function ajax_bookmark_check()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!isset($_POST['zeitung']) || !is_numeric($_POST['zeitung']) ||
+      !isset($_SESSION['uid']))
+    return false;
+
+  return true;
+}
+
+function ajax_bookmark_up()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!ajax_bookmark_check())
+    return false;
+
+  bookmark_up($_POST['zeitung'], $_SESSION['uid']);
+
+  return format_bookmarks();
+}
+
+function ajax_bookmark_down()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!ajax_bookmark_check())
+    return false;
+
+  bookmark_down($_POST['zeitung'], $_SESSION['uid']);
+
+  return format_bookmarks();
+}
+
+function ajax_bookmark_del()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!ajax_bookmark_check())
+    return false;
+
+  bookmark_delete($_POST['zeitung'], $_SESSION['uid']);
+
+  return format_bookmarks();
+}
+
+function ajax_bookmark_add()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!ajax_bookmark_check())
+    return false;
+
+  bookmark_add($_POST['zeitung'], $_SESSION['uid']);
+
+  return format_info_bookmarks();
+}
+
+
+?>
\ No newline at end of file
diff --git a/lib/core.inc b/lib/core.inc
new file mode 100644 (file)
index 0000000..0b157b9
--- /dev/null
@@ -0,0 +1,186 @@
+<?php
+
+function db_connect()
+{
+  global $cfg;
+
+  $dsn = "dbname=".$cfg['dbname'];
+  if (isset($cfg['dbhost'])) $dsn .= " host=".$cfg['dbhost'];
+  if (isset($cfg['dbport'])) $dsn .= " port=".$cfg['dbport'];
+  if (isset($cfg['dbuser'])) $dsn .= " user=".$cfg['dbuser'];
+  if (isset($cfg['dbpass'])) $dsn .= " password=".$cfg['dbpass'];
+
+  $dbh = pg_pconnect ($dsn)
+    or carp("Unable to connect to SQL server");
+  pg_exec ($dbh, "SET DateStyle='ISO'");
+
+  return $dbh;
+}
+
+function db_query($query)
+{
+  global $cfg;
+
+  // error_log($query);
+  $sth = pg_exec ($cfg['dbh'], $query);
+
+  if ($sth === false) {
+    error_log ($query);
+    error_log (pg_last_error($cfg['dbh']));
+    return false;
+  }
+
+  return $sth;
+}
+
+function db_last_id($table, $column)
+{
+  $query = sprintf ("SELECT currval('%s_%s_seq')", $table, $column);
+
+  $sth =  db_query ($query);
+
+  if (!$sth)
+    return false;
+
+  if (pg_num_rows($sth) == 0) {
+    error_log ("$query resulted in an empty set");
+    return false;
+  }
+
+  $row = pg_fetch_row($sth, 0);
+
+  return $row[0];
+}
+
+// preserve <p></p>, <b></b>, <em></em>, <br>, <a href></a>
+function string_sanitise($text)
+{
+  $ntext = preg_replace (array('/<a\s+href=["\']?([^>"\']*)["\']?>([^<]*)<\/a>/i'),
+                        array('[[$1][$2]]'),
+                        $text);
+
+  $ntext = htmlspecialchars($ntext, ENT_QUOTES);
+
+  $ntext = preg_replace(array('/&lt;(\/?(p|br|b|em))&gt;/i',
+                             '/\[\[([^\]]+)\]\[([^\]]+)\]\]/'),
+                       array('<$1>','<a href="$1">$2</a>'),
+                       $ntext);
+
+  return $ntext;
+}
+
+function basepath()
+{
+  global $cfg;
+  global $_SERVER;
+
+  $pos = strpos(strtolower($cfg['home']), strtolower($_SERVER['SERVER_NAME']));
+  $base = substr($cfg['home'], $pos+strlen($_SERVER['SERVER_NAME']));
+
+  $pos = strpos($_SERVER['REQUEST_URI'], "?");
+  if ($pos === false)
+    $uri = $_SERVER['REQUEST_URI'];
+  else 
+    $uri = substr($_SERVER['REQUEST_URI'], 0, $pos);
+
+  if (strpos($uri, $base) === 0) {
+    $cfg['path'] = substr($uri, strlen($base));
+    $pos = strrpos($cfg['path'], '/');
+    if ($pos !== false) {
+      $cfg['dir'] = substr($cfg['path'], 0, $pos);
+    }
+    return str_repeat("../", substr_count($cfg['path'], "/"));
+  }
+}
+
+function logged_in()
+{
+  global $_SESSION;
+
+  return isset($_SESSION['uid']);
+}
+
+function javascript_ok()
+{
+  global $_SESSION;
+
+  if (!logged_in())
+    return true;
+
+  if ($_SESSION['javascript'] == true)
+    return true;
+
+  return false;
+}
+
+function is_spider()
+{
+  global $_SERVER;
+  global $_SESSION;
+
+  if (isset($_SESSION['uid']))
+    if (isset($_SESSION['robot']))
+      return $_SESSION['robot'];
+
+  if (strpos($_SERVER['HTTP_USER_AGENT'], 'Yahoo! Slurp') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Googlebot') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Mediapartners-Google') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'VoilaBot') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Gigabot/3.0') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Speedy Spider') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'LinkWalker/2.0') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'proximic') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Yeti/1.0') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Eurobot/1.0') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'MnoGoSearch/') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'ia_archiver') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Seekbot/1.0') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'MyEngines-Bot') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'larbin_') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'findlinks/1') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'holmes/3.12') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'NoteworthyBot/0.1') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Eurosoft-Bot') !== false ||
+      strpos($_SERVER['HTTP_USER_AGENT'], 'msnbot') !== false) {
+      strpos($_SERVER['HTTP_USER_AGENT'], 'Cityreview Robot') !== false) {
+    if (isset($_SESSION['uid']))
+      $_SESSION['robot'] = true;
+    return true;
+  }
+
+  if (isset($_SESSION['uid']))
+    $_SESSION['robot'] = false;
+  return false;
+}
+
+function format_info_bookmarks()
+{
+  global $_SESSION;
+  global $cfg;
+
+  if (!isset($_SESSION['uid']))
+    return false;
+
+  $query = sprintf("SELECT zeitung,name FROM bookmarks " .
+                  "JOIN zeitungen ON zeitungen.id = zeitung " .
+                  "WHERE uid = %d " .
+                  "ORDER BY priority,name LIMIT 20",
+                  $_SESSION['uid']);
+
+  $sth = db_query($query);
+
+  if ($sth === false || pg_NumRows ($sth) == 0)
+    return false;
+
+  $ret = '<p><ul>';
+  for ($n=0; $n < pg_NumRows ($sth); $n++) {
+    $row = pg_fetch_array ($sth, $n);
+    $ret .= sprintf('<li><a href="%szeitung/%d.html">%s</a></li>',
+                   $cfg['basepath'], $row['zeitung'], $row['name']);
+  }
+  $ret .= '</ul></p>';
+
+  return $ret;
+}
+
+?>
\ No newline at end of file
diff --git a/lib/extern/apache-log-parser.php b/lib/extern/apache-log-parser.php
new file mode 100644 (file)
index 0000000..a4d6883
--- /dev/null
@@ -0,0 +1,102 @@
+<?php\r
+/*\r
++----------------------------------------------+\r
+|                                              |\r
+|         PHP apache log parser class          |\r
+|                                              |\r
++----------------------------------------------+\r
+| Filename   : apache-log-parser.php           |\r
+| Created    : 21-Sep-05 23:28 GMT             |\r
+| Created By : Sam Clarke                      |\r
+| Email      : admin@free-webmaster-help.com   |\r
+| Version    : 1.0                             |\r
+|                                              |\r
++----------------------------------------------+\r
+\r
+http://www.phpclasses.org/browse/download/1/file/10984/name/apache-log-parser.php\r
+\r
+LICENSE\r
+\r
+This program is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License (GPL)\r
+as published by the Free Software Foundation; either version 2\r
+of the License, or (at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+To read the license please visit http://www.gnu.org/copyleft/gpl.html\r
+\r
+*/\r
+\r
+class apache_log_parser\r
+{\r
+\r
+  var $bad_rows; // Number of bad rows\r
+  var $fp; // File pointer\r
+\r
+  function format_log_line($line)\r
+  {\r
+    preg_match("/^(\S+) (\S+) (\S+) \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] \"(\S+) (.*?) (\S+)\" (\S+) (\S+) (\".*?\") (\".*?\")$/", $line, $matches); // pattern to format the line\r
+    return $matches;\r
+  }\r
+\r
+  function format_line($line)\r
+  {\r
+    $logs = $this->format_log_line($line); // format the line\r
+\r
+    if (isset($logs[0])) // check that it formated OK\r
+    {\r
+      $formated_log = array(); // make an array to store the lin info in\r
+      $formated_log['ip'] = $logs[1];\r
+      $formated_log['identity'] = $logs[2];\r
+      $formated_log['user'] = $logs[2];\r
+      $formated_log['date'] = $logs[4];\r
+      $formated_log['time'] = $logs[5];\r
+      $formated_log['timezone'] = $logs[6];\r
+      $formated_log['method'] = $logs[7];\r
+      $formated_log['path'] = $logs[8];\r
+      $formated_log['protocal'] = $logs[9];\r
+      $formated_log['status'] = $logs[10];\r
+      $formated_log['bytes'] = $logs[11];\r
+      $formated_log['referer'] = $logs[12];\r
+      $formated_log['agent'] = $logs[13];\r
+      return $formated_log; // return the array of info\r
+    }\r
+    else\r
+    {\r
+      $this->badRows++; // if the row is not in the right format add it to the bad rows\r
+      return false;\r
+    }\r
+  }\r
+\r
+  function open_log_file($file_name)\r
+  {\r
+    $this->fp = fopen($file_name, 'r'); // open the file\r
+    if (!$this->fp)\r
+    {\r
+      return false; // return false on fail\r
+    }\r
+    return true; // return true on sucsess\r
+  }\r
+\r
+  function close_log_file()\r
+  {\r
+    return fclose($this->fp); // close the file\r
+  }\r
+\r
+  // gets a line from the log file\r
+  function get_line()\r
+  {\r
+    if (feof($this->fp))\r
+    {\r
+       return false;\r
+    }\r
+    $line = fgets ($this->fp, 1024);\r
+    return $line;\r
+  }\r
+\r
+}\r
+?>\r
diff --git a/lib/extern/rfc822.php b/lib/extern/rfc822.php
new file mode 100644 (file)
index 0000000..7e6b702
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+######################################################################################
+#                                                                                    #
+# RFC822 Email Parser                                                                #
+# http://code.iamcal.com/php/rfc822/rfc822.phps                                      #
+#                                                                                    #
+# By Cal Henderson <cal@iamcal.com>                                                  #
+# This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License  #
+# http://creativecommons.org/licenses/by-sa/2.5/                                     #
+#                                                                                    #
+# Revision 2                                                                         #
+#                                                                                    #
+######################################################################################
+
+
+function is_valid_email_address($email){
+    $qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
+    $dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
+    $char = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c'.
+              '\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]';
+    $atom = "$char+";
+
+          $quoted_pair = '\\x5c[\\x00-\\x7f]';
+          $domain_literal = "\\x5b($dtext|$quoted_pair)*\\x5d";
+          $quoted_string = "\\x22($qtext|$quoted_pair)*\\x22";
+          $domain_ref = $atom;
+          $top_domain = "[a-zA-Z]{2,10}";
+          $sub_domain = "($domain_ref|$domain_literal)";
+          $word = "($atom|$quoted_string)";
+          $domain = "$sub_domain(\\x2e$sub_domain)*\\x2e$top_domain";
+          $local_part = "$word(\\x2e$word)*";
+          $addr_spec = "$local_part\\x40$domain";
+          return preg_match("!^$addr_spec$!", $email) ? 1 : 0;
+      }
+
+?>
diff --git a/lib/footer.inc b/lib/footer.inc
new file mode 100644 (file)
index 0000000..cb1f74f
--- /dev/null
@@ -0,0 +1,8 @@
+<div class="pagefooter"></div>
+</div>
+<div class="footer">
+Copyright &copy; 2008 <a href="http://infocon.infodrom.org/">Information & Consulting</a>
+<? if (isset($start)) printf('<br>%7.5f Sekunden', microtime() - $start); ?>
+</div>
+</body>
+</html>
diff --git a/lib/functions.inc b/lib/functions.inc
new file mode 100644 (file)
index 0000000..01c3a5f
--- /dev/null
@@ -0,0 +1,498 @@
+<?php
+
+/*
+ * ==================== Configuration of/for the platform ===============
+ */
+$pages = array('logout.html' => array('lib' => 'login.inc',
+                                     'func' => 'logout'),
+              'login.html' => array('lib' => 'login.inc',
+                                    'func' => 'process_login'),
+              'activate.html' => array('lib' => 'login.inc',
+                                       'func' => 'process_activate'),
+              'passwd.html' => array('lib' => 'login.inc',
+                                     'func' => 'process_passwd'),
+              'options.html' => array('lib' => 'login.inc',
+                                      'func' => 'process_options'),
+              'search.html' => array('lib' => 'search.inc',
+                                     'func' => 'process_search'),
+              'topic.html' => array('lib' => 'board.inc',
+                                    'func' => 'process_topic'),
+              'reply.html' => array('lib' => 'board.inc',
+                                    'func' => 'process_reply'),
+              'tags.html' => array('lib' => 'tags.inc',
+                                    'func' => 'process_tags'),
+              'edit.html' => array('lib' => 'zeitung.inc',
+                                  'func' => 'process_edit'),
+              'new.html' => array('lib' => 'zeitung.inc',
+                                  'func' => 'process_new'),
+              'bookmark.html' => array('lib' => 'bookmarks.inc',
+                                       'func' => 'process_bookmark'),
+              'contact.html' => array('func' => 'process_contact'),
+              'sitemap.html' => array('lib' => 'layout.inc',
+                                      'func' => 'layout_sitemap'),
+              );
+
+$dirs = array('zeitung' => array('func' => 'layout_showpaper'),
+             'archiv' => array('func' => 'layout_archive'),
+             'tag' => array('func' => 'layout_showtag'),
+             'topic' => array('func' => 'layout_topic'),
+             );
+
+
+/*
+ * ==================== Commonly use code ===============================
+ */
+include_once('layout.inc');
+
+function carp($msg)
+{
+  error_log($msg);
+  exit;
+}
+
+function userstatus()
+{
+  global $_SESSION;
+
+  if (isset($_SESSION['uid']))
+    $info = array($_SESSION['online'], $_SESSION['users'], $_SESSION['zeitungen'],
+                 $_SESSION['ztags'], $_SESSION['tags']);
+  else
+    $info = userstatus_info();
+  
+  return sprintf('%d Nutzer von %d online | %d Zeitungen | Bewertungen: %d | Tags: %d',
+                $info[0], $info[1], $info[2], $info[3], $info[4]);
+}
+
+function dispatch()
+{
+  global $cfg;
+  global $_SERVER;
+  global $_SESSION;
+  global $_GET;
+  global $_POST;
+  global $zlist;
+  global $pages;
+  global $dirs;
+
+  $zlist['info'] = array('info_searchform', 'info_new', 'info_tags', 'info_tagcloud',
+                        'info_actions', 'info_bookmarks','info_hitlist');
+
+  if (strlen($cfg['path']) && array_key_exists($cfg['path'], $pages)) {
+      if (array_key_exists('lib', $pages[$cfg['path']]))
+       include_once($pages[$cfg['path']]['lib']);
+      if (array_key_exists('func', $pages[$cfg['path']])) {
+       if (function_exists($pages[$cfg['path']]['func']))
+         $body = $pages[$cfg['path']]['func']();
+       else
+         $body = notfound();
+      }
+  } elseif (strlen($cfg['dir']) && array_key_exists($cfg['dir'], $dirs)) {
+      if (array_key_exists('lib', $dirs[$cfg['dir']]))
+       include_once($dirs[$cfg['dir']]['lib']);
+      if (array_key_exists('func', $dirs[$cfg['dir']])) {
+        if (function_exists($dirs[$cfg['dir']]['func']))
+         $body = $dirs[$cfg['dir']]['func']();
+       else
+         $body = notfound();
+      }
+  } elseif (empty($_SERVER['QUERY_STRING']) &&
+          empty($cfg['path']) && empty($cfg['dir'])) {
+    $body .= load_template('main.html');
+    $zlist['page'] = 'index';
+  } else {
+    $body = notfound();
+  }
+
+  return layout_page($body);
+}
+
+function tagcloud_min()
+{
+  $query = 'SELECT count(uid) AS count FROM zeitung_tags GROUP BY zeitung,tag ORDER BY count ASC LIMIT 1';
+
+  $sth = db_query($query);
+
+  if ($sth === false)
+    return 1;
+
+  if (pg_NumRows($sth) === 0)
+    return 1;
+
+  $row = pg_fetch_array($sth, 0);
+  return $row['count'];
+}
+
+function tagcloud_max()
+{
+  $query = 'SELECT count(uid) AS count FROM zeitung_tags GROUP BY zeitung,tag ORDER BY count DESC LIMIT 1';
+
+  $sth = db_query($query);
+
+  if ($sth === false)
+    return 10;
+
+  if (pg_NumRows($sth) === 0)
+    return 10;
+
+  $row = pg_fetch_array($sth, 0);
+  return $row['count'];
+}
+
+function tag_class($count)
+{
+  global $_SESSION;
+
+  if (isset($_SESSION['uid'])) {
+    if (!isset($_SESSION['tagcloud_lastupdate']) ||
+       $_SESSION["tagcloud_lastupdate"] < time() - 60*60*12) {
+      $min = $_SESSION["tagcloud_min"] = tagcloud_min();
+      $max = $_SESSION["tagcloud_max"] = tagcloud_max();
+      $_SESSION["tagcloud_lastupdate"] = time();
+    }
+  }
+
+  if (!isset($min)) {
+    $min = tagcloud_min();
+    $max = tagcloud_max();
+  }
+
+  if ($count > (int)($min + ($max - $min) * 0.8))
+    return 4;
+  elseif ($count > (int)($min + ($max - $min) * 0.6))
+    return 3;
+  elseif ($count > (int)($min + ($max - $min) * 0.4))
+    return 2;
+  elseif ($count > (int)($min + ($max - $min) * 0.2))
+    return 1;
+  else
+    return 0;
+}
+
+function load_template($template, $replace=false)
+{
+  global $cfg;
+
+  $fname = $cfg['tmpldir'] . '/' . $template;
+  if (!file_exists($fname))
+    return false;
+
+  $f = fopen($fname, 'r');
+  $content = fread($f, filesize($fname));
+  fclose($f);
+
+  if (preg_match_all('/@([^@]+)@/', $content, $matches)) {
+    $fields = array();
+    $values = array();
+
+    $found = array_unique($matches[1]);
+
+    foreach ($found as $field) {
+      $fields[] = '/@'.$field.'@/';
+      if ($replace != false && array_key_exists($field, $replace))
+       $values[] = $replace[$field];
+      else
+       $values[] = '';
+    }
+
+    $content = preg_replace($fields, $values, $content);
+  }
+
+  return $content;
+}
+
+function load_javascript($file)
+{
+  global $cfg;
+
+  if (!javascript_ok())
+    return;
+
+  $fname = $cfg['tmpldir'] . '/' . $file;
+  if (!file_exists($fname))
+    return;
+
+  $f = fopen($fname, 'r');
+  $content = fread($f, filesize($fname));
+  fclose($f);
+
+  $ret = "\n" . '<script type="text/javascript"><!--' . "\n";
+  $ret .= $content;
+  $ret .= "\n" . '//--></script>' . "\n";
+
+  return $ret;
+}
+
+function format_date($date)
+{
+  setlocale(LC_TIME, "de_DE.UTF-8");
+
+  return strftime("%e. %B %Y, %H:%M", strtotime($date));
+}
+
+function format_newspaper($id)
+{
+  global $cfg;
+  global $zlist;
+
+  $query = sprintf("SELECT * FROM zeitungen WHERE id = %d AND deleted IS false", $id);
+
+  $sth = db_query($query) or carp("format_newspaper");
+
+  if (pg_NumRows ($sth) == 0)
+    return false;
+
+  $row = pg_fetch_array ($sth, 0);
+
+  $ret = '<div class="newspaper">';
+  $ret .= sprintf('<h3>%s</h3>', htmlspecialchars($row['name']));
+  $zlist['newspaper'] = htmlspecialchars($row['name']);
+
+  $ret .= sprintf('<p>%s<br>Ort: %s<br>URL: <a href="%s"><code>%s</code></a></p>',
+                 $row['description'], $row['city'],
+                 $row['url'], $row['url']);
+  $ret .= '</div>';
+
+  return $ret;
+}
+
+function format_topten($uid)
+{
+  global $cfg;
+
+  if ($uid > 0)
+    $query = sprintf("SELECT zeitung,name,counter FROM hits " .
+                    "INNER JOIN zeitungen ON id = zeitung " .
+                    "WHERE deleted IS false AND uid = %d " .
+                    "ORDER BY counter DESC LIMIT 10", $uid);
+  else
+    $query = "SELECT zeitung,name,sum(counter) as counter FROM hits " .
+             "INNER JOIN zeitungen ON id = zeitung " .
+             "WHERE deleted IS false " .
+             "GROUP BY zeitung,name ORDER BY counter DESC LIMIT 10";
+
+  $sth = db_query($query) or carp("format_topten");
+
+  if (pg_NumRows ($sth) == 0)
+    return;
+
+  $ret = '<h3>Top 10</h3>';
+  $ret .= '<p><ul>';
+  for ($n=0; $n < pg_NumRows ($sth); $n++) {
+    $row = pg_fetch_array ($sth, $n);
+    $ret .= sprintf('<li><a href="%szeitung/%d.html">%s</a></li>',
+                   $cfg['basepath'], $row['zeitung'], $row['name']);
+  }
+  $ret .= '</ul></p>';
+
+  return $ret;
+}
+
+function format_topic($topic)
+{
+  global $cfg;
+  global $zlist;
+  global $_SERVER;
+
+  $query = sprintf("SELECT topic,archived,zeitung FROM topics WHERE id = %d",
+                  $topic);
+
+  if (($sth = db_query($query)) === false)
+    return warning('Es ist ein Datenbankfehler aufgetreten.');
+
+  if (pg_NumRows ($sth) == 0)
+    return warning('Keine passende Diskussion gefunden.');
+
+  if (($info = pg_fetch_array ($sth, 0)) == false)
+    return warning('Es ist ein Datenbankfehler aufgetreten.');
+
+  $query = sprintf("SELECT nickname,url,created,body FROM article " .
+                  "JOIN users ON users.id = uid " .
+                  "WHERE topic = %d AND article.status = 1 " .
+                  "ORDER BY created", $topic);
+
+  if (($sth2 = db_query($query)) === false) return false;
+
+  if (pg_NumRows ($sth2) > 0) {
+    $ret .= '<div class="topic">';
+    $ret .= sprintf ('<h3>%s</h3>', htmlspecialchars($info['topic']));
+    $col = 0;
+    $zlist['zid'] = $info['zeitung'];
+    $zlist['topic'] = $info['topic'];
+    $zlist['archived'] = $info['archived'] == 't';
+
+    for ($j=0; $j < pg_NumRows ($sth2); $j++) {
+      $row = pg_fetch_array ($sth2, $j);
+
+      $ret .= sprintf('<div class="art%d">', $col);
+
+      if (strlen($row['url']))
+       $author = sprintf('<a href="%s">%s</a>', $row['url'], $row['nickname']);
+      else
+       $author = $row['nickname'];
+
+      $ret .= sprintf('<p><b>%s</b>, %s</p>', $author, format_date($row['created']));
+      $ret .= sprintf('<p>%s</p>', $row['body']);
+      $ret .= '</div>';
+      $col = 1-$col;
+    }
+
+    if ($info['archived'] == 'f' &&
+       strpos($_SERVER['REQUEST_URI'], "/reply.html", 0) === false) {
+      $ret .= '<div class="buttons"><p>';
+      if (logged_in()) {
+       $link_rep = sprintf('%sreply.html?topic=%d', $cfg['basepath'], $topic);
+      } else {
+       $link_rep = sprintf('%slogin.html?from=article', $cfg['basepath']);
+      }
+
+      $ret .= sprintf('<img src="%santworten.gif" width="21" height="17">&nbsp;', $cfg['basepath']);
+      $ret .= sprintf('<a href="%s"><strong>antworten</strong></a>', $link_rep);
+      $ret .= '</p></div>';
+    }
+      
+    $ret .= '</div>';
+  }
+  return $ret;
+}
+
+function format_board($zid, $archived=false)
+{
+  global $cfg;
+  global $zlist;
+
+  $query = sprintf("SELECT id FROM topics " .
+                  "WHERE zeitung = %d AND archived IS %s " .
+                  "ORDER BY created DESC", $zid,
+                  $archived?'true':'false');
+
+  if (($sth = db_query($query)) === false) return false;
+
+  if (pg_NumRows ($sth) == 0 && !$archived) {
+    $zlist['notopic'] = true;
+
+    return $ret;
+  }
+
+  if (pg_NumRows ($sth) > 0) {
+    if ($archived)
+      $ret = '<h3>Abgeschlossene Diskussionen</h3>';
+    else
+      $ret = '<h3>Diskussion</h3>';
+  }
+
+  for ($i=0; $i < pg_NumRows ($sth); $i++) {
+    $row = pg_fetch_array ($sth, $i);
+
+    $ret .= format_topic($row['id']);
+  }
+
+  return $ret;
+}
+
+function fix_url($url) {
+  if (!strlen($url))
+    return false;
+
+  if (strpos($url, "http://") === false)
+    $url = "http://" . $url;
+
+  $parts = parse_url($url);
+
+  if ($parts === false)
+    return false;
+
+  if (empty($parts['path']))
+    $url .= '/';
+
+  return $url;
+}
+
+function is_valid_url($url) {
+  $parts = parse_url($url);
+
+  if (empty($parts['host']) || empty($parts['scheme']) || empty($parts['path']))
+    return false;
+
+  if ($parts['scheme'] != 'http' && $parts['scheme'] != 'https')
+    return false;
+
+  if (!preg_match ('/^[a-zA-Z][a-zA-Z0-9\.-]+$/', $parts['host'], $matches))
+    return false;
+
+  if (preg_match ('/[\\\\<>"\'\(\)\[\]]/', $parts['path'], $matches))
+    return false;
+
+  if (!empty($parts['query']) && preg_match ('/[\\\\<>"\'\(\)\[\]]/', $parts['query'], $matches))
+    return false;
+
+  return true;
+}
+
+function sendmail($to, $name, $subject, $body, $header=array())
+{
+  global $cfg;
+
+  if (empty($to))
+    return false;
+
+  $header[] = 'From: ' . $cfg['from'];
+  if (empty($name))
+    $header[] = 'To: ' . $to;
+  else
+    $header[] = sprintf('To: %s <%s>', $name, $to);
+  $header[] = 'MIME-Version: 1.0';
+  $header[] = 'Content-type: text/plain; charset=utf-8';
+  $header[] = 'Content-Disposition: inline';
+  $header[] = 'Content-Transfer-Encoding: 8bit';
+
+  $sig = load_template('signature');
+  if (!empty($sig))
+    $body .= $sig;
+
+  $subject = mb_encode_mimeheader($subject,"UTF-8", "Q", "\n");
+
+  if (mail ($to, $subject, $body, implode("\n", $header)) === false)
+    return false;
+
+  return true;
+}
+
+function logbook($table,$refid,$column,$old,$new)
+{
+  global $_SESSION;
+
+  $query = sprintf("INSERT INTO logbook (uid,tab,refid,col,oldval,newval,modified) " .
+                  "VALUES (%d,'%s',%d,'%s','%s','%s',now())",
+                  $_SESSION['uid'], $table,$refid,$column,
+                  pg_escape_string($old),
+                  pg_escape_string($new));
+
+  db_query($query);
+}
+
+function hits_inc($zeitung)
+{
+  global $cfg;
+  global $_SESSION;
+
+  if (is_spider())
+    return;
+
+  $uid = isset($_SESSION['uid'])?$_SESSION['uid']:0;
+
+  $query = sprintf("SELECT counter FROM hits WHERE uid = %d AND zeitung = %d", $uid, $zeitung);
+
+  $sth = db_query($query);
+
+  if (pg_NumRows ($sth) == 0)
+    $query = sprintf("INSERT INTO hits (zeitung,uid,counter) " .
+                    "VALUES (%d,%d,1)", $zeitung, $uid);
+  else
+    $query = sprintf("UPDATE hits SET counter = counter + 1 " .
+                    "WHERE zeitung = %d AND uid = %d", $zeitung, $uid);
+
+  db_query($query);
+}
+
+?>
\ No newline at end of file
diff --git a/lib/info.inc b/lib/info.inc
new file mode 100644 (file)
index 0000000..4c868a2
--- /dev/null
@@ -0,0 +1,331 @@
+<?php
+
+function info_searchform()
+{
+  global $cfg;
+  global $zlist;
+
+  $replace = array('basepath' => $cfg['basepath'],
+                  'keyword' => $zlist['keyword']);
+
+  return load_javascript('searchform.js') . load_template('searchform.html', $replace);
+}
+
+function info_new()
+{
+  global $cfg;
+
+  if ($cfg['path'] == 'reply.html' ||
+      $cfg['path'] == 'topic.html' ||
+      $cfg['path'] == 'new.html' ||
+      $cfg['dir'] == 'zeitung')
+    return;
+
+  $query = "SELECT name,id FROM zeitungen " .
+           "WHERE changed > now() - interval '3 months' AND deleted IS false " .
+           "ORDER BY changed DESC limit 10";
+
+  $sth = db_query($query);
+
+  if (pg_NumRows ($sth) == 0)
+    return;
+
+  $ret = '<h3>Neu aufgenommen</h3>';
+  $ret .= '<p><ul>';
+  for ($n=0; $n < pg_NumRows ($sth); $n++) {
+    $row = pg_fetch_array ($sth, $n);
+    $ret .= sprintf('<li><a href="%szeitung/%d.html">%s</a></li>',
+                   $cfg['basepath'], $row['id'], $row['name']);
+  }
+  $ret .= '</ul></p>';
+
+  return $ret;
+}
+
+function info_topten()
+{
+  global $cfg;
+
+  $query = "SELECT zeitung,name,sum(counter) as counter FROM hits " .
+           "INNER JOIN zeitungen ON id = zeitung " .
+           "WHERE deleted IS false " .
+           "GROUP BY zeitung,name ORDER BY counter DESC LIMIT 10";
+
+  $sth = db_query($query) or carp("info_topten");
+
+  if (pg_NumRows ($sth) == 0)
+    return;
+
+  $ret = '<h3>Top 10</h3>';
+  $ret .= '<p><ul>';
+  for ($n=0; $n < pg_NumRows ($sth); $n++) {
+    $row = pg_fetch_array ($sth, $n);
+    $ret .= sprintf('<li><a href="%szeitung/%d.html">%s</a></li>',
+                   $cfg['basepath'], $row['zeitung'], $row['name']);
+  }
+  $ret .= '</ul></p>';
+
+  return $ret;
+}
+
+function info_hitlist()
+{
+  global $cfg;
+  global $_SESSION;
+
+  if (!isset($_SESSION['uid']))
+    return info_topten();
+
+  $query = sprintf("SELECT zeitung,name,counter FROM hits " .
+                  "INNER JOIN zeitungen ON id = zeitung " .
+                  "WHERE deleted IS false AND uid = %d " .
+                  "ORDER BY counter DESC LIMIT 10", $_SESSION['uid']);
+
+  $sth = db_query($query) or carp("info_topten");
+
+  if (pg_NumRows ($sth) == 0)
+    return info_topten();
+
+  $ret = '<h3>Favoriten</h3>';
+  $ret .= '<p><ul>';
+  for ($n=0; $n < pg_NumRows ($sth); $n++) {
+    $row = pg_fetch_array ($sth, $n);
+    $ret .= sprintf('<li><a href="%szeitung/%d.html">%s</a></li>',
+                   $cfg['basepath'], $row['zeitung'], $row['name']);
+  }
+  $ret .= '</ul></p>';
+
+  return $ret;
+}
+
+function info_tags()
+{
+  global $cfg;
+  global $zlist;
+
+  if (!isset($zlist['zid']))
+    return;
+
+  $query = sprintf("SELECT id,tagname,count(uid) AS count " .
+                  "FROM tags JOIN zeitung_tags ON tag = id " .
+                  "WHERE zeitung = %d GROUP BY id,tagname " .
+                  "ORDER BY lower(tagname)",
+                  $zlist['zid']);
+
+  $sth = db_query($query);
+
+  if (pg_NumRows ($sth) == 0)
+    return;
+
+  $ret = '<h3>Tags</h3>';
+  $ret .= '<p class="tagcloud">';
+  for ($n=0; $n < pg_NumRows ($sth); $n++) {
+    $row = pg_fetch_array ($sth, $n);
+
+    $ret .= sprintf('<span class="tag%d"><a href="%stag/%s.html">%s</a></span> ',
+                   tag_class($row['count']), $cfg['basepath'],
+                   urlencode($row['tagname']), $row['tagname']);
+  }
+  $ret .= '</p>';
+
+  return $ret;
+}
+
+function info_tagcloud()
+{
+  global $cfg;
+  global $zlist;
+  global $_SESSION;
+
+  if (!isset($zlist['zid']))
+    return;
+
+  if (!is_numeric($_SESSION['uid']))
+    return;
+
+  $query = sprintf("SELECT id,tagname FROM tags " .
+                  "JOIN zeitung_tags ON tag = id " .
+                  "WHERE zeitung = %d AND uid = %d " .
+                  "ORDER BY lower(tagname)",
+                  $zlist['zid'], $_SESSION['uid']);
+
+  $sth = db_query($query);
+
+  if (pg_NumRows ($sth) == 0)
+    return info_tags();
+
+  $ret = '<h3>Persönliche Tags</h3>';
+  $ret .= '<p class="tagcloud">';
+  for ($n=0; $n < pg_NumRows ($sth); $n++) {
+    $row = pg_fetch_array ($sth, $n);
+
+    $ret .= sprintf('<span class="tag0"><a href="%stag/%s.html">%s</a></span> ',
+                   $cfg['basepath'],
+                   $row['tagname'], $row['tagname']);
+  }
+  $ret .= '</p>';
+
+  return $ret;
+}
+
+function info_archive($zid)
+{
+  global $cfg;
+
+  $query = sprintf('SELECT count(*) FROM topics '.
+                  'WHERE zeitung = %d AND archived IS true',
+                  $zid);
+
+  $sth = db_query($query);
+
+  $row = pg_fetch_array($sth, 0);
+
+  if ($row[0] > 0)
+    return sprintf('<img src="%sarchive.gif" width="27" height="20" alt="">&nbsp;' .
+                  '<a href="%sarchiv/%d.html"><strong>Archiv</strong></a>',
+                  $cfg['basepath'], $cfg['basepath'], $zid);
+
+    return false;
+}
+
+function info_actions()
+{
+  global $cfg;
+  global $zlist;
+  global $_SESSION;
+
+  $title = array('edit' => 'Stammdaten dieser Zeitung bearbeiten',
+                'tags' => 'Persönliche Tags zur Zeitung hinzufügen oder löschen',
+                'add' => 'Neue Zeitung oder Magazin aufnehmen',
+                'newtopic' => 'Neue Diskussion zu dieser Zeitung beginnen',
+                'bookmark' => 'Lesezeichen zu dieser Zeitung setzen',
+                'bookmarks' => 'Persönliche Lesezeichen verwalten',
+                );
+
+  $actions = array();
+  $ret = '';
+
+  if (isset($_SESSION['uid']) && $cfg['path'] == 'options.html')
+    $actions[] = sprintf('<img src="%spasswd.gif" width="27" height="23" alt="">&nbsp;' .
+                        '<a href="%spasswd.html"><strong>Passwort ändern</strong></a>',
+                        $cfg['basepath'], $cfg['basepath']);
+
+  if (($cfg['dir'] == 'zeitung' || $cfg['dir'] == 'archiv' || $cfg['dir'] == 'topic' ) &&
+      isset($zlist['zid'])) {
+    if (isset($_SESSION['uid']))
+      $actions[] = sprintf('<img src="%stag.gif" width="27" height="25" alt="">&nbsp;' .
+                          '<a href="%stags.html?zeitung=%d" title="%s"><strong>Tags verwalten</strong></a>',
+                          $cfg['basepath'], $cfg['basepath'], $zlist['zid'],
+                          $title['tags']);
+    else
+      $actions[] = sprintf('<img src="%stag.gif" width="27" height="25" alt="">&nbsp;' .
+                          '<a href="%slogin.html?from=tags" title="%s"><strong>Tags verwalten</strong></a>',
+                          $cfg['basepath'], $cfg['basepath'], $title['tags']);
+  }
+
+  if ($cfg['dir'] == 'zeitung' && isset($_SESSION['uid'])) {
+    if (javascript_ok()) {
+      
+      $ret .= load_javascript('bookmarks.js');
+      $link = sprintf('href="%sbookmark.html" onclick="return bookmark_action(\'add\',%d);"',
+                     $cfg['basepath'], $zlist['zid']);
+    } else
+      $link = sprintf('href="%sbookmark.html?zeitung=%d"', $cfg['basepath'], $zlist['zid']);
+
+    $actions[] = sprintf('<img src="%sadd.gif" width="27" height="24" alt="">&nbsp;' .
+                        '<a %s title="%s"><strong>Lesezeichen setzen</strong></a>',
+                        $cfg['basepath'], $link,
+                        $title['bookmark']);
+  }
+
+  if ($cfg['path'] == 'options.html' && isset($_SESSION['uid']))
+    $actions[] = sprintf('<img src="%sbookmarks.gif" width="27" height="21" alt="">&nbsp;' .
+                        '<a href="%sbookmark.html" title="%s"><strong>Lesezeichen verwalten</strong></a>',
+                        $cfg['basepath'], $cfg['basepath'],
+                        $title['bookmarks']);
+
+  if ($cfg['dir'] == 'zeitung' && isset($zlist['zid'])) {
+    if (isset($_SESSION['uid']))
+      $actions[] = sprintf('<img src="%sedit.gif" width="27" height="26" alt="">&nbsp;' .
+                          '<a href="%sedit.html?zeitung=%d" title="%s"><strong>Bearbeiten</strong></a>',
+                          $cfg['basepath'], $cfg['basepath'], $zlist['zid'],
+                          $title['edit']);
+    else
+      $actions[] = sprintf('<img src="%sedit.gif" width="27" height="26" alt="">&nbsp;' .
+                          '<a href="%slogin.html?from=edit" title="%s"><strong>Bearbeiten</strong></a>',
+                          $cfg['basepath'], $cfg['basepath'],
+                          $title['edit']);
+  }
+
+  if ($zlist['page'] == 'index' ||
+      $cfg['dir'] == 'zeitung' ||
+      $cfg['dir'] == 'tag') {
+    if (isset($_SESSION['uid']))
+      $actions[] = sprintf('<img src="%snewspaper.gif" width="27" height="25" alt="">&nbsp;' .
+                          '<a href="%snew.html" title="%s"><strong>Neue Zeitung</strong></a>',
+                          $cfg['basepath'], $cfg['basepath'], $title['add']);
+    else
+      $actions[] = sprintf('<img src="%snewspaper.gif" width="27" height="25" alt="">&nbsp;' .
+                          '<a href="%slogin.html?from=new" title="%s"><strong>Neue Zeitung</strong></a>',
+                          $cfg['basepath'], $cfg['basepath'], $title['add']);
+  }
+
+  if ($zlist['notopic'] === true)
+    $text = 'Diskussion';
+  else
+    $text = 'Neues Thema';
+
+  if (($cfg['dir'] == 'zeitung' || $cfg['dir'] == 'archiv') && isset($zlist['zid'])) {
+    if (isset($_SESSION['uid']))
+      $actions[] = sprintf('<img src="%snewtopic.gif" width="27" height="20" alt="">&nbsp;' .
+                          '<a href="%stopic.html?zeitung=%d" title="%s"><strong>%s</strong></a>',
+                          $cfg['basepath'], $cfg['basepath'], $zlist['zid'],
+                          $title['newtopic'], $text);
+    else
+      $actions[] = sprintf('<img src="%snewtopic.gif" width="27" height="20" alt="">&nbsp;' .
+                          '<a href="%slogin.html?from=zeitung" title="%s"><strong>%s</strong></a>',
+                          $cfg['basepath'], $cfg['basepath'], $title['newtopic'], $text);
+  }
+
+  if ($cfg['dir'] == 'zeitung' && isset($zlist['zid'])) {
+    $try = info_archive($zlist['zid']);
+    if ($try !== false)
+      $actions[] = $try;
+  }
+
+  if ($actions) {
+    $ret .= '<p><ul class="action">';
+    foreach ($actions as $row)
+      $ret .= '<li>' . $row . '</li>';
+    $ret .= '</ul></p>';
+  }
+
+  return $ret;
+}
+
+function info_bookmarks()
+{
+  global $cfg;
+  global $_SESSION;
+
+  if (!isset($_SESSION['uid']))
+    return;
+
+  if ($cfg['path'] == 'bookmark.html')
+    return;
+
+  $try = format_info_bookmarks();
+
+  if ($try === false)
+    return;
+
+  $ret = '<h3>Lesezeichen</h3>';
+  $ret .= '<div id="bookmarks">';
+  $ret .= $try;
+  $ret .= '</div>';
+
+  return $ret;
+}
+
+
+?>
\ No newline at end of file
diff --git a/lib/layout.inc b/lib/layout.inc
new file mode 100644 (file)
index 0000000..90a093f
--- /dev/null
@@ -0,0 +1,504 @@
+<?php
+
+include_once('extern/rfc822.php');
+
+function warning($text)
+{
+  global $cfg;
+  $ret = '<p class="warn"><img src="'.$cfg['basepath'].
+    'achtung.gif" width="33" height="32" alt="Achtung!">&nbsp;&nbsp;';
+  $ret .= $text .'</p>';
+  return $ret;
+}
+
+function information($text)
+{
+  global $cfg;
+  $ret = '<p class="info"><img src="'.$cfg['basepath'].
+    'information.gif" width="31" height="31" alt="Info">&nbsp;&nbsp;';
+  $ret .= $text .'</p>';
+  return $ret;
+}
+
+function pageheader()
+{
+  global $cfg;
+  global $zlist;
+  global $_POST;
+  global $_SERVER;
+
+  $ret .= '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">';
+  $ret .= '<html lang="de">';
+  $ret .= '<head>';
+  if (isset($zlist['newspaper']))
+    $ret .= sprintf('<title>Zeitungsliste: %s</title>', $zlist['newspaper']);
+  elseif (isset($zlist['tag']))
+    $ret .= sprintf('<title>Zeitungsliste: Tag %s</title>', $zlist['tag']);
+  else
+    $ret .= '<title>Zeitungsliste</title>';
+  $ret .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
+  $ret .= '<meta name="Author" content="joey@infodrom.org (Joey Schulze)">';
+  $ret .= '<meta name="Language" content="de">';
+  
+  if ($zlist['page'] == 'index') {
+    $ret .= '<meta name="Keywords" content="Zeitung, Zeitungen, Liste, Zeitungsliste, Online-Zeitungen, Zeitungen im Web, Forum, Community">';
+    $ret .= sprintf('<link rel="alternate" type="application/rss+xml" title="Zeitungen" href="%szeitungen.rdf">', $cfg['basepath']);
+  }
+
+  if (is_spider())
+    $ret .= '<meta name="Robots" content="index,follow">';
+  $ret .= '<meta name="Copyright" content="(c) 2008 Information & Consulting">';
+  $ret .= sprintf('<link href="%smain.css" rel="stylesheet" type="text/css">', $cfg['basepath']);
+  $ret .= sprintf('<link rel="icon" href="%sfavicon.ico" type="image/x-icon">', $cfg['basepath']);
+  $ret .= sprintf('<link rel="shortcut icon" href="%sfavicon.ico" type="image/x-icon">', $cfg['basepath']);
+
+  if (isset($zlist['redirect']))
+    $ret .= sprintf('<meta http-equiv="refresh" content="7; URL=%s%s">',
+                   $cfg['home'], $zlist['redirect']);
+
+  $ret .= '</head>';
+
+  if (javascript_ok()) {
+    $ret .= sprintf('<script type="text/javascript" src="%szlist.js"></script>', $cfg['basepath']);
+    $ret .= sprintf('<script type="text/javascript">var zlist_urlbase = "%s";</script>', $cfg['basepath']);
+  }
+
+  $ret .= '<body>';
+  $ret .= '<div class="banner"><h1 class="none"><a href="http://www.debian.org/">Zeitungen online im Netz</a></h1></div>';
+
+  $ret .= '<div class="status">';
+
+  $ret .= '<div class="homestatus"><a href="'.$cfg['home'].'">Home</a>';
+  if ($cfg['path'] != 'contact.html')
+    $ret .= sprintf('&nbsp;&nbsp;&nbsp;<a href="%scontact.html">Kontakt</a>', $cfg['basepath']);
+  if (is_spider())
+    $ret .= sprintf('&nbsp;&nbsp;&nbsp;<a href="%ssitemap.html">Sitemap</a>', $cfg['basepath']);
+  $ret .= '</div>';
+
+  if (logged_in()) {
+    if ($cfg['path'] != "logout.html") {
+      $ret .= '<div class="logstatus">';
+      if ($cfg['path'] != "options.html")
+       $ret .= sprintf('<a href="%soptions.html">Einstellungen</a>&nbsp;&nbsp;&nbsp;',
+                       $cfg['basepath']);
+      $ret .= sprintf('<a href="%slogout.html">Abmelden</a>',
+                     $cfg['basepath']);
+      $ret .= '</div>';
+    }
+  } else {
+    if (($cfg['path'] != "login.html" && $cfg['path'] != "activate.html") ||
+       ($cfg['path'] == 'login.html' && isset($_POST['sendnew'])))
+      $ret .= sprintf('<div class="logstatus"><a href="%slogin.html">Anmelden</a></div>',
+                     $cfg['basepath']);
+  }
+  $ret .= sprintf('<div class="userstatus">%s</div>', userstatus());
+  $ret .= '</div>';
+
+  $ret .= '<div class="page">';
+  if ($_SERVER['SERVER_NAME'] == 'www.zeitungsliste.de' && javascript_ok())
+    $ret .= "\n" . load_template('addsense.js');
+
+  return $ret;
+}
+
+function layout_page($body)
+{
+  global $zlist;
+
+  $ret = '<div class="info">';
+  if (is_array($zlist['info'])) {
+    include_once('info.inc');
+    foreach ($zlist['info'] as $func)
+      $ret .= $func();
+  }
+
+  $ret .= '</div>';
+
+  $ret .= '<div class="main">';
+  $ret .= $body;
+  $ret .= '</div>';
+  return $ret;
+}
+
+function layout_bookmarks($rel, $title)
+{
+  global $cfg;
+
+  // Mehr auf http://www.bikeshops.de/Bikeshops/BikeGuide/BikeGuideWertgarantie.asp
+  $bookmarks = array(
+                    array('text' => 'Mister Wong',
+                          'icon' => 'link_misterwong.gif',
+                          'link' => 'http://www.mister-wong.de/index.php?action=addurl&amp;bm_url=@url@&amp;bm_description=@title@'),
+                    array('text' => 'Delicious',
+                          'icon' => 'link_delicious.gif',
+                          'link' => 'http://del.icio.us/post?v=4&amp;noui&amp;url=@url@&amp;title=@title@'),
+                    array('text' => 'Google Bookmarks',
+                          'icon' => 'link_google.gif',
+                          'link' => 'http://www.google.com/bookmarks/mark?op=add&amp;hl=de&amp;bkmk=@url@&amp;title=@title@'),
+                    array('text' => 'Yahoo Web',
+                          'icon' => 'link_yahoo.gif',
+                          'link' => 'http://myweb2.search.yahoo.com/myresults/bookmarklet?u=@url@&amp;t=@title@'),
+                    array('text' => 'Technorati',
+                          'icon' => 'link_technorati.gif',
+                          'link' => 'http://technorati.com/faves?add=@url@'),
+                    array('text' => 'Digg it',
+                          'icon' => 'link_digg.gif',
+                          'link' => 'http://digg.com/submit?phase=2&amp;url=@url@&amp;title=@title@'),
+                    array('text' => 'Yigg',
+                          'icon' => 'link_yigg.gif',
+                          'link' => 'http://yigg.de/neu?action=addurl&amp;exturl=@url@&amp;exttitle=@title@'),
+                    array('text' => 'Taggle',
+                          'icon' => 'link_taggle.gif',
+                          'link' => 'http://taggle.de/addLinkDetails?mAddress=@url@&amp;title=B@title@&amp;submitted=Weiter'),
+                    array('text' => 'Linkarena',
+                          'icon' => 'link_linkarena.gif',
+                          'link' => 'http://www.linkarena.com/linkadd.php?linkName=@title@&amp;linkURL=@url@'),
+                    array('text' => 'OneView',
+                          'icon' => 'link_oneview.gif',
+                          'link' => 'http://www.oneview.de/quickadd/neu/addBookmark.jsf?URL=@url@&amp;title=@title@'),
+                    array('text' => 'folk it',
+                          'icon' => 'link_folkd.gif',
+                          'link' => 'http://www.folkd.com/submit/@url@'),
+                    array('text' => 'Facebook',
+                          'icon' => 'link_facebook.gif',
+                          'link' => 'http://www.facebook.com/sharer.php?u=@url@&amp;title=@title@'),
+                    array('text' => 'Blinklist',
+                          'icon' => 'link_blinklist.gif',
+                          'link' => 'http://www.blinklist.com/index.php?Action=Blink/addblink.php&Url=@url@&Description=@title@'),
+                    array('text' => 'Furl',
+                          'icon' => 'link_furl.gif',
+                          'link' => 'http://www.furl.net/storeIt.jsp?t=@title@&u=@url@'),
+                    array('text' => 'Reddit',
+                          'icon' => 'link_reddit.gif',
+                          'link' => 'http://reddit.com/submit?url=@url@&title=@title@'),
+                    array('text' => 'Spurl',
+                          'icon' => 'link_spurl.gif',
+                          'link' => 'http://www.spurl.net/spurl.php?url=@url@&title=@title@'),
+                    array('text' => 'Shadows',
+                          'icon' => 'link_shadows.gif',
+                          'link' => 'http://www.shadows.com/features/tcr.htm?url=@url@&title=@title@'),
+                    array('text' => 'newsvine',
+                          'icon' => 'link_newsvine.gif',
+                          'link' => 'http://www.newsvine.com/_wine/save?popoff=1&u=@url@&tags=&blurb=@title@'),
+                    array('text' => 'CXWeb',
+                          'icon' => 'link_cxweb.gif',
+                          'link' => 'http://www.cxweb.de/login/?action=add&amp;address=@url@&amp;title=@title@'),
+                    array('text' => 'Simpy',
+                          'icon' => 'link_simpy.gif',
+                          'link' => 'http://www.simpy.com/simpy/LinkAdd.do?title=@title@&amp;href=@url@'),
+                    array('text' => 'Ma.Gnolia',
+                          'icon' => 'link_magnolia.gif',
+                          'link' => 'http://ma.gnolia.com/bookmarklet/add?url=@url@&amp;title=@title@&amp;description=&amp;tags='),
+                    array('text' => 'StumbleUpon',
+                          'icon' => 'link_stumbleupon.gif',
+                          'link' => 'http://www.stumbleupon.com/submit?url=@url@&amp;title=@title@'),
+                    array('text' => 'linksilo.de',
+                          'icon' => 'link_linksilo.gif',
+                          'link' => 'http://www.linksilo.de/index.php?area=bookmarks&amp;func=bookmark_new&amp;addurl=@url@&amp;addtitle=@title@'),
+                    array('text' => 'bookmarks.cc',
+                          'icon' => 'link_bookmarkscc.gif',
+                          'link' => 'http://www.bookmarks.cc/bookmarken.php?action=neu&amp;url=@url@&amp;title=@title@'),
+                    );
+
+  $url = $cfg['home'] . $rel;
+
+  $ret = '<div class="social_bookmarks">Lesezeichen: ';
+
+  foreach ($bookmarks as $bm) {
+    $ret .= sprintf('<a href="%s" title="%s"><img src="%sbookmarks/%s" width="16" height="16" alt="%s" name="%s" border="0"></a>',
+                   str_replace(array('@url@', '@title@'),
+                               array(htmlspecialchars($url), htmlspecialchars($title)),
+                               $bm['link']),
+                   $bm['text'],
+                   $cfg['basepath'], $bm['icon'], $bm['text'], $bm['text']);
+  }
+
+  $ret .= '</div>';
+
+  return $ret;
+}
+
+/*
+ * Add links to the main page for web spider so that they get the entire database
+ */
+function layout_sitemap()
+{
+  global $_SESSION;
+  global $_SERVER;
+  global $cfg;
+
+  if (!is_spider())
+    header('Location: ' . $cfg['home']);
+
+  $ret = '<h1>Sitemap der Zeitungsliste</h1>';
+
+  $query = 'SELECT tagname FROM tags ORDER BY lower(tagname)';
+
+  $sth = db_query($query);
+
+  if ($sth !== false && pg_NumRows($sth) > 0) {
+    $ret .= '<h3>Tags bzw. Merkmale</h3>';
+    $ret .= '<ul class="gold">';
+
+    for ($i=0; $i < pg_NumRows($sth); $i++) {
+      $row = pg_fetch_array($sth, $i);
+
+      $ret .= sprintf('<li><a href="%stag/%s.html">%s</a></li>',
+                     $cfg['basepath'], urlencode($row['tagname']),
+                     $row['tagname']);
+    }
+
+    $ret .= '</ul>';
+  }
+
+  $query = 'SELECT id,name,city FROM zeitungen WHERE deleted IS false ORDER BY name';
+
+  $sth = db_query($query);
+
+  if ($sth !== false && pg_NumRows($sth) > 0) {
+    $ret .= '<h3>Zeitungen und Magazine</h3>';
+    $ret .= '<ul class="gold">';
+    for ($i=0; $i < pg_NumRows($sth); $i++) {
+      $row = pg_fetch_array($sth, $i);
+
+      $ret .= sprintf('<li><a href="%szeitung/%d.html">%s</a>, %s</li>',
+                     $cfg['basepath'], $row['id'], $row['name'], $row['city']);
+    }
+    $ret .= '</ul>';
+  }
+
+  $query = 'SELECT id,topic FROM topics WHERE ORDER BY created';
+
+  $sth = db_query($query);
+
+  if ($sth !== false && pg_NumRows($sth) > 0) {
+    $ret .= '<h3>Diskussionen</h3>';
+    $ret .= '<ul class="gold">';
+    for ($i=0; $i < pg_NumRows($sth); $i++) {
+      $row = pg_fetch_array($sth, $i);
+
+      $ret .= sprintf('<li><a href="%stopic/%d.html">%s</a></li>',
+                     $cfg['basepath'], $row['id'], $row['topic']);
+    }
+    $ret .= '</ul>';
+  }
+
+  return $ret;
+}
+
+function layout_showpaper($archived=false)
+{
+  global $_GET;
+  global $zlist;
+
+  if (!isset($_GET['zeitung']) || !is_numeric($_GET['zeitung']))
+    $ret = warning('Keine Zeitung oder Magazin gefunden.');
+  else {
+    $zid = $_GET['zeitung'];
+    $details = format_newspaper($zid, true);
+    if ($details === false)
+      $ret .= warning('Keine Zeitung oder Magazin gefunden.');
+    else {
+      $zlist['zid'] = $zid;
+      $ret .= $details;
+      if (!$archived) {
+       hits_inc ($zid);
+       $ret .= format_board($zid);
+      } else {
+       $ret .= format_board($zid, $archived);
+      }
+      $ret .= layout_bookmarks(sprintf('zeitung/%d.html', $zid), $zlist['newspaper']);
+    }
+  }
+
+  return $ret;
+}
+
+function layout_archive()
+{
+  global $zlist;
+  global $_GET;
+  global $cfg;
+
+  if (!isset($_GET['archiv']) || !is_numeric($_GET['archiv']))
+    $ret = warning('Keine Zeitung oder Magazin gefunden.');
+  else {
+    $zid = $_GET['archiv'];
+    $details = format_newspaper($zid, true);
+    if ($details === false)
+      $ret .= warning('Keine Zeitung oder Magazin gefunden.');
+    else {
+      $zlist['zid'] = $zid;
+      $ret .= $details;
+
+      $query = sprintf('SELECT id,topic FROM topics ' .
+                      'WHERE zeitung = %d ORDER BY created DESC',
+                      $_GET['archiv']);
+
+      $sth = db_query($query);
+
+      if (!$sth || pg_NumRows ($sth) == 0)
+       $ret .= warning('Kein Archiv gefunden.');
+      else {
+       $ret .= '<p><ul class="gold">';
+       for ($i=0; $i < pg_NumRows ($sth); $i++) {
+         $row = pg_fetch_array($sth, $i);
+         $ret .= sprintf('<li><a href="%stopic/%d.html">%s</a></li>',
+                         $cfg['basepath'], $row['id'], $row['topic']);
+       }
+       $ret .= '</ul></p>';
+      }
+    }
+  }
+
+  return $ret;
+}
+
+function layout_showtag()
+{
+  global $cfg;
+  global $zlist;
+  global $_GET;
+
+  if (!isset($_GET['tag']))
+    $ret = warning('Keine derartiges Merkmal gefunden.');
+  else {
+    $tagname = $_GET['tag'];
+    $ret .= '<h3>Merkmal <span class="tag">' . $tagname . '</span></h3>';
+
+    $query = sprintf("SELECT zeitungen.id,name,count(uid) AS count FROM zeitungen " .
+                    "JOIN zeitung_tags ON zeitung = id " .
+                    "JOIN tags ON tag = tags.id " .
+                    "WHERE tagname = '%s' " .
+                    "GROUP BY zeitungen.id,name ORDER BY count DESC",
+                    pg_escape_string($tagname));
+
+    $sth = db_query($query);
+
+    $zlist['tag'] = htmlspecialchars($tagname);
+    if (!$sth || pg_NumRows ($sth) == 0) {
+      $ret .= warning('Keine Zeitungen oder Magazine mit diesem Merkmal gefunden.');
+      unset($zlist['newspaper']);
+    } else {
+      $headlines = array('Mäßige','Mittelmäßige','Gute','Häufige','Häufigste');
+      $oldtag = -1;
+
+      for ($i=0; $i < pg_NumRows ($sth); $i++) {
+       $row = pg_fetch_array ($sth, $i);
+       $tag = tag_class($row['count']);
+
+       if ($oldtag != $tag) {
+         if ($oldtag != -1)
+           $ret .= '</ul>';
+         $ret .= sprintf('<h3 class="tag%d">%s Bewertungen</h3>', $tag, $headlines[$tag]);
+         $ret .= '<ul class="gold">';
+         $oldtag = $tag;       
+       }
+
+       $ret .= sprintf('<li><a href="%szeitung/%d.html">%s</a></li>',
+                       $cfg['basepath'], $row['id'], $row['name'], $row['city']);
+      }
+      $ret .= '</ul>';
+
+      $ret .= layout_bookmarks(sprintf('tag/%s.html', htmlspecialchars($tagname)), 'Merkmal '.$tagname);
+    }
+  }
+
+  return $ret;
+}
+
+function layout_topic()
+{
+  global $zlist;
+  global $_GET;
+
+  if  (!isset($_GET['topic']) || !is_numeric($_GET['topic']))
+    $ret = warning('Keine passende Diskussion gefunden.');
+  else {
+    $discussion = format_topic($_GET['topic']);
+
+    if (isset($zlist['zid'])) {
+      $ret .= format_newspaper($zlist['zid'], true);
+
+      if ($zlist['archived'])
+       $ret .= '<h3>Abgeschlossene Diskussion</h3>';
+      else
+       $ret .= '<h3>Diskussion</h3>';
+    }
+    $ret .= $discussion;
+    if (isset($zlist['zid']))
+      $ret .= layout_bookmarks(sprintf('topic/%d.html', $zlist['zid']), $zlist['topic']);
+  }
+
+  return $ret;
+}
+
+function notfound()
+{
+  header("HTTP/1.0 404 Not Found");
+
+  return warning('Diese Seite existiert nicht!');
+}
+
+function contact_send($topic, $email, $body)
+{
+  global $cfg;
+  global $_SESSION;
+  global $_SERVER;
+
+  $header = array();
+  if (!empty($email)) {
+    if (isset($_SESSION['uid']))
+      $header[] = sprintf('Reply-To: %s <%s>',
+                         strlen($_SESSION['realname'])?$_SESSION['realname']:$_SESSION['nickname'],
+                         $email);
+    else
+      $header[] = 'Reply-To: ' . $email;
+  }
+
+  $body .= "\n\n"
+    ."HTTP_USER_AGENT: " . $_SERVER['HTTP_USER_AGENT'] . "\n"
+    ."REMOTE_ADDR    : " . $_SERVER['REMOTE_ADDR'] . "\n";
+
+  if (isset($_SESSION['uid']))
+    $body .= "Nickname       : " . $_SESSION['nickname'] . "\n";
+
+  $subject = str_replace(array('<', '>', '(', ')', '$', '/', '%', '\\', '#', ';', '&'), '', $topic);
+
+  sendmail($cfg['mailto'], '', $subject, $body, $header);
+}
+
+function process_contact()
+{
+  global $_SERVER;
+  global $_POST;
+
+  if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+    if (empty($_POST['topic']))
+      $ret = warning('Sie haben keinen Titel für die Nachricht angegeben!');
+    elseif (empty($_POST['body']))
+      $ret = warning('Sie haben keinen Text der Nachricht angegeben!');
+    elseif (!empty($_POST['email']) && !is_valid_email_address($_POST['email']))
+      $ret = warning('Die angegebene Mail-Adresse ist ungültig.');
+    else {
+      contact_send($_POST['topic'], $_POST['email'], $_POST['body']);
+      $ret = information('Die Nachricht wurde an den Chef geschickt.');
+      $ret .= '<p>Die Bearbeitung kann eine Weile dauern.  Wenn Sie eine '.
+       'Antwort erwarten, sollte diese in den nächsten Tagen an die von '.
+       'Ihnen angegebene Adresse geschickt werden.</p>';
+      return $ret;
+    }
+    $replace = array('topic' => $_POST['topic'],
+                    'email' => $_POST['email'],
+                    'body' => $_POST['body']);
+  } elseif ($_SERVER['REQUEST_METHOD'] == 'GET') {
+    if (isset($_SESSION['email']))
+      $replace = array('email' => $_SESSION['email']);
+    else
+      $replace = array();
+  }
+
+  return load_javascript('contact.js') . load_template('contact.html', $replace);
+}
+
+?>
\ No newline at end of file
diff --git a/lib/login.inc b/lib/login.inc
new file mode 100644 (file)
index 0000000..b59c96d
--- /dev/null
@@ -0,0 +1,668 @@
+<?php
+
+include_once('extern/rfc822.php');
+
+function account_exists($login)
+{
+  global $cfg;
+  global $_SESSION;
+
+  $query = sprintf("SELECT id FROM users WHERE lower(nickname) = lower('%s')",
+                  pg_escape_string($login));
+
+  if (isset($_SESSION['uid']))
+    $query .= sprintf(' AND id <> %d', $_SESSION['uid']);
+
+  $sth = db_query($query);
+
+  # Return true in case of database error
+  if ($sth === false)
+    return true;
+
+  return pg_NumRows ($sth) > 0;
+}
+
+function is_valid_passwd ($nickname, $passwd)
+{
+  if (strtolower($passwd) == strtolower($nickname))
+    return 'Das Passwort darf nicht dem Usernamen entsprechen.';
+
+  if (strlen($passwd) < 4)
+    return 'Das Passwort ist zu kurz.';
+
+  if (strlen($passwd) > 15)
+    return 'Das Passwort ist zu lang.';
+
+  if (!preg_match ('/^[a-zA-Z0-9%!@#^&\*\$\\\+\.\_\-]{4,15}$/', $passwd, $matches))
+    return 'Das Passwort enthält ungültige Zeichen.';
+
+  return true;
+}
+
+function is_valid_username($nickname)
+{
+  $blacklist = array('hitler','stalin');
+
+  if (!preg_match ('/^[a-zA-Z0-9\.\_\-]{4,15}$/', $nickname, $matches))
+    return false;
+
+
+  foreach ($blacklist as $badnick) {
+    if (soundex($nickname) == soundex($badnick))
+      return false;
+  }
+
+  return true;
+}
+
+function is_valid_realname($name)
+{
+  if (preg_match ('/[\\\\<>"\(\)\[\]]/', $name, $matches))
+    return false;
+
+  return true;
+}
+
+function check_account_data()
+{
+  global $_POST;
+  global $zlist;
+
+  $zlist['replace'] = array('nickname' => $_POST['nickname'],
+                           'realname' => $_POST['realname'],
+                           'email' => $_POST['email'],
+                           'url' => $_POST['url']);
+
+  if (!strlen($_POST['nickname']) ||
+      !strlen($_POST['email']))
+    return 'Sie müssen alle Pflichtfelder ausfüllen! Siehe Beschreibung unten.';
+
+  if (account_exists($_POST['nickname']))
+    return 'Dieser Username ist in der Zeitungsliste bereits vergeben.';
+
+  if (!is_valid_email_address($_POST['email']))
+    return 'Die angegebene Mail-Adresse ist ungültig.';
+
+  if (!empty($_POST['url'])) {
+    $_POST['url'] = fix_url($_POST['url']);
+    if (!is_valid_url($_POST['url']))
+      return 'Die angegebene Homepage ist ungültig!';
+  }
+
+  if (!empty($_POST['realname']) && !is_valid_realname($_POST['realname']))
+    return 'Der angegebene Name enthält unerlaubte Zeichen.';
+
+  return is_valid_username($_POST['nickname']);
+}
+
+function check_passwd()
+{
+  global $_POST;
+
+  if (!strlen($_POST['passwd']) || !strlen($_POST['pwcopy']))
+    return 'Sie müssen alle Pflichtfelder ausfüllen! Siehe Beschreibung unten.';
+
+  if (strlen($_POST['passwd']) < 5)
+    return 'Ihr Passwort ist zu kurz, bitte verwenden Sie mindestens 5 Zeichen.';
+
+  if ($_POST['passwd'] != $_POST['pwcopy'])
+    return 'Sie haben sich beim Passwort vertippt.';
+
+  return true;
+}
+
+function passwd ($nickname, $passwd)
+{
+  return md5(md5($passwd). $nickname);
+}
+
+function pwgen ($num)
+{
+  $chars = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz";
+  $count = strlen($chars);
+  $pass = '';
+  srand((double)microtime()*1000000);
+
+  for ($i = 0;$i < $num; $i++) {
+    $pos = rand() % $count;
+    $pass .= substr ($chars, $pos, 1);
+  }
+
+  return $pass;
+}
+
+function account_activate($code)
+{
+  global $cfg;
+
+  if (!strlen($code))
+    return 'Kein Aktivierungscode angegeben.';
+
+  $query = sprintf("SELECT uid FROM activation WHERE code = '%s'", pg_escape_string($code));
+
+  $sth = db_query($query);
+
+  if ($sth === false)
+    return 'Es ist ein Datenbankfehler aufgetreten.';
+
+  if (pg_NumRows($sth) != 1)
+    return 'Der angegebene Aktivierungscode ist ungültig!';
+
+  db_query('BEGIN TRANSACTION');
+
+  $row = pg_fetch_array($sth, 0);
+
+  $query = sprintf('UPDATE users SET status = 1 WHERE id = %d', $row['uid']);
+
+  $sth = db_query($query);
+
+  if ($sth === false) {
+    db_query('ROLLBACK');
+    return 'Es ist ein Datenbankfehler aufgetreten.';
+  }
+
+  $query = sprintf("DELETE FROM activation WHERE code = '%s'", pg_escape_string($code));
+
+  $sth = db_query($query);
+
+  if ($sth === false) {
+    db_query('ROLLBACK');
+    return 'Es ist ein Datenbankfehler aufgetreten.';
+  }
+
+  db_query('COMMIT');
+
+  return true;
+}
+
+function send_activation($email, $user, $code)
+{
+  global $cfg;
+  global $_SERVER;
+
+  $url = sprintf('%sactivate.html?code=%s', $cfg['home'], urlencode($code));
+  $subject = 'Aktivierung Account Zeitungsliste';
+
+  $body = sprintf('Willkommen %s!
+
+Sie haben einen neuen Account in der Zeitungsliste beantragt.
+
+Um diesen zu aktivieren, geben Sie bitte folgende Adresse in
+Ihren Browser ein:
+
+%s
+
+', $user, $url);
+
+  sendmail($email, '', $subject, $body);
+
+  return true;
+}
+
+function process_activate()
+{
+  global $_GET;
+
+  if (($try = account_activate($_GET['code'])) !== true) {
+    $ret = warning($try);
+    } else {
+      $ret = information('Ihr Account ist aktiviert.');
+      $ret .= '<h3>Willkommen!</h3><p class="info">'.
+       'Sie werden automatisch zur <a href="login.html">Login-Seite</a> weitergeleitet. '.
+       'Bitte melden Sie sich dort an.</p>';
+      $zlist['redirect'] = 'login.html';
+    }
+  return $ret;
+}
+
+function process_account_new()
+{
+  global $cfg;
+  global $_POST;
+
+  if (($try = check_account_data()) !== true)
+    return $try;
+
+  if (($try = check_passwd()) !== true)
+    return $try;
+
+  db_query('BEGIN TRANSACTION');
+
+  $query = sprintf('INSERT INTO users (nickname,email,status,passwd,register_date%s%s)' .
+                  "VALUES ('%s','%s',0,'%s',now()%s%s)",
+                  strlen($_POST['realname'])?',realname':'',
+                  strlen($_POST['url'])?',url':'',
+                  $_POST['nickname'],
+                  $_POST['email'],
+                  passwd($_POST['nickname'], $_POST['passwd']),
+                  strlen($_POST['realname'])?",'".pg_escape_string($_POST['realname'])."'":'',
+                  strlen($_POST['url'])?",'".pg_escape_string($_POST['url'])."'":'');
+
+  $sth = db_query($query);
+
+  if ($sth === false) {
+    db_query('ROLLBACK');
+    return 'Es ist ein Datenbankfehler aufgetreten.';
+  }
+
+  $uid = db_last_id('users', 'id');
+
+  $code = md5(pwgen(8));
+
+  $query = sprintf('INSERT INTO activation (code,uid,register_date) '.
+                  "VALUES ('%s',%d,now())", $code, $uid);
+
+  $sth = db_query($query);
+
+  if ($sth === false) {
+    db_query('ROLLBACK');
+    return 'Es ist ein Datenbankfehler aufgetreten.';
+  }
+
+  if (send_activation($_POST['email'],
+                     strlen($_POST['realname'])?$_POST['realname']:$_POST['nickname'],
+                     $code) === false) {
+    db_query('ROLLBACK');
+    return 'Fehler beim Versenden der Aktivierungsmail.';
+  }
+
+  db_query('COMMIT');
+
+  return true;
+}
+
+function update_account()
+{
+  global $_POST;
+  global $_SESSION;
+  global $zlist;
+
+  $query = sprintf("UPDATE users SET nickname='%s',realname='%s',email='%s',url='%s' ".
+                  'WHERE id = %d',
+                  $_POST['nickname'],
+                  pg_escape_string($_POST['realname']),
+                  $_POST['email'],
+                  pg_escape_string($_POST['url']),
+                  $_SESSION['uid']);
+
+  db_query($query);
+
+  if ($_SESSION['nickname'] != $_POST['nickname'])
+    $zlist['newpass'] = true;
+
+  $_SESSION['nickname'] = $_POST['nickname'];
+  $_SESSION['email'] = $_POST['email'];
+  $_SESSION['homepage'] = $_POST['url'];
+  $_SESSION['realname'] = $_POST['realname'];
+}
+
+function update_passwd()
+{
+  global $_POST;
+  global $_SESSION;
+
+  $hash = passwd($_SESSION['nickname'], $_POST['passwd']);
+
+  $query = sprintf("UPDATE users SET passwd='%s' WHERE id = %d",
+                  $hash, $_SESSION['uid']);
+
+  db_query($query);
+}
+
+function checkpass($nickname, $passwd)
+{
+  global $cfg;
+
+  if (empty($nickname) || empty($passwd))
+    return false;
+
+  $query = sprintf("SELECT passwd,nickname FROM users ".
+                  "WHERE lower(nickname) = lower('%s') AND status = 1",
+                  pg_escape_string($nickname));
+
+  $sth = db_query($query);
+
+  if ($sth === false)
+    return false;
+
+  if (pg_NumRows($sth) == 0)
+    return false;
+
+  $row = pg_fetch_array($sth, 0);
+
+  $hash = passwd($row['nickname'], $passwd);
+
+  if (strcmp($row[0], $hash) != 0)
+    return false;
+
+  return true;
+}
+
+function login_user($nickname, $passwd)
+{
+  global $cfg;
+  global $_SERVER;
+  global $_POST;
+  global $_SESSION;
+
+  $query = sprintf("SELECT id,nickname,realname,email,url,passwd FROM users " .
+                  "WHERE lower(nickname) = lower('%s') AND status = 1",
+                   pg_escape_string($nickname));
+
+  $sth = db_query($query);
+
+  if ($sth === false)
+    return false;
+
+  if (pg_NumRows($sth) == 0)
+    return false;
+
+  $row = pg_fetch_array($sth, 0);
+
+  $hash = passwd($row['nickname'], $passwd);
+
+  if (strcmp($row['passwd'], $hash) != 0)
+    return false;
+
+  session_name($cfg['session']);
+  session_start();
+
+  $_SESSION['REMOTE_ADDR'] = $_SERVER["REMOTE_ADDR"];
+  $_SESSION['uid'] = $row['id'];
+  $_SESSION['nickname'] = $row['nickname'];
+  $_SESSION['javascript'] = $_POST['js']=='1'?true:false;
+  $_SESSION['email'] = $row['email'];
+  $_SESSION['homepage'] = $row['url'];
+  $_SESSION['realname'] = $row['realname'];
+
+  $query = sprintf('UPDATE users SET last_login = now() WHERE id = %d', $_SESSION['uid']);
+  db_query($query);
+
+  $query = sprintf('INSERT INTO online (uid,activity) VALUES (%d,now())', $_SESSION['uid']);
+  db_query($query);
+
+  session_update();
+  $_SESSION["lastupdate"] = time();
+
+  return true;
+}
+
+function login_sendnew($nickname)
+{
+  global $cfg;
+
+  if (!strlen($nickname))
+    return 'Kein Username angegeben!';
+
+  $query = 'SELECT id,email,nickname,realname FROM users WHERE status = 1 AND ';
+  if (strstr($nickname, '@') === false)
+    $query .= sprintf("lower(nickname) = lower('%s')", pg_escape_string($nickname));
+  else
+    $query .= sprintf("lower(email) = lower('%s')", pg_escape_string($nickname));
+
+  $sth = db_query($query);
+
+  if ($sth === false)
+    return 'Es ist ein Datenbankfehler aufgetreten.';
+
+  if (pg_NumRows($sth) == 0)
+    return 'Der angegebene Username ist im System nicht bekannt.';
+
+  $row = pg_fetch_array($sth, 0);
+
+  $passwd = pwgen(8);
+
+  $query = sprintf("UPDATE users SET passwd = '%s' WHERE id = %d",
+                  passwd($row['nickname'], $passwd), $row['id']);
+
+  $sth = db_query($query);
+
+  if ($sth === false)
+    return 'Es ist ein Datenbankfehler aufgetreten.';
+
+  $header = array();
+  $header[] = 'From: ' . $cfg['from'];
+  $header[] = sprintf('To: %s <%s>',
+                     strlen($row['realname'])?$row['realname']:$row['nickname'],
+                     $row['email']);
+  $header[] = 'MIME-Version: 1.0';
+  $header[] = 'Content-type: text/plain; charset=utf-8';
+
+  $subject = 'Zeitungsliste: Ihr Neues Passwort';
+
+  $body = sprintf('Moin %s!
+
+Sie oder jemand anderes hat ein neues Passwort für Ihren Account auf
+<%s> angefordert.
+
+Das alte Passwort verliert damit seine Gültigkeit.  Das System hat
+ein neues Passwort für Sie berechnet und eingetragen.
+
+Das neue Passwort lautet %s
+
+Bitte ändern Sie es beim nächsten Einloggen.
+',
+                 strlen($row['realname'])?$row['realname']:$row['nickname'],
+                 $cfg['home'], $passwd);
+
+  $sig = load_template('signature', array());
+  if (strlen($sig))
+    $body .= $sig;
+
+  if (mail ($row['email'], $subject, $body, implode("\n", $header)) === false)
+    return 'Es ist ein Fehler beim Versand der Mail aufgetreten.';
+
+  return true;
+}
+
+function process_login_request()
+{
+  global $_POST;
+
+  if (isset($_POST['new'])) {
+    $try = process_account_new();
+    if ($try === true)
+      return information('Ihr neuer Account wurde angelegt.  Die Aktivierungsmail ist unterwegs.');
+    else {
+      $body = warning($try);
+      $replace = array('nickname' => $_POST['nickname'],
+                      'realname' => $_POST['realname'],
+                      'email' => $_POST['email'],
+                      'url' => $_POST['url']);
+      $body .= load_template('login_new.html', $replace);
+      return $body;
+    }
+  } elseif (isset($_POST['sendnew'])) {
+    $try = login_sendnew($_POST['nickname']);
+    if ($try === true) {
+      $ret = information('Ein neues Passwort wird Ihnen per Mail zugeschickt');
+      $ret .= '<p>Bitte melden Sie sich mit diesem an und ändern Sie das Passwort '.
+       'über den Menüpunkt "Einstellungen".</p>';
+      return $ret;
+    } else {
+      $body = warning($try);
+      $body .= load_template('login.html');
+      return $body;
+    }
+  } else {
+    if (empty($_POST['nickname'])) {
+      $body = warning('Sie haben keinen Usernamen angegeben!');
+    } elseif (empty($_POST['passwd'])) {
+      $body = warning('Sie haben kein Passwort angegeben!');
+    } else {
+      $try = login_user($_POST['nickname'], $_POST['passwd']);
+      if ($try === true)
+       return true;
+      else
+       $body = warning('Das angegebene Passwort ist ungültig!');
+    }
+
+    $replace = array('nickname' => $_POST['nickname']);
+    $body .= load_template('login.html', $replace);
+    return $body;
+  }
+}
+
+function last_activity()
+{
+  global $cfg;
+  global $_SESSION;
+
+  $query = sprintf("SELECT DISTINCT topics.id,topics.topic FROM article " .
+                  "JOIN topics ON article.topic=topics.id " .
+                  "WHERE uid = %d AND article.created > now() - interval'7 days'",
+                  $_SESSION['uid']);
+
+  $sth = db_query($query);
+
+  if ($sth === false || pg_NumRows($sth) == 0)
+    return false;
+
+  $ret = '<h3>Sie haben an folgenden Diskussionen teilgenommen</h3>';
+  $ret .= '<p><ul class="gold">';
+
+  for ($i=0; $i < pg_NumRows($sth); $i++) {
+    $row = pg_fetch_array($sth, $i);
+
+    $ret .= sprintf('<li><a href="%stopic/%d.html">%s</a></li>',
+                   $cfg['basedir'],
+                   $row['id'], $row['topic']);
+  }
+  $ret .= '</ul></p>';
+
+  return $ret;
+}
+
+function process_login()
+{
+  global $_GET;
+  global $_SERVER;
+  global $_SESSION;
+
+  if (isset($_GET['from'])) {
+    if ($_GET['from'] == 'article')
+      $ret .= warning('Um an einer Diskussion teilzunehmen, müssen Sie angemeldet sein.');
+    elseif ($_GET['from'] == 'zeitung')
+      $ret .= warning('Um eine neue Diskussion zu beginnen, müssen Sie angemeldet sein.');
+    elseif ($_GET['from'] == 'new')
+      $ret .= warning('Um eine Zeitung hinzuzufügen, müssen Sie angemeldet sein.');
+    elseif ($_GET['from'] == 'tags')
+      $ret .= warning('Um Tags zu einer Zeitung zu verwalten, müssen Sie angemeldet sein.');
+    elseif ($_GET['from'] == 'edit')
+      $ret .= warning('Um eine Zeitung zu bearbeiten, müssen Sie angemeldet sein.');
+    elseif ($_GET['from'] == 'session')
+      $ret .= warning('Ihre Session ist abgelaufen.  Bitte melden Sie sich erneut an.');
+    $ret .= load_template('login.html');
+  } elseif (isset($_GET['new'])) {
+    $ret = load_template('login_new.html');
+  } elseif ($_SERVER['REQUEST_METHOD'] == 'GET') {
+    $ret = load_template('login.html');
+  } else {
+    $try = process_login_request();
+    if ($try === true) {
+      $ret = information('Hallo '.$_SESSION['nickname'].'! Sie sind jetzt angemeldet.');
+      $try = last_activity();
+      if ($try !== false)
+       $ret .= $try;
+      else
+       $ret .= load_template('main.html');
+    } else
+      $ret = $try;
+  }
+
+  return $ret;
+}
+
+function process_passwd()
+{
+  global $_SESSION;
+  global $_SERVER;
+  global $zlist;
+  global $cfg;
+
+  if (!isset($_SESSION['uid'])) {
+    $ret = warning('Sie sind nicht angemeldet.  Sie werden gleich zur Anmeldung weitergeleitet.');
+    $zlist['redirect'] = 'login.html';
+  } else {
+    if ($_SERVER['REQUEST_METHOD'] == 'GET') {
+      $ret .= load_javascript('passwd.js') . load_template('passwd.html', array('nickname' => $_SESSION['nickname']));
+    } elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
+      if (($try = check_passwd()) !== true) {
+        $ret = warning($try);
+       $ret .= load_javascript('passwd.js') . load_template('passwd.html', array('nickname' => $_SESSION['nickname']));
+      } else {
+        update_passwd();
+        $ret .= information('Ihr neues Passwort ist eingetragen.  Sie werden zur Hauptseite weitergeleitet.');
+        $zlist['redirect'] = '';
+      }
+    }
+  }
+
+  return $ret;
+}
+
+function logout()
+{
+  session_invalidate();
+}
+
+function process_options()
+{
+  global $_SESSION;
+  global $_SERVER;
+  global $_POST;
+  global $zlist;
+  global $cfg;
+
+  $ok = false;
+  $ret = '';
+  if (!isset($_SESSION['uid'])) {
+    $ret .= warning('Sie sind nicht angemeldet.  Sie werden gleich zur Anmeldung weitergeleitet.');
+    $zlist['redirect'] = 'login.html';
+  } else {
+    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+      if (($try = check_account_data()) !== true)
+       $ret .= warning($try);
+      else {
+       update_account();
+       $ret .= information('Ihre persönlichen Daten wurden geändert.  Sie werden zur Hauptseite weitergeleitet.');
+       $ok = true;
+       $zlist['redirect'] = '';
+       if ($zlist['newpass']) {
+         $try = login_sendnew($_POST['nickname']);
+         if ($try === true) {
+           $ret .= '<p>Aus technischen Gründen ist es erforderlich Ihnen ein neues Passwort zu geben. '.
+             'Dieses wird Ihnen per Mail an die im System gespeicherte Mail-Adresse geschickt. '.
+             'Diese Session ist von dieser Änderung nicht betroffen, Sie können daher Ihr Passwort '.
+             'direkt über den Menüpunkt "Passwort" ändern und die Mail ignorieren. '.
+             'Ansonsten melden Sie sich bitte beim nächsten Mal mit dem neuen Passwort an und ändern Sie es.</p>';
+         }
+       }
+      }
+    } else
+      $zlist['replace'] = array('nickname' => $_SESSION['nickname'],
+                               'realname' => $_SESSION['realname'],
+                               'email' => $_SESSION['email'],
+                               'url' => $_SESSION['url']);
+    if (!$ok)
+      $ret .= load_javascript('options.js') . load_template('options.html', $zlist['replace']);
+  }
+
+  return $ret;
+}
+
+function ajax_passwd_check()
+{
+  global $_POST;
+
+  return checkpass($_POST['nickname'], $_POST['passwd']);
+}
+
+function ajax_nickname_check()
+{
+  global $_POST;
+
+  return account_exists($_POST['nickname']);
+}
+
+?>
diff --git a/lib/search.inc b/lib/search.inc
new file mode 100644 (file)
index 0000000..798607a
--- /dev/null
@@ -0,0 +1,146 @@
+<?php
+
+function search_zeitungen($keyword)
+{
+  global $cfg;
+
+  $query = sprintf("SELECT id,name,city FROM zeitungen WHERE deleted IS false AND " .
+                  "( name ILIKE '%%%s%%' OR url ILIKE '%%%s%%' " .
+                  "OR city ILIKE '%%%s%%' OR description ILIKE '%%%s%%') " .
+                  "ORDER BY name",
+                  pg_escape_string($keyword), pg_escape_string($keyword),
+                  pg_escape_string($keyword), pg_escape_string($keyword));
+
+  if (($sth = db_query($query)) === false) return array();
+
+  if (pg_NumRows($sth) == 0) return array();
+
+  $ret = array();
+  for ($i=0; $i < pg_NumRows($sth); $i++) {
+    $row = pg_fetch_array($sth, $i);
+
+    $ret[] = sprintf('<a href="%szeitung/%d.html">%s</a>, %s',
+                    $cfg['basepath'], $row['id'], $row['name'], $row['city']);
+  }
+
+  return $ret;
+}
+
+function search_tags($keyword)
+{
+  global $cfg;
+
+  $query = sprintf("SELECT tagname FROM tags WHERE " .
+                  "tagname ILIKE '%%%s%%' " .
+                  "ORDER BY lower(tagname)",
+                  pg_escape_string($keyword));
+
+  if (($sth = db_query($query)) === false) return array();
+
+  if (pg_NumRows($sth) == 0) return array();
+
+  $ret = array();
+  for ($i=0; $i < pg_NumRows($sth); $i++) {
+    $row = pg_fetch_array($sth, $i);
+
+    $ret[] = sprintf('Tag <a href="%stag/%s.html">%s</a>',
+                    $cfg['basepath'], urlencode($row['tagname']),
+                    $row['tagname']);
+  }
+
+  return $ret;
+}
+
+function search_topics($keyword)
+{
+  global $cfg;
+
+  $query = sprintf("SELECT id,topic FROM topics WHERE " .
+                  "topic ILIKE '%%%s%%' ORDER BY topic",
+                  pg_escape_string($keyword));
+
+  if (($sth = db_query($query)) === false) return array();
+
+  if (pg_NumRows($sth) == 0) return array();
+
+  $ret = array();
+  for ($i=0; $i < pg_NumRows($sth); $i++) {
+    $row = pg_fetch_array($sth, $i);
+
+    $ret[] = sprintf('Diskussion <a href="%stopic/%d.html">%s</a>',
+                    $cfg['basepath'], $row['id'], 
+                    $row['topic']);
+  }
+
+  return $ret;
+}
+
+function process_search()
+{
+  global $_POST;
+  global $zlist;
+
+  if (!strlen($_POST['keyword']))
+    $ret = warning('Sie haben keinen Suchbegriff angegeben!');
+  else {
+    $results = array_merge(search_zeitungen($_POST['keyword']),
+                          search_tags($_POST['keyword']),
+                          search_topics($_POST['keyword']));
+
+    if (count($results)) {
+      $ret = '<ul class="gold">';
+      foreach ($results as $res) {
+       $ret .= '<li>' . $res;
+      }
+      $ret .= '</ul>';
+    } else {
+      $zlist['keyword'] = htmlspecialchars($_POST['keyword']);
+      $ret = information(sprintf('Keine Treffer für "%s" gefunden.', $zlist['keyword']));
+    }
+  }
+
+  return $ret;
+}
+
+function ajax_search_check()
+{
+  global $_POST;
+
+  $keyword = $_POST['keyword'];
+
+  $query = sprintf("SELECT count(*) FROM zeitungen WHERE deleted IS false AND " .
+                  "( name ILIKE '%%%s%%' OR url ILIKE '%%%s%%' " .
+                  "OR city ILIKE '%%%s%%' OR description ILIKE '%%%s%%') ",
+                  pg_escape_string($keyword), pg_escape_string($keyword),
+                  pg_escape_string($keyword), pg_escape_string($keyword));
+
+  if (($sth = db_query($query)) !== false) {
+    $row = pg_fetch_array($sth, 0);
+    if ($row[0] > 0)
+      return true;
+  }
+
+  $query = sprintf("SELECT count(*) FROM tags WHERE " .
+                  "tagname ILIKE '%%%s%%' ",
+                  pg_escape_string($keyword));
+
+  if (($sth = db_query($query)) !== false) {
+    $row = pg_fetch_array($sth, 0);
+    if ($row[0] > 0)
+      return true;
+  }
+
+  $query = sprintf("SELECT count(*) FROM topics WHERE " .
+                  "topic ILIKE '%%%s%%'",
+                  pg_escape_string($keyword));
+
+  if (($sth = db_query($query)) !== false) {
+    $row = pg_fetch_array($sth, 0);
+    if ($row[0] > 0)
+      return true;
+  }
+
+  return false;
+}
+
+?>
\ No newline at end of file
diff --git a/lib/session.inc b/lib/session.inc
new file mode 100644 (file)
index 0000000..c8293f1
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+
+function session_invalidate($dest='')
+{
+  global $cfg;
+  global $_SESSION;
+
+  db_query(sprintf('DELETE FROM online WHERE uid = %d', $_SESSION['uid']));
+
+  setcookie($cfg['session'], '', time()-42000, '/');
+  session_destroy();
+  $_SESSION = array();
+
+  header("Location: " . $cfg['home'] . $dest);
+
+  exit;
+}
+
+function userstatus_info()
+{
+  global $cfg;
+
+  $ret = array();
+
+  $query = 'SELECT count(*) FROM online';
+  $sth = db_query($query);
+  if ($sth === false) {
+    $ret[0] = 0;
+  } else {
+    $row = pg_fetch_array($sth, 0);
+    $ret[0] = $row[0];
+  }
+
+  $query = 'SELECT count(*) FROM users';
+  $sth = db_query($query);
+  if ($sth === false) {
+    $ret[1] = 0;
+  } else {
+    $row = pg_fetch_array($sth, 0);
+    $ret[1] = $row[0];
+  }
+
+  $query = 'SELECT count(*) FROM zeitungen WHERE deleted IS false';
+  $sth = db_query($query);
+  if ($sth === false) {
+    $ret[2] = 0;
+  } else {
+    $row = pg_fetch_array($sth, 0);
+    $ret[2] = $row[0];
+  }
+
+  $query = 'SELECT count(*) FROM zeitung_tags';
+  $sth = db_query($query);
+  if ($sth === false) {
+    $ret[3] = 0;
+  } else {
+    $row = pg_fetch_array($sth, 0);
+    $ret[3] = $row[0];
+  }
+
+  $query = 'SELECT count(*) FROM tags';
+  $sth = db_query($query);
+  if ($sth === false) {
+    $ret[4] = 0;
+  } else {
+    $row = pg_fetch_array($sth, 0);
+    $ret[4] = $row[0];
+  }
+
+  return $ret;
+}
+
+function session_update()
+{
+  global $cfg;
+  global $_SESSION;
+
+  $info = userstatus_info();
+
+  $_SESSION['online'] = $info[0];
+  $_SESSION['users'] = $info[1];
+  $_SESSION['zeitungen'] = $info[2];
+  $_SESSION['ztags'] = $info[3];
+  $_SESSION['tags'] = $info[4];
+}
+
+function session_init()
+{
+  global $cfg;
+  global $_COOKIE;
+  global $_SERVER;
+  global $_SESSION;
+
+  if (isset($_COOKIE[$cfg['session']])) {
+    session_name($cfg["session"]);
+    session_start();
+
+    if ($_SESSION["REMOTE_ADDR"] != $_SERVER["REMOTE_ADDR"] ||
+        !isset($_SESSION["uid"]))
+      session_invalidate('login.html?from=session');
+
+    $query = sprintf('UPDATE online SET activity = now() WHERE uid = %d', $_SESSION['uid']);
+    db_query($query);
+
+    if ($_SESSION["lastupdate"] < time() - 60) {
+      session_update();
+      $_SESSION["lastupdate"] = time();
+    }
+  }
+}
+
+?>
\ No newline at end of file
diff --git a/lib/tags.inc b/lib/tags.inc
new file mode 100644 (file)
index 0000000..af42106
--- /dev/null
@@ -0,0 +1,227 @@
+<?php
+
+function format_tags($zid)
+{
+  global $cfg;
+  global $_SESSION;
+
+  $query = 'SELECT id,tagname FROM tags ORDER BY lower(tagname)';
+  if (($sth = db_query($query)) === false) return;
+
+  $tags = array();
+  for ($i=0; $i < pg_NumRows ($sth); $i++) {
+    $row = pg_fetch_array ($sth, $i);
+    $tags[$row['id']] = $row['tagname'];
+  }
+
+  $query = sprintf('SELECT id,tagname FROM tags ' .
+                  'JOIN zeitung_tags ON id = tag ' .
+                  'WHERE zeitung = %d AND uid = %d ' .
+                  'ORDER BY lower(tagname)',
+                  $zid, $_SESSION['uid']);
+
+  if (($sth = db_query($query)) === false) return;
+
+  if (pg_NumRows($sth) > 0) {
+    $ret_mytags = '<p class="tagcloud">';
+    for ($i=0; $i < pg_NumRows ($sth); $i++) {
+      $row = pg_fetch_array ($sth, $i);
+      if (javascript_ok())
+       $link = sprintf('href="%stags.html" onclick="return tag_action(\'del\',%d,%d);"',
+                       $cfg['basepath'], $zid, $row['id']);
+      else
+       $link = sprintf('href="%stags.html?zeitung=%d&deltag=%d"',
+                       $cfg['basepath'], $zid, $row['id']);
+      $ret_mytags .= sprintf('<span class="tag1"><a %s>%s</a></span> ',
+                            $link, $row['tagname']);
+      unset($tags[$row['id']]);
+    }
+    $ret_mytags .= '</p>';
+  }
+
+  if (count($tags)) {
+    $ret_rest = '<p class="tagcloud">';
+    foreach ($tags as $id => $tagname) {
+      if (javascript_ok())
+       $link = sprintf('href="%stags.html" onclick="return tag_action(\'add\',%d,%d);"',
+                       $cfg['basepath'], $zid, $id);
+      else
+       $link = sprintf('href="%stags.html?zeitung=%d&deltag=%d"',
+                       $cfg['basepath'], $zid, $id);
+      $ret_rest .= sprintf('<span class="tag1"><a %s>%s</a></span> ',
+                          $link, $tagname);
+    }
+    $ret_rest .= '</p>';
+  }
+
+  return array($ret_mytags, $ret_rest);
+}
+
+function tag_add($zid, $tag, $uid)
+{
+  $query = sprintf('INSERT INTO zeitung_tags (zeitung,tag,uid) ' .
+                  'VALUES (%d,%d,%d)', $zid, $tag, $uid);
+  db_query($query);
+}
+
+function tag_del($zid, $tag, $uid)
+{
+  $query = sprintf('DELETE FROM zeitung_tags WHERE zeitung = %d ' .
+                  'AND tag = %d AND uid = %d', $zid, $tag, $uid);
+  db_query($query);
+}
+
+function tag_addnew($zid, $tag, $uid)
+{
+  db_query('BEGIN TRANSACTION');
+
+  $query = sprintf("INSERT INTO tags (tagname) VALUES ('%s')",
+                  pg_escape_string($tag));
+
+  if (($sth = db_query($query)) === false) {
+    db_query('ROLLBACK');
+    return;
+  }
+
+  $id = db_last_id('tags', 'id');
+
+  tag_add($zid, $id, $uid);
+  db_query('COMMIT');
+}
+
+function tag_sanitise($tag)
+{
+  return  str_replace(array('<', '>', '(', ')', '$', '/', '%', '\\', '#', ';', '&'), '', $tag);
+}
+
+function process_tags()
+{
+  global $cfg;
+  global $zlist;
+  global $_SESSION;
+  global $_GET;
+  global $_POST;
+
+  if (isset($_GET['zeitung']) && is_numeric($_GET['zeitung']))
+    $zid = $_GET['zeitung'];
+  elseif (isset($_POST['zeitung']) && is_numeric($_POST['zeitung']))
+    $zid = $_POST['zeitung'];
+  else
+    return warning('Keine Zeitung oder Magazin gefunden!');
+
+  $try = format_newspaper($zid, true);
+  if ($try === false)
+    $ret .= warning('Keine Zeitung oder Magazin gefunden!');
+  else {
+    $ret .= $try;
+
+    if (!isset($_SESSION['uid']))
+      $ret .= warning('Sie sind nicht angemeldet.  Zum Hinzufügen von Tags ist das erforderlich.');
+    else {
+      if (isset($_GET['addtag']) && is_numeric($_GET['addtag'])) {
+       tag_add($zid, $_GET['addtag'], $_SESSION['uid']);
+       header(sprintf('Location: tags.html?zeitung=%d', $zid));
+      } elseif (isset($_GET['deltag']) && is_numeric($_GET['deltag'])) {
+       tag_del($zid, $_GET['deltag'], $_SESSION['uid']);
+       header(sprintf('Location: tags.html?zeitung=%d', $zid));
+      } elseif (isset($_POST['newtag'])) {
+       if (empty($_POST['newtag']))
+         $ret .= warning('Sie haben vergessen, ein Merkmal anzugeben!');
+       else {
+         tag_addnew($zid, tag_sanitise($_POST['newtag']), $_SESSION['uid']);
+         header(sprintf('Location: tags.html?zeitung=%d', $zid));
+       }
+      } else {
+
+       $ret .= sprintf('<p class="info"><img src="%stag.gif" width="27" height="25" alt="">&nbsp; ' .
+                       '<strong>Tags verwalten</strong></p>',
+                       $cfg['basepath']);
+
+       $tags = format_tags($zid);
+       $replace = array('zeitung' => $zid,
+                        'mytags'=> $tags[0],
+                        'tags' => $tags[1]);
+       $ret .= load_javascript('tags.js') . load_template('tags.html', $replace);
+      }
+    }
+  }
+
+  return $ret;
+}
+
+function ajax_tag_check()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!isset($_POST['zeitung']) || !is_numeric($_POST['zeitung']) ||
+      !isset($_POST['tag']) || !is_numeric($_POST['tag']) ||
+      !isset($_SESSION['uid']))
+    return false;
+
+  return true;
+}
+
+function ajax_tag_add()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!ajax_tag_check())
+    return false;
+
+  tag_add($_POST['zeitung'], $_POST['tag'], $_SESSION['uid']);
+
+  return format_tags($_POST['zeitung']);
+}
+
+function ajax_tag_del()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!ajax_tag_check())
+    return false;
+
+  tag_del($_POST['zeitung'], $_POST['tag'], $_SESSION['uid']);
+
+  return format_tags($_POST['zeitung']);
+}
+
+function ajax_tag_new()
+{
+  global $_POST;
+  global $_SESSION;
+
+  if (!isset($_POST['zeitung']) || !is_numeric($_POST['zeitung']) ||
+      !isset($_POST['tag']) ||
+      !isset($_SESSION['uid']))
+    return false;
+
+  tag_addnew($_POST['zeitung'], tag_sanitise($_POST['tag']), $_SESSION['uid']);
+
+  return format_tags($_POST['zeitung']);
+}
+
+function ajax_tag_exists()
+{
+  global $_POST;
+
+  if (!isset($_POST['tag']))
+    return true; // eigentlich false, aber da true=exists einen Fehler liefert...
+
+  $query = sprintf("SELECT id FROM tags WHERE lower(tagname) = lower('%s')",
+                  pg_escape_string(tag_sanitise($_POST['tag'])));
+
+  $sth = db_query($query);
+
+  if ($sth === false)
+    return true; // eigentlich false, aber da true=exists einen Fehler liefert...
+
+  if (pg_NumRows($sth) == 0)
+    return false;
+
+  return true;
+}
+
+?>
\ No newline at end of file
diff --git a/lib/zeitung.inc b/lib/zeitung.inc
new file mode 100644 (file)
index 0000000..7fde775
--- /dev/null
@@ -0,0 +1,250 @@
+<?php
+
+function zeitung_load($zid)
+{
+  $query = sprintf('SELECT id,name,url,city,description FROM zeitungen ' .
+                  'WHERE deleted IS false AND id = %d', $zid);
+
+  if (($sth = db_query($query)) === false) return false;
+
+  return pg_fetch_array($sth, 0);
+}
+
+function zeitung_delete($zid)
+{
+  $query = sprintf('UPDATE zeitungen SET deleted = true WHERE id = %d', $zid);
+
+  if (db_query($query) === false) return false;
+
+  logbook('zeitungen', $zid, 'deleted', 'false', 'true');
+
+  return true;
+}
+
+function zeitung_check_url($url, $zid=false)
+{
+  $query = sprintf("SELECT name FROM zeitungen WHERE lower(url) = lower('%s')",
+                  pg_escape_string($url));
+
+  if ($zid !== false)
+    $query .= sprintf(' AND id <> %d', $zid);
+
+  if (($sth = db_query($query)) === false) return false;
+
+  if (pg_NumRows($sth) == 0) return false;
+
+  $row = pg_fetch_array($sth, 0);
+
+  return $row['name'];
+}
+
+function zeitung_check_data()
+{
+  global $_POST;
+
+  if (empty($_POST['name']) ||
+      empty($_POST['city']) ||
+      empty($_POST['url']) ||
+      empty($_POST['description']))
+    return 'Sie müssen alle Pflichtfelder ausfüllen! Siehe Beschreibung unten.';
+
+  $_POST['url'] = fix_url($_POST['url']);
+  if (!is_valid_url($_POST['url']))
+    return 'Die angegebene Homepage ist ungültig!';
+
+  if ($_POST['city'] == 'Deutschland (Stadt)')
+    return 'Sie haben keinen Erscheinungsort angegeben!';
+
+  if (isset($_POST['zeitung']))
+    $try = zeitung_check_url($_POST['url'], $_POST['zeitung']);
+  else
+    $try = zeitung_check_url($_POST['url']);
+  if ($try !== false)
+    return 'Die angegebene URL ist bereits als "'.$try.'" gespeichert.';
+
+  return true;
+}
+
+function zeitung_reportnew($id)
+{
+  global $_SESSION;
+  global $_SERVER;
+  global $_POST;
+  global $cfg;
+
+  $url = sprintf('%szeitung/%d.html', $cfg['home'], $id);
+  $subject = 'Neue Zeitung '.$_POST['name'];
+
+
+  $body = "Folgende Zeitung wurde neu im System aufgenommen:\n\n";
+
+  $body .= "Zeitung    : " . $_POST['name'] . "\n"
+          ."URL        : " . $_POST['url'] . "\n"
+          ."Ort        : " . $_POST['city'] . "\n"
+          ."Description: " . $_POST['description'] . "\n"
+          ."\n"
+          ."Nickname: " . $_SESSION['nickname'] . "\n"
+          ."Realname: " . $_SESSION['realname'] . "\n"
+          ."E-Mail  : " . $_SESSION['email'] . "\n"
+          ."\n"
+          ."HTTP_USER_AGENT: " . $_SERVER['HTTP_USER_AGENT'] . "\n"
+          ."REMOTE_ADDR    : " . $_SERVER['REMOTE_ADDR'] . "\n";
+
+  $body .= "\n" . $url . "\n";
+
+  return sendmail($cfg['mailto'], '', $subject, $body);
+}
+
+function zeitung_update($zid)
+{
+  global $_POST;
+
+  $query = sprintf("UPDATE zeitungen SET name='%s',city='%s',url='%s',description='%s' " .
+                  'WHERE id = %d',
+                  pg_escape_string(htmlspecialchars(trim($_POST['name']))),
+                  pg_escape_string(htmlspecialchars(trim($_POST['city']))),
+                  pg_escape_string(htmlspecialchars(trim($_POST['url']))),
+                  pg_escape_string(htmlspecialchars(trim($_POST['description']))),
+                  $zid);
+
+  $old = zeitung_load($zid);
+
+  if (db_query($query) === false) return false;
+
+  foreach (array('name','city','url','description') as $col) {
+    if ($old[$col] != $_POST[$col])
+      logbook('zeitungen', $zid, $col, $old[$col], htmlspecialchars(trim($_POST[$col])));
+  }
+
+  return true;
+}
+
+function zeitung_insert()
+{
+  global $_POST;
+
+  // Bei Problemen das Feld 'deleted' wieder rausnehmen und manuell approven
+  $query = sprintf("INSERT INTO zeitungen (name,city,url,description,deleted,changed) " .
+                  "VALUES ('%s','%s','%s','%s',false,now())",
+                  pg_escape_string(htmlspecialchars(trim($_POST['name']))),
+                  pg_escape_string(htmlspecialchars(trim($_POST['city']))),
+                  pg_escape_string(htmlspecialchars(trim($_POST['url']))),
+                  pg_escape_string(htmlspecialchars(trim($_POST['description']))));
+
+  if (db_query($query) === false) return false;
+
+  $id = db_last_id('zeitungen', 'id');
+
+  logbook('zeitungen', $id, 'name', '', htmlspecialchars(trim(trim($_POST['name']))));
+
+  zeitung_reportnew($id);
+
+  return $id;
+}
+
+function process_edit()
+{
+  global $_SESSION;
+  global $_SERVER;
+  global $_POST;
+  global $_GET;
+  global $zlist;
+
+  if (isset($_GET['zeitung']) && is_numeric($_GET['zeitung']))
+    $zid = $_GET['zeitung'];
+  elseif (isset($_POST['zeitung']) && is_numeric($_POST['zeitung']))
+    $zid = $_POST['zeitung'];
+  else
+    return warning('Keine Zeitung oder Magazin gefunden!');
+
+  $ok = false;
+  $try = format_newspaper($zid, 1);
+  if ($try === false)
+    $ret .= warning('Keine Zeitung oder Magazin gefunden!');
+  else {
+    $ret .= $try;
+
+    if (!isset($_SESSION['uid']))
+      $ret .= warning('Sie sind nicht angemeldet.  Zum Bearbeiten von Zeitungen ist das erforderlich.');
+    else {
+      if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+       if (isset($_POST['delete'])) {
+         zeitung_delete($zid);
+         $ret .= information('Die Zeitung wurde gelöscht.');
+         $ok = true;
+       } else {
+         $try = zeitung_check_data();
+         if ($try !== true) {
+           $ret .= warning($try);
+           $replace = array('id' => $zid,
+                            'name' => htmlspecialchars($_POST['name']),
+                            'city' => htmlspecialchars($_POST['city']),
+                            'url' => htmlspecialchars($_POST['url']),
+                            'description' => htmlspecialchars($_POST['description']));
+         } else {
+           zeitung_update($zid);
+           $ret .= information('Die Zeitung wurde aktualisiert.');
+           $ok = true;
+           $zlist['redirect'] = sprintf('zeitung/%d.html', $zid);
+         }
+       }
+      } else
+       $replace = zeitung_load($zid);
+      if (!$ok)
+       $ret .= load_template('zeitung.html', $replace);
+    }
+  }
+
+  return $ret;
+}
+
+function process_new()
+{
+  global $_SESSION;
+  global $_SERVER;
+  global $_POST;
+  global $_GET;
+  global $zlist;
+
+  $ok = false;
+  if (!isset($_SESSION['uid']))
+    $ret .= warning('Sie sind nicht angemeldet.  Zum Hinzufügen von Zeitungen ist das erforderlich.');
+  else {
+    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+      $try = zeitung_check_data();
+      if ($try !== true) {
+       $ret .= warning($try);
+       $replace = array('name' => htmlspecialchars($_POST['name']),
+                        'city' => htmlspecialchars($_POST['city']),
+                        'url' => htmlspecialchars($_POST['url']),
+                        'description' => htmlspecialchars($_POST['description']));
+      } else {
+       $zid = zeitung_insert();
+       if ($zid === false) {
+         $ret .= warning('Es ist ein Datenbankfehler aufgetreten.');
+         $ok = true;
+       } else {
+         $ret .= information('Die Zeitung wurde hinzugefügt.');
+         $zlist['redirect'] = sprintf('zeitung/%d.html', $zid);
+         $ok = true;
+       }
+      }
+    } else
+      $replace = array('city' => 'Deutschland (Stadt)');
+    if (!$ok)
+      $ret .= load_javascript('zeitung.js') . load_template('zeitung_new.html', $replace);
+  }
+
+  return $ret;
+}
+
+function ajax_zeitung_check_url()
+{
+  global $_POST;
+
+  if (empty($_POST['url'])) return false;
+
+  return zeitung_check_url($_POST['url']);
+}
+
+?>
\ No newline at end of file
diff --git a/templates/addsense.js b/templates/addsense.js
new file mode 100644 (file)
index 0000000..7f42e1d
--- /dev/null
@@ -0,0 +1,12 @@
+<div align="center">
+<script type="text/javascript">
+google_ad_client = "pub-3134552371074068";
+google_ad_slot = "4797640533";
+google_ad_width = 728;
+google_ad_height = 90;
+//-->
+</script>
+<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+</script>
+</div>
+
diff --git a/templates/bookmarks.js b/templates/bookmarks.js
new file mode 100644 (file)
index 0000000..c870417
--- /dev/null
@@ -0,0 +1,14 @@
+function bookmark_action(action,zid)
+{
+    var info;
+
+    info = zlist_fetch('bookmark_'+action, ['zeitung', zid]);
+
+    if (info != false) {
+       var div = document.getElementById('bookmarks');
+       if (div)
+           div.innerHTML = info;
+    }
+
+    return false;
+}
diff --git a/templates/contact.html b/templates/contact.html
new file mode 100644 (file)
index 0000000..3d23f0a
--- /dev/null
@@ -0,0 +1,47 @@
+<style type="text/css">
+div.thisform {
+  width: auto;
+  margin-left: 10px;
+}
+textarea {
+  width: 100%;
+  height: 100px;
+  margin-bottom: 5px;
+}
+</style>
+
+<div class="thisform">
+<div class="formular">
+<h3>Nachricht an den Chef schicken</h3>
+
+<form method="post" action="contact.html">
+<table>
+
+<tr>
+<td class="font" align="right"><label for="topic">Titel:</label></td>
+<td align="left"><input type="text" name="topic" id="topic" tabindex="3" value="@topic@" size="65" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="email">E-Mail:</label></td>
+<td align="left"><input type="text" name="email" id="email" tabindex="4" value="@email@" size="65" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right" valign="top"><label for="body">Text:</label></td>
+<td align="left"><textarea name="body" id="body" tabindex="5">@body@</textarea></td>
+</tr>
+
+</table>
+
+<input class="button" type="submit" tabindex="6" value="Abschicken" onclick="return check_contactform();">
+<input class="button" type="reset" tabindex="7" value="Zurücksetzen">
+
+</form>
+
+</div>
+</div>
+
+<p>Die Mail-Adresse ist optional.  Sie müssen sie nur dann angeben,
+wenn Sie (a) eine Antwort wünschen und (b) nicht im System angemeldet
+sind.</p>
diff --git a/templates/contact.js b/templates/contact.js
new file mode 100644 (file)
index 0000000..8eeaee5
--- /dev/null
@@ -0,0 +1,26 @@
+function check_contactform()
+{
+  var topic = document.getElementById('topic');
+  var body = document.getElementById('body');
+  var email = document.getElementById('email');
+
+  if (!topic || !body)
+    return false;
+
+  if (topic.value.length == 0) {
+      alert('Sie haben keinen Titel für die Nachricht angegeben!');
+      return false;
+  }
+
+  if (body.value.length == 0) {
+      alert('Sie haben keinen Text der Nachricht angegeben!');
+      return false;
+  }
+
+  if (email.value.length > 0 && !zlist_valid_email(email.value)) {
+      alert('Die angegebene Mail-Adresse ist ungültig.');
+      return false;
+  }
+
+  return true;
+}
diff --git a/templates/login.html b/templates/login.html
new file mode 100644 (file)
index 0000000..7d220cb
--- /dev/null
@@ -0,0 +1,114 @@
+<style type="text/css">
+div.thisform {
+  width: 400px;
+  margin-left: 50px;
+}
+</style>
+
+<div class="thisform">
+<div class="formular">
+<h3>Anmelden</h3>
+Sie besitzen noch keinen Account? <a href="login.html?new=1">Legen Sie einen neuen an.</a>
+
+<form method="post" id="login" action="login.html">
+<input type="hidden" name="js" value="0">
+<table>
+
+<tr>
+<td class="font" align="right"><label for="nickname">Username:</label></td>
+<td align="left"><input type="text" name="nickname" id="nickname" tabindex="3" value="@nickname@" size="30" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="passwd">Passwort:</label></td>
+<td align="left"><input type="password" name="passwd" id="passwd" tabindex="4" value="" size="30" /></td>
+</tr>
+
+</table>
+
+<input class="button" type="submit" tabindex="5" value="Anmelden" onclick="return check_loginform(true);">
+<input class="button" type="submit" tabindex="6" name="sendnew" value="Passwort zusenden" onclick="return check_loginform(false);">
+
+</form>
+<script type="text/javascript">
+document.forms['login'].js.value = "1";
+
+function check_loginform(checkpass)
+{
+  var nick = document.getElementById('nickname');
+
+  if (!nick)
+    return false;
+
+  if (nick.value.length == 0) {
+      alert('Sie haben keinen Usernamen angegeben!');
+      return false;
+  }
+
+  if (checkpass) {
+      var pass = document.getElementById('passwd');
+
+      if (!pass)
+         return false;
+
+      if (pass.value.length == 0) {
+         alert('Sie haben kein Passwort angegeben!');
+         return false;
+      }
+
+      var info = zlist_fetch('passwd_check', ['nickname', nick.value, 'passwd', pass.value]);
+
+      if (!info) {
+         alert('Das angegebene Passwort ist ungültig!');
+         return false;
+      }
+  }
+
+  return true;
+}
+</script>
+</div>
+</div>
+
+<h3>Wozu brauche ich überhaupt einen Account?</h3>
+
+<p>Die interaktive Nutzung dieses Webangebots kann nur mit einem
+persönlichen Account genutzt werden.  Um Tags für Zeitungen und
+Magazine zu vergeben und um an Diskussionen mit anderen Nutzern
+teilzunehmen wird ein persönlicher Account benötigt.</p>
+
+<h3>Ich habe mein Passwort vergessen, was nun?</h3>
+
+<p>Keine Panik!  Geben Sie oben ihren Usernamen an und drücken Sie auf
+die Taste "Passwort zusenden".  Sie erhalten anschließend eine Mail
+mit Details zu Ihrem Account.</p>
+
+<p>Wenn Sie auch den Usernamen nicht mehr wissen, geben Sie
+stattdessen ihre Mail-Adresse im Formular an.  Wenn die Adresse im
+System bekannt ist, erhalten Sie anschließend eine Mail mit Details zu
+Ihrem Account.</p>
+
+<h3>Verarbeitung und Weitergabe persönlicher Daten</h3>
+
+<p>Personenbezogene Daten sind alle Informationen zu Ihrer Identität
+wie beispielsweise Ihr Name und Ihre E-Mail-Adresse.  Auf der
+Zeitungsliste werden Ihre persönlichen Daten ausschließlich für die
+Bereitstellung der Dienste unter www.zeitungsliste.de verwendet.  Ihre
+personenbezogenen Daten werden nicht an Dritte weitergeben noch
+anderweitig außerhalb dieser Website genutzt.</p>
+
+<p>In diesem System werden nur die unbedingt erforderlichen
+persönlichen Informationen verwendet, die für den Betrieb der Website
+vonnöten sind.</p>
+
+<h3>Cookies</h3>
+
+<p>Cookies sind Informationen, die zwischen Browser und Webserver
+ausgetauscht werden und zusätzlich auf Ihrer Festplatte abgelegt
+werden können.  Sie werden auf dieser Web-Präsenz nur für die
+Bereitstellung der Dienste verwendet.  Die Lebensdauer wird dabei auf
+einen Tag beschränkt.  Beim Ausloggen werden Cookies ebenfalls
+ungültig.</p>
+
+<p>Um sich am System anzumelden, muß Ihr Browser Cookies
+akzeptieren.</p>
diff --git a/templates/login_new.html b/templates/login_new.html
new file mode 100644 (file)
index 0000000..90b97e6
--- /dev/null
@@ -0,0 +1,136 @@
+<style type="text/css">
+div.login {
+  width: auto;
+  margin-left: 20px;
+}
+</style>
+
+<div class="login">
+<div class="formular">
+<h3>Neuen Account anlegen</h3>
+
+<form method="post" action="login.html">
+<input type="hidden" name="new" value="1">
+<table>
+
+<tr>
+<td class="font" align="right"><label for="nickname">Username:</label></td>
+<td align="left"><input type="text" name="nickname" id="nickname" tabindex="3" value="@nickname@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="realname">Name:</label></td>
+<td align="left"><input type="text" name="realname" id="realname" tabindex="4" value="@realname@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="email">E-Mail:</label></td>
+<td align="left"><input type="text" name="email" id="email" tabindex="5" value="@email@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="url">Homepage:</label></td>
+<td align="left"><input type="text" name="url" id="url" tabindex="6" value="@url@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="passwd">Passwort:</label></td>
+<td align="left"><input type="password" name="passwd" id="passwd" tabindex="7" value="" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="pwcopy">Wiederholen:</label></td>
+<td align="left"><input type="password" name="pwcopy" id="pwcopy" tabindex="8" value="" size="50" /></td>
+</tr>
+
+</table>
+
+<input class="button" type="submit" tabindex="9" value="Anmelden" onclick="return check_loginform();">
+<input class="button" type="reset" tabindex="10" value="Zurücksetzen">
+
+</form>
+<script type="text/javascript">
+function check_loginform()
+{
+  var nick = document.getElementById('nickname');
+  var email = document.getElementById('email');
+  var pass = document.getElementById('passwd');
+  var pwcp = document.getElementById('pwcopy');
+  var url = document.getElementById('url');
+
+  if (!nick || !email || !pass || !pwcp)
+    return false;
+
+  if (nick.value.length == 0 || email.value.length == 0) {
+      alert('Sie müssen alle Pflichtfelder ausfüllen!\nSiehe Beschreibung unten.');
+      return false;
+  }
+
+  if (pass.value.length == 0) {
+      alert('Sie haben kein Passwort angegeben!');
+      return false;
+  }
+
+  if (pwcp.value.length == 0) {
+      alert('Sie haben das Passwort nicht wiederholt!');
+      return false;
+  }
+
+  if (pass.value.length < 5) {
+      alert('Ihr Passwort ist zu kurz, bitte verwenden Sie mindestens 5 Zeichen.');
+      return false;
+  }
+
+  if (pass.value != pwcp.value) {
+      alert('Sie haben sich beim Passwort vertippt.');
+      return false;
+  }
+
+  if (!zlist_valid_email(email.value)) {
+      alert('Die angegebene Mail-Adresse ist ungültig.');
+      return false;
+  }
+
+  if (url.value.length > 0 && !zlist_valid_url(url.value)) {
+      alert('Die angegebene Homepage ist ungültig!');
+      return false;
+  }
+
+  if (zlist_fetch('nickname_check', ['nickname', nick.value])) {
+      alert('Dieser Username ist in der Zeitungsliste bereits vergeben.');
+      return false;
+  }
+
+  return true;
+}
+</script>
+
+</div>
+</div>
+
+<h3>Pflichtfelder</h3>
+
+<p>Bis auf das Feld "Name" und "Homepage" müssen alle Felder ausgefüllt
+sein, um sich erfolgreich anzumelden.  Sie dürfen den Usernamen frei
+wählen, diesen werden Sie später zum Anmelden auf dieser Website
+benötigen.  Der Username darf Leerzeichen enthalten.</p>
+
+<h3>Mail-Adresse</h3>
+
+<p>Die Mail-Adresse muß gültig sein und Ihnen gehören.  An diese
+Adresse wird vom System eine Mail mit Informationen zur Aktivierung
+Ihres Accounts geschickt.  Erst danach können Sie den neuen Account
+auch verwenden.</p>
+
+<h3>Optionale Felder</h3>
+
+<p>Sie dürfen das Feld "Name" freilassen.  Mit anderen Worten, Sie
+müssen dem System nicht ihren tatsächlichen bürgerlichen Namen
+mitteilen.  Wenn Sie einen Namen angeben, wird dieser nur in der
+persönlichen Ansprache an Sie (in Mails und auf spezieleln Webseiten)
+verwendet.  Sie dürfen gerne anonym bleiben und lediglich unter Ihrem
+Usernamen firmieren.</p>
+
+<p>Das Feld "Homepage" ist ebenfalls optional und darf leer gelassen
+werden.  Falls Sie die Adresse Ihrer Homepage angeben, wird diese im
+System als Link zu ihrem Usernamen verwendet.</p>
diff --git a/templates/main.html b/templates/main.html
new file mode 100644 (file)
index 0000000..0edc164
--- /dev/null
@@ -0,0 +1,23 @@
+<h3>Zeitungsliste &ndash; Zeitungen im Netz</h3>
+
+<p>Diese Website verwaltetet eine umfassende Liste von zumeist
+deutschsprachigen Zeitungen im Netz sowie Magazinen, deren Inhalte
+ganz oder teilweise im World Wide Web angeboten werden.</p>
+
+<p>Dieses Verzeichnis wird komplett von der Community der
+Zeitungsliste gepflegt und aktuell gehalten.  Die Mitgliedschaft ist
+kostenlos.  Die Zeitungen und Magazine sind nicht streng in Kategorien
+eingeteilt, stattdessen werden von den Nutzern dieser Website Tags
+vergeben.  Dadurch entsteht eine viel stärker an den Nutzern
+orientierte Klassifizierung der verschiedenen Zeitschriften.</p>
+
+<p>Um die volle Funktionalität dieser Website nutzen zu können,
+sollten Sie eingeloggt sein und sowohl Cookies akzeptieren als auch
+Javascript ausführen.  Das reine Verzeichnis von Zeitungen kann jedoch
+auch ohne diese genutzt werden, lediglich die interaktiven
+Möglichkeiten stehen dann nicht zur Verfügung.</p>
+
+<p>Wir sind nicht für die Inhalte auf von diesem Verzeichnis
+verlinkten externen Seiten verantwortlich.  Für Diskussionsbeiträge in
+diesem Verzeichnis zeichnen sich die jeweiligen Autoren
+verantwortlich.
diff --git a/templates/options.html b/templates/options.html
new file mode 100644 (file)
index 0000000..21ae7f9
--- /dev/null
@@ -0,0 +1,68 @@
+<style type="text/css">
+div.thisform {
+  width: auto;
+  margin-left: 20px;
+}
+</style>
+
+<div class="thisform">
+<div class="formular">
+<h3>Einstellungen für @nickname@</h3>
+
+<form method="post" action="options.html">
+<table>
+
+<tr>
+<td class="font" align="right"><label for="nickname">Username:</label></td>
+<td align="left"><input type="text" name="nickname" id="nickname" tabindex="2" value="@nickname@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="realname">Name:</label></td>
+<td align="left"><input type="text" name="realname" id="realname" tabindex="3" value="@realname@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="email">E-Mail:</label></td>
+<td align="left"><input type="text" name="email" id="email" tabindex="4" value="@email@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="url">Homepage:</label></td>
+<td align="left"><input type="text" name="url" id="url" tabindex="5" value="@url@" size="50" /></td>
+</tr>
+
+</table>
+
+<input class="button" type="submit" tabindex="6" value="Ändern" onclick="return check_optionsform();">
+<input class="button" type="reset" tabindex="7" value="Zurücksetzen">
+
+</form>
+
+</div>
+</div>
+
+<h3>Pflichtfelder</h3>
+
+<p>Die Felder "Username" und "E-Mail" müssen ausgefüllt sein.  Wenn
+Sie den Usernamen ändern werden auch archivierte Diskussionsbeiträge
+dem neuen Usernamen zugeordnet.</p>
+
+<h3>Mail-Adresse</h3>
+
+<p>Die Mail-Adresse muß gültig sein und Ihnen gehören.  An diese
+Adresse schickt das System eine Mail mit einem neuen Paßwort, falls
+Sie Ihres vergessen haben.</p>
+
+<h3>Optionale Felder</h3>
+
+<p>Sie dürfen das Feld "Name" freilassen.  Mit anderen Worten, Sie
+müssen dem System nicht ihren tatsächlichen bürgerlichen Namen
+mitteilen.  Wenn Sie einen Namen angeben, wird dieser nur in der
+persönlichen Ansprache an Sie (in Mails und auf spezieleln Webseiten)
+verwendet.  Sie dürfen gerne anonym bleiben und lediglich unter Ihrem
+Usernamen firmieren.</p>
+
+<p>Das Feld "Homepage" ist ebenfalls optional und darf leer gelassen
+werden.  Falls Sie die Adresse Ihrer Homepage angeben, wird diese im
+System als Link zu ihrem Usernamen verwendet.</p>
diff --git a/templates/options.js b/templates/options.js
new file mode 100644 (file)
index 0000000..94a64e3
--- /dev/null
@@ -0,0 +1,26 @@
+function check_optionsform()
+{
+  var nick = document.getElementById('nickname');
+  var email = document.getElementById('email');
+  var url = document.getElementById('url');
+
+  if (!nick || !email)
+    return false;
+
+  if (nick.value.length == 0 || email.value.length == 0) {
+      alert('Sie müssen alle Pflichtfelder ausfüllen!\nSiehe Beschreibung unten.');
+      return false;
+  }
+
+  if (url.value.length > 0 && !zlist_valid_url(url.value)) {
+      alert('Die angegebene Homepage ist ungültig!');
+      return false;
+  }
+
+  if (zlist_fetch('nickname_check', ['nickname', nick.value])) {
+      alert('Dieser Username ist in der Zeitungsliste bereits vergeben.');
+      return false;
+  }
+
+  return true;
+}
diff --git a/templates/passwd.html b/templates/passwd.html
new file mode 100644 (file)
index 0000000..fae757a
--- /dev/null
@@ -0,0 +1,33 @@
+<style type="text/css">
+div.thisform {
+  width: 400px;
+  margin-left: 50px;
+}
+</style>
+
+<div class="thisform">
+<div class="formular">
+<h3>Passwort für @nickname@ ändern</h3>
+
+<form method="post" action="passwd.html">
+<table>
+
+<tr>
+<td class="font" align="right"><label for="passwd">Passwort:</label></td>
+<td align="left"><input type="password" name="passwd" id="passwd" tabindex="2" value="" size="30" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="pwcopy">Wiederholen:</label></td>
+<td align="left"><input type="password" name="pwcopy" id="pwcopy" tabindex="3" value="" size="30" /></td>
+</tr>
+
+</table>
+
+<input class="button" type="submit" tabindex="4" value="Ändern" onclick="return check_passwdform();">
+<input class="button" type="reset" tabindex="5" value="Zurücksetzen">
+
+</form>
+
+</div>
+</div>
diff --git a/templates/passwd.js b/templates/passwd.js
new file mode 100644 (file)
index 0000000..df30547
--- /dev/null
@@ -0,0 +1,30 @@
+function check_passwdform()
+{
+  var pass = document.getElementById('passwd');
+  var pwcp = document.getElementById('pwcopy');
+
+  if (!pass || !pwcp)
+    return false;
+
+  if (pass.value.length == 0) {
+      alert('Sie haben kein Passwort angegeben!');
+      return false;
+  }
+
+  if (pwcp.value.length == 0) {
+      alert('Sie haben das Passwort nicht wiederholt!');
+      return false;
+  }
+
+  if (pass.value.length < 5) {
+      alert('Ihr Passwort ist zu kurz, bitte verwenden Sie mindestens 5 Zeichen.');
+      return false;
+  }
+
+  if (pass.value != pwcp.value) {
+      alert('Sie haben sich beim Passwort vertippt.');
+      return false;
+  }
+
+  return true;
+}
diff --git a/templates/reply.html b/templates/reply.html
new file mode 100644 (file)
index 0000000..5738cf6
--- /dev/null
@@ -0,0 +1,46 @@
+<style type="text/css">
+div.thisform {
+  width: auto;
+  margin-left: 0px;
+}
+textarea {
+  width: 100%;
+  width: 500px;
+  height: 100px;
+  margin-bottom: 5px;
+}
+</style>
+
+<div class="thisform">
+<div class="formular">
+<h3>@title@</h3>
+
+<form method="post" action="reply.html">
+<input type="hidden" name="topic" value="@topic@" />
+<table>
+
+<tr>
+<td class="font" align="right" valign="top"><label for="body">Text:</label></td>
+<td align="left"><textarea name="body" id="body" tabindex="3">@body@</textarea></td>
+</tr>
+
+</table>
+
+<input class="button" type="submit" tabindex="4" value="Abschicken" onclick="return check_replyform();">
+<input class="button" type="reset" tabindex="5" value="Zurücksetzen">
+
+</form>
+
+</div>
+</div>
+
+<p>Bitte gehen Sie sparsam mit HTML-Elementen im Text um.  Die meisten
+Konstrukte werden nicht unterstützt, um das Layout der Seiten nicht
+durcheinander zu bringen.  Sie dürfen jedoch gerne folgende Tags
+verwenden &lt;p&gt;&lt;/p&gt;, &lt;b&gt;&lt;/b&gt;,
+&lt;em&gt;&lt;/em&gt;, &lt;br&gt;, um Ihren Artikel lesbarer zu
+gestalten und einzelne Passagen hervorzuheben.</p>
+
+<p>Externe Links in Artikeln sind ebenfalls möglich, verwenden Sie dazu
+bitte die einfache Form des Anchor-Tags &lt;a
+href=&quot;link&quot;&gt;text&lt;/a&gt;.</p>
diff --git a/templates/reply.js b/templates/reply.js
new file mode 100644 (file)
index 0000000..086c28b
--- /dev/null
@@ -0,0 +1,14 @@
+function check_replyform()
+{
+  var body = document.getElementById('body');
+
+  if (!body)
+    return false;
+
+  if (body.value.length == 0) {
+      alert('Sie haben keinen Text für die Diskussion angegeben!');
+      return false;
+  }
+
+  return true;
+}
diff --git a/templates/searchform.html b/templates/searchform.html
new file mode 100644 (file)
index 0000000..03a587a
--- /dev/null
@@ -0,0 +1,20 @@
+<style type="text/css">
+.searchform {
+  text-align: right;
+}
+.searchform form {
+  margin-bottom: 4px;
+}
+.searchform input {
+  font-size: 10px;
+  padding: 0;
+  margin: 0;
+}
+</style>
+
+<div class="searchform">
+<form id="searchform" method="post" action="@basepath@search.html" onsubmit="return check_searchform();">
+<input type="text" name="keyword" id="keyword" tabindex="1" value="@keyword@" size="17" />
+<input class="button" type="submit" tabindex="2" value="Suchen">
+</form></div>
+
diff --git a/templates/searchform.js b/templates/searchform.js
new file mode 100644 (file)
index 0000000..e4c8175
--- /dev/null
@@ -0,0 +1,22 @@
+function check_searchform()
+{
+  var inp = document.getElementById('keyword');
+
+  if (!inp)
+    return false;
+
+  if (inp.value.length == 0) {
+    alert('Sie haben keinen Suchbegriff angegeben!');
+    return false;
+  }
+
+  var info = zlist_fetch('search_check', ['keyword', inp.value]);
+
+  if (!info) {
+      alert('Keine Treffer für "'+inp.value+'" gefunden.');
+      return false;
+  }
+
+  return true;
+}
+
diff --git a/templates/signature b/templates/signature
new file mode 100644 (file)
index 0000000..72c4d63
--- /dev/null
@@ -0,0 +1,3 @@
+
+-- 
+Zeitungen im Netz                    http://www.zeitungsliste.de/
diff --git a/templates/tags.html b/templates/tags.html
new file mode 100644 (file)
index 0000000..046ff13
--- /dev/null
@@ -0,0 +1,25 @@
+<table width="100%" alt="">
+
+<tr bgcolor="#77dc4b">
+ <th width="40%" class="font" valign="top">Persönliche Tags</th>
+ <th width="60%" class="font" valign="top">Noch nicht vergebene Tags</th>
+</tr>
+
+<tr>
+ <td width="40%" class="font" valign="top"><div id="mytags">@mytags@</div></td>
+ <td width="60%" class="font" valign="top"><div id="tags">@tags@</div>
+
+<form method="post" action="tags.html">
+<input type="hidden" name="zeitung" id="zeitung" value="@zeitung@">
+
+Neuer Tag: <input type="text" name="newtag" id="newtag" tabindex="3" value="" size="17" />
+
+<br>
+<input class="button" type="submit" tabindex="4" value="Hinzufügen" onclick="return process_newtag();">
+<input class="button" type="reset" tabindex="5" value="Zurücksetzen">
+</form>
+
+</td>
+</tr>
+
+</table>
diff --git a/templates/tags.js b/templates/tags.js
new file mode 100644 (file)
index 0000000..e03e881
--- /dev/null
@@ -0,0 +1,45 @@
+function check_newtag()
+{
+  var newtag = document.getElementById('newtag');
+
+  if (!newtag)
+    return false;
+
+  if (newtag.value.length == 0) {
+      alert('Sie haben vergessen, ein Merkmal anzugeben!');
+      return false;
+  }
+
+  if (zlist_fetch('tag_exists', ['tag', newtag.value])) {
+      alert('Dieses Merkmal ist (evtl. in anderer Schreibweise)\nbereits vorhanden.');
+      return false;
+  }
+  return true;
+}
+
+function tag_action(action,zid,tag)
+{
+    var info;
+
+    info = zlist_fetch('tag_'+action, ['zeitung', zid, 'tag', tag]);
+
+    if (info != false) {
+       document.getElementById('mytags').innerHTML = info[0];
+       document.getElementById('tags').innerHTML = info[1];
+    }
+
+    return false;
+}
+
+function process_newtag()
+{
+    if (check_newtag()) {
+       var newtag = document.getElementById('newtag');
+       var zeitung = document.getElementById('zeitung');
+
+       tag_action('new', zeitung.value, newtag.value);
+       newtag.value = '';
+    }
+
+    return false;
+}
diff --git a/templates/topic.html b/templates/topic.html
new file mode 100644 (file)
index 0000000..f094714
--- /dev/null
@@ -0,0 +1,50 @@
+<style type="text/css">
+div.thisform {
+  width: auto;
+  margin-left: 10px;
+}
+textarea {
+  width: 100%;
+  height: 100px;
+  margin-bottom: 5px;
+}
+</style>
+
+<div class="thisform">
+<div class="formular">
+<h3>Neues Thema diskutieren</h3>
+
+<form method="post" action="topic.html">
+<input type="hidden" name="zeitung" value="@zeitung@" />
+<table>
+
+<tr>
+<td class="font" align="right"><label for="topic">Titel:</label></td>
+<td align="left"><input type="text" name="topic" id="topic" tabindex="3" value="@topic@" size="65" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right" valign="top"><label for="body">Text:</label></td>
+<td align="left"><textarea name="body" id="body" tabindex="4">@body@</textarea></td>
+</tr>
+
+</table>
+
+<input class="button" type="submit" tabindex="5" value="Abschicken" onclick="return check_topicform();">
+<input class="button" type="reset" tabindex="6" value="Zurücksetzen">
+
+</form>
+
+</div>
+</div>
+
+<p>Bitte gehen Sie sparsam mit HTML-Elementen im Text um.  Die meisten
+Konstrukte werden nicht unterstützt, um das Layout der Seiten nicht
+durcheinander zu bringen.  Sie dürfen jedoch gerne folgende Tags
+verwenden &lt;p&gt;&lt;/p&gt;, &lt;b&gt;&lt;/b&gt;,
+&lt;em&gt;&lt;/em&gt;, &lt;br&gt;, um Ihren Artikel lesbarer zu
+gestalten und einzelne Passagen hervorzuheben.</p>
+
+<p>Externe Links in Artikeln sind ebenfalls möglich, verwenden Sie dazu
+bitte die einfache Form des Anchor-Tags &lt;a
+href=&quot;link&quot;&gt;text&lt;/a&gt;.</p>
diff --git a/templates/topic.js b/templates/topic.js
new file mode 100644 (file)
index 0000000..7f828c2
--- /dev/null
@@ -0,0 +1,20 @@
+function check_topicform()
+{
+  var topic = document.getElementById('topic');
+  var body = document.getElementById('body');
+
+  if (!topic || !body)
+    return false;
+
+  if (topic.value.length == 0) {
+      alert('Sie haben keinen Titel für die Diskussion angegeben!');
+      return false;
+  }
+
+  if (body.value.length == 0) {
+      alert('Sie haben keinen Text für die Diskussion angegeben!');
+      return false;
+  }
+
+  return true;
+}
diff --git a/templates/zeitung.html b/templates/zeitung.html
new file mode 100644 (file)
index 0000000..800b10d
--- /dev/null
@@ -0,0 +1,57 @@
+<style type="text/css">
+div.thisform {
+  width: auto;
+  margin-left: 20px;
+  margin-right: 20px;
+}
+textarea {
+  width: 100%;
+  height: 100px;
+  margin-bottom: 5px;
+}
+</style>
+
+<div class="thisform">
+<div class="formular">
+<h3>@name@ bearbeiten</h3>
+
+<form method="post" action="edit.html">
+<input type="hidden" name="zeitung" value="@id@">
+<table>
+
+<tr>
+<td class="font" align="right"><label for="name">Name:</label></td>
+<td align="left"><input type="text" name="name" id="name" tabindex="3" value="@name@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="city">Ort:</label></td>
+<td align="left"><input type="text" name="city" id="city" tabindex="4" value="@city@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="url">Homepage:</label></td>
+<td align="left"><input type="text" name="url" id="url" tabindex="5" value="@url@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right" valign="top"><label for="description">Text:</label></td>
+<td align="left"><textarea name="description" tabindex="6" >@description@</textarea></td>
+</tr>
+
+
+</table>
+
+<input class="button" type="submit" tabindex="7" value="Ändern">
+<input class="button" type="submit" tabindex="8" name="delete" value="Löschen">
+<input class="button" type="reset" tabindex="9" value="Zurücksetzen">
+
+</form>
+
+</div>
+</div>
+
+<h3>Pflichtfelder</h3>
+
+<p>Wenn Sie Informationen zu einer Zeitung ändern, denken Sie bitte
+daran, daß alle Felder ausgefüllt sein müssen.</p>
diff --git a/templates/zeitung.js b/templates/zeitung.js
new file mode 100644 (file)
index 0000000..a258a6f
--- /dev/null
@@ -0,0 +1,36 @@
+function check_paperform()
+{
+  var name = document.getElementById('name');
+  var city = document.getElementById('city');
+  var url = document.getElementById('url');
+  var description = document.getElementById('description');
+
+  if (!name || !city || !url || !description)
+    return false;
+
+  if (name.value.length == 0 || city.value.length == 0 ||
+      url.value.length == 0 || description.value.length == 0) {
+      alert('Sie müssen alle Pflichtfelder ausfüllen!\nSiehe Beschreibung unten.');
+      return false;
+  }
+
+  if (!zlist_valid_url(url.value)) {
+      alert('Die angegebene Homepage ist ungültig!');
+      return false;
+  }
+
+  var info = zlist_fetch('zeitung_check_url', ['url', url.value]);
+
+  if (info != false) {
+      alert('Die angegebene URL ist bereits für "' + info + '" gespeichert.');
+      return false;
+  }
+
+  if (city.value == 'Deutschland (Stadt)') {
+      alert('Sie haben keinen Erscheinungsort angegeben!');
+      return false;
+  }
+
+  return true;
+}
+
diff --git a/templates/zeitung_new.html b/templates/zeitung_new.html
new file mode 100644 (file)
index 0000000..4b0a057
--- /dev/null
@@ -0,0 +1,55 @@
+<style type="text/css">
+div.thisform {
+  width: auto;
+  margin-left: 20px;
+  margin-right: 20px;
+}
+textarea {
+  width: 100%;
+  height: 100px;
+  margin-bottom: 5px;
+}
+</style>
+
+<div class="thisform">
+<div class="formular">
+<h3>Neue Zeitung hinzufügen</h3>
+
+<form method="post" action="new.html">
+<table>
+
+<tr>
+<td class="font" align="right"><label for="name">Name:</label></td>
+<td align="left"><input type="text" name="name" id="name" tabindex="2" value="@name@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="city">Ort:</label></td>
+<td align="left"><input type="text" name="city" id="city" tabindex="3" value="@city@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right"><label for="url">Homepage:</label></td>
+<td align="left"><input type="text" name="url" id="url" tabindex="4" value="@url@" size="50" /></td>
+</tr>
+
+<tr>
+<td class="font" align="right" valign="top"><label for="description">Text:</label></td>
+<td align="left"><textarea name="description" id="description" tabindex="5" >@description@</textarea></td>
+</tr>
+
+
+</table>
+
+<input class="button" type="submit" tabindex="6" value="Hinzufügen" onclick="return check_paperform();">
+<input class="button" type="reset" tabindex="7" value="Zurücksetzen">
+
+</form>
+
+</div>
+</div>
+
+<h3>Pflichtfelder</h3>
+
+<p>Alle Felder in diesem Formular sind Pflichtfelder und müssen
+ausgefüllt werden.</p>
diff --git a/www/achtung.gif b/www/achtung.gif
new file mode 100644 (file)
index 0000000..04895f0
Binary files /dev/null and b/www/achtung.gif differ
diff --git a/www/add.gif b/www/add.gif
new file mode 100644 (file)
index 0000000..9b02b43
Binary files /dev/null and b/www/add.gif differ
diff --git a/www/ajax.php b/www/ajax.php
new file mode 100644 (file)
index 0000000..702e599
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+
+require_once('config.php');
+include_once('ajax.inc');
+
+echo json_encode (ajax_process()) . "\n";
+
+?>
\ No newline at end of file
diff --git a/www/antworten.gif b/www/antworten.gif
new file mode 100644 (file)
index 0000000..a99ffaa
Binary files /dev/null and b/www/antworten.gif differ
diff --git a/www/archive.gif b/www/archive.gif
new file mode 100644 (file)
index 0000000..4018dae
Binary files /dev/null and b/www/archive.gif differ
diff --git a/www/bookmarks.gif b/www/bookmarks.gif
new file mode 100644 (file)
index 0000000..240ce38
Binary files /dev/null and b/www/bookmarks.gif differ
diff --git a/www/config.php b/www/config.php
new file mode 100644 (file)
index 0000000..f133f21
--- /dev/null
@@ -0,0 +1,61 @@
+<?
+$_config = array();
+
+$_config['www.zeitungsliste.de'] = array();
+
+$_config['www.zeitungsliste.de']['home'] = 'http://www.zeitungsliste.de/';
+$_config['www.zeitungsliste.de']['libdir'] = '/org/zeitungsliste.de/lib';
+$_config['www.zeitungsliste.de']['tmpldir'] = '/org/zeitungsliste.de/templates';
+$_config['www.zeitungsliste.de']['dbname'] = 'zlist';
+$_config['www.zeitungsliste.de']['dbuser'] = 'www-data';
+# dbpass, dbhost, dbport -> defaults
+
+// $_config['www.zeitungsliste.de']['from'] = 'Zeitungsliste <master@zeitungsliste.de>';
+$_config['www.zeitungsliste.de']['from'] = 'Zeitungsliste <master@zeitungsliste.de>';
+$_config['www.zeitungsliste.de']['session'] = 'zsession_id';
+$_config['www.zeitungsliste.de']['mailto'] = 'joey@infodrom.org';
+
+/*
+ * ----------------------------------------------------------------------
+ */
+
+$_config['luonnotar.infodrom.org'] = array();
+
+$_config['luonnotar.infodrom.org']['home'] = 'http://luonnotar.infodrom.org/~joey/z/';
+$_config['luonnotar.infodrom.org']['libdir'] = '/home/joey/luonnotar_html/z/lib';
+$_config['luonnotar.infodrom.org']['tmpldir'] = '/home/joey/luonnotar_html/z/lib/templates';
+$_config['luonnotar.infodrom.org']['dbname'] = 'zlist';
+$_config['luonnotar.infodrom.org']['dbuser'] = 'www-data';
+# dbpass, dbhost, dbport -> defaults
+
+// $_config['luonnotar.infodrom.org']['from'] = 'Zeitungsliste <master@zeitungsliste.de>';
+$_config['luonnotar.infodrom.org']['from'] = 'Zeitungsliste <master@luonnotar.infodrom.org>';
+$_config['luonnotar.infodrom.org']['session'] = 'zsession_id';
+$_config['luonnotar.infodrom.org']['mailto'] = 'joey@infodrom.org';
+
+/*
+ * ==================== Start of the platform ===========================
+ */
+
+if (!array_key_exists('SERVER_NAME', $_SERVER))
+  exit;
+
+if (!array_key_exists($_SERVER['SERVER_NAME'], $_config))
+  exit;
+
+$cfg = $_config[$_SERVER['SERVER_NAME']];
+
+ini_set ('include_path', $cfg['libdir'] . ':' . ini_get('include_path'));
+
+mb_internal_encoding('UTF-8');
+
+include_once('core.inc');
+
+$cfg['dbh'] = db_connect();
+$cfg['basepath'] = basepath();
+$zlist = array();
+
+include_once('session.inc');
+session_init();
+
+?>
diff --git a/www/delete.gif b/www/delete.gif
new file mode 100644 (file)
index 0000000..4a9dd33
Binary files /dev/null and b/www/delete.gif differ
diff --git a/www/down.png b/www/down.png
new file mode 100644 (file)
index 0000000..ed70760
Binary files /dev/null and b/www/down.png differ
diff --git a/www/edit.gif b/www/edit.gif
new file mode 100644 (file)
index 0000000..ea99f7e
Binary files /dev/null and b/www/edit.gif differ
diff --git a/www/favicon.ico b/www/favicon.ico
new file mode 100644 (file)
index 0000000..ba2bb18
Binary files /dev/null and b/www/favicon.ico differ
diff --git a/www/index.php b/www/index.php
new file mode 100644 (file)
index 0000000..b1230b9
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+$start = microtime();
+
+require_once('config.php');
+include_once('functions.inc');
+
+$body = dispatch();
+
+print pageheader();
+print $body;
+
+include_once('footer.inc');
+
+?>
\ No newline at end of file
diff --git a/www/information.gif b/www/information.gif
new file mode 100644 (file)
index 0000000..1753c05
Binary files /dev/null and b/www/information.gif differ
diff --git a/www/listitem.gif b/www/listitem.gif
new file mode 100644 (file)
index 0000000..8744b9d
Binary files /dev/null and b/www/listitem.gif differ
diff --git a/www/main.css b/www/main.css
new file mode 100644 (file)
index 0000000..9248100
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * General settings
+ */
+body {
+  font-family: Verdana, Helvetica, Arial, sans-serif;
+  font-size: 13px;
+  line-height: 120%;
+  background-color: #31930b;
+  color: black;
+  padding: 0;
+  margin-left: 2%;
+  margin-right: 2%;
+}
+
+/*
+ * No underline for links
+ */
+a:link, a:visited {
+  text-decoration: none;
+  cursor: pointer;
+}
+a:link:hover, a:visited:hover {
+  color: red;
+}
+
+/*
+ * General layout
+ */
+.font {
+  font-size: 13px;
+}
+.smallfont {
+  font-size: 11px;
+}
+.none {
+  display: none;
+}
+
+h3.bar {
+  padding-left: 5px;
+  padding-bottom: 1px;
+  font-size: 14px;
+  background: #cfcfcf;
+}
+
+p.warn {
+  color: red;
+  font-weight: bold;
+  padding-left: 5px;
+}
+p.info {
+  color: #3b3bd0;
+  font-weight: bold;
+  padding-left: 5px;
+}
+p.warn img {
+  vertical-align: middle;
+}
+p.info img {
+  vertical-align: middle;
+}
+
+ul.gold {
+  list-style-type: disc;
+  list-style-image: url(listitem.gif);
+  text-indent: -0.5em;
+}
+
+div.banner {
+  margin: 0;
+  padding-bottom: 10px;
+  background-color: #1c451d;
+  background-image: url(zlist.png);
+  background-repeat: no-repeat;
+  background-attachment: scroll;
+  background-position: center;
+  display: block;
+  height: 80px;
+}
+
+div.status {
+  margin: 0;
+  background-color: #1c451d;
+  font-size: 11px;
+  color: orange;
+}
+div.userstatus {
+  text-align: center;
+}
+div.homestatus {
+  float: left;
+  text-align: left;
+  font-weight: bold;
+  padding-left: 7px;
+}
+div.logstatus {
+  float: right;
+  text-align: right;
+  font-weight: bold;
+  padding-right: 5px;
+}
+div.homestatus a:link, div.homestatus a:visited, div.logstatus a:link, div.logstatus a:visited {
+  color: orange;
+}
+div.logstatus a:link:hover, div.logstatus a:visited:hover {
+  color: red;
+}
+
+div.page {
+  border: 1px solid #1c451d;
+  background-color: #f7f7f7;
+  margin: 0;
+  padding: 10px;
+  clear: both;
+}
+
+div.main {
+  margin-top: 0;
+  padding-top: 0;
+  margin-right: 180px;
+}
+
+div.info {
+  float: right;
+  width: 170px;
+  margin-top: 0;
+  padding-top: 0;
+  padding-left: 0;
+}
+
+div.info h3 {
+  background-color: #77dc4b;
+  margin-top: 0px;
+  margin-bottom: 2px;
+  padding-left: 5px;
+  padding-right: 5px;
+  font-size: 12px;
+  line-height: 14px;
+}
+div.info p {
+  background-color: #d4f3bd;
+  padding-left: 4px;
+  margin: 0;
+  margin-bottom: 5px;
+}
+div.info p img {
+  vertical-align: middle;
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+div.info ul {
+  background-color: #d4f3bd;
+  margin: 0;
+  margin-bottom: 10px;
+  padding-left: 5px;
+  padding-right: 2px;
+  list-style: none;
+}
+div.info ul li {
+  font-size: 10px;
+  line-height: 14px;
+}
+
+ul.action li {
+  font-weight: bold;
+}
+ul.action li img {
+  vertical-align: middle;
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+
+div.newspaper {
+  background-color: #d2fdb2;
+  margin-bottom: 10px;
+}
+div.newspaper h3 {
+  background-color: #35a006;
+  margin-top: 0px;
+  margin-bottom: 0px;
+  padding-left: 10px;
+  padding-right: 5px;
+  padding-top: 2px;
+  padding-bottom: 2px;
+}
+div.newspaper p {
+  margin: 10px;
+  padding-left: 5px;
+  padding-right: 5px;
+  padding-bottom: 4px;
+}
+div.newspaper code {
+  font-size: 90%;
+}
+
+div.topic {
+  border: 1px solid #31930b;
+  margin-bottom: 10px;
+  padding: 0;
+}
+div.topic h3 {
+  background-color: #a2ef83;
+  margin-top: 0px;
+  margin-bottom: 0px;
+  padding-left: 5px;
+  padding-right: 5px;
+  padding-top: 2px;
+  padding-bottom: 2px;
+}
+div.topic p {
+  padding-left: 5px;
+  padding-right: 5px;
+  padding-top: 5px;
+  padding-bottom: 5px;
+  margin: 0;
+}
+div.art0 p {
+  background-color: #ffffff;
+}
+div.art1 p {
+  background-color: #d7fdb9;
+}
+
+p.tagcloud {
+  padding-bottom: 5px;
+}
+p.tagcloud span {
+  font-weight: bold;
+}
+p.tagcloud span a {
+  color: #36648b;
+}
+p.tagcloud span a:hover {
+  background: #36648b;
+  color: white;
+}
+span.tag0 { font-size: 10px; }
+span.tag1 { font-size: 14px; }
+span.tag2 { font-size: 18px; }
+span.tag3 { font-size: 22px; }
+span.tag4 { font-size: 26px; }
+
+h3 span.tag {
+  font-size: 24px;
+  color: #36648b;
+}
+
+h3.tag0, h3.tag1, h3.tag2, h3.tag3, h3.tag4 {
+  padding-left: 5px;
+  padding-top: 2px;
+  padding-bottom: 4px;
+  font-size: 14px;
+}
+h3.tag4 { background-color: #35a006; }
+h3.tag3 { background-color: #46c30f; }
+h3.tag2 { background-color: #77dc4b; }
+h3.tag1 { background-color: #a2ef83; }
+h3.tag0 { background-color: #c0f8aa; }
+
+div.buttons {
+  background-color: #f7f7f7;
+  text-align: right;
+}
+div.buttons img {
+  vertical-align: middle;
+}
+
+div.formular {
+  margin: 0;
+  padding: 0;
+  padding-left: 10px;
+  padding-right: 10px;
+  line-height: 1.5em;
+  border: 1px solid #1c451d;
+  background-color: #d9f3c1;
+}
+div.formular h3 {
+  padding-bottom: 10px;
+  border-bottom: 3px solid #31930b;
+}
+
+input, select, textarea {
+  background-color: #e6e6e6;
+  border: 1px solid #31930b;
+}
+input {
+  padding-left: 2px;
+}
+input.button {
+  width: auto;
+  margin-top: 3px;
+}
+input.button:hover {
+  border: 1px solid #1c451d;
+  background-color: #c0f8aa;
+  color: black;
+}
+
+div.social_bookmarks {
+  border: 1px solid #b0b0b0;
+  background-color: #dedede;
+  padding-left: 3px;
+}
+div.social_bookmarks img {
+  vertical-align: middle;
+  margin: 2px;
+}
+
+table.bookmarks {
+  font-size: 13px;
+}
+table.bookmarks img {
+  vertical-align: middle;
+}
+
+div.pagefooter {
+  clear: both;
+}
+div.footer {
+  margin-top: 5px;
+  text-align: center;
+} 
+div.footer a:link, div.footer a:visited {
+  color: black;
+}
+div.footer a:link:hover, div.footer a:visited:hover {
+  color: red;
+}
diff --git a/www/newspaper.gif b/www/newspaper.gif
new file mode 100644 (file)
index 0000000..752ac55
Binary files /dev/null and b/www/newspaper.gif differ
diff --git a/www/newtopic.gif b/www/newtopic.gif
new file mode 100644 (file)
index 0000000..fb4c5a2
Binary files /dev/null and b/www/newtopic.gif differ
diff --git a/www/passwd.gif b/www/passwd.gif
new file mode 100644 (file)
index 0000000..7d2f67d
Binary files /dev/null and b/www/passwd.gif differ
diff --git a/www/tag.gif b/www/tag.gif
new file mode 100644 (file)
index 0000000..d359a6d
Binary files /dev/null and b/www/tag.gif differ
diff --git a/www/up.png b/www/up.png
new file mode 100644 (file)
index 0000000..bcd1069
Binary files /dev/null and b/www/up.png differ
diff --git a/www/zlist.js b/www/zlist.js
new file mode 100644 (file)
index 0000000..d717f17
--- /dev/null
@@ -0,0 +1,49 @@
+function zlist_encode(param)
+{
+    var ret= '';
+
+    for (var i=0; i < param.length; i+=2) {
+       if (ret.length)
+           ret += '&';
+       ret += encodeURIComponent(param[i]) +'='+ encodeURIComponent(param[i+1])
+    }
+
+    return ret;
+}
+
+function zlist_fetch(func, param)
+{
+  var request = false;
+  var formdata = null;
+
+  if (window.XMLHttpRequest)
+    request = new XMLHttpRequest();
+  else if (window.ActiveXObject)
+    request = new ActiveXObject('Microsoft.XMLHTTP');
+
+  if (!request)
+    return false;
+
+  request.open ('POST', zlist_urlbase + 'ajax.php', false);
+
+  formdata = 'function='+ encodeURIComponent(func);
+
+  if (param)
+      formdata += '&' + zlist_encode(param);
+
+  request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  request.send(formdata);
+
+  return eval(request.responseText);
+}
+
+function zlist_valid_email(email)
+{
+    return true;
+}
+
+function zlist_valid_url(url)
+{
+    return true;
+}
diff --git a/www/zlist.png b/www/zlist.png
new file mode 100644 (file)
index 0000000..f25a830
Binary files /dev/null and b/www/zlist.png differ