summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2000-10-10 10:52:19 +0000
committerDries Buytaert <dries@buytaert.net>2000-10-10 10:52:19 +0000
commit4a6c6de758960a2f98ba58f20a1c17c6ee67111c (patch)
treed0466a04feb29ce5769d90ffb8041b78412faa82 /includes
parent73077e8778cfd890f51023f6683e70904317cc6f (diff)
downloadbrdo-4a6c6de758960a2f98ba58f20a1c17c6ee67111c.tar.gz
brdo-4a6c6de758960a2f98ba58f20a1c17c6ee67111c.tar.bz2
Huge update - I don't have time to write everything down but the directory
structure changes, some sections are expanded. Take a look at the source code or ask me to elaborate on certain issues/topics.
Diffstat (limited to 'includes')
-rw-r--r--includes/admin.inc78
-rw-r--r--includes/backend.inc241
-rw-r--r--includes/ban.inc52
-rw-r--r--includes/calendar.inc76
-rw-r--r--includes/config.inc115
-rw-r--r--includes/database.inc62
-rw-r--r--includes/function.inc106
-rw-r--r--includes/log.inc17
-rw-r--r--includes/submission.inc35
-rw-r--r--includes/template.inc128
-rw-r--r--includes/theme.inc11
-rw-r--r--includes/user.inc83
12 files changed, 1004 insertions, 0 deletions
diff --git a/includes/admin.inc b/includes/admin.inc
new file mode 100644
index 000000000..4d0ed0dda
--- /dev/null
+++ b/includes/admin.inc
@@ -0,0 +1,78 @@
+<?
+
+
+function admin_icon($name) {
+ global $section;
+ if ($name == $section) print " <TD ALIGN=\"center\" BGCOLOR=\"#CCCCCC\"><A HREF=\"admin.php?section=$name\"><IMG SRC=\"images/admin-$name.png\" BORDER=\"0\"></A><BR>$name</TD>\n";
+ else print " <TD ALIGN=\"center\" VALIGN=\"middle\"><A HREF=\"admin.php?section=$name\"><IMG SRC=\"images/admin-$name.png\" BORDER=\"0\"></A><BR>$name</TD>\n";
+}
+
+function admin_header() {
+ global $sitename, $section, $status;
+
+ ?>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+ <HTML>
+ <HEAD><TITLE><? echo $sitename; ?> administration center</TITLE></HEAD>
+ <STYLE>
+ body { font-family: helvetica, arial; }
+ h1 { font-size: 14pt; font-weight: bold; color: #006699; }
+ h2 { font-family: helvetica, arial; font-size: 12pt; font-weight: bold; }
+ h3 { font-family: helvetica, arial; font-size: 14pt; font-weight: bold; }
+ th { font-family: helvetica, arial; text-align: center; background-color: #CCCCCC; color: #885555; }
+ td { font-family: helvetica, arial; }
+ </STYLE>
+ <BODY BGCOLOR="#FFFFFF" LINK="#006699" VLINK="#004499" ALINK="#FF0000">
+ <TABLE BORDER="0" CELLPADDING="0" CELLSPACING="2" WIDTH="780">
+ <TR><TD COLSPAN="10"><H1><? echo "$sitename"; ?> administration center</H1></TD></TR>
+ <TR><TD BGCOLOR="#000000" COLSPAN="10" WIDTH="100%"><IMG SRC="images/pixel.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR>
+ <TR>
+ <?
+ admin_icon("stories");
+ admin_icon("comments");
+ admin_icon("diaries");
+ admin_icon("accounts");
+ admin_icon("misc");
+ admin_icon("bans");
+ admin_icon("logs");
+ admin_icon("stats");
+ admin_icon("info");
+ admin_icon("home");
+ ?>
+ </TR>
+ <TR><TD BGCOLOR="#000000" COLSPAN="10" WIDTH="100%"><IMG SRC="images/pixel.gif" WIDTH="1" HEIGHT="0" ALT=""></TD></TR>
+ <TR><TD COLSPAN="10">&nbsp;</TD></TR>
+ <?
+ if ($status) {
+ ?>
+ <TR><TD COLSPAN="10"><BIG><B>status:</B> <? echo $status; ?></BIG></TD></TR>
+ <TR><TD COLSPAN="10">&nbsp;</TD></TR>
+ <?
+ }
+ ?>
+ <TR>
+ <TD COLSPAN="10">
+ <?
+}
+
+function admin_box($title, $body) {
+ print "<TABLE BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"2\" WIDTH=\"100%\">\n";
+ print " <TR><TD><FONT COLOR=\"#83997A\"><B>$title</B></A></TD></TR>\n";
+ print " <TR><TD BGCOLOR=\"#000000\" WIDTH=\"100%\"><IMG SRC=\"images/pixel.gif\" WIDTH=\"1\" HEIGHT=\"0\" ALT=\"\"></TD></TR>\n";
+ print " <TR><TD>&nbsp;</TD></TR>\n";
+ print " <TR><TD>$body</TD></TR>\n";
+ print "</TABLE>\n";
+ print "<BR><BR>\n";
+}
+
+function admin_footer() {
+ ?>
+ </TD>
+ </TR>
+ </TABLE>
+ </BODY>
+ </HTML>
+ <?
+}
+
+?> \ No newline at end of file
diff --git a/includes/backend.inc b/includes/backend.inc
new file mode 100644
index 000000000..30f39c942
--- /dev/null
+++ b/includes/backend.inc
@@ -0,0 +1,241 @@
+<?
+
+include "includes/function.inc";
+
+class backend {
+
+ // Channel properties:
+ var $id;
+ var $url;
+ var $site;
+ var $file;
+ var $contact;
+ var $timestamp;
+
+ // Contains the raw rdf/rss/xml file:
+ var $data;
+
+ // Contains the parsed rdf/rss/xml file:
+ var $headlines = array(); // latest headlines
+
+
+ #####
+ # Syntax.......: backend(...);
+ # Description..: Constructor - initializes the internal variables.
+ #
+ function backend($id, $site, $url, $file, $contact, $timout = 1800) {
+ ### Get channel info:
+ $result = db_query("SELECT * FROM channel WHERE id = '$id' OR site = '$site'");
+
+ if ($channel = db_fetch_object($result)) {
+ ### Initialize internal variables:
+ $this->id = $channel->id;
+ $this->site = $channel->site;
+ $this->file = $channel->file;
+ $this->url = $channel->url;
+ $this->contact = $channel->contact;
+ $this->timestamp = $channel->timestamp;
+
+ ### Check to see whether we have to update our headlines first:
+ if (time() - $this->timestamp > $timout) $this->url2sql();
+
+ ### Read headlines:
+ $result = db_query("SELECT * FROM headlines WHERE id = $this->id ORDER BY number");
+ while ($headline = db_fetch_object($result)) {
+ array_push($this->headlines, "<A HREF=\"$headline->link\">$headline->title</A>");
+ }
+
+ }
+ else {
+ $this->site = $site;
+ $this->url = $url;
+ $this->file = $file;
+ $this->contact = $contact;
+ }
+ }
+
+ #####
+ # Syntax.......: rdf2sql(optional timout value in seconds);
+ # Description..: Reads a RDF file from a server, parses it and inserts
+ # the fresh data in a MySQL table.
+ #
+ function rdf2sql($timout = 10) {
+ if ($this->file) {
+ ### Decode URL:
+ $url = parse_url($this->file);
+ $host = $url[host];
+ $port = $url[port] ? $url[port] : 80;
+ $path = $url[path];
+
+ // print "<PRE><B>Debug:</B> $url - $host - $port - $path</PRE>";
+
+ ### Retrieve data from website:
+ $fp = fsockopen($host, $port, &$errno, &$errstr, $timout);
+
+ if ($fp) {
+ ### Get data from URL:
+ fputs($fp, "GET $path HTTP/1.0\n");
+ fputs($fp, "User-Agent: headline grabber\n");
+ fputs($fp, "Host: ". $host ."\n");
+ fputs($fp, "Accept: */*\n\n");
+
+ while(!feof($fp)) $data .= fgets($fp, 128);
+
+ // print "<PRE>$data</PRE><HR>";
+
+ if (strstr($data, "200 OK")) {
+
+ ### Remove existing entries:
+ $result = db_query("DELETE FROM headlines WHERE id = $this->id");
+
+ ### Strip all 'junk':
+ $data = ereg_replace("<?xml.*/image>", "", $data);
+ $data = ereg_replace("</rdf.*", "", $data);
+ $data = chop($data);
+
+ ### Iterating through our data processing each entry/item:
+ $items = explode("</item>", $data);
+ $number = 0;
+
+ for (reset($items); $item = current($items); next($items)) {
+ ### Extract data:
+ $link = ereg_replace(".*<link>", "", $item);
+ $link = ereg_replace("</link>.*", "", $link);
+ $title = ereg_replace(".*<title>", "", $item);
+ $title = ereg_replace("</title>.*", "", $title);
+
+ ### Clean headlines:
+ $title = stripslashes(fixquotes($title));
+
+ ### Count the number of stories:
+ $number += 1;
+
+ ### Insert item in database:
+ $result = db_query("INSERT INTO headlines (id, title, link, number) VALUES('$this->id', '$title', '$link', '$number')");
+ }
+
+ ### Mark channels as being updated:
+ $result = db_query("UPDATE channel SET timestamp = '". time() ."' WHERE id = $this->id");
+ $this->timestamp = time();
+ }
+ else print "<HR>RDF parser: 404 error?<BR><BR><PRE>$data</PRE><HR>";
+ }
+ }
+ }
+
+
+ #####
+ # Syntax.......: rss2sql(optional timout value in seconds);
+ # Description..: Reads a RSS file from a server, parses it and inserts
+ # the fresh data in a MySQL table.
+ #
+ function rss2sql($timout = 10) {
+ print "backend->rss2sql : TODO<BR>";
+ }
+
+
+ #####
+ # Syntax.......: xml2sql(optional timout value in seconds);
+ # Description..: Reads a XML file from a server, parses it and inserts
+ # the fresh data in a MySQL table.
+ #
+ function xml2sql($timout = 10) {
+ print "backend->xml2sql : TODO<BR>";
+ }
+
+
+ #####
+ # Syntax.......: url2sql(optional timout value in seconds);
+ # Description..: Generic function to fetch fresh headlines. It checks whether
+ # we are dealing with a remote RDF, RSS or XML file and calls
+ # the appropriate function to fetch the headline. The function
+ # is an abstraction towards the programmer as he doesn't need
+ # to know with what file extension we are dealing.
+ #
+ function url2sql($timout = 10) {
+ if (strstr($this->file, ".rdf")) $this->rdf2sql($timout);
+ if (strstr($this->file, ".rss")) $this->rss2sql($timout);
+ if (strstr($this->file, ".xml")) $this->xml2sql($timout);
+ }
+
+
+ #####
+ # Syntax.......:
+ # Description..:
+ #
+ function displayHeadlines($timout = 1800) {
+ global $theme;
+
+ ### Get channel info:
+ $result = db_query("SELECT * FROM channel WHERE site = '$this->site'");
+
+ if ($this->id) {
+
+ ### Check to see whether we have to update our headlines first:
+ if (time() - $this->timestamp > $timout) $this->url2sql();
+
+ ### Grab headlines from database:
+ $result = db_query("SELECT * FROM headlines WHERE id = $this->id ORDER BY number");
+ while ($headline = db_fetch_object($result)) {
+ $content .= "<LI><A HREF=\"$headline->link\">$headline->title</A></LI>";
+ }
+ ### Add timestamp:
+ $update = round((time() - $this->timestamp) / 60);
+ $content .= "<P ALIGN=\"right\">[ <A HREF=\"backend.php?op=reset&site=$this->site\"><FONT COLOR=\"$theme->hlcolor2\">reset</FONT></A> | updated $update min. ago ]</P>";
+
+ ### Display box:
+ $theme->box("$this->site", $content);
+ }
+ else print "<P>Warning: something whiched happened: specified channel could not be found in database.</P>";
+ }
+
+
+ #####
+ # Syntax.......: add()
+ # Description..: Adds this backend to the database.
+ #
+ function add() {
+ ### Add channel:
+ $result = db_query("INSERT INTO channel (site, file, url, contact, timestamp) VALUES ('$this->site', '$this->file', '$this->url', '$this->contact', 42)");
+ }
+
+
+ #####
+ # Syntax.......: delete()
+ # Description..: Deletes this backend
+ #
+ function delete() {
+ ### Delete channel:
+ $result = db_query("DELETE FROM channel WHERE id = $this->id");
+
+ ### Delete headlines:
+ $result = db_query("DELETE FROM headlines WHERE id = $this->id");
+ }
+
+ #####
+ # Syntax.......: refresh()
+ # Description..: Deletes all headlines associated with this backend.
+ #
+ function refresh() {
+ ### Delete headlines:
+ $result = db_query("DELETE FROM headlines WHERE id = $this->id");
+
+ ### Mark channel as invalid to enforce an update:
+ $result = db_query("UPDATE channel SET timestamp = 42 WHERE id = $this->id");
+ }
+
+ #####
+ # Syntax.......: dump()
+ # Description..: Dumps the content of this class to screen.
+ #
+ function dump() {
+ print "<B>Dump backend:</B><BR>";
+ print "Id: $this->id<BR>";
+ print "Site: $this->site<BR>";
+ print "URL: $this->url<BR>";
+ print "File: $this->file<BR>";
+ print "Contact: $this->contact<BR>";
+ }
+}
+
+?>
diff --git a/includes/ban.inc b/includes/ban.inc
new file mode 100644
index 000000000..1d9fa095e
--- /dev/null
+++ b/includes/ban.inc
@@ -0,0 +1,52 @@
+<?
+
+$type2index = array("addresses" => 0x01,
+ "profanity" => 0x02,
+ "hostnames" => 0x03,
+ "usernames" => 0x04);
+$index2type = array(0x01 => "addresses",
+ 0x02 => "profanity",
+ 0x03 => "hostnames",
+ 0x04 => "usernames");
+
+function ban_match($mask, $category) {
+ ### Perform query:
+ $result = db_query("SELECT * FROM bans WHERE type = $category AND LOWER('$mask') LIKE LOWER(mask)");
+
+ ### Return result:
+ return db_fetch_object($result);
+}
+
+function ban_add($mask, $category, $reason, $message = "") {
+ global $index2type;
+
+ if (empty($mask)) {
+ $message = "Failed: empty banmasks are not allowed.<P>\n";
+ }
+ else if ($ban = db_fetch_object(db_query("SELECT * FROM bans WHERE type = $category AND '$mask' LIKE mask"))) {
+ $message = "Failed: ban is already matched by '$ban->mask'.<P>\n";
+ }
+ else {
+ $result = db_query("INSERT INTO bans (mask, type, reason, timestamp) VALUES ('$mask', '$category', '$reason', '". time() ."')");
+ $message = "Added new ban with mask `$mask'.<P>\n";
+
+ ### Add log entry:
+ watchdog(1, "added new ban `$mask' to category `". $index2type[$category] ."' with reason `$reason'.");
+ }
+}
+
+function ban_delete($id) {
+ global $index2type;
+
+ $result = db_query("SELECT * FROM bans WHERE id = $id");
+
+ if ($ban = db_fetch_object($result)) {
+ ### Perform query:
+ $result = db_query("DELETE FROM bans WHERE id = $id");
+
+ ### Deleted log entry:
+ watchdog(1, "removed ban `$ban->mask' from category `". $index2type[$ban->type] ."'.");
+ }
+}
+
+?>
diff --git a/includes/calendar.inc b/includes/calendar.inc
new file mode 100644
index 000000000..561363c33
--- /dev/null
+++ b/includes/calendar.inc
@@ -0,0 +1,76 @@
+<?
+
+class calendar {
+ var $date;
+
+ function calendar($date) {
+ $this->date = $date;
+ }
+
+ function display() {
+ global $PHP_SELF;
+
+ ### Extract information from the given date:
+ $month = date("n", $this->date);
+ $year = date("Y", $this->date);
+ $day = date("d", $this->date);
+
+ ### Extract first day of the month:
+ $first = date("w", mktime(0, 0, 0, $month, 1, $year));
+
+ ### Extract last day of the month:
+ $last = date("t", mktime(0, 0, 0, $month, 1, $year));
+
+ ### Calculate previous and next months dates:
+ $prev = mktime(0, 0, 0, $month - 1, $day, $year);
+ $next = mktime(0, 0, 0, $month + 1, $day, $year);
+
+ ### Generate calendar header:
+ $output .= "\n<!-- calendar -->\n";
+ $output .= "<TABLE WIDTH=\"100%\" BORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"1\">\n";
+ $output .= " <TR><TD ALIGN=\"center\" COLSPAN=\"7\"><SMALL><A HREF=\"$PHP_SELF?date=$prev\">&lt;</A> &nbsp; ". date("F Y", $this->date) ." &nbsp; <A HREF=\"$PHP_SELF?date=$next\">&gt;</A></SMALL></TD></TR>\n";
+ $output .= " <TR><TD ALIGN=\"center\"><SMALL>S</SMALL></TD><TD ALIGN=\"center\"><SMALL>M</SMALL></TD><TD ALIGN=\"center\"><SMALL>T</SMALL></TD><TD ALIGN=\"center\"><SMALL>W</SMALL></TD><TD ALIGN=\"center\"><SMALL>T</SMALL></TD><TD ALIGN=\"center\"><SMALL>F</SMALL></TD><TD ALIGN=\"center\"><SMALL>S</SMALL></TD></TR>\n";
+
+ ### Initialize temporary variables:
+ $nday = 1;
+ $sday = $first;
+
+ ### Loop through all the days of the month:
+ while ($nday <= $last) {
+ ### Set up blank days for first week of the month:
+ if ($first) {
+ $output .= " <TR><TD COLSPAN=\"$first\">&nbsp</TD>\n";
+ $first = 0;
+ }
+
+ ### Start every week on a new line:
+ if ($sday == 0) $output .= " <TR>\n";
+
+ ### Print one cell:
+ $date = mktime(24, 0, 0, $month, $nday, $year);
+ if ($nday == $day) $output .= " <TD ALIGN=\"center\"><SMALL><B>$nday</B></SMALL></TD>\n";
+ else if ($date > time()) $output .= " <TD ALIGN=\"center\"><SMALL>$nday</SMALL></TD>\n";
+ else $output .= " <TD ALIGN=\"center\"><SMALL><A HREF=\"$PHP_SELF?date=$date\" STYLE=\"text-decoration: none;\">$nday</A></SMALL></TD>\n";
+
+ ### Start every week on a new line:
+ if ($sday == 6) $output .= " </TR>\n";
+
+ ### Update temporary variables:
+ $sday++;
+ $sday = $sday % 7;
+ $nday++;
+ }
+
+ ### Complete the calendar:
+ if ($sday) {
+ $end = 7 - $sday;
+ $output .= " <TD COLSPAN=\"$end\">&nbsp;</TD>\n </TR>\n";
+ }
+ $output .= "</TABLE>\n\n";
+
+ ### Return calendar:
+ return $output;
+ }
+}
+
+?>
diff --git a/includes/config.inc b/includes/config.inc
new file mode 100644
index 000000000..4d54bca98
--- /dev/null
+++ b/includes/config.inc
@@ -0,0 +1,115 @@
+<?
+
+#
+# MySQL settings:
+#
+
+$dbhost = "zind.net";
+$dbuname = "dries";
+$dbpass = "Abc123";
+$dbname = "dries";
+
+#$dbhost = "localhost";
+#$dbuname = "dries";
+#$dbpass = "oakley";
+#$dbname = "dries";
+
+#
+# Name of the site
+#
+$sitename = "drop.org";
+
+#
+# Contact information:
+# The contact information will be used to send out automated mails
+# to users, account holders or visitors.
+$contact_email = "droppies@zind.net";
+$contact_signature = "Kind regards,\n\n-- the drop.org crew\nhttp://beta.drop.org/";
+
+#
+# Notify:
+# Set to '1' to receive an e-mail when news has been submitted
+# through submit.php
+#
+$notify = 0;
+
+#
+# Notify information:
+# The notify information will be used to send out automated mails
+# for internal purpose.
+#
+$notify_email = $contact_email;
+$notify_subject = "submission: ";
+$notify_message = "New submission: '$subject'\n\n$story";
+$notify_from = "droppies@zind.net";
+
+#
+# Comment meta reasons:
+#
+$comment_votes = array("none" => "none", "-1" => "-1", "0" => "0", "+1" => "+ 1", "+2" => "+ 2", "+3" => "+ 3", "+4" => "+ 4", "+5" => "+ 5");
+
+#
+# Categories:
+#
+$categories = array("Announcements",
+ "Arts & Humanities",
+ "Business & Economy",
+ "Coding & Webdesign",
+ "Computers & Internet",
+ "Drop.org",
+ "Entertainment",
+ "Freedom",
+ "Government",
+ "News & Media",
+ "Science",
+ "Society & Culture");
+
+#
+# Allowed HTML tags:
+#
+$allowed_html = "<A><B><BR><DD><DL><DT><EM><HR><I><IL><SMALL><OL><U><UL>";
+
+#
+# Name of the 'anonymous' user account:
+#
+$anonymous = "Anonymous Chicken";
+
+
+#
+# Themes:
+#
+$themes = array("Marvin" => array(
+ "themes/marvin/marvin.theme",
+ "white, simple"),
+ "Zaphod" => array(
+ "themes/zaphod/zaphod.theme",
+ "yellow, simple"),
+ "UnConeD" => array(
+ "themes/unconed/unconed.theme",
+ "gray, flashy"));
+
+#
+# Submission moderation votes:
+# changing $submission_votes will affect the integrity of your
+# database. In short, the database field user.history will
+# become invalid, and will need to be reset! Please, do not
+# change this setting unless you have an empty database or
+# unless you know what you are doing.
+$submission_votes = array("neutral (+0)" => "+ 0",
+ "post it (+1)" => "+ 1",
+ "dump it (-1)" => "- 1");
+
+#
+# Submission moderation thresholds:
+#
+$submission_post_threshold = "2";
+$submission_dump_threshold = "-2";
+
+#
+# Debug flag:
+# Set to '1' if you are using Windows so the engine won't try
+# to send out mails and such. When using Unix or Linux, set
+# to '0'
+$mail = 0;
+
+?> \ No newline at end of file
diff --git a/includes/database.inc b/includes/database.inc
new file mode 100644
index 000000000..3721fbd65
--- /dev/null
+++ b/includes/database.inc
@@ -0,0 +1,62 @@
+<?
+/*
+ * These functions build the foundation for accessing the database:
+ * it is a general database abstraction layer suitable for several
+ * databases. Currently, the only supported database is MySQL but
+ * it should be straightforward to port it to any other database:
+ * just adjust the handlers to your needs.
+ */
+
+function db_connect() {
+ global $dbhost, $dbuname, $dbpass, $dbname;
+ mysql_pconnect($dbhost, $dbuname, $dbpass) or die(mysql_Error());
+ mysql_select_db($dbname) or die ("Unable to select database");
+ // NOTE: we are using a persistent connection!
+}
+
+function db_insert($query, $debug = false) {
+ // NOTE:
+ // add spam- and/or flood-checks
+
+ db_query($query, $debug);
+}
+
+function db_query($query, $debug = false) {
+ ### perform query:
+ $qid = mysql_query($query);
+
+ ### debug output (if required):
+ if ($debug || empty($qid)) {
+ print "<PRE>query: ". htmlspecialchars($query) ."<BR>error message: ". mysql_error() ."</PRE>";
+ }
+
+ ### return result from query:
+ return $qid;
+}
+
+function db_fetch_object($qid) {
+ if ($qid) return mysql_fetch_object($qid);
+}
+
+function db_num_rows($qid) {
+ if ($qid) return mysql_num_rows($qid);
+}
+
+function db_fetch_row($qid) {
+ if ($qid) return mysql_fetch_row($qid);
+}
+
+function db_fetch_array($qid) {
+ if ($qid) return mysql_fetch_array($qid);
+}
+
+function db_result($qid, $field) {
+ if ($qid) return mysql_result($qid, $field);
+}
+
+#
+# Automatically connect to database:
+#
+db_connect();
+
+?> \ No newline at end of file
diff --git a/includes/function.inc b/includes/function.inc
new file mode 100644
index 000000000..de2dbaac0
--- /dev/null
+++ b/includes/function.inc
@@ -0,0 +1,106 @@
+<?
+
+include "includes/database.inc";
+include "includes/log.inc";
+
+function id2story($id) {
+ ### Perform query:
+ $result = db_query("SELECT s.*, u.userid FROM stories s LEFT JOIN users u ON s.author = u.id WHERE s.id = $id");
+ return db_fetch_object($result);
+}
+
+function dbsave($dbase, $data, $id=0) {
+ foreach ($data as $key=>$value) {
+ if ($key == "passwd") { $query .= "$key=PASSWORD('". addslashes($value) ."'), "; }
+ else { $query .= "$key='". addslashes($value) ."', "; }
+ }
+ $query = substr($query, 0, -2);
+
+ if (!empty($id)) { db_query("UPDATE $dbase SET $query WHERE id=$id") or die(mysql_error()); return $id; }
+ else { db_query("INSERT INTO $dbase SET $query") or die(mysql_error()); return mysql_insert_id(); }
+}
+
+function load_theme() {
+ global $user, $themes;
+
+ if ($user->theme && file_exists($themes[$user->theme][0])) {
+ include $themes[$user->theme][0];
+ }
+ else {
+ include $themes[key($themes)][0];
+ }
+
+ return new Theme();
+}
+
+function check_input($message) {
+ return str_replace("\"", "&quot;", stripslashes($message));
+}
+
+function check_output($message) {
+ global $allowed_html;
+ return nl2br(strip_tags(stripslashes($message), $allowed_html));
+}
+
+function discussion_num_replies($id, $count = 0) {
+ $result = db_query("SELECT COUNT(cid) FROM comments WHERE pid = $id");
+ return ($result) ? mysql_result($result, 0) : 0;
+}
+
+function format_plural($count, $one, $more) {
+ return ($count == 1) ? "$count $one" : "$count $more";
+}
+
+function format_date($timestamp, $type = "medium") {
+ switch ($type) {
+ case "small":
+ $date = date("D, m/d/y - H:i", $timestamp);
+ break;
+ case "medium":
+ $date = date("l, m/d/Y - H:i", $timestamp);
+ break;
+ case "large":
+ $date = date("D, M d, Y - H:i", $timestamp);
+ break;
+ case "extra large":
+ $date = date("l, F dS, Y - H:i", $timestamp);
+ break;
+ default:
+ $date = date("D, M d, Y - H:i", $timestamp);
+ }
+ return $date;
+}
+
+function format_data($field, $replacement = "<I>n/a</I>") {
+ return ($field) ? $field : $replacement;
+}
+
+function format_username($username, $admin = 0) {
+ if ($username) return ($admin) ? "<A HREF=\"admin.php?section=accounts&op=view&name=$username\">$username</A>" : "<A HREF=\"account.php?op=view&name=$username\">$username</A>";
+ else { global $anonymous; return $anonymous; }
+}
+
+function format_email_address($address) {
+ return ($address) ? "<A HREF=\"mailto:$address\">$address</A>" : format_data($address);
+}
+
+function format_url($address, $description = "") {
+ // POSSIBLE EXTENSIONS:
+ // 1. add `http://' in case it's missing.
+ // 2. add a trailing `/' in case it's missing.
+ // 3. remove any parameters in the URI.
+ $description = ($description) ? $description : $address;
+ return ($address) ? "<A HREF=\"$address\">$description</A>" : format_data($address);
+}
+
+function format_story_link($story, $subject = "") {
+ global $user;
+ $output .= "<A HREF=\"discussion.php?id=$story->id";
+ $output .= ($user->umode) ? "&mode=$user->umode" : "&mode=threaded";
+ $output .= ($user->uorder) ? "&order=$user->uorder" : "&order=0";
+ $output .= ($user->thold) ? "&thold=$user->thold" : "&thold=0";
+ $output .= ($subject) ? "\">$subject</A>" : "\">$story->subject</A>";
+ return $output;
+}
+
+?>
diff --git a/includes/log.inc b/includes/log.inc
new file mode 100644
index 000000000..2883a8d84
--- /dev/null
+++ b/includes/log.inc
@@ -0,0 +1,17 @@
+<?
+
+
+function watchdog($level, $message) {
+ global $user;
+
+ ### Perform query to add new log entry:
+ db_query("INSERT INTO logs (level, timestamp, user, message, hostname) VALUES ($level, '". time() ."', '". addslashes($user->id) ."', '". addslashes($message) ."', '". getenv("REMOTE_ADDR") ."')");
+
+ ### Periodically remove old log entries:
+ if (time() % 20 == 0) {
+ $timestamp = time() - 1209600; // 2 weeks
+ db_query("DELETE FROM logs WHERE timestamp < $timestamp");
+ }
+}
+
+?>
diff --git a/includes/submission.inc b/includes/submission.inc
new file mode 100644
index 000000000..376c84059
--- /dev/null
+++ b/includes/submission.inc
@@ -0,0 +1,35 @@
+<?
+
+function submission_count() {
+ $result = db_query("SELECT COUNT(id) FROM stories WHERE status = 1");
+ return ($result) ? mysql_result($result, 0) : 0;
+}
+
+function submission_score($id) {
+ $result = db_query("SELECT score FROM stories WHERE id = $id");
+ return ($result) ? mysql_result($result, 0) : 0;
+}
+
+function submission_vote($id, $vote, $comment) {
+ global $user, $submission_post_threshold, $submission_dump_threshold;
+
+ if (!user_getHistory($user->history, "s$id")) {
+ ### Update submission's score- and votes-field:
+ db_query("UPDATE stories SET score = score $vote, votes = votes + 1 WHERE id = $id");
+
+ ### Update the comments (if required):
+ if ($comment) db_query("INSERT INTO comments (sid, author, subject, comment, hostname, timestamp) VALUES($id, $user->id, '". addslashes(substr($comment, 0, 29)) ." ...', '". addslashes($comment) ."', '". getenv("REMOTE_ADDR") ."', '". time() ."')");
+
+ ### Update user's history record:
+ user_setHistory($user, "s$id", $vote); // s = submission
+
+ ### Update story table (if required):
+ $result = db_query("SELECT * FROM stories WHERE id = $id");
+ if ($submission = db_fetch_object($result)) {
+ if ($submission->score >= $submission_post_threshold) db_query("UPDATE stories SET status = 2, timestamp = '". time() ."' WHERE id = $id");
+ if ($submission->score <= $submission_dump_threshold) db_query("UPDATE stories SET status = 0, timestamp = '". time() ."' WHERE id = $id");
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/includes/template.inc b/includes/template.inc
new file mode 100644
index 000000000..08d469d94
--- /dev/null
+++ b/includes/template.inc
@@ -0,0 +1,128 @@
+<?
+include "includes/user.inc";
+
+function display_morelink($theme, $story) {
+ return ($story->article) ? "[ <A HREF=\"discussion.php?id=$story->id\"><FONT COLOR=\"$theme->hlcolor2\"><B>read more</B></FONT></A> | ". strlen($story->article) ." bytes | <A HREF=\"discussion.php?id=$story->id\"><FONT COLOR=\"$theme->hlcolor2\">". format_plural($story->comments, "comment", "comments") ."</FONT></A> ]" : "[ <A HREF=\"discussion.php?id=$story->id\"><FONT COLOR=\"$theme->hlcolor2\">". format_plural($story->comments, "comment", "comments") ."</FONT></A> ]";
+}
+
+function display_moderation_results($theme, $story) {
+ global $user;
+
+ if ($user->id && $story->id && $vote = user_getHistory($user->history, "s$story->id")) {
+ $output .= "<P><B>You voted `$vote'.</B></P>\n";
+ $output .= "<P>\n";
+ $output .= "<B>Other people voted:</B><BR>\n";
+
+ $result = db_query("SELECT * FROM users WHERE history LIKE '%s$story->id%'");
+ while ($account = db_fetch_object($result)) {
+ $output .= "". format_username($account->userid) ." voted `". user_getHistory($account->history, "s$story->id") ."'.<BR>";
+ }
+
+ $theme->box("Moderation results", $output);
+ }
+}
+
+function display_related_links($theme, $story) {
+ ### Parse story for <A HREF="">-tags:
+ $text = stripslashes("$story->abstract $story->updates $story->article");
+ while ($text = stristr($text, "<A HREF=")) {
+ $link = substr($text, 0, strpos(strtolower($text), "</a>") + 4);
+ $text = stristr($text, "</A>");
+ if (!stristr($link, "mailto:")) $content .= "<LI>$link</LI>";
+ }
+
+ ### Stories in the same category:
+ $content .= " <LI>More about <A HREF=\"search.php?category=". urlencode($story->category) ."\">$story->category</A>.</LI>";
+
+ ### Stories from the same author:
+ if ($story->userid) $content .= " <LI>Also by <A HREF=\"search.php?author=". urlencode($story->userid) ."\">$story->userid</A>.</LI>";
+
+ $theme->box("Related links", $content);
+}
+
+function display_old_headlines($theme, $num = 10) {
+ global $user;
+
+ if ($user->storynum) $result = db_query("SELECT id, subject, timestamp FROM stories WHERE status = 2 ORDER BY timestamp DESC LIMIT $user->storynum, $num");
+ else $result = db_query("SELECT id, subject, timestamp FROM stories WHERE status = 2 ORDER BY timestamp DESC LIMIT $num, $num");
+
+ while ($story = db_fetch_object($result)) {
+ if ($time != date("F jS", $story->timestamp)) {
+ $content .= "<P><B>". date("l, M jS", $story->timestamp) ."</B></P>\n";
+ $time = date("F jS", $story->timestamp);
+ }
+ $content .= "<LI>". format_story_link($story) ."</LI>\n";
+ }
+ $content .= "<P ALIGN=\"right\">[ <A HREF=\"search.php\"><FONT COLOR=\"$theme->hlcolor2\">more</FONT></A> ]</P>";
+
+ $theme->box("Older headlines", $content);
+}
+
+function display_comment_moderation($id, $author, $score, $votes) {
+ global $user, $comment_votes;
+
+ if ($user && $user->userid != $author && !user_getHistory($user->history, "c$id")) {
+ $output .= "<SELECT NAME=\"moderate[$id]\">\n";
+ foreach ($comment_votes as $key=>$value) $output .= " <OPTION VALUE=\"$value\">$key</OPTION>\n";
+ $output .= "</SELECT>\n";
+ }
+ else {
+ $output .= "<TABLE BORDER=\"0\" CELLSPACING=\"1\" CELLPADDING=\"0\"><TR><TD>score:</TD><TD>$score</TD></TR><TR><TD>votes:</TD><TD>$votes</TR></TABLE>";
+ }
+
+ print $output;
+}
+
+function display_new_diaries($theme, $num = 20) {
+ $result = db_query("SELECT u.userid, d.timestamp FROM diaries d LEFT JOIN users u ON d.author = u.id ORDER BY timestamp DESC LIMIT $num");
+
+ while ($diary = db_fetch_object($result)) {
+ if ($time != date("F jS", $diary->timestamp)) {
+ $content .= "<P><B>". date("l, M jS", $diary->timestamp) ."</B></P>\n";
+ $time = date("F jS", $diary->timestamp);
+ }
+ $content .= "<LI><A HREF=\"diary.php?op=view&name=$diary->userid\">$diary->userid</A></LI>\n";
+ }
+ $content .= "<P ALIGN=\"right\">[ <A HREF=\"diary.php\"><FONT COLOR=\"$theme->hlcolor2\">more</FONT></A> ]</P>";
+ $theme->box("Recent diary entries", $content);
+}
+
+function display_new_headlines($theme, $num = 10) {
+ global $user;
+
+ $content = "";
+ $result = db_query("SELECT id, subject FROM stories WHERE status = 2 ORDER BY id DESC LIMIT $num");
+ while ($story = db_fetch_object($result)) $content .= "<LI>". format_story_link($story) ."</LI>\n";
+ $content .= "<P ALIGN=\"right\">[ <A HREF=\"search.php\"><FONT COLOR=\"$theme->hlcolor2\">more</FONT></A> ]</P>";
+ $theme->box("Latest headlines", $content);
+}
+
+function display_calendar($theme, $date) {
+ include "includes/calendar.inc";
+ $calendar = new calendar($date);
+ $theme->box("Browse archives", $calendar->display());
+}
+
+function display_account($theme) {
+ global $user;
+
+ if ($user && $user->userid) {
+ function submission_number() {
+ $result = db_query("SELECT COUNT(id) FROM stories WHERE status = 1");
+ return ($result) ? mysql_result($result, 0) : 0;
+ }
+
+ ### Display account settings:
+ $content = "<LI><A HREF=\"account.php\">view your information</A></LI>";
+ $content .= "<LI><A HREF=\"account.php?op=user\">edit your information</A></LI>";
+ $content .= "<LI><A HREF=\"account.php?op=page\">customize your page</A></LI>";
+ $content .= "<LI><A HREF=\"account.php?op=discussion\">track your comments</A></LI>";
+ $content .= "<LI><A HREF=\"submission.php\">moderate submissions</A> (<FONT COLOR=\"red\">". submission_number() ."</FONT>)</LI>";
+ $content .= "<LI><A HREF=\"diary.php?op=view&name=$user->userid\">update your diary</A></LI>";
+ $content .= "<LI><A HREF=\"account.php?op=logout\">logout</A></LI>";
+
+ $theme->box("$user->userid's account", "$content");
+ }
+}
+
+?>
diff --git a/includes/theme.inc b/includes/theme.inc
new file mode 100644
index 000000000..93c6b62ff
--- /dev/null
+++ b/includes/theme.inc
@@ -0,0 +1,11 @@
+<?
+
+include "includes/config.inc";
+include "includes/function.inc";
+include "includes/template.inc";
+
+global $user;
+
+$theme = load_theme();
+
+?> \ No newline at end of file
diff --git a/includes/user.inc b/includes/user.inc
new file mode 100644
index 000000000..115c940c0
--- /dev/null
+++ b/includes/user.inc
@@ -0,0 +1,83 @@
+<?
+
+$access = array("Administrator" => 0x00000001,
+ "User manager" => 0x00000002,
+ "News manager" => 0x00000004);
+
+class User {
+ function User($userid, $passwd="") {
+ $result = db_query("SELECT * FROM users WHERE LOWER(userid) = LOWER('$userid') && passwd = PASSWORD('$passwd') && STATUS = 0");
+ if (db_num_rows($result) == 1) {
+ foreach (db_fetch_row($result) as $key=>$value) { $field = mysql_field_name($result, $key); $this->$field = stripslashes($value); $this->field[] = $field; }
+ }
+ }
+}
+
+function user_save() {
+ global $user;
+ ### Compose query to update user record:
+}
+
+function user_rehash() {
+ global $user;
+ $result = db_query("SELECT * FROM users WHERE id=$user->id");
+ if (db_num_rows($result) == 1) {
+ foreach (db_fetch_array($result) as $key=>$value) { $user->$key = stripslashes($value); }
+ }
+}
+
+function user_valid($access = 0) {
+ global $user;
+ if ($user->userid) {
+ user_rehash(); // synchronisation purpose
+ $user->last_access = time();
+ $user->last_host = ($GLOBALS[REMOTE_HOST]) ? $GLOBALS[REMOTE_HOST] : $GLOBALS[REMOTE_ADDR];
+ db_query("UPDATE users SET last_access = '$user->last_access', last_host = '$user->last_host' WHERE id = $user->id");
+ if ($user->access & $access || $access == 0) return 1;
+ }
+ return 0;
+}
+
+function user_getHistory($history, $field) {
+ $data = explode(";", $history);
+ for (reset($data); current($data); next($data)) {
+ $entry = explode(":", current($data));
+ if (reset($entry) == $field) $rval = end($entry);
+ }
+ return $rval;
+}
+
+function user_setHistory(&$user, $field, $value) {
+
+ $history = $user->history;
+ if (!$value) {
+ ### remove entry:
+ $data = explode(";", $history);
+ for (reset($data); current($data); next($data)) {
+ $entry = explode(":", current($data));
+ if ($entry[0] != $field) $rval .= "$entry[0]:$entry[1];";
+ }
+ }
+ else if (strstr($history, "$field:")) {
+ ### found: update exsisting entry:
+ $data = explode(";", $history);
+ for (reset($data); current($data); next($data)) {
+ $entry = explode(":", current($data));
+ if ($entry[0] == $field) $entry[1] = $value;
+ $rval .= "$entry[0]:$entry[1];";
+ }
+ }
+ else {
+ ### not found: add new entry:
+ $rval = "$history$field:$value;";
+ }
+ $user->history = $rval;
+
+ ### save new history:
+ $query .= "UPDATE users SET ";
+ foreach ($user->field as $key=>$field) { $value = $user->$field; $query .= "$field = '". addslashes($value) ."', "; }
+ $query .= " id = $user->id WHERE id = $user->id";
+ db_query($query);
+}
+
+?>