diff -urN drupal-4.4.2/.htaccess drupal4blog/.htaccess
--- drupal-4.4.2/.htaccess	Fri Dec 19 02:53:11 2003
+++ drupal4blog/.htaccess	Sun Jul 11 22:39:19 2004
@@ -64,4 +64,4 @@
   RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
 </IfModule>
 
-# $Id: .htaccess,v 1.56 2003/12/18 18:53:11 dries Exp $
+# $Id: .htaccess,v 1.1 2004/07/11 14:39:19 jseng Exp $
diff -urN drupal-4.4.2/INSTALL.txt drupal4blog/INSTALL.txt
--- drupal-4.4.2/INSTALL.txt	Sat Feb 14 21:29:01 2004
+++ drupal4blog/INSTALL.txt	Sun Jul 11 22:39:19 2004
@@ -1,4 +1,4 @@
-// $Id: INSTALL.txt,v 1.1 2004/02/14 13:29:01 dries Exp $
+// $Id: INSTALL.txt,v 1.1 2004/07/11 14:39:19 jseng Exp $
 
 REQUIREMENTS
 ------------
diff -urN drupal-4.4.2/UPGRADE.txt drupal4blog/UPGRADE.txt
--- drupal-4.4.2/UPGRADE.txt	Thu Jan  1 07:30:00 1970
+++ drupal4blog/UPGRADE.txt	Sun Jul 11 22:39:19 2004
@@ -0,0 +1,40 @@
+// $Id: UPGRADE.txt,v 1.1 2004/07/11 14:39:19 jseng Exp $
+
+For those upgrading from 4.4.1 and 4.4.2 to Drupal for Bloggers (D4B),
+
+1) Point your browser to http://your.drupal.site/db-update.php
+
+2) Select Drupal 4.4.1 or Drupal 4.4.2 as appropriate and then click Upgrade
+
+This process will create the neccessary tables and fields for D4B. 
+It will also enable several modules and configure some common settings.
+
+What it DOES NOT do:
+
+1) It does not alter user roles and permission. 
+
+   D4B by default has
+   a) a new user role called 'blogger' with neccessary blogging permission
+   b) more user permission for anonymous user
+
+2) It enables profile.module but does not enable the fields.
+
+   D4B by default enable these fields: realname, email and homepage.
+
+3) It does not alter your theme 
+
+   D4B by default uses simple.theme
+
+4) It does not alter your block layout
+
+   D4B by default has the following blocks enabled: Blog Admin, Blogs, 
+   Calender to browse archive, Search box, Syndicate and Taxonomy
+
+----
+
+For those upgrading from previous version of D4B:
+
+1) For v0.6 and below, you need to execute db-update.php as above
+
+2) For v0.7, v0.8, v0.9, there is no change in database. So you can just
+   replace all the Drupal files and that's it.
diff -urN drupal-4.4.2/cron.php drupal4blog/cron.php
--- drupal-4.4.2/cron.php	Sat Jan  3 00:28:45 2004
+++ drupal4blog/cron.php	Sun Jul 11 22:39:19 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: cron.php,v 1.20 2004/01/02 16:28:45 dries Exp $
+// $Id: cron.php,v 1.1 2004/07/11 14:39:19 jseng Exp $
 
 include_once "includes/bootstrap.inc";
 include_once "includes/common.inc";
diff -urN drupal-4.4.2/database/database.mysql drupal4blog/database/database.mysql
--- drupal-4.4.2/database/database.mysql	Sun Feb 22 06:38:00 2004
+++ drupal4blog/database/database.mysql	Thu Jul 29 00:24:55 2004
@@ -128,6 +128,9 @@
   status tinyint(3) unsigned NOT NULL default '0',
   thread varchar(255) NOT NULL,
   users longtext,
+  name varchar(60) default NULL,
+  mail varchar(60) default NULL,
+  homepage varchar(60) default NULL,
   PRIMARY KEY  (cid),
   KEY lid (nid)
 ) TYPE=MyISAM;
@@ -301,6 +304,18 @@
 ) TYPE=MyISAM;
 
 --
+-- Table structure for table 'blog'
+--
+
+CREATE TABLE blog (
+  nid int(10) unsigned NOT NULL default '0',
+  extended longtext NOT NULL,
+  excerpt longtext NOT NULL,
+  format tinyint(2) NOT NULL default '0',
+  PRIMARY KEY  (nid)
+) TYPE=MyISAM;
+
+--
 -- Table structure for table 'page'
 --
 
@@ -390,7 +405,6 @@
 -- Table structure for table 'sessions'
 --
 
-
 CREATE TABLE sessions (
   uid int(10) unsigned NOT NULL,
   sid varchar(32) NOT NULL default '',
@@ -518,6 +532,7 @@
   status tinyint(4) NOT NULL default '0',
   timezone varchar(8) default NULL,
   language char(2) NOT NULL default '',
+  picture varchar(255) NOT NULL default '',
   init varchar(64) default '',
   data longtext,
   rid int(10) unsigned NOT NULL default '0',
@@ -537,6 +552,18 @@
 ) TYPE=MyISAM;
 
 --
+-- Table structure for table 'blogroll'
+--
+
+CREATE TABLE blogroll (
+  nid int(10) unsigned NOT NULL default '0',
+  url varchar(128) NOT NULL default '',
+  xml varchar(128) NOT NULL default '',
+  priority int(2) unsigned NOT NULL default '50',
+  PRIMARY KEY (nid)
+) TYPE=MyISAM;
+
+--
 -- Table structure for table 'vocabulary'
 --
 
@@ -570,29 +597,106 @@
 ) TYPE=MyISAM;
 
 --
+-- Table structure for table 'trackback'
+--
+
+CREATE TABLE trackback (
+  nid int(10) unsigned NOT NULL default '0',
+  pinged longtext,
+  toping longtext,
+  PRIMARY KEY  (nid)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'trackback_pingme'
+--
+
+CREATE TABLE trackback_pingme (
+  nid int(10) unsigned not null,
+  cid int (10) unsigned not null
+) TYPE=MyISAM;
+ 
+
+--
+-- Table structure for table 'subscriptions'
+--
+
+CREATE TABLE subscriptions(
+  sid      int(10) unsigned not null,
+  uid      int(10) unsigned not null,
+  stype    varchar(4) not null
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'theme_simple'
+--
+
+CREATE TABLE theme_simple(
+  id        int(10) unsigned not null default '0',
+  name      varchar(32) not null,
+  php       longtext,
+  raw       longtext,
+  PRIMARY KEY  (id, name)
+) TYPE=MyISAM;
+
+--
 -- Insert some default values
 --
 
 INSERT INTO system VALUES ('modules/admin.module','admin','module','',1,0,0);
+INSERT INTO system VALUES ('modules/archive.module','archive','module','',1,0,0);
 INSERT INTO system VALUES ('modules/block.module','block','module','',1,0,0);
 INSERT INTO system VALUES ('modules/comment.module','comment','module','',1,0,0);
 INSERT INTO system VALUES ('modules/help.module','help','module','',1,0,0);
 INSERT INTO system VALUES ('modules/node.module','node','module','',1,0,0);
-INSERT INTO system VALUES ('modules/page.module','page','module','',1,0,0);
-INSERT INTO system VALUES ('modules/story.module','story','module','',1,0,0);
+INSERT INTO system VALUES ('modules/blog.module','blog','module','',1,0,0);
+INSERT INTO system VALUES ('modules/blogadmin.module','blogadmin','module','',1,0,0);
+INSERT INTO system VALUES ('modules/ping.module','ping','module','',1,0,0);
+INSERT INTO system VALUES ('modules/search.module','search','module','',1,0,0);
 INSERT INTO system VALUES ('modules/taxonomy.module','taxonomy','module','',1,0,0);
-INSERT INTO system VALUES ('themes/xtemplate/xtemplate.theme','xtemplate','theme','Internet explorer, Netscape, Opera',1,0,0);
+INSERT INTO system VALUES ('modules/profile.module','profile','module','',1,0,0);
+INSERT INTO system VALUES ('modules/tracker.module','tracker','module','',1,0,0);
+INSERT INTO system VALUES ('modules/trackback.module','trackback','module','',1,0,0);
+INSERT INTO system VALUES ('modules/upload.module', 'upload', 'module','',1,0,0);
+INSERT INTO system VALUES ('modules/blogapi.module', 'blogapi', 'module','',1,0,0);
+INSERT INTO system VALUES ('modules/path.module', 'path', 'module','',1,0,0);
+INSERT INTO system VALUES ('modules/urlfilter.module', 'urlfilter', 'module','',1,0,0);
+INSERT INTO system VALUES ('modules/subscriptions.module', 'subscriptions', 'module','',1,0,0);
+INSERT INTO system VALUES ('modules/tag.module', 'tag', 'module','',1,0,0);
+INSERT INTO system VALUES ('modules/captcha.module', 'captcha', 'module','',1,0,0);
+
+INSERT INTO system VALUES ('themes/simple/simple.theme','simple','theme','Internet explorer, Netscape, Opera',1,0,0);
+
 INSERT INTO users (uid, name, mail, rid) VALUES ('0', '', '', '1');
 
 INSERT INTO role (rid, name) VALUES (1, 'anonymous user');
-INSERT INTO permission VALUES (1,'access content',0);
+INSERT INTO permission VALUES (1,'access comments, access content, access trackback, post trackback, post comments, post comments without approval, download files (simple), search content',0);
 
 INSERT INTO role (rid, name) VALUES (2, 'authenticated user');
-INSERT INTO permission VALUES (2,'access comments, access content, post comments, post comments without approval',0);
+INSERT INTO permission VALUES (2,'access comments, access content, access trackback, post trackback, post comments, post comments without approval, download files (simple), maintain subscriptions, search content',0);
+
+INSERT INTO role (rid, name) VALUES (3, 'blogger');
+INSERT INTO permission VALUES (3,'access comments, access content, access trackback, administer comments, post trackback, post comments, post comments without approval, create blog entry, edit own blog, download files (simple), upload files (simple), maintain files (simple), maintain subscriptions, search content',0);
+
+INSERT INTO url_alias (src, dst) VALUES ('node/feed', 'index.rdf');
 
 REPLACE variable SET name='update_start', value='s:10:"2004-02-21;"';
-REPLACE variable SET name='theme_default', value='s:9:"xtemplate";';
+REPLACE variable SET name='blogapi_engine', value='s:1:"2";';
+REPLACE variable SET name='teaser_length', value='s:4:"2000";';
+
+REPLACE variable SET name='theme_default', value='s:6:"simple";';
+
+REPLACE blocks SET module = 'archive', delta = '0', status = '1', weight='-10';
+REPLACE blocks SET module = 'taxonomy', delta = '0', status = '1', weight='-8';
+REPLACE blocks SET module = 'blogadmin', delta = '0', status = '1', weight='0';
+REPLACE blocks SET module = 'blog', delta = '0', status = '1';
+REPLACE blocks SET module = 'user', delta = '0', status = '1', weight='8';
+REPLACE blocks SET module = 'user', delta = '1', status = '1', weight='9';
+REPLACE blocks SET module = 'node', delta = '0', status = '1', weight='10';
+
+# enable real name and homepage by default
+INSERT INTO variable VALUES ( 'profile_private_fields', 'a:20:{i:0;s:1:"0";i:1;s:8:"realname";i:2;s:1:"0";i:3;s:1:"0";i:4;s:1:"0";i:5;s:1:"0";i:6;s:1:"0";i:7;s:1:"0";i:8;s:1:"0";i:9;s:1:"0";i:10;s:1:"0";i:11;s:1:"0";i:12;s:1:"0";i:13;s:1:"0";i:14;s:1:"0";i:15;s:8:"homepage";i:16;s:1:"0";i:17;s:1:"0";i:18;s:1:"0";i:19;s:1:"0";}' );
 
-REPLACE blocks SET module = 'user', delta = '0', status = '1';
-REPLACE blocks SET module = 'user', delta = '1', status = '1';
+INSERT INTO variable VALUES ( 'profile_public_fields', 'a:20:{i:0;s:1:"0";i:1;s:8:"realname";i:2;s:1:"0";i:3;s:1:"0";i:4;s:1:"0";i:5;s:1:"0";i:6;s:1:"0";i:7;s:1:"0";i:8;s:1:"0";i:9;s:1:"0";i:10;s:1:"0";i:11;s:1:"0";i:12;s:1:"0";i:13;s:1:"0";i:14;s:1:"0";i:15;s:8:"homepage";i:16;s:1:"0";i:17;s:1:"0";i:18;s:1:"0";i:19;s:1:"0";}' );
 
+INSERT INTO vocabulary VALUES (1, 'Category', 'Categories for Blog Entries', 0, 0, 1, 0, 'blog', 0);
diff -urN drupal-4.4.2/database/updates.inc drupal4blog/database/updates.inc
--- drupal-4.4.2/database/updates.inc	Wed Apr 14 02:07:02 2004
+++ drupal4blog/database/updates.inc	Sun Jul 11 22:39:19 2004
@@ -1,5 +1,5 @@
 <?php
-/* $Id: updates.inc,v 1.2.2.1 2004/04/13 18:07:02 dries Exp $ */
+/* $Id: updates.inc,v 1.1 2004/07/11 14:39:19 jseng Exp $ */
 
 // Define the various updates in an array("date : comment" => "function");
 $sql_updates = array(
diff -urN drupal-4.4.2/db-update.php drupal4blog/db-update.php
--- drupal-4.4.2/db-update.php	Thu Jan  1 07:30:00 1970
+++ drupal4blog/db-update.php	Fri Sep  3 00:23:51 2004
@@ -0,0 +1,254 @@
+<?php
+// $Id: db-update.php,v 1.1 2004/07/11 14:39:19 jseng Exp $
+/*
+** USAGE:
+**
+** - Point your browser to "http://www.site.com/db-update.php" and follow
+**   the instructions.
+**
+** - If you are not logged in as administrator, you will need to modify the
+**   statement below. Change the 1 into a 0 to disable the access check.
+**   After finishing the upgrade, open this file and change the 0 back into
+**   a 1!
+*/
+
+$dblog_version = 'Drupal for blogger v0.11';
+
+// Disable access checking?
+$access_check = 1;
+
+include_once "includes/bootstrap.inc";
+include_once "includes/common.inc";
+
+if (!ini_get("safe_mode")) {
+  set_time_limit(180);
+}
+
+$update_types = array(
+  'v0.10'   => 'Drupal for Blogger v0.10',
+  'v0.6'    => 'Drupal for Blogger v0.6',
+  '4.4.2'   => 'Drupal 4.4.2',
+  '4.4.1'   => 'Drupal 4.4.1',
+);
+
+function update_page_header($title) {
+  $output = "<html><head><title>$title</title>";
+  $output .= <<<EOF
+      <link rel="stylesheet" type="text/css" media="print" href="misc/print.css" />
+      <style type="text/css" title="layout" media="Screen">
+        @import url("misc/drupal.css");
+      </style>
+EOF;
+  $output .= "</head><body>";
+  $output .= "<div id=\"logo\"><a href=\"http://drupal.org/\"><img src=\"misc/druplicon-small.gif\" alt=\"Druplicon - Drupal logo\" title=\"Druplicon - Drupal logo\" /></a></div>";
+  $output .= "<div id=\"update\"><h1>$title</h1>";
+  return $output;
+}
+
+function update_page_footer() {
+  return "</div></body></html>";
+}
+
+function update_sql($sql) {
+  $result = db_query($sql);
+  if ($result) {
+    return array('1', nl2br(htmlentities($sql)) ." ", "<div style=\"color: green;\">OK</div>\n");
+  }
+  else {
+    return array('0', nl2br(htmlentities($sql)) ." ", "<div style=\"color: red;\">FAILED</div>\n");
+  }
+}
+
+function update_process($title,$result) {
+  print "<strong>$title</strong><br/>\n<pre>\n";
+  foreach ($result as $ret) {
+    print $ret[1];
+    print $ret[2];
+  }
+  print "</pre>\n";
+}
+
+/*** update funcs ***/
+
+function v06tov07_users() {
+  $ret = array();
+  $ret[] = update_sql("ALTER TABLE {users} ADD picture varchar(255) NOT NULL default ''");
+  return $ret;
+}
+
+function v06tov07_comment() {
+  $ret = array();
+  $ret[] = update_sql("ALTER TABLE {comments} ADD name varchar(60) default NULL");
+  $ret[] = update_sql("ALTER TABLE {comments} ADD mail varchar(60) default NULL");
+  $ret[] = update_sql("ALTER TABLE {comments} ADD homepage varchar(60) default NULL");
+
+  $results = db_query("SELECT * FROM {comments}");
+  while ($comment = db_fetch_object($results)) {
+    $anon = unserialize($comment->anon);
+    $ret[] = db_query("UPDATE {comments} SET name = '%s', mail = '%s', homepage = '%s' WHERE cid=%d",$anon->anon_name, $anon->anon_mail, $anon->anon_url,$comment->cid);
+  }
+  $ret[] .= update_sql("ALTER TABLE {comments} DROP anon");
+  return $ret;
+}
+
+function v06tov07_trackback() {
+  $ret = array();
+  $ret[] = update_sql("ALTER TABLE {tb} RENAME TO {trackback}");
+  $ret[] = update_sql("CREATE TABLE trackback_pingme (nid int(10) unsigned not null, cid int(10) unsigned not null)");
+  return $ret;
+}
+
+function v06tov07_theme_simple() {
+  $ret = array();
+  $ret[] = update_sql("CREATE TABLE theme_simple (id int(10) unsigned not null default '0', name varchar(32) not null, php longtext, raw longtext, PRIMARY KEY (id, name))");
+  return $ret;
+}
+
+function v06tov07_subscriptions() {
+  $ret = array();
+  $ret[] = update_sql("CREATE TABLE subscriptions (sid int(10) unsigned not null, uid int(10) unsigned not null, stype varchar(4) not null)");
+  return $ret;
+}
+
+function v10tov11_blogroll() {
+  $ret = array();
+  $ret[] = update_sql("CREATE TABLE blogroll ( nid int(10) unsigned NOT NULL default '0', url varchar(128) NOT NULL default '', xml varchar(128) NOT NULL default '', priority int(2) unsigned NOT NULL default '50', PRIMARY KEY (nid))");
+  return $ret;
+}
+
+/*** end d4b update funcs ***/
+function d441tov010_comments() {
+  $ret = array();
+  $ret[] = update_sql("ALTER TABLE {comments} ADD name varchar(60) default NULL");
+  $ret[] = update_sql("ALTER TABLE {comments} ADD mail varchar(60) default NULL");
+  $ret[] = update_sql("ALTER TABLE {comments} ADD homepage varchar(60) default NULL");
+  return $ret;
+}
+
+function d441tov010_blog() {
+  $ret = array();
+  $ret[] = update_sql("CREATE TABLE blog (nid int(10) unsigned NOT NULL default '0', extended longtext NOT NULL, excerpt longtext NOT NULL, format tinyint(2) NOT NULL default '0', PRIMARY KEY (nid))");
+  return $ret;
+}
+
+function d441tov010_users() {
+  $ret = array();
+  $ret[] = update_sql("ALTER TABLE {users} ADD picture varchar(255) default NULL default ''");
+  return $ret;
+}
+
+function d441tov010_trackback() {
+  $ret = array();
+  $ret[] = update_sql("CREATE TABLE trackback (nid int(10) unsigned NOT NULL default '0', pinged longtext, toping longtext, PRIMARY KEY(nid))");
+  $ret[] = update_sql("CREATE TABLE trackback_pingme (nid int(10) unsigned not null, cid int (10) unsigned not null)");
+  return $ret;
+}
+
+function d441tov010_subscriptions() {
+  $ret = array();
+  $ret[] = update_sql("CREATE TABLE subscriptions(sid int(10) unsigned not null, uid int(10) unsigned not null, stype varchar(4) not null)");
+  return $ret;
+}
+
+function d441tov010_enable_modules() {
+  $ret = array();
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/archive.module','archive','module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/blog.module','blog','module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/blogadmin.module','blogadmin','module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/ping.module','ping','module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/search.module','search','module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/profile.module','profile','module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/trackback.module','trackback','module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/upload.module', 'upload', 'module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/blogapi.module', 'blogapi', 'module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/path.module', 'path', 'module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/urlfilter.module', 'urlfilter', 'module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/subscriptions.module', 'subscriptions', 'module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/tag.module', 'tag', 'module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/captcha.module', 'captcha', 'module','',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('themes/simple/simple.theme','simple','theme','Internet explorer, Netscape, Opera',1,0,0)");
+  $ret[] = update_sql("REPLACE INTO system VALUES ('modules/upload.module', 'upload', 'module','',1,0,0)");
+  return $ret;
+}
+
+function d441tov010_misc() {
+  $ret = array();
+  $ret[] = update_sql("REPLACE INTO url_alias (src, dst) VALUES ('node/feed', 'index.rdf')");
+  $ret[] = update_sql("REPLACE variable SET name='blogapi_engine', value='s:1:\"2\";'");
+  $ret[] = update_sql("REPLACE variable SET name='teaser_length', value='s:4:\"2000\";'");
+  return $ret;
+}
+
+/*** end update funcs ***/
+
+function update_page() {
+  global $user, $update_types, $dblog_version;
+
+  $edit = $_POST["edit"];
+  if ($_POST["op"] != 'Upgrade' || !$edit['from'])
+    return update_info();
+
+  print update_page_header("$dblog_version database upgrade");
+  switch ($edit['from']) {
+    case 'v0.6':
+      update_process("Updating v0.6 users table",v06tov07_users());
+      update_process("Updating v0.6 comments table",v06tov07_comment());
+      update_process("Updating v0.6 trackback table",v06tov07_trackback());
+      update_process("Creating table for simple theme",v06tov07_theme_simple());
+      update_process("Creating table for subscriptions",v06tov07_subscriptions());
+    case 'v0.10':
+      update_process("Creating table for blogroll",v10tov11_blogroll());
+      break;
+
+    case '4.4.1':
+    case '4.4.2':
+      update_process("Updating 4.4.1 comments table",d441tov010_comments());
+      update_process("Creating table for blog",d441tov010_blog());
+      update_process("Updating 4.4.1 users table",d441tov010_users());
+      update_process("Creating tables for trackback",d441tov010_trackback());
+      update_process("Creating table for subscriptions",d441tov010_subscriptions());
+      update_process("Creating table for simple theme",v06tov07_theme_simple());
+      update_process("Enabling blogger modules",d441tov010_enable_modules());
+      update_process("Misc upgrade settings",d441tov010_misc());
+      break;
+  }
+  print update_page_footer();
+}
+
+function update_info() {
+  global $update_types, $dblog_version;
+
+  print update_page_header("$dblog_version database upgrade");
+  print "<ol>\n";
+  print "<li>Use this script to <strong>upgrade an existing Drupal (or 'Drupal for Blogger') installation</strong> to 'Drupal for Blogger'.  You don't need this script when installing 'Drupal for Blogger' from scratch.</li>";
+  print "<li>Before doing anything, <b>backup your database</b> (e.g. <code>mysqldump -p your_drupal_db</code>). This may alter some fields and your data might be lost!</li>\n";
+  print "<li>Don't upgrade your database twice as it may cause problems.</li>\n";
+  print "</ol>";
+
+  $form .= "<center><table border=0 width=90%><tr><td width=20%>";
+  $form .= form_select(t('Upgrade from'), 'from', '', $update_types);
+  $form .= "</td><td align=left>";
+  $form .= form_submit(t('Upgrade'));
+  $form .= "</td></tr></table>";
+  print form($form);
+  print update_page_footer();
+}
+
+if (isset($_POST["op"])) {
+  include_once "includes/bootstrap.inc";
+  include_once "includes/common.inc";
+
+  // Access check:
+  if (($access_check == 0) || ($user->uid == 1)) {
+    update_page();
+  }
+  else {
+    print update_page_header("Access denied");
+    print "Access denied.  You are not authorized to access to this page.  Please log in as the user with user ID #1. If you cannot log-in, you will have to edit <code>db-update.php</code> to by-pass this access check; in that case, open <code>db-update.php</code> in a text editor and follow the instructions at the top.";
+    print update_page_footer();
+  }
+}
+else {
+  update_info();
+}
+?>
diff -urN drupal-4.4.2/includes/bootstrap.inc drupal4blog/includes/bootstrap.inc
--- drupal-4.4.2/includes/bootstrap.inc	Sat Feb 21 22:08:07 2004
+++ drupal4blog/includes/bootstrap.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-/* $Id: bootstrap.inc,v 1.11 2004/02/21 14:08:07 kjartan Exp $ */
+/* $Id: bootstrap.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $ */
 
 function conf_init() {
 
diff -urN drupal-4.4.2/includes/common.inc drupal4blog/includes/common.inc
--- drupal-4.4.2/includes/common.inc	Tue Jun 22 04:15:19 2004
+++ drupal4blog/includes/common.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-/* $Id: common.inc,v 1.328.2.11 2004/06/21 20:15:19 dries Exp $ */
+/* $Id: common.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $ */
 
 /**
  * @defgroup common Core functions
@@ -40,18 +40,24 @@
  * @{
  */
 function drupal_set_message($message = NULL, $type = "status") {
-  static $stored_message = array();
+  if (!isset($_SESSION['messages'])) {
+    $_SESSION['messages'] = array();
+  }
 
   if (isset($message)) {
-    $stored_message[] = array($message, $type);
+    $_SESSION['messages'][] = array($message, $type);
   }
 
-  return $stored_message;
+  return $_SESSION['messages'];
 }
 
 function drupal_get_messages() {
-  return drupal_set_message();
+  $messages = drupal_set_message();
+  $_SESSION['messages'] = array();
+
+  return $messages;
 }
+
 /* @} */
 
 /**
@@ -80,7 +86,6 @@
 
   if (!isset($breadcrumb)) {
     $breadcrumb = menu_get_active_breadcrumb();
-    array_pop($breadcrumb);
   }
 
   return $breadcrumb;
@@ -96,7 +101,7 @@
  */
 
 function drupal_set_html_head($data = NULL) {
-  static $stored_head;
+  static $stored_head = '';
 
   if (!is_null($data)) {
     $stored_head .= "$data\n";
@@ -155,6 +160,10 @@
   elseif (function_exists("conf_url_rewrite")) {
     return conf_url_rewrite($path, 'outgoing');
   }
+  else {
+    // No alias found. Return the normal path.
+    return $path;
+  }
 }
 
 /**
@@ -181,7 +190,7 @@
  * @{
  */
 function drupal_set_header($header = NULL) {
-  static $stored_headers;
+  static $stored_headers = '';
 
   if (!is_null($header)) {
     header($header);
@@ -216,10 +225,17 @@
 function drupal_goto($url = NULL, $query = NULL, $fragment = NULL) {
 
   /*
-  ** Translate &amp; to simply & in the absolute URL
+  ** If not valid absolute URL, convert it to be one
+  ** If it is, then $query and $fragment is not used
   */
+  if (!valid_url($url,TRUE))
+    $url = url($url,$query,$fragment,TRUE);
 
-  $url = str_replace("&amp;", "&", url($url, $query, $fragment, TRUE));
+  /*
+  ** Translate &amp; to simply & in the absolute URL
+  */
+  
+  $url = str_replace("&amp;", "&", $url);
 
   /*
   ** It is advised to use "drupal_goto()" instead of PHP's "header()" as
@@ -253,24 +269,40 @@
  * Generates a 404 error if the request can not be handled.
  */
 function drupal_not_found() {
-  header("HTTP/1.0 404 Not Found");
-  watchdog("httpd", "404 error: '". check_query($_GET["q"]) ."' not found");
+  header('HTTP/1.0 404 Not Found');
+  watchdog('httpd', t('404 error: "%page" not found', array('%page' => check_query($_GET["q"]))));
 
   $path = drupal_get_normal_path(variable_get('site_404', ''));
-
+  $status = MENU_FALLTHROUGH;
   if ($path) {
     menu_set_active_item($path);
+    $status = menu_execute_active_handler();
   }
 
-  if ($path && menu_active_handler_exists()) {
-    menu_execute_active_handler();
-  }
-  else {
+  if ($status != MENU_FOUND) {
     print theme('page', '', t('Page not found'));
   }
 }
 
 /**
+ * Generates a 403 error if the request is not allowed.
+ */
+function drupal_access_denied() {
+  header('HTTP/1.0 403 Forbidden');
+
+  $path = drupal_get_normal_path(variable_get('site_403', ''));
+  $status = MENU_FALLTHROUGH;
+  if ($path) {
+    menu_set_active_item($path);
+    $status = menu_execute_active_handler();
+  }
+
+  if ($status != MENU_FOUND) {
+    print theme('page', message_access(), t('Access denied'));
+  }
+}
+
+/**
  * Flexible and powerful HTTP client implementation. Allows to GET, POST, PUT
  * or any other HTTP requests. Handles redirects.
  *
@@ -342,7 +374,6 @@
   // Parse response.
   list($headers, $result->data) = explode("\r\n\r\n", $response, 2);
   $headers = preg_split("/\r\n|\n|\r/", $headers);
-
   list($protocol, $code, $text) = explode(' ', trim(array_shift($headers)), 3);
   $result->headers = array();
 
@@ -395,7 +426,7 @@
   $entry = $types[$errno] .": $message in $filename on line $line.";
 
   if ($errno & E_ALL ^ E_NOTICE) {
-    watchdog("error", $types[$errno] .": $message in $filename on line $line.");
+    watchdog('error', t('%error: %message in %file on line %line.', array('%error' => $types[$errno], '%message' => $message, '%file' => $filename, '%line' => $line)));
     if (error_reporting()) {
       print "<pre>$entry</pre>";
     }
@@ -557,10 +588,20 @@
 /**
  * Verify the syntax of the given URL.
  *
- * @param $url an URL
+ * @param $url
+ *   an URL
+ * @param $absolute
+ *   is the URL to be verified absolute, ie. of the form \<scheme\>://\<hostname\>/...?
+ * @return
+ *   valid syntax: TRUE; FALSE otherwise
  */
-function valid_url($url) {
-  return preg_match("/^[a-zA-z0-9\/:_\-_\.,]+$/", $url);
+function valid_url($url, $absolute = FALSE) {
+  if ($absolute) {
+    return preg_match("/^(http|https|ftp):\/\/[a-z0-9\/:_\-_\.\?,~=#&]+$/i", $url);
+  }
+  else {
+    return preg_match("/^[a-z0-9\/:_\-_\.,]+$/i", $url);
+  }
 }
 
 function valid_input_data($data) {
@@ -586,13 +627,17 @@
     $match += preg_match("/\Walert\s*\(/i", $data);
 
     // check attributes:
-    $match += preg_match("/\W(dynsrc|datasrc|data|lowsrc|on[a-z]+)\s*=[^>]+?>/i", $data);
+
+    /* 
+    $match += preg_match("/\W(dynsrc|datasrc|data|lowsrc|on[a-z]+)\s*=[^>]+?>/i", $data); 
+     */
+    $match += preg_match("/\W(dynsrc|datasrc|data|lowsrc)\s*=[^>]+?>/i", $data);
 
     // check tags:
     $match += preg_match("/<\s*(applet|script|object|style|embed|form|blink|meta|html|frame|iframe|layer|ilayer|head|frameset|xml)/i", $data);
 
     if ($match) {
-      watchdog("warning", "terminated request because of suspicious input data: ". drupal_specialchars($data));
+      watchdog('warning', t('terminated request because of suspicious input data: %data', array('%data' => drupal_specialchars($data))));
       return 0;
     }
   }
@@ -624,9 +669,8 @@
     $output = module_invoke($type, "search_item", $item);
   }
   else {
-    $output = " <strong><u><a href=\"". $item["link"] ."\">". $item["title"] ."</a></u></strong><br />";
-    $output .= " <small>" . t($type) . ($item["user"] ? " - ". $item["user"] : "") ."". ($item["date"] ? " - ". format_date($item["date"], "small") : "") ."</small>";
-    $output .= "<br /><br />";
+    $output = " <dt class=\"title\"><a href=\"". $item["link"] ."\">". $item["title"] ."</a></dt>";
+    $output .= " <dd class=\"small\">" . t($type) . ($item["user"] ? " - ". $item["user"] : "") ."". ($item["date"] ? " - ". format_date($item["date"], "small") : "") ."</dd>";
   }
 
   return $output;
@@ -652,7 +696,7 @@
     $action = url("search");
   }
 
-  $output = " <br /><input type=\"text\" class=\"form-text\" size=\"50\" value=\"". check_form($keys) ."\" name=\"keys\" />";
+  $output = " <div class=\"search-form\"><br /><input type=\"text\" class=\"form-text\" size=\"50\" value=\"". check_form($keys) ."\" name=\"keys\" />";
   $output .= " <input type=\"submit\" class=\"form-submit\" value=\"". t("Search") ."\" />\n";
 
   if ($options) {
@@ -664,10 +708,9 @@
         $output .= " <input type=\"checkbox\" name=\"edit[type][$name]\" ". ($edit["type"][$name] ? " checked=\"checked\"" : "") ." /> ". t($name);
       }
     }
+    $output .= "</div>";
   }
 
-  $form .= "<br />";
-
   return form($output, "post", $action);
 }
 
@@ -676,6 +719,7 @@
  */
 function search_data($keys = NULL) {
   $edit = $_POST["edit"];
+  $output = '';
 
   if (isset($keys)) {
     foreach (module_list() as $name) {
@@ -683,9 +727,11 @@
         list($title, $results) = module_invoke($name, "search", $keys);
         if ($results) {
           $output .= "<h2>$title</h2>";
+          $output .= "<dl class=\"search-results\">";
           foreach ($results as $entry) {
             $output .= search_item($entry, $name);
           }
+          $output .= "</dl>";
         }
       }
     }
@@ -733,7 +779,7 @@
   $output = "<channel>\n";
   $output .= " <title>". drupal_specialchars(strip_tags($title)) ."</title>\n";
   $output .= " <link>". drupal_specialchars(strip_tags($link)) ."</link>\n";
-  $output .= " <description>". drupal_specialchars($description) ."</description>\n";
+  $output .= " <description>". drupal_specialchars(strip_tags($description)) ."</description>\n";
   $output .= " <language>". drupal_specialchars(strip_tags($language)) ."</language>\n";
   foreach ($args as $key => $value) {
     $output .= " <$key>". drupal_specialchars(strip_tags($value)) ."</$key>\n";
@@ -805,6 +851,7 @@
  */
 function format_interval($timestamp, $granularity = 2) {
   $units = array("1 year|%count years" => 31536000, "1 week|%count weeks" => 604800, "1 day|%count days" => 86400, "1 hour|%count hours" => 3600, "1 min|%count min" => 60, "1 sec|%count sec" => 1);
+  $output = '';
   foreach ($units as $key => $value) {
     $key = explode("|", $key);
     if ($timestamp >= $value) {
@@ -817,7 +864,7 @@
       break;
     }
   }
-  return ($output) ? $output : t("0 sec");
+  return $output ? $output : t("0 sec");
 }
 
 /**
@@ -860,6 +907,7 @@
   }
 
   $max = strlen($format);
+  $date = '';
   for ($i = 0; $i <= $max; $c = $format{$i++}) {
     if (strpos('AaDFlM', $c)) {
       $date .= t(gmdate($c, $timestamp));
@@ -922,7 +970,17 @@
     ** the true author of the content.
     */
 
-    $output = $object->name;
+    if ($object->homepage) {
+      $output = "<a href=\"$object->homepage\">$object->name</a>";
+    }
+    else if ($object->mail) {
+      $output = "<a href=\"mailto:$object->mail\">$object->name</a>";
+    }
+    else {
+      $output = $object->name;
+    }
+
+    $output .= ' ('. t('not verified') .')';
   }
   else {
     $output = t(variable_get("anonymous", "Anonymous"));
@@ -943,64 +1001,127 @@
   return "<form action=\"$action\" method=\"$method\"". drupal_attributes($attributes) .">\n$form\n</form>\n";
 }
 
-function form_item($title, $value, $description = NULL, $id = NULL) {
-  return theme("form_element", $title, $value, $description, $id);
+/**
+ * File an error against the form with the specified name.
+ */
+function form_set_error($name, $message) {
+  $GLOBALS['form'][$name] = $message;
+  drupal_set_message($message, 'error');
+}
+
+/**
+ * Return true when errors have been set.
+ */
+function form_has_errors() {
+  return isset($GLOBALS['form']);
+}
+
+/**
+ * Return the error message filed against the form with the specified name.
+ */
+function _form_get_error($name) {
+  return $GLOBALS['form'][$name];
+}
+
+function _form_get_class($name, $required, $error) {
+  return $name. ($required ? ' required' : '') . ($error ? ' error' : '');
+}
+
+function form_item($title, $value, $description = NULL, $id = NULL, $required = FALSE, $error = FALSE) {
+  return theme("form_element", $title, $value, $description, $id, $required, $error);
 }
 
 function form_group($legend, $group, $description = NULL) {
   return "<fieldset>" . ($legend ? "<legend>$legend</legend>" : "") . $group . ($description ? "<div class=\"description\">$description</div>" : "") . "</fieldset>\n";
 }
 
-function form_radio($title, $name, $value = 1, $checked = 0, $description = NULL, $attributes = NULL) {
-  $element = "<input type=\"radio\" class=\"form-radio\" name=\"edit[$name]\" value=\"$value\"". ($checked ? " checked=\"checked\"" : "") . drupal_attributes($attributes) .' />';
+function form_radio($title, $name, $value = 1, $checked = 0, $description = NULL, $attributes = NULL, $required = FALSE) {
+  $element = "<input type=\"radio\" class=\"". _form_get_class('form-radio', $required, _form_get_error($name)) ."\" name=\"edit[$name]\" value=\"$value\"". ($checked ? " checked=\"checked\"" : "") . drupal_attributes($attributes) .' />';
   if (!is_null($title)) {
     $element = "<label class=\"option\">$element $title</label>";
   }
-  return theme('form_element', NULL, $element, $description);
+  return theme('form_element', NULL, $element, $description, $required, _form_get_error($name));
 }
 
-function form_radios($title, $name, $value, $options, $description = NULL) {
+function form_radios($title, $name, $value, $options, $description = NULL, $required = FALSE) {
   if (count($options) > 0) {
+    $choices = '';
     foreach ($options as $key => $choice) {
       $choices .= "<label class=\"option\"><input type=\"radio\" class=\"form-radio\" name=\"edit[$name]\" value=\"$key\"". ($key == $value ? " checked=\"checked\"" : "") ." /> $choice</label><br />";
     }
-    return theme('form_element', $title, $choices, $description);
+    return theme('form_element', $title, $choices, $description, $required, _form_get_error($name));
   }
 }
 
-function form_checkbox($title, $name, $value = 1, $checked = 0, $description = NULL, $attributes = NULL) {
-  $element = "<input type=\"checkbox\" class=\"form-checkbox\" name=\"edit[$name]\" id=\"edit-$name\" value=\"". $value ."\"". ($checked ? " checked=\"checked\"" : "") . drupal_attributes($attributes) .' />';
+function form_checkbox($title, $name, $value = 1, $checked = 0, $description = NULL, $attributes = NULL, $required = FALSE) {
+  $element = "<input type=\"checkbox\" class=\"". _form_get_class('form-checkbox', $required, _form_get_error($name)) ."\" name=\"edit[$name]\" id=\"edit-$name\" value=\"". $value ."\"". ($checked ? " checked=\"checked\"" : "") . drupal_attributes($attributes) .' />';
   if (!is_null($title)) {
     $element = "<label class=\"option\">$element $title</label>";
   }
-  return form_hidden($name, 0) . theme('form_element', NULL, $element, $description);
+  return form_hidden($name, 0) . theme('form_element', NULL, $element, $description, $required, _form_get_error($name));
 }
 
-function form_textfield($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL) {
+function form_checkboxes($title, $name, $values, $options, $description = NULL, $required = FALSE) {
+  if (count($options) > 0) {
+    if (!isset($values)) {
+      $values = array();
+    }
+    $choices = '';
+    foreach ($options as $key => $choice) {
+      $choices .= "<label class=\"option\"><input type=\"checkbox\" class=\"form-checkbox\" name=\"edit[$name][]\" value=\"$key\"". (in_array($key, $values) ? " checked=\"checked\"" : "") ." /> $choice</label><br />";
+    }
+    return theme('form_element', $title, $choices, $description, $required, _form_get_error($name));
+  }
+}
+
+function form_textfield($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL, $required = FALSE) {
   $size = $size ? " size=\"$size\"" : "";
-  return theme("form_element", $title, "<input type=\"text\" maxlength=\"$maxlength\" class=\"form-text\" name=\"edit[$name]\" id=\"$name\"$size value=\"". check_form($value) ."\"". drupal_attributes($attributes) ." />", $description, $name);
+  return theme("form_element", $title, "<input type=\"text\" maxlength=\"$maxlength\" class=\"". _form_get_class('form-text', $required, _form_get_error($name)) ."\" name=\"edit[$name]\" id=\"$name\"$size value=\"". check_form($value) ."\"". drupal_attributes($attributes) ." />", $description, $name, $required, _form_get_error($name));
 }
 
-function form_password($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL) {
+function form_password($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL, $required = FALSE) {
   $size = $size ? " size=\"$size\"" : "";
-  return theme("form_element", $title, "<input type=\"password\" class=\"form-password\" maxlength=\"$maxlength\" name=\"edit[$name]\" id=\"$name\"$size value=\"". check_form($value) ."\"". drupal_attributes($attributes) ." />", $description, $name);
+  return theme("form_element", $title, "<input type=\"password\" class=\"". _form_get_class('form-password', $required, _form_get_error($name)) ."\" maxlength=\"$maxlength\" name=\"edit[$name]\" id=\"$name\"$size value=\"". check_form($value) ."\"". drupal_attributes($attributes) ." />", $description, $name, $required, _form_get_error($name));
 }
 
-function form_textarea($title, $name, $value, $cols, $rows, $description = NULL, $attributes = NULL) {
+function form_textarea($title, $name, $value, $cols, $rows, $description = NULL, $attributes = NULL, $required = FALSE) {
   $cols = $cols ? " cols=\"$cols\"" : "";
   module_invoke_all("textarea", $name);  // eg. optionally plug in a WYSIWYG editor
-  return theme("form_element", $title, "<textarea wrap=\"virtual\"$cols rows=\"$rows\" name=\"edit[$name]\" id=\"$name\"". drupal_attributes($attributes) .">". check_form($value) ."</textarea>", $description, $name);
+  return theme("form_element", $title, "<textarea wrap=\"virtual\"$cols rows=\"$rows\" name=\"edit[$name]\" id=\"$name\"". drupal_attributes($attributes) .">". check_form($value) ."</textarea>", $description, $name, $required, _form_get_error($name));
 }
 
-function form_select($title, $name, $value, $options, $description = NULL, $extra = 0, $multiple = 0) {
+/**
+ * Outputs a form select item.
+ *
+ * @param $options Array containing the options to choose from. The basic format
+ *                 is "value" => "label". If you want to group options together
+ *                 (with <optgroup> tags), the format becomes "group name" =>
+ *                 $options, where $options is an array of "value" => "label"
+ *                 pairs.
+ *
+ *                 Examples:
+ *                 @verbatim $flavor = array(1 => "Vanilla", 2 => "Chocolate", 3 => "Strawberry"); @endverbatim
+ *                 @verbatim $order = array("Food" => array(1 => "Ice cream", 2 => "Hamburger"), "Drink" => array(1 => "Cola", 2 => "Water")); @endverbatim
+ */
+function form_select($title, $name, $value, $options, $description = NULL, $extra = 0, $multiple = 0, $required = FALSE) {
+  $select = '';
   foreach ($options as $key => $choice) {
-    $select .= "<option value=\"$key\"". (is_array($value) ? (in_array($key, $value) ? " selected=\"selected\"" : "") : ($value == $key ? " selected=\"selected\"" : "")) .">". check_form($choice) ."</option>";
+    if (is_array($choice)) {
+      $select .= "<optgroup label=\"$key\">";
+      foreach ($choice as $key => $choice) {
+        $select .= "<option value=\"$key\"". (is_array($value) ? (in_array($key, $value) ? " selected=\"selected\"" : "") : ($value == $key ? " selected=\"selected\"" : "")) .">". check_form($choice) ."</option>";
+      }
+      $select .= "</optgroup>";
+    }
+    else {
+      $select .= "<option value=\"$key\"". (is_array($value) ? (in_array($key, $value) ? " selected=\"selected\"" : "") : ($value == $key ? " selected=\"selected\"" : "")) .">". check_form($choice) ."</option>";
+    }
   }
-  return theme("form_element", $title, "<select name=\"edit[$name]". ($multiple ? "[]" : "") ."\"". ($multiple ? " multiple " : "") . ($extra ? " $extra" : "") ." id=\"$name\">$select</select>", $description, $name);
+  return theme("form_element", $title, "<select name=\"edit[$name]". ($multiple ? "[]" : "") ."\"". ($multiple ? " multiple=\"multiple\" " : "") . ($extra ? " $extra" : "") ." id=\"$name\">$select</select>", $description, $name, $required, _form_get_error($name));
 }
 
-function form_file($title, $name, $size, $description = NULL) {
-  return theme("form_element", $title, "<input type=\"file\" class=\"form-file\" name=\"edit[$name]\" id=\"$name\" size=\"$size\" />\n", $description, $name);
+function form_file($title, $name, $size, $description = NULL, $required = FALSE) {
+  return theme("form_element", $title, "<input type=\"file\" class=\"". _form_get_class('form-file', $required, _form_get_error($name)) ."\" name=\"edit[$name]\" id=\"$name\" size=\"$size\" />\n", $description, $name, $required, _form_get_error($error));
 }
 
 function form_hidden($name, $value) {
@@ -1038,9 +1159,7 @@
     $script = (strpos($_SERVER["SERVER_SOFTWARE"], "Apache") === false) ? "index.php" : "";
   }
 
-  if ($alias = drupal_get_path_alias($url)) {
-    $url = $alias;
-  }
+  $url = drupal_get_path_alias($url);
 
   if (isset($fragment)) {
     $fragment = "#$fragment";
diff -urN drupal-4.4.2/includes/conf.php drupal4blog/includes/conf.php
--- drupal-4.4.2/includes/conf.php	Sat Mar 13 02:27:28 2004
+++ drupal4blog/includes/conf.php	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: conf.php,v 1.27.4.1 2004/03/12 18:27:28 dries Exp $
+// $Id: conf.php,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 #
 # Database settings:
diff -urN drupal-4.4.2/includes/database.inc drupal4blog/includes/database.inc
--- drupal-4.4.2/includes/database.inc	Wed Oct  1 13:18:02 2003
+++ drupal4blog/includes/database.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: database.inc,v 1.27 2003/10/01 05:18:02 dries Exp $
+// $Id: database.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 function db_prefix_tables($sql) {
   global $db_prefix;
diff -urN drupal-4.4.2/includes/database.mysql.inc drupal4blog/includes/database.mysql.inc
--- drupal-4.4.2/includes/database.mysql.inc	Mon Dec  8 14:32:18 2003
+++ drupal4blog/includes/database.mysql.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: database.mysql.inc,v 1.21 2003/12/08 06:32:18 dries Exp $
+// $Id: database.mysql.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 function db_connect($url) {
   $url = parse_url($url);
@@ -10,7 +10,7 @@
   }
 
   mysql_connect($url["host"], $url["user"], $url["pass"]) or die(mysql_error());
-  mysql_select_db(substr($url["path"], 1)) or die("unable to select database");
+  mysql_select_db(substr($url["path"], 1)) or die("unable to select database - ".substr($url["path"],1));
 
   /*
   ** Note that you can change the 'mysql_connect' statement to 'mysql_pconnect'
diff -urN drupal-4.4.2/includes/database.pear.inc drupal4blog/includes/database.pear.inc
--- drupal-4.4.2/includes/database.pear.inc	Mon Dec  8 14:32:18 2003
+++ drupal4blog/includes/database.pear.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: database.pear.inc,v 1.22 2003/12/08 06:32:18 dries Exp $
+// $Id: database.pear.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 require_once 'DB.php';
 
diff -urN drupal-4.4.2/includes/file.inc drupal4blog/includes/file.inc
--- drupal-4.4.2/includes/file.inc	Thu Mar 25 03:03:00 2004
+++ drupal4blog/includes/file.inc	Sun Aug  8 05:21:36 2004
@@ -1,5 +1,5 @@
 <?php
-/* $Id: file.inc,v 1.10.2.1 2004/03/24 19:03:00 dries Exp $ */
+/* $Id: file.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $ */
 
 /**
  * @defgroup file File interface
@@ -286,6 +286,28 @@
     }
   }
   return 0;
+}
+
+function file_save_data($data, $dest, $replace = 0) {
+  if (!valid_input_data($data)) {
+    watchdog('error', t('Possible exploit abuse: invalid data.'));
+    drupal_set_message(t("file upload failed: invalid data."), 'error');
+    return 0;
+  }   
+  $temp = variable_get('file_directory_temp', (PHP_OS == 'WINNT' ? 'c:\\windows\\temp' : '/tmp'));
+  $file = tempnam($temp, 'file');
+  if (!$fp = fopen($file, 'w')) {
+    drupal_set_message(t('unable to create file.'), 'error');
+    return 0;
+  }
+  fwrite($fp, $data);
+  fclose($fp);
+
+  if (!file_move($file, $dest)) {
+    return 0;
+  }
+
+  return $file;
 }
 
 /**
diff -urN drupal-4.4.2/includes/menu.inc drupal4blog/includes/menu.inc
--- drupal-4.4.2/includes/menu.inc	Sun Feb 15 22:56:50 2004
+++ drupal4blog/includes/menu.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-/* $Id: menu.inc,v 1.37 2004/02/15 14:56:50 dries Exp $ */
+/* $Id: menu.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $ */
 
 /**
  * @defgroup menu Menu system
@@ -10,49 +10,103 @@
 define('MENU_HIDE', 1);
 define('MENU_HIDE_NOCHILD', 2);
 
+define('MENU_NORMAL', 0);
+define('MENU_MODIFIED', 1);
+define('MENU_LOCKED', 2);
+define('MENU_CUSTOM', 3);
+
+define('MENU_FALLTHROUGH', 0);
+define('MENU_DENIED', 1);
+define('MENU_FOUND', 2);
+
 /** @} */
 
 /**
  * Register a menu item with the menu system.
  *
  * @ingroup menu
- * @param $path Location then menu item refers to.
+ * @param $path Location the menu item refers to. Do not add a trailing slash.
  * @param $title The title of the menu item to show in the rendered menu.
- * @param $callback The function to call when this is the active menu item.
+ * @param $callback
+ * - string - The function to call when this is the active menu item.
+ * - MENU_FALLTHROUGH - Use the callback defined by the menu item's parent.
+ * - MENU_DENIED - Deny access to this menu item by this user.
  * @param $weight Heavier menu items sink down the menu.
- * @param $hidden
- * - MENU_SHOW show the menu (default).
- * - MENU_HIDE hide the menu item, but register a callback.
- * - MENU_HIDE_NOCHILD hide the menu item when it has no children.
+ * @param $visibility
+ * - MENU_SHOW - Show the menu item (default).
+ * - MENU_HIDE - Hide the menu item, but register a callback.
+ * - MENU_HIDE_NOCHILD - Hide the menu item when it has no children.
+ * @param $status
+ * - MENU_NORMAL - The menu item can be moved (default).
+ * - MENU_LOCKED - The administrator may not modify the item.
  */
-function menu($path, $title, $callback = NULL, $weight = 0, $hidden = MENU_SHOW) {
-  global $_list;
+function menu($path, $title, $callback = MENU_FALLTHROUGH, $weight = 0, $visibility = MENU_SHOW, $status = MENU_NORMAL) {
+  global $_menu;
 
   // add the menu to the flat list of menu items:
-  $_list[$path] = array("title" => $title, "callback" => $callback, "weight" => $weight, "hidden" => $hidden);
+  $_menu['list'][$path] = array('title' => $title, 'callback' => $callback, 'weight' => $weight, 'visibility' => $visibility, 'status' => $status);
+}
+
+/**
+ * Return the menu data structure.
+ *
+ * @ingroup menu
+ * The returned structure contains much information that is useful only
+ * internally in the menu system. External modules are likely to need only
+ * the ['visible'] element of the returned array. All menu items that are
+ * accessible to the current user and not hidden will be present here, so
+ * modules and themes can use this structure to build their own representations
+ * of the menu.
+ *
+ * $menu['visible'] will contain an associative array, the keys of which
+ * are menu IDs. The values of this array are themselves associative arrays,
+ * with the following key-value pairs defined:
+ * - 'title' - The displayed title of the menu or menu item. It will already
+ *   have been translated by the locale system.
+ * - 'path' - The Drupal path to the menu item. A link to a particular item
+ *   can thus be constructed with l($item['title'], $item['path']).
+ * - 'children' - A linear list of the menu ID's of this item's children.
+ *
+ * Menu ID 0 is the "root" of the menu. The children of this item are the
+ * menus themselves (they will have no associated path). Menu ID 1 will
+ * always be one of these children; it is the default "Navigation" menu.
+ */
+function menu_get_menu() {
+  global $_menu;
+  global $user;
+
+  if (!isset($_menu['items'])) {
+    menu_build();
+  }
+
+  return $_menu;
 }
 
 /**
  * Returns an array with the menu items that lead to the specified path.
  */
 function menu_get_trail($path) {
-  global $_list;
+  $menu = menu_get_menu();
 
   $trail = array();
 
-  while ($path) {
-    if ($_list[$path]) {
-      array_unshift($trail, $path);
-    }
-
-    $path = substr($path, 0, strrpos($path, "/"));
+  // Find the ID of the given path.
+  while ($path && !$menu['path index'][$path]) {
+    $path = substr($path, 0, strrpos($path, '/'));
+  }
+  $mid = $menu['path index'][$path];
+
+  // Follow the parents up the chain to get the trail.
+  while ($mid && $menu['items'][$mid]) {
+    array_unshift($trail, $mid);
+    $mid = $menu['items'][$mid]['pid'];
   }
 
   return $trail;
 }
 
 /**
- * Returns the path of the active menu item.
+ * Returns the ID of the active menu item.
  * @ingroup menu
  */
 function menu_get_active_item() {
@@ -64,34 +118,34 @@
  * @ingroup menu
  */
 function menu_set_active_item($path = NULL) {
-  global $_list;
-  static $stored_path;
+  static $stored_mid;
+  $menu = menu_get_menu();
 
-  if (is_null($stored_path) || !empty($path)) {
+  if (is_null($stored_mid) || !empty($path)) {
     if (empty($path)) {
-      $path = $_GET["q"];
+      $path = $_GET['q'];
     }
     else {
       $_GET['q'] = $path;
     }
 
-    while ($path && !$_list[$path]) {
-      $path = substr($path, 0, strrpos($path, "/"));
+    while ($path && !$menu['path index'][$path]) {
+      $path = substr($path, 0, strrpos($path, '/'));
     }
-    $stored_path = $path;
+    $stored_mid = $menu['path index'][$path];
   }
 
-  return $stored_path;
+  return $stored_mid;
 }
 
 /**
  * Returns the title of the active menu item.
  */
 function menu_get_active_title() {
-  global $_list;
+  $menu = menu_get_menu();
 
-  if ($path = menu_get_active_item()) {
-    return ucfirst($_list[$path]["title"]);
+  if ($mid = menu_get_active_item()) {
+    return ucfirst($menu['items'][$mid]['title']);
   }
 }
 
@@ -101,10 +155,10 @@
 function menu_get_active_help() {
 
   if (menu_active_handler_exists()) {
-    $path = $_GET["q"];
-    $output = "";
+    $path = $_GET['q'];
+    $output = '';
 
-    $return = module_invoke_all("help", $path);
+    $return = module_invoke_all('help', $path);
     foreach ($return as $item) {
       if (!empty($item)) {
         $output .= $item ."\n";
@@ -118,168 +172,318 @@
  * Returns an array of rendered menu items in the active breadcrumb trail.
  */
 function menu_get_active_breadcrumb() {
+  $menu = menu_get_menu();
 
-  $links[] = l(t("Home"), "");
+  $links[] = l(t('Home'), '');
 
-  $trail = menu_get_trail($_GET["q"]);
-  foreach ($trail as $item) {
-    $links[] = _render_item($item);
+  $trail = menu_get_trail(drupal_get_path_alias($_GET['q']));
+
+  // The last item in the trail is the page title; don't display it here.
+  array_pop($trail);
+
+  foreach ($trail as $mid) {
+    // Don't show hidden menu items or items without valid link targets.
+    if (isset($menu['visible'][$mid]) && $menu['items'][$mid]['path'] != '') {
+      $links[] = _menu_render_item($mid);
+    }
   }
 
   return $links;
 }
 
-
 /**
  * Execute the handler associated with the active menu item.
  */
 function menu_execute_active_handler() {
-  global $_list;
+  $menu = menu_get_menu();
 
-  $path = menu_get_active_item();
+  $path = $_GET['q'];
+  while ($path && (!$menu['path index'][$path] || $menu['items'][$menu['path index'][$path]]['callback'] === MENU_FALLTHROUGH)) {
+    $path = substr($path, 0, strrpos($path, '/'));
+  }
+  $mid = $menu['path index'][$path];
+  if ($menu['items'][$mid]['callback'] === MENU_DENIED) {
+    return MENU_DENIED;
+  }
 
-  if ($_list[$path]["callback"]) {
-    $arg = substr($_GET["q"], strlen($path) + 1);
-    if (isset($arg)) {
-      return call_user_func_array($_list[$path]["callback"], explode("/", $arg));
+  if (is_string($menu['items'][$mid]['callback'])) {
+    $arg = substr($_GET['q'], strlen($menu['items'][$mid]['path']) + 1);
+    if (strlen($arg)) {
+      call_user_func_array($menu['items'][$mid]['callback'], explode('/', $arg));
     }
     else {
-      return call_user_func($_list[$path]["callback"]);
+      call_user_func($menu['items'][$mid]['callback']);
     }
+    return MENU_FOUND;
   }
+
+  return MENU_FALLTHROUGH;
 }
 
+/**
+ * Return true if a valid callback can be called from the current path.
+ */
 function menu_active_handler_exists() {
-  global $_list;
+  $menu = menu_get_menu();
+
+  $path = $_GET['q'];
+  while ($path && (!$menu['path index'][$path] || $menu['items'][$menu['path index'][$path]]['callback'] === MENU_FALLTHROUGH)) {
+    $path = substr($path, 0, strrpos($path, '/'));
+  }
+  $mid = $menu['path index'][$path];
 
-  $path = menu_get_active_item();
+  if ($menu['items'][$mid]['callback'] === MENU_FALLTHROUGH) {
+    return FALSE;
+  }
+  if ($menu['items'][$mid]['callback'] === MENU_DENIED) {
+    return FALSE;
+  }
 
-  return function_exists($_list[$path]["callback"]);
+  return function_exists($menu['items'][$mid]['callback']);
 }
 
 /**
  * Returns true when the path is in the active trail.
  */
-function menu_in_active_trail($path) {
+function menu_in_active_trail($mid) {
   static $trail;
 
   if (empty($trail)) {
-    $trail = menu_get_trail($_GET["q"]);
+    $trail = menu_get_trail(drupal_get_path_alias($_GET['q']));
   }
 
-  return in_array($path, $trail);
+  return in_array($mid, $trail);
 }
 
 /**
- * Returns true when the menu has visisble children.
+ * Returns a rendered menu tree.
  */
-function menu_has_visible_children($item) {
-  global $_list;
+function menu_tree($pid = 1) {
+  static $trail;
+  $menu = menu_get_menu();
+  $output = '';
+
+  if (empty($trail)) {
+    $trail = menu_get_trail($_GET['q']);
+  }
+
+  if (isset($menu['visible'][$pid]) && $menu['visible'][$pid]['children']) {
 
-  if ($_list[$item]['children']) {
-    foreach ($_list[$item]['children'] as $child) {
-      if ($_list[$child]['hidden'] == MENU_SHOW) {
-        return true;
+    foreach ($menu['visible'][$pid]['children'] as $mid) {
+      $style = (count($menu['visible'][$mid]['children']) ? (menu_in_active_trail($mid)  ? 'expanded' : 'collapsed') : 'leaf');
+      $output .= "<li class=\"$style\">";
+      $output .= _menu_render_item($mid);
+      if (menu_in_active_trail($mid)) {
+        $output .= menu_tree($mid);
       }
+      $output .= "</li>\n";
+    }
+
+    if ($output != '') {
+      $output  = "\n<ul>\n$output\n</ul>\n";
     }
   }
 
-  return false;
+  return $output;
 }
 
 /**
- * Returns a rendered menu tree.
+ * Build the menu by querying both modules and the database.
  */
-function menu_tree($parent = "", $hidden = 0) {
-  global $_list;
-  static $trail;
-  $output = "";
+function menu_build() {
+  global $_menu;
+  global $user;
 
-  if (empty($trail)) {
-    $trail = menu_get_trail($_GET["q"]);
-  }
+  // Start from a clean slate.
+  $_menu = array();
+
+  // Build a sequential list of all menu items.
+  module_invoke_all('link', 'system');
+
+  $_menu['path index'] = array();
+  // Set up items array, including default "Navigation" menu.
+  $_menu['items'] = array(0 => array(), 1 => array('pid' => 0, 'title' => t('Navigation'), 'weight' => -50, 'visibility' => MENU_SHOW, 'status' => MENU_LOCKED));
 
-  if (isset($_list[$parent]) && $_list[$parent]["children"]) {
+  // Menu items not in the DB get temporary negative IDs.
+  $temp_mid = -1;
 
-    usort($_list[$parent]["children"], "_menu_sort");
-    foreach ($_list[$parent]["children"] as $item) {
-      /*
-      ** Don't render the menu when it is hidden, or when it has no call-back
-      ** nor children.  The latter check avoids that useless links are being
-      ** rendered.
-      */
-      $visible = menu_has_visible_children($item);
-      if (($_list[$item]["hidden"] == MENU_SHOW && $_list[$item]["callback"]) ||
-         ($_list[$item]["hidden"] == MENU_SHOW && $visible) ||
-         ($_list[$item]["hidden"] == MENU_HIDE_NOCHILD && $visible)) {
-        $style = ($visible ? (menu_in_active_trail($item)  ? "expanded" : "collapsed") : "leaf");
-        $output .= "<li class=\"$style\">";
-        $output .= _render_item($item);
-        if (menu_in_active_trail($item)) {
-          $output .= menu_tree($item);
+  foreach ($_menu['list'] as $path => $data) {
+    $mid = $temp_mid;
+    $_menu['items'][$mid] = array('path' => $path, 'title' => $data['title'], 'callback' => $data['callback'], 'weight' => $data['weight'], 'visibility' => $data['visibility'], 'status' => $data['status']);
+    $_menu['path index'][$path] = $mid;
+
+    $temp_mid--;
+  }
+
+  // Now fetch items from the DB, reassigning menu IDs as needed.
+  if (module_exist('menu')) {
+    $result = db_query('SELECT * FROM {menu}');
+    while ($item = db_fetch_object($result)) {
+      // First, add any custom items added by the administrator.
+      if ($item->status == MENU_CUSTOM) {
+        $_menu['items'][$item->mid] = array('pid' => $item->pid, 'path' => $item->path, 'title' => $item->title, 'callback' => MENU_FALLTHROUGH, 'weight' => $item->weight, 'visibility' => MENU_SHOW, 'status' => MENU_CUSTOM);
+        $_menu['path index'][$item->path] = $item->mid;
+      }
+      // Don't display non-custom menu items if no module declared them.
+      else if ($old_mid = $_menu['path index'][$item->path]) {
+        $_menu['items'][$item->mid] = $_menu['items'][$old_mid];
+        unset($_menu['items'][$old_mid]);
+        $_menu['path index'][$item->path] = $item->mid;
+        // If administrator has changed item position, reflect the change.
+        if ($item->status == MENU_MODIFIED) {
+          $_menu['items'][$item->mid]['title'] = $item->title;
+          $_menu['items'][$item->mid]['pid'] = $item->pid;
+          $_menu['items'][$item->mid]['weight'] = $item->weight;
+          $_menu['items'][$item->mid]['visibility'] = $item->visibility;
+          $_menu['items'][$item->mid]['status'] = $item->status;
         }
-        $output .= "</li>\n";
       }
-      else if ($_list[$item]["hidden"] == MENU_HIDE && $_list[$item]["children"]) {
-        $output .= menu_tree($item, 1);
+    }
+  }
+
+  // Establish parent-child relationships.
+  foreach ($_menu['items'] as $mid => $item) {
+    if (!isset($item['pid'])) {
+      // Parent's location has not been customized, so figure it out using the path.
+      $parent = $item['path'];
+      do {
+        $parent = substr($parent, 0, strrpos($parent, '/'));
       }
+      while ($parent && !$_menu['path index'][$parent]);
+
+      $pid = $parent ? $_menu['path index'][$parent] : 1;
+      $_menu['items'][$mid]['pid'] = $pid;
+    }
+    else {
+      $pid = $item['pid'];
     }
 
-    if ($output != '' && $hidden != MENU_HIDE) {
-      $output  = "\n<ul>\n$output\n</ul>\n";
+    // Don't make root a child of itself.
+    if ($mid) {
+      if (isset ($_menu['items'][$pid])) {
+        $_menu['items'][$pid]['children'][] = $mid;
+      }
+      else {
+        // If parent is missing, it is a menu item that used to be defined
+        // but is no longer. Default to a root-level "Navigation" menu item.
+        $_menu['items'][1]['children'][] = $mid;
+      }
     }
   }
 
-  return $output;
+  // Prepare to display trees to the user as required.
+  menu_build_visible_tree();
 }
 
 /**
- * Query to module to build the menu.
+ * Find all visible items in the menu tree, for ease in displaying to user.
+ *
+ * Since this is only for display, we only need title, path, and children
+ * for each item.
  */
-function menu_build($type) {
-  /*
-  ** Build a sequential list of all menus items.
-  */
-
-  module_invoke_all("link", $type);
+function menu_build_visible_tree($pid = 0) {
+  global $_menu;
 
-  /*
-  ** Tree-ify the sequential list of menu items by adding each
-  ** menu item to the 'children' array of their direct parent.
-  */
+  if (isset($_menu['items'][$pid])) {
+    $parent = $_menu['items'][$pid];
 
-  global $_list;
+    $children = array();
+    if ($parent['children']) {
+      usort($parent['children'], '_menu_sort');
+      foreach ($parent['children'] as $mid) {
+        $children = array_merge($children, menu_build_visible_tree($mid));
+      }
+    }
+    $visible = ($parent['visibility'] == MENU_SHOW) ||
+      ($parent['visibility'] == MENU_HIDE_NOCHILD && count($children) > 0);
 
-  foreach ($_list as $path => $data) {
+    if ($parent['callback'] === MENU_FALLTHROUGH) {
+      // Follow the path up to find the actual callback.
+      $path = $parent['path'];
+      while ($path && (!$_menu['path index'][$path] || $_menu['items'][$_menu['path index'][$path]]['callback'] === MENU_FALLTHROUGH)) {
+        $path = substr($path, 0, strrpos($path, '/'));
+      }
+      $callback_mid = $_menu['path index'][$path];
+      $allowed = $_menu['items'][$callback_mid]['callback'] !== MENU_DENIED;
+    }
+    else {
+      $allowed = $parent['callback'] !== MENU_DENIED;
+    }
 
-    /*
-    ** Find $path's direct parent:
-    */
-    $parent = $path;
-    do {
-      $parent = substr($parent, 0, strrpos($parent, "/"));
+    if ($visible && $allowed) {
+      $_menu['visible'][$pid] = array('title' => $parent['title'], 'path' => $parent['path'], 'children' => $children);
+      foreach ($children as $mid) {
+        $_menu['visible'][$mid]['pid'] = $pid;
+      }
+      return array($pid);
+    }
+    else {
+      return $children;
     }
-    while ($parent && !$_list[$parent]);
+  }
+
+  return array();
+}
 
-    if ($path) {
-      $_list[$parent]["children"][] = $path;
+/**
+ * Populate the database representation of the menu.
+ *
+ * @ingroup menu
+ * This need only be called at the start of pages that modify the menu.
+ */
+function menu_rebuild() {
+  cache_clear_all();
+  menu_build();
+  $menu = menu_get_menu();
+
+  $new_items = array();
+  foreach ($menu['items'] as $mid => $item) {
+    if ($mid < 0 && ($item->status != MENU_LOCKED)) {
+      $new_mid = db_next_id('menu_mid');
+      if (isset($new_items[$item['pid']])) {
+        $new_pid = $new_items[$item['pid']]['mid'];
+      }
+      else {
+        $new_pid = $item['pid'];
+      }
+
+      // Fix parent IDs for menu items already added.
+      if ($item['children']) {
+        foreach ($item['children'] as $child) {
+          if (isset($new_items[$child])) {
+            $new_items[$child]['pid'] = $new_mid;
+          }
+        }
+      }
+
+      $new_items[$mid] = array('mid' => $new_mid, 'pid' => $new_pid, 'path' => $item['path'], 'title' => $item['title'], 'weight' => $item['weight'], 'visibility' => $item['visibility'], 'status' => $item['status']);
     }
   }
+
+  foreach ($new_items as $item) {
+    db_query('INSERT INTO {menu} (mid, pid, path, title, weight, visibility, status) VALUES (%d, %d, \'%s\', \'%s\', %d, %d, %d)', $item['mid'], $item['pid'], $item['path'], $item['title'], $item['weight'], $item['visibility'], $item['status']);
+  }
+
+  // Rebuild the menu to account for any changes.
+  menu_build();
 }
 
+/**
+ * Comparator routine for use in sorting menu items.
+ */
 function _menu_sort($a, $b) {
-  global $_list;
+  $menu = menu_get_menu();
 
-  $a = &$_list[$a];
-  $b = &$_list[$b];
+  $a = &$menu['items'][$a];
+  $b = &$menu['items'][$b];
 
-  return $a["weight"] < $b["weight"] ? -1 : ($a["weight"] > $b["weight"] ? 1 : ($a["title"] < $b["title"] ? -1 : 1));
+  return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
 }
 
-function _render_item($path) {
-  global $_list;
+function _menu_render_item($mid) {
+  $menu = menu_get_menu();
 
-  return l($_list[$path]["title"], $path);
+  return l($menu['items'][$mid]['title'], $menu['items'][$mid]['path']);
 }
 
 
diff -urN drupal-4.4.2/includes/module.inc drupal4blog/includes/module.inc
--- drupal-4.4.2/includes/module.inc	Wed Jan 28 02:14:25 2004
+++ drupal4blog/includes/module.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: module.inc,v 1.52 2004/01/27 18:14:25 dries Exp $
+// $Id: module.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 // initialize modules:
 function module_init() {
diff -urN drupal-4.4.2/includes/pager.inc drupal4blog/includes/pager.inc
--- drupal-4.4.2/includes/pager.inc	Fri Apr 16 06:19:08 2004
+++ drupal4blog/includes/pager.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: pager.inc,v 1.23.2.1 2004/04/15 22:19:08 dries Exp $
+// $Id: pager.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 /**
  * @defgroup pager Pager interface
@@ -72,11 +72,11 @@
   global $pager_total;
   if ($pager_total[$element] > $limit) {
     $output .= "<div id=\"pager\" class=\"container-inline\">";
-    $output .= "<div>". pager_first(($tags[0] ? $tags[0] : t("first page")), $limit, $element, $attributes) ."</div>";
-    $output .= "<div>". pager_previous(($tags[1] ? $tags[1] : t("previous page")), $limit, $element, 1, $attributes) ."</div>";
+    $output .= "<div>". pager_first(($tags[0] ? $tags[0] : t("&laquo;")), $limit, $element, $attributes) ."</div>";
+    $output .= "<div>". pager_previous(($tags[1] ? $tags[1] : t("prev")), $limit, $element, 1, $attributes) ."</div>";
     $output .= "<div>". pager_list($limit, $element, ($tags[2] ? $tags[2] : 9 ), "", $attributes) ."</div>";
-    $output .= "<div>". pager_next(($tags[3] ? $tags[3] : t("next page")), $limit, $element, 1, $attributes) ."</div>";
-    $output .= "<div>". pager_last(($tags[4] ? $tags[4] : t("last page")), $limit, $element, $attributes) ."</div>";
+    $output .= "<div>". pager_next(($tags[3] ? $tags[3] : t("next")), $limit, $element, 1, $attributes) ."</div>";
+    $output .= "<div>". pager_last(($tags[4] ? $tags[4] : t("&raquo;")), $limit, $element, $attributes) ."</div>";
     $output .= "</div>";
 
     return $output;
diff -urN drupal-4.4.2/includes/session.inc drupal4blog/includes/session.inc
--- drupal-4.4.2/includes/session.inc	Sat Jan 17 18:06:04 2004
+++ drupal4blog/includes/session.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: session.inc,v 1.6 2004/01/17 10:06:04 dries Exp $
+// $Id: session.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 session_set_save_handler("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");
 session_start();
diff -urN drupal-4.4.2/includes/tablesort.inc drupal4blog/includes/tablesort.inc
--- drupal-4.4.2/includes/tablesort.inc	Tue May 25 13:03:43 2004
+++ drupal4blog/includes/tablesort.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: tablesort.inc,v 1.16.2.2 2004/05/25 05:03:43 dries Exp $
+// $Id: tablesort.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 function tablesort_init($header) {
   static $ts;
@@ -95,7 +95,7 @@
   // user has not specified a sort.  check module for default and if none, use 'asc'
   else {
     foreach ($headers as $header) {
-      if (is_array($header) && isset($header['sort'])) {
+      if (isset($header['sort'])) {
         return $header['sort'];
       }
     }
diff -urN drupal-4.4.2/includes/theme.inc drupal4blog/includes/theme.inc
--- drupal-4.4.2/includes/theme.inc	Mon May 24 13:11:09 2004
+++ drupal4blog/includes/theme.inc	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 <?php
-/* $Id: theme.inc,v 1.189.2.2 2004/05/24 05:11:09 dries Exp $ */
+/* $Id: theme.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $ */
 
 /**
  * @file
diff -urN drupal-4.4.2/includes/xmlrpc.inc drupal4blog/includes/xmlrpc.inc
--- drupal-4.4.2/includes/xmlrpc.inc	Tue Jan  6 20:09:41 2004
+++ drupal4blog/includes/xmlrpc.inc	Sun Jul 11 22:32:33 2004
@@ -1,7 +1,7 @@
 <?php
 // by Edd Dumbill (C) 1999-2001
 // <edd@usefulinc.com>
-// $Id: xmlrpc.inc,v 1.12 2004/01/06 12:09:41 unconed Exp $
+// $Id: xmlrpc.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 
 // Copyright (c) 1999,2000,2001 Edd Dumbill.
diff -urN drupal-4.4.2/includes/xmlrpcs.inc drupal4blog/includes/xmlrpcs.inc
--- drupal-4.4.2/includes/xmlrpcs.inc	Tue Jan  6 20:09:41 2004
+++ drupal4blog/includes/xmlrpcs.inc	Sun Jul 11 22:32:33 2004
@@ -1,7 +1,7 @@
 <?php
 // by Edd Dumbill (C) 1999-2001
 // <edd@usefulinc.com>
-// $Id: xmlrpcs.inc,v 1.9 2004/01/06 12:09:41 unconed Exp $
+// $Id: xmlrpcs.inc,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 // Copyright (c) 1999,2000,2001 Edd Dumbill.
 // All rights reserved.
diff -urN drupal-4.4.2/index.php drupal4blog/index.php
--- drupal-4.4.2/index.php	Wed Dec 17 05:06:33 2003
+++ drupal4blog/index.php	Sun Jul 11 22:39:19 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: index.php,v 1.77 2003/12/16 21:06:33 dries Exp $
+// $Id: index.php,v 1.1 2004/07/11 14:39:19 jseng Exp $
 
 include_once "includes/bootstrap.inc";
 drupal_page_header();
@@ -13,6 +13,13 @@
   menu_execute_active_handler();
 }
 else {
+  // check for notfound before returning error
+  $query = check_query($_GET['q']);
+  foreach (module_list() as $name) {
+    $result = module_invoke($name, "notfound");
+    if ($result && $result != $query) return drupal_goto($result);
+  }
+
   drupal_not_found();
 }
 
diff -urN drupal-4.4.2/misc/drupal.css drupal4blog/misc/drupal.css
--- drupal-4.4.2/misc/drupal.css	Wed Feb 25 07:34:30 2004
+++ drupal4blog/misc/drupal.css	Sun Jul 11 22:32:33 2004
@@ -1,4 +1,4 @@
-/* $Id: drupal.css,v 1.56 2004/02/24 23:34:30 unconed Exp $ */
+/* $Id: drupal.css,v 1.2 2004/07/11 14:32:33 jseng Exp $ */
 
 form {
   margin: 0;
diff -urN drupal-4.4.2/misc/print.css drupal4blog/misc/print.css
--- drupal-4.4.2/misc/print.css	Wed Nov 26 03:26:21 2003
+++ drupal4blog/misc/print.css	Sun Jul 11 22:32:33 2004
@@ -1,4 +1,4 @@
-/* $Id: print.css,v 1.4 2003/11/25 19:26:21 dries Exp $ */
+/* $Id: print.css,v 1.2 2004/07/11 14:32:33 jseng Exp $ */
 
 body {
   margin: 1em;
diff -urN drupal-4.4.2/modules/admin.module drupal4blog/modules/admin.module
--- drupal-4.4.2/modules/admin.module	Mon Feb 16 04:09:46 2004
+++ drupal4blog/modules/admin.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: admin.module,v 1.43 2004/02/15 20:09:46 dries Exp $
+// $Id: admin.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function admin_help($section) {
   switch ($section) {
diff -urN drupal-4.4.2/modules/aggregator.module drupal4blog/modules/aggregator.module
--- drupal-4.4.2/modules/aggregator.module	Fri Jun 18 02:35:47 2004
+++ drupal4blog/modules/aggregator.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-/* $Id: aggregator.module,v 1.165.2.6 2004/06/17 18:35:47 dries Exp $ */
+/* $Id: aggregator.module,v 1.1 2004/07/11 14:50:57 jseng Exp $ */
 
 function aggregator_help($section) {
   switch ($section) {
diff -urN drupal-4.4.2/modules/archive.module drupal4blog/modules/archive.module
--- drupal-4.4.2/modules/archive.module	Sat Mar  6 04:57:05 2004
+++ drupal4blog/modules/archive.module	Sun Aug 22 19:00:40 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: archive.module,v 1.51 2004/03/05 20:57:05 dries Exp $
+// $Id: archive.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function archive_help($section) {
   $output = "";
@@ -26,28 +26,28 @@
   $end_of_today = mktime(23, 59, 59, date("n", $offset), date("d", $offset), date("Y", $offset)) + $user->timezone;
 
   // Extract the requested date:
-  if ($edit["year"] && $edit["month"] && $edit["day"]) {
+  if ($edit["year"]) {
     $year = $edit["year"];
     $month = $edit["month"];
     $day = $edit["day"];
 
-    $requested = mktime(0, 0, 0, $month, $day, $year) + $user->timezone;
+    $requested = mktime(0, 0, 0, $month, ($day ? $day : 1), $year) + $user->timezone;
   }
-  else if (arg(0) == "archive" && arg(3)) {
+  else if (arg(0) == "archive" && arg(2)) {
     $year = arg(1);
     $month = arg(2);
     $day = arg(3);
 
-    $requested = mktime(0, 0, 0, $month, $day, $year) + $user->timezone;
+    $requested = mktime(0, 0, 0, $month, ($day ? $day : 1), $year) + $user->timezone;
   }
   else {
-    $year = date("Y", time());
-    $month  = date("n", time());
-    $day = date("d", time());
-
     $requested = $end_of_today + $user->timezone;
   }
 
+  # $day = (isset($day) ? $day : date('d'));
+  $month = (isset($month) ? $month : date('n'));
+  $year = (isset($year) ? $year : date('Y'));
+
   $start_of_month = mktime(0, 0, 0, $month, 1, $year);
 
   // Extract first day of the month:
@@ -58,7 +58,10 @@
 
   $end_of_month = mktime(23, 59, 59, $month, $last, $year);
 
-  $cache = cache_get("archive:calendar:$day-$month-$year");
+  if ($day) 
+    $cache = cache_get("archive:calendar:$day-$month-$year");
+  else
+    $cache = cache_get("archive:calendar:$month-$year");
 
   if (!empty($cache)) {
     return $cache->data;
@@ -66,9 +69,9 @@
 
   // Calculate previous and next months dates and check for shorter months (28/30 days)
   $prevmonth = mktime(23, 59, 59, $month - 1, 1, $year);
-  $prev = mktime(23, 59, 59, $month - 1, min(date("t", $prevmonth), $day), $year);
+  $prev = mktime(23, 59, 59, $month - 1, min(date("t", $prevmonth), ($day ? $day : 1)), $year);
   $nextmonth = mktime(23, 59, 59, $month + 1, 1, $year);
-  $next = mktime(23, 59, 59, $month + 1, min(date("t", $nextmonth), $day), $year);
+  $next = mktime(23, 59, 59, $month + 1, min(date("t", $nextmonth), ($day ? $day : 1)), $year);
 
 
   $result = db_query("SELECT created FROM {node} WHERE status = 1 AND created > $start_of_month AND created < $end_of_month");
@@ -83,13 +86,17 @@
   $output .= "\n<!-- calendar -->\n";
   $output .= "<div class=\"calendar\">";
   $output .= "<table summary=\"". t('A calendar to browse the archives') .".\">\n";
-  $output .= " <tr><td colspan=\"7\" class=\"header-month\">". l("&laquo;", "archive/". date("Y/m/d", $prev)) ." ". format_date($requested, "custom", "F") . date(" Y", $requested) ." ". ($nextmonth <= time() ? l("&raquo;", "archive/". date("Y/m/d", $next)) : "&nbsp;") ."</td></tr>\n";
+  if (variable_get("archive_by",1) == 2) {
+    $output .= " <tr><td colspan=\"7\" class=\"header-month\">". l("&laquo;", "archive/". date("Y/m/d", $prev)) ." ". l(date("F Y", $requested), "archive/" . date("Y/m/d", $requested)) ." ". ($nextmonth <= time() ? l("&raquo;", "archive/". date("Y/m/d", $next)) : "&nbsp;") ."</td></tr>\n";
+  } else {
+    $output .= " <tr><td colspan=\"7\" class=\"header-month\">". l("&laquo;", "archive/". date("Y/m", $prev)) ." ". l(date("F Y", $requested), "archive/" . date("Y/m", $requested)) ." ". ($nextmonth <= time() ? l("&raquo;", "archive/". date("Y/m", $next)) : "&nbsp;") ."</td></tr>\n";
+  }
 
   // First day of week (0 => Sunday, 1 => Monday, ...)
   $cday = $weekstart = variable_get("default_firstday", 0);
 
   // Last day of week
-  ($weekstart - 1 == -1) ? $lastday = 6 : $lastday = $weekstart - 1;
+  ($weekstart == 0) ? $lastday = 6 : $lastday = $weekstart - 1;
 
   // Generate the days of the week:
   $firstcolumn = mktime(0, 0, 0, 3, 20 + $weekstart, 1994);
@@ -129,7 +136,7 @@
       $daytext = "<div>$nday</div>";
       $dayclass = "day-normal";
     }
-    if ($date == $requested) {
+    if ($date == $requested && isset($day)) {
       $output .= "  <td class=\"day-selected\">$daytext</td>\n";
     }
     else if ($date == $start_of_today) {
@@ -161,7 +168,44 @@
 
   $output .= "</table></div>\n\n";
 
-  cache_set("archive:calendar:$day-$month-$year", $output, 1);
+  if ($day) 
+    cache_set("archive:calendar:$day-$month-$year", $output, 1);
+  else
+    cache_set("archive:calendar:$month-$year", $output, 1);
+
+  return $output;
+}
+
+function archive_calendar_listing() {
+  $cache = cache_get("archive:calendar:listing");
+  if (!empty($cache)) {
+    return $cache->data;
+  }
+
+  $start = time(); $until = time();
+  $result = db_query("SELECT * FROM {node}");
+  while ($node = db_fetch_object($result)) {
+    if ($node->created) {
+      if ($node->created < $start) $start = $node->created;
+      if ($node->created > $until) $until = $node->created;
+    }
+  }
+
+  $archive_months = variable_get("archive_months", 0);
+  $count = 0;
+  $output = "<div class=\"item-list\"><ul>"; 
+  for ($time = $until; $time > $start; $time -= 28*24*60*60) {
+    $dy = date("F Y",$time);
+    if ($dy != $last) {
+      $last = $dy;
+      $output .= "<li>" . l($dy, "archive/" . date('Y/m', $time)) . "</li>";
+      $count++;
+      if ($archive_months && $count>=$archive_months) break;
+    }
+  }
+  $output .= "</ul></div>";
+
+  cache_set("archive:calendar:listing", $output);
 
   return $output;
 }
@@ -170,14 +214,19 @@
   global $date;
   if ($op == "list") {
     $blocks[0]["info"] = t("Calendar to browse archives");
+    $blocks[1]["info"] = t("Browse archives by months");
     return $blocks;
   }
   else if (user_access("access content")) {
     switch ($delta) {
       case 0:
-        $block["subject"] = t("Browse archives");
+        $block["subject"] = t("Archives");
         $block["content"] = archive_calendar();
         return $block;
+      case 1:
+        $block["subject"] = t("Archives");
+        $block["content"] = archive_calendar_listing();
+        return $block;
     }
   }
 }
@@ -216,19 +265,35 @@
     $day = arg(3);
   }
 
+  switch (variable_get("archive_by",1)) {
+    case 2:
+      $day = (isset($day) ? $day : date('d'));
+    case 1:
+      $month = (isset($month) ? $month : date('n'));
+    default:
+      $year = (isset($year) ? $year : date('Y'));
+  }
+
   $date = mktime(0, 0, 0, $month, $day, $year) - $user->timezone;
-  $date_end = mktime(0, 0, 0, $month, $day + 1, $year) - $user->timezone;
+  if ($month == 0) {
+    $date_end = mktime(0, 0, 0, $month, $day, $year + 1) - $user->timezone;
+  } else if ($day == 0) {
+    $date_end = mktime(0, 0, 0, $month + 1, $day, $year) - $user->timezone;
+  } else {
+    $date_end = mktime(0, 0, 0, $month, $day + 1, $year) - $user->timezone;
+  }
 
   /*
   ** Prepare the values of the form fields:
   */
 
-  $years = drupal_map_assoc(range(2000, 2005));
-  $months = array(1 => t("January"), 2 => t("February"), 3 => t("March"), 4 => t("April"), 5 => t("May"), 6 => t("June"), 7 => t("July"), 8 => t("August"), 9 => t("September"), 10 => t("October"), 11 => t("November"), 12 => t("December"));
-  $days = drupal_map_assoc(range(0, 31));
+  $years = drupal_map_assoc(range(2000, 2010));
+  $months = array(0 => t("All"), 1 => t("January"), 2 => t("February"), 3 => t("March"), 4 => t("April"), 5 => t("May"), 6 => t("June"), 7 => t("July"), 8 => t("August"), 9 => t("September"), 10 => t("October"), 11 => t("November"), 12 => t("December"));
+
+  $days = array_merge(array(0 => "All"), drupal_map_assoc(range(1, 31)));
 
   $start = "<div class=\"container-inline\">";
-  $start .= form_select("", "year", ($year ? $year : date("Y")), $years). form_select("", "month", ($month ? $month : date("m")), $months) . form_select("", "day", ($day ? $day : date("d")), $days) . form_submit(t("Show"));
+  $start .= form_select("", "year", $year, $years). form_select("", "month", $month, $months) . form_select("", "day", $day, $days) . form_submit(t("Show"));
   $start .= "</div>";
   $output .= form($start);
 
@@ -237,21 +302,30 @@
   ** selected.
   */
 
-  if ($year && $month && $day) {
-    $result = db_query_range("SELECT nid FROM {node} WHERE status = '1' AND created > %d AND created < %d ORDER BY created", $date, $date_end, 0, 20);
+  $result = db_query_range("SELECT nid FROM {node} WHERE status = '1' AND created > %d AND created < %d ORDER BY created", $date, $date_end, 0, 20);
 
-    while ($nid = db_fetch_object($result)) {
-      $output .= node_view(node_load(array("nid" => $nid->nid)), 1);
-    }
+  while ($nid = db_fetch_object($result)) {
+    $output .= node_view(node_load(array("nid" => $nid->nid)), 1);
   }
+
   print theme("page", $output);
 }
 
 function archive_settings() {
+  $group = form_select(t("First day of week"), "default_firstday", variable_get("default_firstday", 0), array(0 => t("Sunday"), 1 => t("Monday"), 2 => t("Tuesday"), 3 => t("Wednesday"), 4 => t("Thursday"), 5 => t("Friday"), 6 => t("Saturday")), t("The first day of the week.  By changing this value you choose how the calendar block is rendered."));
+  $group .= form_select(t("Archive by"), "archive_by", variable_get("archive_by", 1), array(0 => t("Year"), 1 => t("Month"), 2 => t("Day")), t("Default archive by year, day or month."));
+  $output .= form_group(t("Calendar Archives"), $group);
 
-  $output .= form_select(t("First day of week"), "default_firstday", variable_get("default_firstday", 0), array(0 => t("Sunday"), 1 => t("Monday"), 2 => t("Tuesday"), 3 => t("Wednesday"), 4 => t("Thursday"), 5 => t("Friday"), 6 => t("Saturday")), t("The first day of the week.  By changing this value you choose how the calendar block is rendered."));
+  $group = form_select(t("Numbers of months"), "archive_months", variable_get("archive_months", 0), array( 0 => "all", 5 => "5", 10 => "10", 15 => "15", 20 => "20" ), t("Number of months to display on monthly archive blocks"));
+  $output .= form_group(t("Monthly Archives"), $group);
 
   return $output;
+}
+
+function archive_blogadmin($type) {
+  if ($type == "options") {
+    return array(l(t("Archive options"),"admin/system/modules/archive") => t("Configure archive options."));
+  }
 }
 
 ?>
diff -urN drupal-4.4.2/modules/atom.module drupal4blog/modules/atom.module
--- drupal-4.4.2/modules/atom.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/atom.module	Sun Jul 11 22:50:57 2004
@@ -0,0 +1,83 @@
+<?php
+// $Id: atom.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+function atom_help($section) {
+  $output = "";
+	    
+  switch ($section) {
+    case "admin/system/modules#description":
+	  $output = t("Provides an Atom 0.3 feed");
+	  break;
+  }
+  return $output;
+}
+
+function atom_link($type, $node = 0, $main) {
+  if ($type == "system") {
+    if (user_access('access content')) {
+      menu('atom/feed', t('atom feed'), 'atom_feed', 0, MENU_HIDE);
+    }
+  }
+}
+				  
+function atom_menu() {
+  $items = array();
+  drupal_set_html_head("<link rel=\"alternate\" type=\"application/atom+xml\" title=\"Atom\" href=\"". url("atom/feed") ."\" />");
+  $items[] = array('path' => 'atom/feed', 'title' => t('atom feed'),
+                   'callback' => 'atom_feed',
+                   'access' => user_access('access content'),
+                   'type' => MENU_CALLBACK);
+  return $items;
+}
+
+function atom_feed() {
+  global $base_url;
+  $output = "";
+  $last_mod = 0;
+    $nodes = db_query_range("SELECT n.nid, u.uid, u.name FROM {node} n, {users} u WHERE n.uid = u.uid AND n.promote = '1' AND n.status = '1' ORDER BY n.created DESC", 0, variable_get('default_nodes_feed',15));
+
+    while ($node = db_fetch_object($nodes)) {
+      $item = node_load(array("nid" => $node->nid));
+      $link = url("node/view/$node->nid", NULL, NULL, true);
+      $output .= "  <entry>\n";
+      $output .= "    <title>". $item->title ."</title>\n";
+      $output .= "    <link rel=\"alternate\" type=\"text/html\" href=\"". $link ."\" />\n";
+      $output .= "    <id>$link</id>\n";
+      $output .= "    <issued>". _atom_timestamp2w3dtf($item->created) ."</issued>\n";
+      $output .= "    <modified>". _atom_timestamp2w3dtf($item->changed) ."</modified>\n";
+      $last_mod = $item->changed;
+      $output .= "    <author>\n";
+      if ($node->name) {
+        $output .= "      <name>". $node->name ."</name>\n";
+      }
+      else {
+        $output .= "      <name>". variable_get('anonymous', 'Anonymous') ."</name>\n";
+      }
+      $output .= "    </author>\n";
+      $output .= "  </entry>\n";
+    }
+
+    header("Content-Type: application/xml");
+    print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+    print "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\">\n";
+
+    $title = variable_get('site_name', 'drupal');
+    if (variable_get('site_slogan','')) 
+      $title .= ' - ' . variable_get('site_slogan','');
+    print "  <title>$title</title>\n";
+    print "  <link rel=\"alternate\" type=\"text/html\" href=\"". $base_url. "\"/>\n";
+    print "  <modified>". _atom_timestamp2w3dtf($last_mod) ."</modified>\n";
+    print $output;
+    print "</feed>\n";
+}
+
+function _atom_timestamp2w3dtf($timestamp) {
+  $tz = date("O", $timestamp);
+  return date("Y-m-d", $timestamp) ."T". date("H:i:s", $timestamp) . substr($tz, 0, 3) . ":" . substr($tz, 3, 2);
+}
+
+function atom_default_node() {
+  drupal_set_html_head("<link rel=\"alternate\" type=\"application/atom+xml\" title=\"Atom\" href=\"". url("atom/feed") ."\" />");
+}
+
+?>
diff -urN drupal-4.4.2/modules/block.module drupal4blog/modules/block.module
--- drupal-4.4.2/modules/block.module	Sat Jun 19 06:20:56 2004
+++ drupal4blog/modules/block.module	Thu Jul 15 21:54:04 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: block.module,v 1.107.2.3 2004/06/18 22:20:56 dries Exp $
+// $Id: block.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function block_help($section = "admin/help#block") {
   $output = "";
@@ -375,8 +375,8 @@
         if (!($block['throttle'] && (module_invoke("throttle", "status") > 4))) {
           $block = array_merge($block, module_invoke($block['module'], 'block', 'view', $block['delta']));
         }
-        if (isset($block['content']) && $block['content']) {
-          $blocks[$region]["$block[module]_$block[delta]"] = (object) $block;
+        if (isset($block['content']) && strip_tags($block['content'], '<img><input>')) {
+           $blocks[$region]["$block[module]_$block[delta]"] = (object) $block;
         }
       }
     }
diff -urN drupal-4.4.2/modules/blog.module drupal4blog/modules/blog.module
--- drupal-4.4.2/modules/blog.module	Tue May 25 02:43:31 2004
+++ drupal4blog/modules/blog.module	Sun Jul 11 22:50:57 2004
@@ -1,18 +1,31 @@
 <?php
-// $Id: blog.module,v 1.168.2.2 2004/05/24 18:43:31 dries Exp $
+// $Id: blog.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function blog_settings() {
-  $output = form_textarea(t("Explanation or submission guidelines"), "blog_help", variable_get("blog_help", ""), 70, 4, t("This text is displayed at the top of the blog submission form.  It's useful for helping or instructing your users."));
-  $output .= form_select(t("Minimum number of words in a blog entry"), "minimum_blog_size", variable_get("minimum_blog_size", 0), drupal_map_assoc(array(0, 10, 25, 50, 75, 100, 125, 150, 175, 200)), t("The minimum number of words a personal blog entry should contain.  This is useful to rule out submissions that do not meet the site's standards, such as short test posts."));
+  $group = form_textarea(t("Explanation or submission guidelines"), "blog_help", variable_get("blog_help", ""), 70, 4, t("This text is displayed at the top of the blog submission form.  It's useful for helping or instructing your users."));
+  $group .= form_select(t("Minimum number of words in a blog entry"), "minimum_blog_size", variable_get("minimum_blog_size", 0), drupal_map_assoc(array(0, 10, 25, 50, 75, 100, 125, 150, 175, 200)), t("The minimum number of words a blog entry should contain.  This is useful to rule out submissions that do not meet the site's standards, such as short test posts."));
+  $group .= form_select(t("Display blog link in each entry"), "blog_link", variable_get("blog_link", 1), array( 0 => "No", 1 => "Yes" ), t("Each blog entry has a link which looks like 'user's blog'. Some people may prefer not to display such link."));
+  $output = form_group(t('Blog Entry settings'), $group);
+
+  $group = form_textfield(t("Block title"), "blog_block_title", variable_get("blog_block_title", "Recent Entries"), 70, 180, t("") . " " . t("Title of the Blog block, e.g. Recent Entries"));
+  $group .= form_select(t("Numbers of Entries"), "blog_block_entries", variable_get("blog_block_entries", 10), drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 50)), t("Numbers of latest entries to display in block."));
+  $output .= form_group(t('Blog Block settings'), $group);
+
+  $group = form_select(t("RSS feed"), "blog_syndicate_rss", variable_get("blog_syndicate_rss",0), array(0 => "Full entry in RSS", 1 => "Teaser in RSS"), t("Format of the entries in syndication"));
+  /* 
+  $group .= form_select(t("Number of entries"), "blog_syndicate_entries", variable_get("blog_syndicate_entries", 15), drupal_map_assoc(array(10, 15, 20, 25, 30, 50)), t("Number of last entries to display in syndicate."));
+  */
+  $output .= form_group(t('Syndicate settings'),$group);
+
   return $output;
 }
 
 function blog_node_name($node) {
-  return t("personal blog entry");
+  return t("blog entry");
 }
 
 function blog_perm() {
-  return array("edit own blog");
+  return array("create blog entry", "edit own blog");
 }
 
 function blog_access($op, $node) {
@@ -23,7 +36,7 @@
   }
 
   if ($op == "create") {
-    return user_access("edit own blog") && $user->uid;
+    return user_access("create blog entry");
   }
 
   if ($op == "update") {
@@ -36,13 +49,43 @@
 
 }
 
+/**
+ * Respond to node insertion.
+ */
+function blog_insert($node) {
+  db_query("INSERT INTO {blog} (nid, extended, excerpt, format) VALUES (%d, '%s', '%s', %d)", $node->nid, $node->extended, $node->excerpt, $node->format);
+}
+
+/**
+ * Respond to node updating.
+ */
+function blog_update($node) {
+  db_query("UPDATE {blog} SET extended = '%s', excerpt = '%s', format = %d WHERE nid = %d", $node->extended, $node->excerpt, $node->format, $node->nid);
+}
+
+/**
+ * Respond to node deletion
+ */
+function blog_delete(&$node) {
+  db_query("DELETE FROM {blog} WHERE nid = %d", $node->nid);
+}
+
+/**
+ * Load node-type-specific information.
+ */
+function blog_load($node) {
+  return db_fetch_object(db_query("SELECT extended, excerpt, format FROM {blog} WHERE nid = %d", $node->nid));
+}
+
 function blog_user($type, &$edit, &$user) {
   switch ($type) {
     case "view_public":
     case "view_private":
+      $output = "";
       if (user_access("edit own blog", $user)) {
-        return form_item(t("Blog"), l(t("view recent blog entries"), "blog/$user->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $user->name)))));
+        $output .= form_item(t("Blog"), l(t("view recent blog entries"), "blog/$user->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $user->name)))));
       }
+      return $output;
   }
 }
 
@@ -54,7 +97,7 @@
       $output .= t("
       <p>Drupal's blog module allows registered users to maintain an online weblog (commonly known as a blog), often referred to as an online journal or diary.  These can be filled with daily thoughts, poetry, boneless blabber, spiritual theories, intimate details, valuable experiences, cynical rants, semi-coherent comments, writing experiments, artistic babblings, critics on current facts, fresh insights, diverse dreams, chronicles and mumbling madness available for public consumption.</p>
       <p>Blogs are made up of individual entries (nodes) that are timestamped and are typically viewed by day as you would a diary.  Blogs often contain links to things you've seen and/or agree/disagree with.  A typical example of a long term blog can be seen at %scripting-com.</p>
-      <p>The blog module adds a \"user blogs\" navigation link to the site, which takes any visitor to a page that displays the most recent blog entries from all the users on the site. Personal user menus gain a \"create a blog entry\" link (which takes you to a submission form) and a \"view personal blog\" link (which displays your blog entries as other people will see them).  On the bottom of each of your own blog entries, there is an \"edit this blog entry\" link that lets you edit or delete that entry.</p>
+      <p>The blog module adds a \"user blogs\" navigation link to the site, which takes any visitor to a page that displays the most recent blog entries from all the users on the site. Personal user menus gain a \"create a blog entry\" link (which takes you to a submission form) and a \"view blog\" link (which displays your blog entries as other people will see them).  On the bottom of each of your own blog entries, there is an \"edit this blog entry\" link that lets you edit or delete that entry.</p>
       <p>If a user has the ability to post blogs, then the import module (news aggregator) will display a blog-it link <strong>(b)</strong> next to each news item in its lists.  Click on this and you will be taken to the blog submission form, with the title, a link to the item, and a link to the source into the body text already in the text box, ready for you to add your explanation.  This actively encourages people to add blog entries about things they see and hear elsewhere in the Drupal site and from your syndicated partner sites.</p>", array("%scripting-com" => "<a href=\"http://www.scripting.com/\">http://www.scripting.com/</a>"));
       break;
     case 'admin/system/modules#description':
@@ -84,18 +127,18 @@
     $account = $user;
   }
 
-  $result = db_query_range("SELECT n.nid, n.title, n.teaser, n.created, u.name, u.uid FROM {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE n.type = 'blog' AND u.uid = %d AND n.status = 1 ORDER BY n.nid DESC", $uid, 0, 15);
+  $result = db_query_range("SELECT * FROM {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE n.type = 'blog' AND u.uid = %d AND n.status = 1 ORDER BY n.created DESC", $uid, 0, variable_get("blog_syndicate_entries", 15));
   $channel["title"] = $account->name ."'s blog";
   $channel["link"] = url("blog/$uid", NULL, NULL, TRUE);
-  $channel["description"] = $term->description;
+  $channel["description"] = variable_get('site_mission','');
   node_feed($result, $channel);
 }
 
 function blog_feed_last() {
-  $result = db_query_range("SELECT n.nid, n.title, n.teaser, n.created, u.name, u.uid FROM {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.nid DESC", 0, 15);
-  $channel["title"] = variable_get("site_name", "drupal") ." blogs";
-  $channel["link"] = url("blog");
-  $channel["description"] = $term->description;
+  $result = db_query_range("SELECT *  FROM {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.nid DESC", 0, variable_get("blog_syndicate_entries",15));
+  $channel["title"] = variable_get("site_name", "drupal");
+  $channel["link"] = url("", NULL, NULL, TRUE);
+  $channel["description"] = variable_get('site_mission','');
   node_feed($result, $channel);
 }
 
@@ -112,7 +155,7 @@
   $output .= theme('pager', NULL, variable_get("default_nodes_main", 10));
   $output .= theme('xml_icon', url("blog/feed/$account->uid"));
 
-  drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="RSS - '. $title .'" href="'. url("blog/feed/$account->uid") .'" />');
+  drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="RSS - '. $title .'" href="'. url("blog/feed/$account->uid", NULL, NULL, TRUE) .'" />');
   print theme("page", $output, $title);
 }
 
@@ -129,7 +172,7 @@
   $output .= theme('pager', NULL, variable_get("default_nodes_main", 10));
   $output .= theme('xml_icon', url('blog/feed'));
 
-  drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="RSS - blogs" href="'. url('blog/feed') .'" />');
+  drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="RSS - blogs" href="'. url('blog/feed', NULL, NULL, TRUE) .'" />');
   print theme("page", $output);
 }
 
@@ -139,7 +182,7 @@
   ** Validate the size of the blog:
   */
 
-  if (isset($node->body) && count(explode(" ", $node->body)) < variable_get("minimum_blog_size", 0)) {
+  if (isset($node->body) && count(explode(" ", $node->body." ".$node->extended)) < variable_get("minimum_blog_size", 0)) {
     $error["body"] = theme("error", t("The body of your blog is too short."));
   }
 
@@ -170,7 +213,14 @@
     $output .= implode("", taxonomy_node_form("blog", $node));
   }
 
-  $output .= form_textarea(t("Body"), "body", $node->body, 60, 15, $error["body"] ? $error["body"] : filter_tips_short());
+  $output .= form_textarea(t("Entry Body"), "body", $node->body, 60, 10, "");
+
+  $output .= form_textarea(t("Extended Entry"), "extended", $node->extended, 60, 15, "");
+
+  $output .= form_textarea(t("Excerpt"), "excerpt", $node->excerpt, 60, 5, $error["body"] ? $error["body"] : filter_tips_short());
+
+  $format_type = array(-1 => "No formatting", 0 => "Convert Line Breaks", 1 => "Simple Wiki");
+  $output .= form_select(t("Text Formatting"), "format", $node->format, $format_type, t("'Convert Line Breaks' enclose your paragraph in &lt;p&gt; and &lt;/p&gt; tag for you which is what most bloggers are used to. 'No formatting' assume you will do all HTML formatting. 'Simple Wiki' supports very basic Wiki Formatting Rules."));
 
   return $output;
 }
@@ -197,7 +247,7 @@
 }
 
 function blog_content($node, $main = 0) {
-  return node_prepare($node, $main);
+  return _blog_prepare($node, $main);
 }
 
 function blog_view($node, $main = 0, $page = 0) {
@@ -223,7 +273,7 @@
   if ($type == "system") {
     if (user_access("edit own blog")) {
       menu("node/add/blog", t("blog entry"), "node_page", 0);
-      menu("blog/". $user->uid, t("my blog"), "blog_page", 1);
+      menu("blog/". $user->uid, t("blog archives"), "blog_page", 1);
     }
     if (user_access("access content")) {
       menu("blog", t("blogs"), "blog_page", 0, MENU_HIDE);
@@ -235,11 +285,13 @@
   }
 
   if ($type == "node" && $node->type == "blog") {
-    if (blog_access("update", $node)) {
-      $links[] = l(t("edit this blog entry"), "node/edit/$node->nid", array("title" => t("Edit this blog entry.")));
-    }
-    elseif (arg(0) != 'blog' && arg(1) != $node->uid) {
-      $links[] = l(t("%username's blog", array("%username" => $node->name)), "blog/$node->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $node->name))));
+    if (variable_get("blog_link",1)) {
+      if (blog_access("update", $node) && !user_access('administer nodes')) {
+        $links[] = l(t("edit blog"), "node/edit/$node->nid", array("title" => t("Edit this blog entry.")));
+      }
+      elseif (arg(0) != 'blog' && arg(1) != $node->uid) {
+        $links[] = l(t("%username's blog", array("%username" => $node->name)), "blog/$node->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $node->name))));
+      }
     }
   }
 
@@ -254,12 +306,241 @@
   }
   else {
     if (user_access("access content")) {
-      $block["content"] = node_title_list(db_query_range("SELECT n.title, n.nid FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.nid DESC", 0, 10));
-      $block["content"] .= "<div class=\"more-link\">". l(t("more"), "blog", array("title" => t("Read the latest blog entries."))) ."</div>";
-      $block["subject"] = t("Blogs");
+      //$block["content"] = node_title_list(db_query_range("SELECT n.title, n.nid FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.created DESC", $_GET['from']+variable_get('default_nodes_main',10), variable_get("blog_block_entries",10)));
+      // $block["content"] .= "<div class=\"more-link\">". l(t("more"), "blog", array("title" => t("Read the latest blog entries."))) ."</div>";
+
+      $block["content"] = node_title_list(db_query_range("SELECT n.title, n.nid FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.created DESC", 0, variable_get("blog_block_entries",10)));
+      $block["subject"] = variable_get("blog_block_title", "Recent Entries");
     }
     return $block;
   }
+}
+
+
+/*
+ * modified from check_output() from filter.module
+ */
+function check_output_without_nl2br($text) {
+  if (isset($text)) {
+    // Filter content on output:
+    $filters = filter_list();
+
+    // Give filters the chance to escape HTML-like data such as code or formulas
+    // (from this point on, the input can be treated as HTML)
+    if (variable_get("filter_html", FILTER_HTML_DONOTHING) != FILTER_HTML_ESCAPE) {
+      foreach ($filters as $module => $filter) {
+        $text = module_invoke($module, "filter", "prepare", $text);
+      }
+    }
+
+    // HTML handling is done before all regular filtering activities
+    $text = filter_default($text);
+
+    // Regular filtering
+    foreach ($filters as $module => $filter) {
+      $text = module_invoke($module, "filter", "process", $text);
+    }
+  }
+  else {
+    $text = message_na();
+  }
+
+  return $text;
+}
+
+function blog_blogadmin($type = "") {
+  $list = array();
+
+  if ($type == "block") {
+    if (user_access("create blog entry"))
+      $list[] = l(t("new blog entry"), "node/add/blog");
+  } else if ($type == "options") {
+    if (user_access("administer site configuration")) {
+      $list[l(t("Blog entries options"),"admin/system/modules/blog")] = t("Define options for your blog entries and RSS syndication.");
+    }
+  }
+
+  return $list;
+}
+
+function _blog_process_format($node,$str) {
+  if ($node->format < 0) {
+    return check_output_without_nl2br($str);
+  }
+
+  // Convert Line Breaks
+  if ($node->format == 0) {
+    return check_output($str);
+
+    $paras = preg_split("/\r?\n\r?\n/",$str);
+    foreach ($paras as $id => $p) {
+      if (!$p) { 
+          $paras[$id] = "<br />";
+      } else {
+        $paras[$id] = "<p>". check_output($p) ."</p>";
+      }
+    }
+    return implode("\n\n",$paras);
+  }
+
+  // Simple Wiki
+  if ($node->format == 1) {
+    //include_once "modules/wiki.module";
+    //return _wiki_transform($str);
+    $wiki_search = array(
+      "/('*)'''(.*?)'''/",
+      "/''(.*)''/",
+      "/----+/",
+      "/\[(http|https|ftp|mailto):(\S+)\s+([^\]]+)\]/",
+      "/^(http|https|ftp):\/\/(\S+)(gif|jpg|png|bmp|jpeg)/",
+      "/([^\"\[])(http|https|ftp|mailto):(\S+)/",
+    );
+
+    $wiki_replace = array(
+      "\\1<strong>\\2</strong>",
+      "<em>\\1</em>",
+      "<hr/>",
+      "<a href=\"\\1:\\2\">\\3</a>",
+      "<img src=\"\\1://\\2\\3\" /><br/>",
+      "\\1<a href=\"\\2:\\3\">\\2:\\3</a>",
+    );
+
+    $paras = preg_split("/\r?\n\r?\n/",$str);
+    foreach ($paras as $id => $p) {
+      $paras[$id] = "<p>" .  check_output(
+         preg_replace($wiki_search,$wiki_replace,$p)) . "</p>";
+    }
+    return implode("\n\n",$paras);
+  }
+
+  return $str;
+}
+
+function _blog_prepare($node,$main = 0) {
+    $node->readmore = (strlen($node->extended) > 0 
+                   || strlen($node->excerpt > 0));
+    if ($main == 0) {
+        $str = rtrim($node->body) . "\n\n" . rtrim($node->extended);
+        $node->body = _blog_process_format($node,$str);
+    } else {
+        if (strlen(rtrim($node->excerpt)) > 0) 
+          $str = rtrim($node->excerpt);
+        else
+          $str = rtrim($node->body);
+        /*
+        if ($node->readmore) {
+          $link = url("node/view/$node->nid", NULL, NULL, TRUE);
+          $str .= " ...<a href=\"$links\">read more</a>";
+        }
+        */
+        $node->teaser = _blog_process_format($node,$str);
+    }
+    return $node;
+}
+
+function _blog_format_rss_item($title, $link, $description, $args = array()) {
+  // arbitrary elements may be added using the $args associative array
+  $output = "<item>\n";
+  $output .= " <title>". drupal_specialchars(strip_tags($title)) ."</title>\n";
+  $output .= " <link>". drupal_specialchars(strip_tags($link)) ."</link>\n";
+  $output .= " <description>". $description ."</description>\n";
+  foreach ($args as $key => $value) {
+    $output .= "<$key>". drupal_specialchars(strip_tags($value)) ."</$key>\n";
+  }
+  $output .= "</item>\n";
+
+  return $output;
+}
+
+function blog_feed_item($node) {
+  $link = url("node/view/$node->nid", NULL, NULL, TRUE);
+
+  switch (variable_get("blog_syndicate_rss",0)) {
+    case 0:
+      $node = _blog_prepare($node,0);
+      $desc = drupal_specialchars($node->body);
+      break;
+    case 1:
+      $node = _blog_prepare($node,1);
+      $node->teaser .= "...<a href=\"$links\">read more</a>";
+      $desc = drupal_specialchars($node->teaser);
+      break;
+  }
+
+  $terms = array();
+  if (module_exist("taxonomy")) {
+    foreach (taxonomy_node_get_terms($node->nid) as $term) {
+      $terms = array_merge($terms,array("dc:subject" => $term->name));
+      break;
+    }
+  }
+
+  return _blog_format_rss_item($node->title, $link, $desc, 
+    array_merge($terms, array(
+      'dc:date' => encode_iso8601($node->created),
+      'dc:creator' => $node->name,
+    ))
+  );
+}
+
+// xmlrpc.php already has iso8601_encode but that does not handle
+// timezone which we need for RSS
+function encode_iso8601($time) {
+  $tzd = date('O',$time);
+  $tzd = $tzd[0] . str_pad((int) abs(($tzd/100)),2,"0",STR_PAD_LEFT) . ":" .
+                   str_pad((int) abs(($tzd%100)),2,"0",STR_PAD_LEFT);
+  $date = date('Y-m-d\TH:i:s',$time).$tzd;
+  return $date;
+}
+
+function blog_search($keys) {
+
+  // Return the results of performing a search using the indexed search
+  // for this particular type of node.
+  //
+  // Pass an array to the 'do_search' function which dictates what it
+  // will search through, and what it will search for
+  //
+  // "keys"'s value is the keywords entered by the user
+  //
+  // "type"'s value is used to identify the node type in the search
+  // index.
+  //
+  // "select"'s value is used to relate the data from the specific nodes
+  // table to the data that the search_index table has in it, and the the
+  // do_search functino will rank it.
+  //
+  // The select must always provide the following fields - lno, title,
+  // created, uid, name, count
+  //
+  $find = do_search(array('keys' => $keys, 'type' => 'blog', 'select' => "select s.lno as lno, n.title as title, n.created as created, u.uid as uid, u.name as name, s.count as count FROM {search_index} s, {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE s.lno = n.nid AND s.type = 'blog' AND s.word like '%' AND n.status = 1"));
+
+  return array(t('Matching blog entries ranked in order of relevance'), $find);
+}
+
+function blog_update_index() {
+
+  // Return an array of values to dictate how to update the search index
+  // for this particular type of node.
+  //
+  // "last_update"'s value is used with variable_set to set the
+  // last time this node type had an index update run.
+  //
+  // "node_type"'s value is used to identify the node type in the search
+  // index.
+  //
+  // "select"'s value is used to select the node id and text fields from
+  // the table we are indexing. In this case, we also check against the
+  // last run date for the nodes update.
+
+  return array('last_update' => 'blog_cron_last', 'node_type' => 'blog', 'select' => "SELECT b.nid as lno, n.title as text1, n.body as text2, b.extended as text3, b.excerpt as text4 FROM {node} n, {blog} b WHERE b.nid = n.nid AND n.status = 1 AND n.moderate = 0 and (n.created > " . variable_get('blog_cron_last', 1) . " or n.changed > " .  variable_get('blog_cron_last', 1) . ")");
+}
+
+function blog_notfound() {
+  $query = basename(check_query($_GET["q"]));
+  $account = user_load(array("name" => $query, "status" => 1));
+  if ($account)
+    return 'blog/'.$account->uid;
 }
 
 ?>
diff -urN drupal-4.4.2/modules/blogadmin.module drupal4blog/modules/blogadmin.module
--- drupal-4.4.2/modules/blogadmin.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/blogadmin.module	Sun Jul 11 22:50:57 2004
@@ -0,0 +1,91 @@
+<?php
+// $Id: blogadmin.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+function blogadmin_help($section) {
+  switch ($section) {
+    case "admin/system/modules#description":
+      return t("Provides simple blog administration block. (Requires: drupal4blog patches)");
+  }
+}
+
+function blogadmin_link($type) {
+  if ($type == "system")
+    menu("blogadmin", t("blogadmin"), "blogadmin_page", 0, MENU_HIDE);
+}
+
+function blogadmin_page() {
+  $type = strip_tags(arg(1));
+
+  switch (arg(1)) {
+    case "options":
+      $output = blogadmin_default($type);
+      break;
+      
+    default:
+      $output = blogadmin_default("page");
+      break;
+  }
+  print $output;
+}
+
+function blogadmin_default($type = "page") {
+  $menu = module_invoke_all("blogadmin",$type);
+
+  /*
+  ** These should goes into the respective *_blogadmin() but leave it here
+  ** because we do not want to change too many modules
+  */
+  if ($type == "options") {
+     if (user_access("administer site configuration")) {
+      if (module_exist("system"))
+        $menu[l(t("Theme options"),"admin/system/themes/simple")] =
+          t("Configure drupal look and feel.");
+    } 
+  }
+
+  $output = "";
+
+  foreach ($menu as $l => $m) {
+    $output .= "<ul><li>".$l."<ul><li>".$m."</li></ul></li></ul>\n";
+  }
+
+  if ($type == "options") return theme("page",$output, t("Options"));
+
+  return theme("page",$output, t("Blog Admin"));
+}
+
+function blogadmin_block($op = "list", $delta = 0) {
+  if ($op == "list") {
+    $block[0]['info'] = t("Blog Admin");
+    return $block;
+  }
+
+  $block["subject"] = t("Blog Admin");
+
+  $menu = module_invoke_all("blogadmin","block");
+  /*
+  ** These should goes into the respective *_blogadmin() but leave it here
+  ** because we do not want to change too many modules
+  */
+  if (user_access("administer users"))
+    if (module_exist("user"))
+      $menu[] = l(t("users accounts"),"admin/user");
+
+  if (user_access("administer site configuration"))
+    if (module_exist("system"))
+      $menu[] = l(t("general config"),"admin/system");
+
+  if (user_access("administer site configuration"))
+    if (module_exist("block"))
+      $menu[] = l(t("sidebar config"),"admin/system/block");
+
+  if (user_access("administer site configuration"))
+    $menu[] = l(t("features options"),"blogadmin/options");
+
+  
+  $block["content"] = theme_item_list($menu);
+
+  return $block;
+}
+
+?>
diff -urN drupal-4.4.2/modules/blogapi.module drupal4blog/modules/blogapi.module
--- drupal-4.4.2/modules/blogapi.module	Sun May 23 05:32:51 2004
+++ drupal4blog/modules/blogapi.module	Sun Aug 22 21:50:18 2004
@@ -1,7 +1,9 @@
 <?php
+// $Id: blogapi.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
-// $Id: blogapi.module,v 1.5.2.3 2004/05/22 21:32:51 dries Exp $
-
+/**
+ * Implementation of hook_help().
+ */
 function blogapi_help($section) {
   switch ($section) {
     case 'admin/help#blogapi':
@@ -11,6 +13,64 @@
   }
 }
 
+function blogapi_settings() {
+  $output = form_select(t("XML-RPC Engine"), "blogapi_engine", variable_get("blogapi_engine",0), array(0 => "Blogger", 1 => "MetaWeblog", 2 => "Movabletype"), t("Select preferred  engine in RSD."));
+  return $output;
+}
+
+function blogapi_link($type, $node = 0, $main) {
+  if ($type == "system") {
+    menu("blogapi", t("RSD"), "blogapi_blogapi", 0, MENU_HIDE);
+  }
+}
+
+function blogapi_blogapi() {
+  switch (arg(1)) {
+    case "rsd":
+      blogapi_rsd();
+      break;
+    default:
+      drupal_not_found();
+      break;
+  }
+}
+
+function blogapi_rsd() {
+  global $base_url;
+
+  $xmlrpc = $base_url . FILE_SEPARATOR . "xmlrpc.php";
+  $base = url("",NULL,NULL,TRUE);
+  $blogid = 1; # until we figure out how to handle multiple bloggers
+
+  $metaweblog = "false"; $blogger = "false"; $mt = "false";
+  if (variable_get("blogapi_engine",0) == 0) {
+    $blogger = "true";
+  } else if (variable_get("blogapi_engine",0) == 1) {
+    $metaweblog = "true";
+  } else if (variable_get("blogapi_engine",0) == 2) {
+    $mt = "true";
+  }
+
+  print <<<__RSD__
+<?xml version="1.0"?> 
+<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
+  <service>
+    <engineName>Drupal</engineName> 
+    <engineLink>http://www.drupal.org/</engineLink>
+    <homePageLink>$base</homePageLink>
+    <apis>
+      <api name="MetaWeblog" preferred="$metaweblog" apiLink="$xmlrpc" blogID="$blogid" />
+      <api name="Blogger" preferred="$blogger" apiLink="$xmlrpc" blogID="$blogid" />
+      <api name="Movabletype" preferred="$mt" apiLink="$xmlrpc" blogID="$blogid" />
+    </apis>
+  </service>
+</rsd>
+__RSD__;
+}
+
+/**
+ * Implementation of hook_xmlrpc().
+ */
 function blogapi_xmlrpc() {
   $methods = array('blogger.getUsersBlogs' => array('function' => 'blogapi_get_users_blogs'),
                    'blogger.getUserInfo' => array('function' => 'blogapi_get_user_info'),
@@ -22,18 +82,24 @@
                    'metaWeblog.editPost' => array('function' => 'blogapi_edit_post'),
                    'metaWeblog.getPost' => array('function' => 'blogapi_get_post'),
                    'metaWeblog.newMediaObject' => array('function' => 'blogapi_new_media_object'),
-                   'metaWeblog.getCategories' => array('function' => 'blogapi_get_categories'),
+                   'metaWeblog.getCategories' => array('function' => 'blogapi_get_category_list'),
                    'metaWeblog.getRecentPosts' => array('function' => 'blogapi_get_recent_posts'),
+                   'mt.getRecentPostTitles' => array('function' => 'blogapi_get_recent_post_titles'),
                    'mt.getCategoryList' => array('function' => 'blogapi_get_category_list'),
                    'mt.getPostCategories' => array('function' => 'blogapi_get_post_categories'),
-                   'mt.setPostCategories' => array('function' => 'blogapi_set_post_categories')
+                   'mt.setPostCategories' => array('function' => 'blogapi_set_post_categories'),
+                   'mt.getTrackbackPings' => array('function' => 'blogapi_get_trackback_pings'),
+                   'mt.supportedTextFilters' => array('function' => 'blogapi_supported_text_filters'),
+                   'mt.supportedMethods' => array('function' => 'blogapi_supported_methods'),
+                   'mt.publishPost' => array('function' => 'blogapi_publish_post')
                    );
 
   return $methods;
 }
 
-/** api functions */
-
+/**
+ * Blogging API callback. Finds the URL of a user's blog.
+ */
 function blogapi_get_users_blogs($req_params) {
   $params = blogapi_convert($req_params);
   // Remove unused appkey from bloggerAPI.
@@ -47,7 +113,7 @@
                                   'blogid' => new xmlrpcval($user->uid),
                                   'blogName' => new xmlrpcval($user->name . "'s blog")),
                             'struct');
-    $resp = new xmlrpcval(array($struct), "array");
+    $resp = new xmlrpcval(array($struct), 'array');
     return new xmlrpcresp($resp);
   }
   else {
@@ -55,6 +121,9 @@
   }
 }
 
+/**
+ * Blogging API callback. Returns profile information about a user.
+ */
 function blogapi_get_user_info($req_params) {
   $params = blogapi_convert($req_params);
 
@@ -67,7 +136,7 @@
                                   'firstname' => new xmlrpcval($name[0], 'string'),
                                   'nickname' => new xmlrpcval($user->name, 'string'),
                                   'email' => new xmlrpcval($user->mail, 'string'),
-                                  'url' => new xmlrpcval(url('blog/view/' . $user->uid, NULL, NULL, true), 'string')),
+                                  'url' => new xmlrpcval(url('blog/' . $user->uid, NULL, NULL, true), 'string')),
                             'struct');
     return new xmlrpcresp($struct);
   }
@@ -76,6 +145,9 @@
   }
 }
 
+/**
+ * Blogging API callback. Inserts a new blog post as a node.
+ */
 function blogapi_new_post($req_params) {
   $params = blogapi_convert($req_params);
 
@@ -89,54 +161,89 @@
     return blogapi_error($user);
   }
 
-  $promote = variable_get("node_promote_blog", 0);
-  $comment = variable_get("node_comment_blog", 2);
-  $moderate = variable_get("node_moderate_blog", 0);
-  $revision = variable_get("node_revision_blog", 0);
-
   // check for bloggerAPI vs. metaWeblogAPI
   if (is_array($params[3])) {
     $title = $params[3]['title'];
     $body = $params[3]['description'];
+    $datecreated = iso8601_decode($params[3]['dateCreated'],1);
+    $mt_allow_comments = $params[3]['mt_allow_comments'];
+    $mt_allow_pings = $params[3]['mt_allow_pings'];
+    $mt_convert_breaks = $params[3]['mt_convert_breaks'];
+    $mt_text_more = $params[3]['mt_text_more'];
+    $mt_excerpt = $params[3]['mt_excerpt'];
+    $mt_keywords = $params[3]['mt_keywords'];
+    if (is_array($params[3]['mt_tb_ping_urls'])) {
+      foreach ($params[3]['mt_tb_ping_urls'] as $tb) 
+        $mt_tb_ping_urls .= $tb." ";
+      $mt_tb_ping_urls .= trim($mt_tb_ping_urls);
+    }
   }
   else {
     $title = blogapi_blogger_title($params[3]);
     $body = $params[3];
   }
 
+  $promote = variable_get('node_promote_blog', 1);
+  $comment = variable_get('node_comment_blog', 2);
+  $moderate = variable_get('node_moderate_blog', 0);
+  $revision = variable_get('node_revision_blog', 0);
+
+  if (isset($mt_allow_comments)) {
+    switch ($mt_allow_comments) {
+      case 0: 
+        $comment = 0;
+        break;
+      case 1:
+        $comment = 2;
+        break;
+      case 2:
+        $comment = 1;
+        break;
+    }
+  }
+
   if (!valid_input_data($title, $body)) {
-    return blogapi_error(t("Terminated request because of suspicious input data."));
+    return blogapi_error(t('Terminated request because of suspicious input data.'));
   }
 
   $node = node_validate(array('type' => 'blog',
+                              'created' => $datecreated,
                               'uid' => $user->uid,
                               'name' => $user->name,
                               'title' => $title,
                               'body' => $body,
+                              'extended' => $mt_text_more,
+                              'excerpt' => $mt_excerpt,
+                              'format' => $mt_convert_breaks,
+                              'tb_url' => $mt_tb_ping_urls,
                               'status' => $params[4],
                               'promote' => $promote,
                               'comment' => $comment,
                               'moderate' => $moderate,
                               'revision' => $revision
                               ), $error);
-
   if (count($error) > 0) {
     return blogapi_error($error);
   }
 
-  if (!node_access("create", $node)) {
+  if (!node_access('create', $node)) {
     return blogapi_error(message_access());
   }
 
-  $nid = node_save($node);
-  if ($nid) {
-    watchdog("special", "$node->type: added '$node->title' using blog API", l(t("view post"), "node/view/$nid"));
-    return new xmlrpcresp(new xmlrpcval($nid, 'string'));
+  $node->nid = node_save($node);
+
+  if ($node->nid) {
+    if (function_exists("trackback_send")) trackback_send($node);
+    watchdog('special', "$node->type: added '$node->title' using blog API", l(t('view post'), "node/view/$node->nid"));
+    return new xmlrpcresp(new xmlrpcval($node->nid, 'string'));
   }
 
   return blogapi_error(t('error storing post'));
 }
 
+/**
+ * Blogging API callback. Modifies the specified blog node.
+ */
 function blogapi_edit_post($req_params) {
   $params = blogapi_convert($req_params);
   if (count($params) == 6) {
@@ -162,19 +269,51 @@
   if (is_array($params[3])) {
     $title = $params[3]['title'];
     $body = $params[3]['description'];
+    $datecreated = iso8601_decode($params[3]['dateCreated'],1);
+    $mt_allow_comments = $params[3]['mt_allow_comments'];
+    $mt_allow_pings = $params[3]['mt_allow_pings'];
+    $mt_convert_breaks = $params[3]['mt_convert_breaks'];
+    $mt_text_more = $params[3]['mt_text_more'];
+    $mt_excerpt = $params[3]['mt_excerpt'];
+    $mt_keywords = $params[3]['mt_keywords'];
+    if (is_array($params[3]['mt_tb_ping_urls'])) {
+      foreach ($params[3]['mt_tb_ping_urls'] as $tb) 
+        $mt_tb_ping_urls .= $tb." ";
+      $mt_tb_ping_urls .= trim($mt_tb_ping_urls);
+    }
   }
   else {
     $title = blogapi_blogger_title($params[3]);
     $body = $params[3];
   }
 
+  if (isset($mt_allow_comments)) {
+    switch ($mt_allow_comments) {
+      case 0: 
+        $comment = 0;
+        break;
+      case 1:
+        $comment = 2;
+        break;
+      case 2:
+        $comment = 1;
+        break;
+    }
+  }
+
   if (!valid_input_data($title, $body)) {
-    return blogapi_error(t("Terminated request because of suspicious input data."));
+    return blogapi_error(t('Terminated request because of suspicious input data.'));
   }
 
   $node->title = $title;
   $node->body = $body;
+  $node->extended = $mt_text_more;
+  $node->excerpt = $mt_excerpt;
+  $node->format = $mt_convert_breaks;
+  $node->tb_url = $mt_tb_ping_urls;
   $node->status = $params[4];
+  $node->created = $datecreated;
+  $node->comment = $comment;
   $node = node_validate($node, $error);
 
   if (count($error) > 0) {
@@ -185,15 +324,21 @@
   foreach ($terms as $term) {
     $node->taxonomy[] = $term->tid;
   }
-  $nid = node_save($node);
-  if ($nid) {
-    watchdog("special", "$node->type: updated '$node->title' using blog API", l(t("view post"), "node/view/$nid"));
-    return new xmlrpcresp(new xmlrpcval(true, "boolean"));
+
+  $node->nid = node_save($node);
+
+  if ($node->nid) {
+    if (function_exists("trackback_send")) trackback_send($node);
+    watchdog('special', "$node->type: updated '$node->title' using blog API", l(t('view post'), "node/view/$node->nid"));
+    return new xmlrpcresp(new xmlrpcval(true, 'boolean'));
   }
 
   return blogapi_error(t('error storing node'));
 }
 
+/**
+ * Blogging API callback. Returns a specified blog node.
+ */
 function blogapi_get_post($req_params) {
   $params = blogapi_convert($req_params);
   $user = blogapi_validate_user($params[1], $params[2]);
@@ -202,16 +347,35 @@
   }
 
   $node = node_load(array('nid' => $params[0]));
+  switch ($node->comment) {
+    case 0:
+      $comment = 0;
+      break;
+    case 1:
+      $comment = 2;
+      break;
+    default:
+      $comment = 1;
+      break;
+  }
   $blog = new xmlrpcval(array('userid' => new xmlrpcval($node->name, 'string'),
-                              'dateCreated' => new xmlrpcval(iso8601_encode($node->created), "dateTime.iso8601"),
+                              'dateCreated' => new xmlrpcval(iso8601_encode($node->created), 'dateTime.iso8601'),
                               'title' => new xmlrpcval($node->title, 'string'),
+                              'link' => new xmlrpcval(url("node/view/" . $node->nid, NULL, NULL, TRUE), 'string'),
+                              'permaLink' => new xmlrpcval(url("node/view/" . $node->nid, NULL, NULL, TRUE), 'string'),
                               'description' => new xmlrpcval($node->body, 'string'),
+                              'mt_text_more' => new xmlrpcval($node->extended, 'string'),
+                              'mt_excerpt' => new xmlrpcval($node->excerpt, 'string'),
+                              'mt_allow_comments' => new xmlrpcval($comment, 'string'),
                               'postid' => new xmlrpcval($node->nid, 'string')),
                         'struct');
 
   return new xmlrpcresp($blog);
 }
 
+/**
+ * Blogging API callback. Removes the specified blog node.
+ */
 function blogapi_delete_post($req_params) {
   $params = blogapi_convert($req_params);
 
@@ -221,14 +385,48 @@
   }
 
   $ret = node_delete(array('nid' => $params[1], 'confirm' => 1));
-  return new xmlrpcresp(new xmlrpcval(true, "boolean"));
+  return new xmlrpcresp(new xmlrpcval(true, 'boolean'));
 }
 
+/**
+ * Blogging API callback. Inserts a file into Drupal.
+ *
+ * This has yet to be implemented.
+ */
 function blogapi_new_media_object($req_params) {
-  return blogapi_error('not implemented');
+  $params = blogapi_convert($req_params);
+  $user = blogapi_validate_user($params[1], $params[2]);
+  if (!$user->uid) {
+    return blogapi_error($user);
+  }
+
+  $name = variable_get("upload_path","public") . FILE_SEPARATOR . basename($params[3]['name']);
+  $data = $params[3]['bits'];
+
+  if (!$data) {
+    return blogapi_error(t('No file sent'));
+  }
+
+  if (!$file = file_save_data($data, $name)) {
+    return blogapi_error(t('Error storing file'));
+  }
+
+  // Return the successful result.
+  $result = new xmlrpcval(array('url' => new xmlrpcval(file_create_url($file), 'string')), 'struct');
+  return new xmlrpcresp($result);
 }
 
+/**
+ * Blogging API callback. Returns a list of the taxonomy terms that can be
+ * associated with a blog node.
+ */
 function blogapi_get_category_list($req_params) {
+  $params = blogapi_convert($req_params);
+  $user = blogapi_validate_user($params[1], $params[2]);
+  if (!$user->uid) {
+    return blogapi_error($user);
+  }
+
   $vocabularies = module_invoke('taxonomy', 'get_vocabularies', 'blog', 'vid');
   $categories = array();
   if ($vocabularies) {
@@ -245,9 +443,13 @@
       }
     }
   }
-  return new xmlrpcresp(new xmlrpcval($categories, "array"));
+  return new xmlrpcresp(new xmlrpcval($categories, 'array'));
 }
 
+/**
+ * Blogging API callback. Returns a list of the taxonomy terms that are
+ * assigned to a particular node.
+ */
 function blogapi_get_post_categories($req_params) {
   $params = blogapi_convert($req_params);
   $user = blogapi_validate_user($params[1], $params[2]);
@@ -267,9 +469,12 @@
                                         'isPrimary' => new xmlrpcval(true, 'boolean')),
                                   'struct');
   }
-  return new xmlrpcresp(new xmlrpcval($categories, "array"));
+  return new xmlrpcresp(new xmlrpcval($categories, 'array'));
 }
 
+/**
+ * Blogging API callback. Assigns taxonomy terms to a particular node.
+ */
 function blogapi_set_post_categories($req_params) {
   $params = blogapi_convert($req_params);
   $user = blogapi_validate_user($params[1], $params[2]);
@@ -286,6 +491,9 @@
   return new xmlrpcresp(new xmlrpcval(true, 'boolean'));
 }
 
+/**
+ * Blogging API callback. Returns the latest few postings in a user's blog.
+ */
 function blogapi_get_recent_posts($req_params) {
   $params = blogapi_convert($req_params);
 
@@ -300,19 +508,104 @@
 
   $result = db_query_range("SELECT n.nid, n.title, n.body, n.created, u.name FROM {node} n, {users} u WHERE n.uid=u.uid AND n.type = 'blog' AND n.uid = %d ORDER BY n.created DESC",  $user->uid, 0, $params[3]);
   while ($blog = db_fetch_object($result)) {
+    $blog = node_load(array('nid' => $blog->nid));
     $blogs[] = new xmlrpcval(array('userid' => new xmlrpcval($blog->name, 'string'),
-                                   'dateCreated' => new xmlrpcval(iso8601_encode($blog->created), "dateTime.iso8601"),
+                                   'dateCreated' => new xmlrpcval(iso8601_encode($blog->created), 'dateTime.iso8601'),
                                    'content' => new xmlrpcval("<title>$blog->title</title>$blog->body", 'string'),
                                    'title' => new xmlrpcval($blog->title, 'string'),
                                    'description' => new xmlrpcval($blog->body, 'string'),
+                                   'mt_text_more' => new xmlrpcval($blog->extended, 'string'),
+                                   'mt_excerpt' => new xmlrpcval($blog->excerpt, 'string'),
+                                   'mt_convert_breaks' => new xmlrpcval($blog->format, 'string'),
                                    'postid' => new xmlrpcval($blog->nid, 'string')),
                              'struct');
   }
-  return new xmlrpcresp(new xmlrpcval($blogs, "array"));
+  return new xmlrpcresp(new xmlrpcval($blogs, 'array'));
 }
 
-/** helper functions */
+function blogapi_get_recent_post_titles($req_params) {
+  $params = blogapi_convert($req_params);
 
+  // Remove unused appkey (from bloggerAPI).
+  if (count($params) == 5) {
+    $params = array_slice($params, 1);
+  }
+  $user = blogapi_validate_user($params[1], $params[2]);
+  if (!$user->uid) {
+    return blogapi_error($user);
+  }
+
+  $result = db_query_range("SELECT n.nid, n.title, n.body, n.created, u.name FROM {node} n, {users} u WHERE n.uid=u.uid AND n.type = 'blog' AND n.uid = %d ORDER BY n.created DESC",  $user->uid, 0, $params[3]);
+  while ($blog = db_fetch_object($result)) {
+    $blogs[] = new xmlrpcval(array('userid' => new xmlrpcval($blog->name, 'string'),
+                                   'dateCreated' => new xmlrpcval(iso8601_encode($blog->created), 'dateTime.iso8601'),
+                                   'content' => new xmlrpcval("<title>$blog->title</title>$blog->body", 'string'),
+                                   'title' => new xmlrpcval($blog->title, 'string'),
+                                   'postid' => new xmlrpcval($blog->nid, 'string')),
+                             'struct');
+  }
+  return new xmlrpcresp(new xmlrpcval($blogs, 'array'));
+}
+
+function blogapi_publish_post($message) {
+  $params = blogapi_convert($req_params);
+
+  $user = blogapi_validate_user($params[1], $params[2]);
+  if (!$user->uid) {
+    return blogapi_error($user);
+  }
+
+  // Okay, we don't need the silly rebuild on Drupal so lets return true :-)
+  return new xmlrpcresp(new xmlrpcval(1, 'boolean'));
+}
+
+function blogapi_get_trackback_pings($message) {
+  $params = blogapi_convert($req_params);
+
+  $tbping = array();
+
+  $query = db_query("SELECT * from {trackback_pingme} WHERE nid = %d", $params[0]);
+  if (db_num_rows($query) && module_exist('comment')) {
+    while ($result = db_fetch_object($query)) {
+      $comment = db_fetch_object(db_query('SELECT * FROM {comments} WHERE cid=%d',$result->cid));
+      $tbping[] = new xmlrpcval(array('pingTitle' => $comment->subject,
+                                      'pingURL' => $comment->homepage,
+                                      'pingIP' => $comment->hostname),
+                                'struct');      
+    }
+  }
+
+  return new xmlrpcresp(new xmlrpcval($tbping, 'array'));
+}
+
+function blogapi_supported_text_filters($message) {
+  $filters[] = new xmlrpcval(array('key' => new xmlrpcval('-1', 'string'),
+                                   'label' => new xmlrpcval('No formatting', 'string')), 
+                                   'struct');
+
+  $filters[] = new xmlrpcval(array('key' => new xmlrpcval('0', 'string'),
+                                   'label' => new xmlrpcval('Convert Line Break', 'string')), 
+                                   'struct');
+
+  $filters[] = new xmlrpcval(array('key' => new xmlrpcval('1', 'string'),
+                                   'label' => new xmlrpcval('Simple Wiki', 'string')), 
+                                   'struct');
+
+  return new xmlrpcresp(new xmlrpcval($filters, 'array'));
+}
+
+function blogapi_supported_methods($message) {
+  $xmlrpc = blogapi_xmlrpc();
+  foreach ($methods as $k => $v) {
+    $methods[] = $k;
+  }
+
+  return new xmlrpcresp(new xmlrpcval($methods, 'array'));
+}
+
+/**
+ * Process the parameters to an XMLRPC callback, and return them as an array.
+ */
 function blogapi_convert($params) {
   $cparams = array();
   $num_params= $params->getNumParams();
@@ -325,6 +618,9 @@
   return $cparams;
 }
 
+/**
+ * Prepare an error message for returning to the XMLRPC caller.
+ */
 function blogapi_error($message) {
   global $xmlrpcusererr;
 
@@ -335,6 +631,9 @@
   return new xmlrpcresp(0, $xmlrpcusererr + 1, strip_tags($message));
 }
 
+/**
+ * Ensure that the given user has permission to edit a blog.
+ */
 function blogapi_validate_user($username, $password) {
   global $user;
 
@@ -353,14 +652,22 @@
   }
 }
 
+/**
+ * For the blogger API, extract the node title from the contents field.
+ */
 function blogapi_blogger_title(&$contents) {
-  if (eregi("<title>([^<]*)</title>", $contents, $title)) {
+  if (eregi('<title>([^<]*)</title>', $contents, $title)) {
     $title = strip_tags($title[0]);
-    $contents = ereg_replace("<title>[^<]*</title>", "", $contents);
+    $contents = ereg_replace('<title>[^<]*</title>', '', $contents);
   }
   else {
     list($title, $rest) = explode("\n", $contents, 2);
   }
   return $title;
 }
+
+function blogapi_default_node() {
+  drupal_set_html_head('<link rel="EditURI" type="application/rsd+xml" title="RSD" href="' . url('blogapi/rsd',NULL,NULL,TRUE) . '" />');
+}
+
 ?>
diff -urN drupal-4.4.2/modules/blogroll.module drupal4blog/modules/blogroll.module
--- drupal-4.4.2/modules/blogroll.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/blogroll.module	Fri Sep  3 00:11:15 2004
@@ -0,0 +1,181 @@
+<?php
+// $Id$
+
+function blogroll_init() {
+  // make sure it is not promoted by defaulted, which is different from others
+  variable_set('node_promote_blogroll', variable_get('node_promote_blogroll', 0));
+}
+
+function blogroll_help($section) {
+  $output = "";
+
+  switch ($section) {
+    case 'admin/system/modules#description':
+      $output = t("Enables blogrolls");
+      break;
+    case 'blogroll':
+    case 'node/add#blogroll':
+      $oneclick = url("blogroll/add",NULL,NULL,TRUE);
+      $output = t("A blogroll is a bookmark for bloggers. If RSS or Atom feed is also defined, it also aggregates contents from other blogs. You can also drag the 1-click <a href=\"javascript:void(rollpop=window.open('$oneclick&url='+escape(location.href)+'&title='+escape(document.title),'blogit','scrollbars=no,width=500,height=400,left=50,top=150,status=yes,resizable=yes'));rollpop.focus();\">blogroll</a> your bookmark.");
+      break;
+  }
+  return $output;
+}
+
+function blogroll_perm() {
+  return array("maintain blogroll");
+}
+
+function blogroll_access($op, $node) {
+  global $user;
+
+  if ($op == "view") {
+    return $node->status;
+  }
+
+  if ($op == "create") {
+    return user_access('maintain blogroll');
+  }
+
+  if ($op == "update") {
+    return user_access('maintain blogroll');
+  }
+
+  if ($op == "delete") {
+    return user_access('maintain blogroll');
+  }
+}
+
+function blogroll_link($type, $node = 0, $main) {
+  global $user;
+
+  $links = array();
+
+  if ($type == "system") {
+    if (user_access("maintain blogroll")) {
+      menu('blogroll', t('blogroll'), 'blogroll_page', 0, MENU_HIDE);
+      menu("node/add/blogroll", t('blogroll'), 'node_page', 0);
+    }
+  }
+
+  return $links;
+}
+
+function blogroll_form(&$node, &$error) {
+  if (!$node['url']) 
+    $node['url'] = $_GET['url'];
+
+  $output .= form_textfield(t('URL'), 'url', $node['url'], 60, 128, $error['url']);
+  $output .= form_textfield(t('RSS or Atom Feed'), 'xml', $node['xml'], 60, 128, $error['xml'] ? $error['xml'] : '(todo : auto subscribe to feed)');
+  $output .= form_textarea(t('Description'), 'body', $node['body'], 60, 3, $error['body']);
+  //$output .= form_select(t('Priority'), 'priority', $node['priority'] ? $node['priority'] : 50, drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95)),'');
+
+  return $output;
+}
+
+function blogroll_add() {
+  global $user;
+
+  $edit = $_POST['edit'];
+
+  $form .= form_textfield(t('Title'), 'title', $edit['title'] ? $edit['title'] : $_GET['title'], 60, 128, $error['url']);
+  $form .= blogroll_form($edit,$error);
+  $form .= form_hidden('uid',$user->uid);
+  $form .= form_hidden('created',time());
+  $form .= form_hidden('type','blogroll');
+
+  $form .= form_submit(t('Add Blogroll'));
+  $form .= form_button(t('Close'), "op", "button", array("onClick" => "window.close()"));
+  
+  $output = form($form);
+
+  print theme('popup', $output, '');
+}
+
+function blogroll_save() {
+  $edit = $_POST['edit'];
+
+  if (!$edit['title'] && !$edit['url'])
+    return blogroll_add();
+
+  node_save(array2object($edit));
+
+  $header = array(t('name'),'');
+  $rows[] = array(t('Title'),$edit['title']);
+  $rows[] = array(t('URL'),$edit['url']);
+  $rows[] = array(t('Feed'),$edit['xml']);
+  $rows[] = array(t('Description'),$edit['body']);
+
+  $output = theme('table', $header, $rows);
+  $output .= form_button(t('Close'), "op", "button", array("onClick" => "window.close()"));
+
+  print theme('popup', $output);
+}
+
+function blogroll_view() {
+  $result = db_query("SELECT n.*, b.* FROM {node} n, {blogroll} b WHERE b.nid = n.nid AND n.type='blogroll'");
+  $header = array(t('title'),t('url'));
+  while ($node = db_fetch_object($result)) {
+    $rows[] = array(l($node->title, "admin/node/edit/$node->nid"),"<a href=\"$node->url\">$node->url</a>");
+  }
+  $output .= theme('table', $header, $rows);
+  print theme('page', $output);
+  return;
+}
+
+function blogroll_page() {
+  $op = $_POST['op'] ? $_POST['op'] : arg(1);
+
+  switch ($op) {
+    case 'add':
+      blogroll_add();
+      return;
+    case t('Add Blogroll'):
+      blogroll_save();
+      return;
+    default:
+      blogroll_view();
+      return;
+  }
+}
+
+function blogroll_insert($node) {
+  db_query("INSERT INTO {blogroll} (nid, url, xml, priority) VALUES (%d, '%s', '%s', %d)", $node->nid, $node->url, $node->xml, $node->priority);
+}
+
+function blogroll_update($node) {
+  db_query("UPDATE {blogroll} SET url = '%s', xml = '%s', priority = %d WHERE nid = %d", $node->url, $node->xml, $node->priority, $node->nid);
+}
+
+function blogroll_delete(&$node) {
+  db_query("DELETE FROM {blogroll} WHERE nid = %d", $node->nid);
+}
+
+function blogroll_load($node) {
+  return db_fetch_object(db_query("SELECT url, xml, priority FROM {blogroll} WHERE nid = %d", $node->nid));
+}
+
+function blogroll_node_name($node) {
+  return t('blogroll');
+}
+
+function blogroll_block($op = "list", $delta = 0) {
+  if ($op == "list") {
+    $blocks[0]["info"] = t("Blogroll");
+    return $blocks;
+  }
+
+  $output = "<div class=\"item-list\"><ul>";
+
+  $result = db_query("SELECT n.*, b.* FROM {node} n, {blogroll} b WHERE b.nid = n.nid AND n.type='blogroll'");
+  while ($node = db_fetch_object($result)) {
+    $output .= "<li><a href=\"".$node->url."\">".$node->title."</a></li>";
+  }
+  $output .= "</ul></div>";
+
+  $block["subject"] = t("Blogroll");
+  $block["content"] = $output;
+  return $block;
+}
+
+?>
diff -urN drupal-4.4.2/modules/book.module drupal4blog/modules/book.module
--- drupal-4.4.2/modules/book.module	Sat Mar 20 21:47:14 2004
+++ drupal4blog/modules/book.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: book.module,v 1.216.2.1 2004/03/20 13:47:14 dries Exp $
+// $Id: book.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function book_node_name($node) {
   return t("book page");
diff -urN drupal-4.4.2/modules/captcha.module drupal4blog/modules/captcha.module
--- drupal-4.4.2/modules/captcha.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/captcha.module	Thu Jul 15 12:14:58 2004
@@ -0,0 +1,245 @@
+<?php
+// $Id: captcha.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+function captcha_init() {
+  global $_captcha_default_format, $_captcha_formats;
+
+  $_captcha_imagetypes = imagetypes();
+  $_captcha_formats = array();
+  
+  if ($_captcha_imagetypes & IMG_BMP) {
+    $_captcha_default_format = 3;
+    $_captcha_formats = array_merge(array(3 => 'BMP'), $_captcha_formats);
+  } 
+  
+  if ($_captcha_imagetypes & IMG_JPG) {
+    $_captcha_default_format = 2;
+    $_captcha_formats = array_merge(array(2 => 'JPG'), $_captcha_formats);
+  } 
+  
+  if ($_captcha_imagetypes & IMG_GIF) {
+    $_captcha_default_format = 1;
+    $_captcha_formats = array_merge(array(1 => 'GIF'), $_captcha_formats);
+  } 
+  
+  if ($_captcha_imagetypes & IMG_PNG) {
+    $_captcha_default_format = 0;
+    $_captcha_formats = array_merge(array(0 => 'PNG'), $_captcha_formats);
+  } 
+}
+
+function captcha_help($section) {
+  switch ($section) {
+    case 'admin/system/modules#description':
+      $output = t('Users would be shown a graphic image with some text which they will have to enter manually to verify they are not a bot. CAPTCHA requires PHP to be compiled with GD support.');
+      break;
+    case 'admin/system/modules/captcha':
+      $output = t("%CAPTCHA which stands for 'Completely Automated Public Turning test to Tell Computers and Humans Apart' can be enabled to prevent bots from spamming comments. When posting comments, Users would be shown a graphic image with some text which they will have to enter manually. While it is an effectively way to stop bots, it is critizes for been unfriendly to the visual handicaps.", array("%CAPTCHA" => '<a href="http://en.wikipedia.org/wiki/CAPTCHA">CATPCHA</a>'));
+      if (!function_exists('imagecreate')) {
+        $output .= " ".t("<b>CAPTCHA requirs PHP to be compiled with GD support which you don't have.</b>");
+      }
+      break;
+  }
+  return $output;
+}
+
+function captcha_settings() {
+  global $_captcha_default_format, $_captcha_formats;
+
+  $group = form_select(t('CAPTCHA Length'), 'captcha_length', variable_get('captcha_length', 6), array(4 => '4', 6 => '6', 8 => '8', 10 => '10'), t('Length of the CAPTCHA. If this is too short, it is easily guessable. If it is too long, it become a hassle for user'));
+  $group .= form_select(t('Image format'), 'captcha_format', variable_get('captcha_format', $_captcha_default_format), $_captcha_formats, t("Output captcha image format. These are the formats supported in your PHP so if you can't see the image, try another one."));
+  $output .= form_group(t('CAPTCHA Options'),$group);
+
+  if (function_exists('imagecreate')) {
+    $group = form_radios(t('user registration'), 'captcha_newuser', variable_get('captcha_newuser', 0), array(0 => t('No CAPTCHA support'), 1 => t('CAPTCHA support')));
+    $group .= form_radios(t('comments'), 'captcha_comment', variable_get('captcha_comment', 0), array(0 => t('No CAPTCHA support'), 1 => t('CAPTCHA support'), 2 => t('CAPTCHA support only for anonymous user')));
+    foreach (node_list() as $type) {
+      $group .= form_radios(t(node_invoke($type,'node_name')), "captcha_node_$type", variable_get("captcha_node_$type", 0), array(0 => t('No CAPTCHA support'), 1 => t('CAPTCHA support'), 2 => t('CAPTCHA support only for anonymous user')));
+    }
+    $output .= form_group(t('CAPTCHA Hook'),$group);
+  }
+  return $output;
+}
+
+function captcha_link($type, $node = 0, $main) {
+  if ($type  == 'system') {
+    menu('captcha', t('captcha image'), 'captcha_image', 0, MENU_HIDE);
+  }
+}
+
+function _captcha_generate_secret() {
+  $start = pow(10,variable_get('captcha_length',6)-1);
+  $end   = pow(10,variable_get('captcha_length',6))-1;
+  $_SESSION['captcha'] = rand($start,$end);
+}
+
+function captcha_comment($op,$comment) {
+  global $user;
+
+  // not enabled
+  if (variable_get('captcha_comment',0) == 0) return;
+
+  // no GD support :P
+  if (!function_exists('imagecreate')) return;
+
+  switch ($op) {
+    case 'form':
+      if (variable_get('captcha_comment',0) == 1
+      || (variable_get('captcha_comment',0) == 2 && !$user->uid)) {
+        return form_textfield('<img src="'.url('captcha').'">', 'captcha', $edit['captcha'], 50, 32, t('Please enter the code as seen in the image above to post your comment.'));
+      }
+      break;
+    case 'validate':
+      if (variable_get('captcha_comment',0) == 1
+      || (variable_get('captcha_comment',0) == 2 && !$user->uid)) {
+        if ($_POST['op'] == t('Post comment') 
+        &&  $comment['captcha'] != $_SESSION['captcha']) {
+          form_set_error('captcha', t('You have not entered the code as shown in the image correctly.'));
+        }
+      }
+      break;
+    case 'insert':
+    case 'update':
+      _captcha_generate_secret();
+      break;
+  }
+}
+
+function captcha_user($type, $edit, &$user) {
+  // if it not a new user registration, don't do anything
+  if ($user->uid) return;
+  
+  // not enabled;
+  if (variable_get('captcha_newuser',0) == 0) return;
+
+  // no GD support :P
+  if (!function_exists('imagecreate')) return;
+
+  switch ($type) {
+    case 'new form':
+      return form_textfield('<img src="'.url('captcha').'">', 'captcha', $edit['captcha'], 50, 32, t('Please enter the code as seen in the image above to post your comment.'));
+      break;
+    case 'new validate':
+      if ($edit['captcha'] != $_SESSION['captcha']) {
+        return t('You have not entered the code as shown in the image correctly.');
+      } 
+      _captcha_generate_secret();
+      break;
+  }
+}
+
+function captcha_nodeapi(&$node, $op, $arg) {
+  global $user;
+
+  $type = $node->type;
+  
+  // not enabled
+  if (variable_get("captcha_node_$type",0) == 0) return;
+
+  // no GD support :P
+  if (!function_exists('imagecreate')) return;
+
+  switch ($op) {
+    case 'form post':
+      if (variable_get("captcha_node_$type",0) == 1
+      || (variable_get("captcha_node_$type",0) == 2 && !$user->uid)) {
+        return form_textfield('<img src="'.url('captcha').'">', 'captcha', $edit['captcha'], 50, 32, t('Please enter the code as seen in the image above to post your comment.'));
+      }
+      break;
+    case 'validate':
+      if (variable_get("captcha_node_$type",0) == 1
+      || (variable_get("captcha_node_$type",0) == 2 && !$user->uid)) {
+        if ($edit['captcha'] != $_SESSION['captcha']) {
+          return t('You have not entered the code as shown in the image correctly.');
+        }
+      }
+      break;
+    case 'insert':
+    case 'update':
+      _captcha_generate_secret();
+      break;
+  }
+}
+
+function captcha_image() {
+  global $_captcha_default_format, $_captcha_formats;
+  switch (variable_get('captcha_format',$_captcha_default_format)) {
+    case 3:
+      header('Content-type: image/bmp');
+      break;
+    case 2:
+      header('Content-type: image/jpg');
+      break;
+    case 1:
+      header('Content-type: image/gif');
+      break;
+    default:
+      header('Content-type: image/png');
+      break;
+  }
+
+  // no GD support :P
+  if (!function_exists('imagecreate')) 
+    return drupal_goto();
+
+  if (!$_SESSION['captcha']) 
+    _captcha_generate_secret();
+
+  // never never cache the image
+  header('Expires: Mon, 01 Jan 1997 05:00:00 GMT');
+  header('Cache-Control: no-store, no-cache, must-revalidate');
+  header('Cache-Control: post-check=0, pre-check=0', false);
+  header('Pragma: no-cache');
+
+  // define the image
+  $im_length = (variable_get('captcha_length',6)+1)*10;
+  $im = imagecreate($im_length,25);
+
+  // define the color we going to use
+  $c_background = imagecolorallocate($im,224,224,224);
+  $c_border = imagecolorallocate($im,0,0,0);
+  $c_line = imagecolorallocate($im,192,192,192);
+  $c_code = imagecolorallocate($im,128,128,128);
+
+  // fill in the background
+  imagefill($im,0,0,$c_background);
+
+  // draw the border lines
+  for ($i=0;$i<$im_length;$i+=5) 
+    imageline($im,$i,0,$i,24,$c_line);
+
+  for ($i=0;$i<25;$i+=5) 
+    imageline($im,0,$i,$im_length-1,$i,$c_line);
+
+  imagerectangle($im,0,0,$im_length-1,24,$c_border);
+
+  // write the code
+  imagestring($im,5,8,5,$_SESSION['captcha'],$c_code);
+
+  // output the image
+  switch (variable_get('captcha_format',$_captcha_default_format)) {
+    case 3:
+      imagebmp($im);
+      break;
+    case 2:
+      imagejpeg($im);
+      break;
+    case 1:
+      imagegif($im);
+      break;
+    default:
+      imagepng($im);
+      break;
+  }
+
+  // destroy it after output
+  imagedestroy($im);
+}
+
+function captcha_exit() {
+  // Okay, very silly to flush the cache after the system caches it.
+  // but captcha is never suppose to be cachable by the system
+  cache_clear_all('/captcha');
+}
+
+?>
diff -urN drupal-4.4.2/modules/comment.module drupal4blog/modules/comment.module
--- drupal-4.4.2/modules/comment.module	Thu May 20 18:45:26 2004
+++ drupal4blog/modules/comment.module	Mon Aug  9 08:33:59 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: comment.module,v 1.224.2.9 2004/05/20 10:45:26 dries Exp $
+// $Id: comment.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function comment_help($section = "admin/help#comment") {
   $output = "";
@@ -9,6 +9,7 @@
       $output = t("
       <p>When enabled, the Drupal comment module creates a discussion board for each Drupal node. Users can post comments to discuss a forum topic, weblog post, collaborative book page, etc.</p>
       <h3>User control of comment display</h3>
+      <p>(<i>Only for Partial or Full Comment Control</i>)</p>
       <p>Attached to each comment board is a control panel for customizing the way that comments are displayed. Users can control the chronological ordering of posts (newest or oldest first) and the number of posts to display on each page. Additional settings include:</p>
       <ul>
       <li><strong>Threaded</strong> -- Displays the posts grouped according to conversations and subconversations, much like the subject view of an e-mail client.</li>
@@ -40,11 +41,13 @@
       </ul>
 
       <h3>Comment moderation</h3>
+      <p>(<i>Only for Full Comment Control</i>)</p>
       <p>On sites with active commenting from users, the administrator can turn over comment moderation to the community. </p>
       <p>With comment moderation, each comment is automatically assigned an initial rating. As users read comments, they can apply a vote which affects the comment rating. At the same time, users have an additional option in the control panel which allows them to set a threshold for the comments they wish to view. Those comments with ratings lower than the set threshold will not be shown.</p>
       <p>To enable moderation, the administrator must grant <a href=\"%permission\">moderate comments</a> permissions. Then, a number of options in <a href=\"%comment-moderation\">administer &raquo; comments &raquo; moderation</a> must be configured.</p>
 
       <h4>Moderation votes</h4>
+      <p>(<i>Only for Full Comment Control</i>)</p>
       <p>The first step is to create moderation labels which allow users to rate a comment.  Go to <a href=\"%comment-votes\">administer &raquo; comments &raquo; moderation &raquo; votes</a>. In the <em>vote</em> field, enter the textual labels which users will see when casting their votes. Some examples are</p>
       <ul>
       <li>Excellent +3</li>
@@ -59,14 +62,17 @@
 
       <h4>Moderator vote/values matrix</h4>
 
+      <p>(<i>Only for Full Comment Control</i>)</p>
       <p>Next go to <a href=\"%comment-matrix\">administer &raquo; comments &raquo; moderation &raquo; matrix</a>. Enter the values for the vote labels for each permission role in the vote matrix. The values entered here will be used to create the rating for each comment.</p>
       <p>NOTE: Comment ratings are calculated by averaging user votes with the initial rating.</p>
       <h4>Creating comment thresholds</h4>
+      <p>(<i>Only for Full Comment Control</i>)</p>
       <p>In <a href=\"%comment-thresholds\">administer &raquo; comments &raquo; moderation &raquo; thresholds</a>, you'll have to create some comment thresholds to make the comment rating system useful. When comment moderation is enabled and the thresholds are created, users will find another comment control panel option for selecting their thresholds. They'll use the thresholds you enter here to filter out comments with low ratings. Consequently, you'll probably want to create more than one threshold to give users some flexibility in filtering comments.</p>
       <p>When creating the thresholds, note that the <em>Minimum score</em> is asking you for the lowest rating that a comment can have in order to be displayed.</p>
       <p>To see a common example of how thresholds work, you might visit <a href=\"%slashdot\">Slashdot</a> and view one of their comment boards associated with a story. You can reset the thresholds in their comment control panel.</p>
 
       <h4>Initial comment scores</h4>
+      <p>(<i>Only for Full Comment Control</i>)</p>
       <p>Finally, you may want to enter some <em>initial comment scores</em>. In <a href=\"%comment-initial\">administer &raquo; comments &raquo; initial comment scores</a> you can assign a beginning rating for all comments posted by a particular permission role. If you do not assign any initial scores, Drupal will assign a rating of <strong>0</strong> as the default.</p>", array("%comment-config" => url("admin/system/modules/comment"), "%site-config" => url("admin/system"), "%user-permissions" => url("admin/user/permission"), "%tracker" => url("tracker"), "%download-notify" => "http://drupal.org/project/releases", "%permission" => url("admin/user/permission"), "%comment-moderation" => url("admin/comment/moderation"), "%comment-votes" => url("admin/comment/moderation/votes"), "%comment-matrix" => url("admin/comment/moderation/matrix"), "%comment-thresholds" => url("admin/comment/moderation/filters"), "%slashdot" => " http://slashdot.org", "%comment-initial" => url("admin/comment/moderation/roles")));
       break;
     case 'admin/system/modules#description':
@@ -110,32 +116,87 @@
 }
 
 function comment_help_page() {
-  print theme("page", comment_help());
+  print theme('page', comment_help());
 }
 
 function comment_settings() {
-  $group  = form_radios(t("Default display mode"), "comment_default_mode", variable_get("comment_default_mode", 4), _comment_get_modes(), t("The default view for comments. Expanded views display the body of the comment. Threaded views keep replies together."));
-  $group .= form_radios(t("Default display order"), "comment_default_order", variable_get("comment_default_order", 1), _comment_get_orders(), t("The default sorting for new users and anonymous users while viewing comments. These users may change their view using the comment control panel. For registered users, this change is remembered as a persistent user preference."));
-  $group .= form_select(t("Default comments per page"), "comment_default_per_page", variable_get("comment_default_per_page", "50"), _comment_per_page(), t("Default number of comments for each page: more comments are distributed in several pages."));
-  $group .= form_radios(t("Comment controls"), "comment_controls", variable_get("comment_controls", 0), array(t("Display above the comments"), t("Display below the comments"), t("Display above and below the comments"), t("Do not display")), t("Position of the comment controls box.  The comment controls let the user change the default display mode and display order of comments."));
-  $output = form_group(t('Comment viewing options'), $group);
+  $group = form_radios(t("Comment Complexity"), "comment_complex", variable_get("comment_complex", 0), array(0 => t("Simple Comment Control"), 1 => t("Partial Comment Control (no moderation)"), 2 => t("Full Comment Control")),t("'Simple Comment Control' is easier to managed and sufficient for most people. 'Partial Comment Control' enables threaded comments but no moderation features. 'Full Comment Control' gives you complete control."));
+  $output .= form_group(t('Comment control'), $group);
 
-  $group  = form_radios(t("Preview comment"), "comment_preview", variable_get("comment_preview", 1), array(t("Optional"), t("Required")), t("Must users preview comments before submitting?"));
-  $group .= form_radios(t("Location of comment submission form"), "comment_form_location", variable_get("comment_form_location", 0), array(t("Display on separate page"), t("Display below post or comments")), t("The location of the comment submission form."));
+  $group = "";
+  if (variable_get("comment_complex",0)) {
+    $group  = form_radios(t("Default display mode"), "comment_default_mode", variable_get("comment_default_mode", 4), _comment_get_modes(), t("The default view for comments. Expanded views display the body of the comment. Threaded views keep replies together."));
+    $group .= form_radios(t("Default display order"), "comment_default_order", variable_get("comment_default_order", 1), _comment_get_orders(), t("The default sorting for new users and anonymous users while viewing comments. These users may change their view using the comment control panel. For registered users, this change is remembered as a persistent user preference."));
+    $group .= form_select(t("Default comments per page"), "comment_default_per_page", variable_get("comment_default_per_page", "50"), _comment_per_page(), t("Default number of comments for each page: more comments are distributed in several pages."));
+    $group .= form_radios(t("Comment controls"), "comment_controls", variable_get("comment_controls", 0), array(t("Display above the comments"), t("Display below the comments"), t("Display above and below the comments"), t("Do not display")), t("Position of the comment controls box.  The comment controls let the user change the default display mode and display order of comments."));
+    $output .= form_group(t('Comment viewing options'), $group);
+  }
+
+  $group  = form_radios(t('Anonymous poster settings'), 'comment_anonymous', variable_get('comment_anonymous', 1), array(t('Anonymous posters may not enter their contact information'), t('Anonymous posters may leave their contact information'), t('Anonymous posters must leave their contact information')), t('This feature is only useful if you allow anonymous users to post comments.  See the <a href="%url">permissions page</a>.'), array('%url' => url('user/admin/permission')));
+  if (variable_get("comment_complex",0)) {
+    $group .= form_radios(t("Comment subject field"), "comment_subject_field", variable_get('comment_subject_field', 0), array(t("Disabled"), t("Enabled")), t('Must users provide a subject for their comments?'));
+    $group .= form_radios(t("Preview comment"), 'comment_preview', variable_get('comment_preview', 1), array(t("Optional"), t("Required"), t("Only for Anonymous User")), t("Must users preview comments before submitting?"));
+    $group .= form_radios(t("Location of comment submission form"), "comment_form_location", variable_get("comment_form_location", 1), array(t("Display on separate page"), t("Display below post or comments")), t("The location of the comment submission form."));
+  }
   $output .= form_group(t('Comment posting settings'), $group);
 
-  $result = db_query("SELECT fid, filter FROM {moderation_filters} ");
-  while ($filter = db_fetch_object($result)) {
-    $thresholds[$filter->fid] = ($filter->filter);
-  }
-  if ($thresholds) {
-    $group = form_select(t("Default threshold"), "comment_default_threshold", variable_get("comment_default_threshold", 0), $thresholds, t("Thresholds are values below which comments are hidden. These thresholds are useful for busy sites which want to hide poor comments from most users."));
-    $output .= form_group(t('Comment moderation settings'), $group);
+  $group   = form_radios(t("Filter HTML tags"), "comment_filter_html", variable_get("comment_filter_html", FILTER_HTML_STRIP), array(FILTER_HTML_DONOTHING => t("Do not filter"), FILTER_HTML_STRIP => t("Strip tags"), FILTER_HTML_ESCAPE => t("Escape tags")), t("How to deal with HTML and PHP tags in user-contributed content. If set to \"Strip tags\", dangerous tags are removed.  If set to \"Escape tags\", all HTML is escaped and presented as it was typed."));
+  if (variable_get("comment_complex",0)) {
+    $group  .= form_textfield(t("Allowed HTML tags"), "comment_allowed_html", variable_get("comment_allowed_html", "<a> <b> <strong> <i> <br> <blockquote>"), 64, 255, t("If \"Strip tags\" is selected, optionally specify tags which should not be stripped.  'ON*' attributes are always stripped."));
+    $group  .= form_radios(t("HTML style attributes"), "comment_filter_style", variable_get("comment_filter_style", FILTER_STYLE_STRIP), array(FILTER_STYLE_ALLOW => t("Allowed"), FILTER_STYLE_STRIP => t("Removed")), t("If \"Strip tags\" is selected, you can choose whether 'STYLE' attributes are allowed or removed from input."));
+  }
+  $output .= form_group(t("Comment HTML filtering"), $group);
+
+  if (variable_get("comment_complex",0)>1) {
+    $result = db_query("SELECT fid, filter FROM {moderation_filters} ");
+    while ($filter = db_fetch_object($result)) {
+      $thresholds[$filter->fid] = ($filter->filter);
+    }
+    if ($thresholds) {
+      $group = form_select(t("Default threshold"), "comment_default_threshold", variable_get("comment_default_threshold", 0), $thresholds, t("Thresholds are values below which comments are hidden. These thresholds are useful for busy sites which want to hide poor comments from most users."));
+      $output .= form_group(t('Comment moderation settings'), $group);
+    }
   }
 
   return $output;
 }
 
+function comment_ip_greylist($edit) {
+  $headers = array(t('delete'),t("ip address/block"));
+
+  $rows = array();
+  $blacklist = unserialize(variable_get('comment_blacklist',''));
+  if (is_array($blacklist))
+    foreach ($blacklist as $black) {
+      $rows[] = array(form_checkbox('', 'black-delete]['.$black, 1), $black);
+    }
+
+  $group = "<p>".t("Specify an IP address or a range of IP addresses to blacklist.  If anonymous comments comes from blacklist, it will be put onto moderation queue. This is only use if the default action is to allow posting <i>without</i> moderation.")."</p>"; 
+  $group .= theme("table", $headers, $rows);
+  $group .= "<br />";
+  
+  $group .= form_textfield(t('Add IP Ban'), 'add_black', '', 40, 20, t('Add IP address (e.g. 192.168.0.1) or block of IP addresses (e.g. 192.168.0.) to blacklist.'));
+  $group .= form_submit(t('Update blacklist'));
+  $output .= form_group(t("blacklist for anonymous comments"), $group);
+
+  $rows = array();
+  $whitelist = unserialize(variable_get('comment_whitelist',''));
+  if (is_array($whitelist))
+    foreach ($whitelist as $white) {
+      $rows[] = array(form_checkbox('', 'white-delete]['.$white, 1), $white);
+    }
+
+  $group = "<p>".t("Specify an IP address or a range of IP addresses to whitelist.  If anonymous comments comes from whitelist, it will be posted without moderation. This is only use if the default action is to allow posting <i>with</i> moderation.")."</p>"; 
+  $group .= theme("table", $headers, $rows);
+  $group .= "<br />";
+  
+  $group .= form_textfield(t('Add IP Allow'), 'add_white', '', 40, 20, t('Add IP address (e.g. 192.168.0.1) or block of IP addresses (e.g. 192.168.0.) to allow list.'));
+  $group .= form_submit(t('Update whitelist'));
+  $output .= form_group(t("whitelist for anonymous comments"), $group);
+
+  return form($output);
+}
+
 function comment_user($type, $edit, &$user) {
   switch ($type) {
     case "view_public":
@@ -144,10 +205,10 @@
         return form_item(t("Signature"), check_output($user->signature));
       }
       break;
-    case "edit_form":
+    case "edit_form": case 'edit':
       // when user tries to edit his own data
-      return array(t('Personal information') => form_textarea(t("Signature"), "signature", $user->signature, 70, 3, t("Your signature will be publicly displayed at the end of your comments.") ."<br />". filter_tips_short()));
-    case "edit_validate":
+    return array(t('Personal information') => form_textarea(t("Signature"), "signature", $user->signature, 64, 3, t("Your signature will be publicly displayed at the end of your comments.") ."<br />". filter_tips_short(array('filter_html' => variable_get("comment_filter_html", FILTER_HTML_STRIP), 'allowed_html' => variable_get("comment_allowed_html", "<a> <b> <strong> <i> <br> <blockquote>"), 'filter_style' => variable_get("comment_filter_style", FILTER_STYLE_STRIP)))));
+    case "edit_validate": case 'validate':
       // validate user data editing
       return array("signature" => $edit["signature"]);
   }
@@ -170,13 +231,14 @@
   }
 
 }
+
 function comment_referer_save() {
   $_SESSION["comment_referer"] = arg(0) ."/". arg(1) ."/". arg(2);
 }
 
-/*
-** Restores the referer from a persistent variable:
-*/
+function comment_node_url() {
+  return arg(0) ."/". arg(1) ."/". arg(2);
+}
 
 function comment_referer_load() {
   return $_SESSION["comment_referer"];
@@ -185,8 +247,9 @@
 function comment_edit($cid) {
   global $user;
 
-  $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status != 2", $cid));
+  $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status != 2', $cid));
   $comment = drupal_unpack($comment);
+  $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
   if (comment_access("edit", $comment)) {
     return comment_preview(object2array($comment));
   }
@@ -203,8 +266,9 @@
     */
 
     if ($pid) {
-      $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $pid));
+      $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0', $pid));
       $comment = drupal_unpack($comment);
+      $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
       $output .= theme("comment_view", $comment);
     }
     else if (user_access("access content")) {
@@ -217,22 +281,82 @@
     */
 
     if (node_comment_mode($nid) != 2) {
-      $output .= theme("box", t("Reply"), t("This discussion is closed: you can't post new comments."));
+      $output .= theme('box', t("Reply"), t("This discussion is closed: you can't post new comments."));
     }
     else if (user_access("post comments")) {
       $output .= theme("comment_form", array("pid" => $pid, "nid" => $nid), t("Reply"));
     }
     else {
-      $output .= theme("box", t("Reply"), t("You are not authorized to post comments."));
+      $output .= theme('box', t("Reply"), t("You are not authorized to post comments."));
     }
   }
   else {
-    $output .= theme("box", t("Reply"), t("You are not authorized to view comments."));
+    $output .= theme('box', t("Reply"), t("You are not authorized to view comments."));
   }
 
   return $output;
 }
 
+function comment_validate_form($edit) {
+  global $user;
+
+  /*
+  ** Invoke other validation
+  */
+  module_invoke_all('comment', 'validate', $edit);
+
+  /*
+  ** Validate the session secret
+  */
+  if ($_POST['op'] == t('Post comment') 
+  &&  $edit['secret'] != $_SESSION['secret']) {
+    form_set_error('secret', t('You have attempt to post comment without going through the web interface.'));
+  }
+
+  /*
+  ** Validate the comment's body.
+  */
+
+  if ($edit['comment'] == '') {
+    form_set_error('comment', t('The body of your comment is empty.'));
+  }
+
+  /*
+  ** Check validity of name, mail and homepage (if given)
+  */
+
+  if (!$user->uid) {
+    if (variable_get('comment_anonymous', 1) > 0) {
+      if ($edit['name']) {
+        $taken = db_result(db_query("SELECT COUNT(uid) FROM {users} WHERE LOWER(name) = '%s'", strip_tags($edit['name'])), 0);
+
+        if ($taken != 0) {
+          form_set_error('name', t('The name you used belongs to a registered user.'));
+        }
+
+      }
+      else if (variable_get('comment_anonymous', 1) == 2) {
+        form_set_error('name', t('You have to leave your name.'));
+      }
+
+      if ($edit['mail']) {
+        if (!valid_email_address($edit['mail'])) {
+          form_set_error('mail', t('The e-mail address you specifed is not valid.'));
+        }
+      }
+      else if (variable_get('comment_anonymous', 1) == 2) {
+        form_set_error('mail', t('You have to leave an e-mail address.'));
+      }
+
+      if ($edit['homepage']) {
+        if (!valid_url($edit['homepage'], TRUE)) {
+          form_set_error('homepage', t('The URL of your homepage is not valid.  Remember that it must be fully qualified, i.e. of the form <code>http://example.com/directory</code>.'));
+        }
+      }
+    }
+  }
+}
+
 function comment_preview($edit) {
   global $user;
 
@@ -247,19 +371,20 @@
   */
 
   $comment->uid = $user->uid;
-  $comment->name = $user->name;
   $comment->timestamp = time();
+  $comment->name = $user->name ? $user->name : $comment->name;
 
   /*
   ** Preview the comment:
   */
 
   $output .= theme("comment_view", $comment, theme('links', module_invoke_all('link', 'comment', $comment, 1)));
-  $output .= theme("comment_form", $edit, t("Reply"));
+  $output .= theme("comment_form", $edit, t("Reply"), 1);
 
   if ($edit["pid"]) {
-    $comment = db_fetch_object(db_query("SELECT c.*, u.uid, u.name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0", $edit["pid"]));
+    $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0', $edit["pid"]));
     $comment = drupal_unpack($comment);
+    $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
     $output .= theme("comment_view", $comment);
   }
   else {
@@ -273,70 +398,97 @@
 function comment_post($edit) {
   global $user;
 
-  if (user_access("post comments") && node_comment_mode($edit["nid"]) == 2) {
+  // expire cookies in 90 days
+  $expire = time() + 60*60*24*90;
+
+  setcookie('anon_name', $edit['name'], $expire, '/');
+  setcookie('anon_mail', $edit['mail'], $expire, '/');
+  setcookie('anon_url', $edit['homepage'], $expire, '/');
+
+  if (user_access("post comments") && node_comment_mode($edit['nid']) == 2) {
 
     /*
     ** Validate the comment's subject.  If not specified, extract
     ** one from the comment's body.
     */
 
-    $edit["subject"] = strip_tags($edit["subject"]);
+    $edit['subject'] = strip_tags($edit['subject']);
 
-    if ($edit["subject"] == "") {
-      $edit["subject"] = truncate_utf8(strip_tags($edit["comment"]), 29);
+    if ($edit['subject'] == "") {
+      $edit['subject'] = truncate_utf8(strip_tags($edit['comment']), 29);
     }
 
-    /*
-    ** Validate the comment's body.
-    */
-
-    if ($edit["comment"] == "") {
-      return array(t("Empty comment"), t("The comment you submitted is empty."));
-    }
-
-    /*
-    ** Check for duplicate comments.  Note that we have to use the
-    ** validated/filtered data to perform such check.
-    */
-
-    $duplicate = db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE pid = %d AND nid = %d AND subject = '%s' AND comment = '%s'", $edit["pid"], $edit["nid"], $edit["subject"], $edit["comment"]), 0);
+    if (!form_has_errors()) {
+      /*
+      ** Check for duplicate comments.  Note that we have to use the
+      ** validated/filtered data to perform such check.
+      */
 
-    if ($duplicate != 0) {
-      watchdog("warning", "comment: duplicate '". $edit["subject"] ."'");
-      return array(t("Duplicate comment"), t("The comment you submitted has already been inserted."));
-    }
-    else {
+      $duplicate = db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE pid = %d AND nid = %d AND subject = '%s' AND comment = '%s'", $edit["pid"], $edit["nid"], $edit['subject'], $edit['comment']), 0);
+      if ($duplicate != 0) {
+        watchdog('warning', t('comment: duplicate "%comment-subject"', array('%comment-subject' => $edit["subject"])));
+      }
 
       if ($edit["cid"]) {
-
         /*
         ** Update the comment in the database.  Note that the update
         ** query will fail if the comment isn't owned by the current
         ** user.
         */
 
-        db_query("UPDATE {comments} SET subject = '%s', comment = '%s' WHERE cid = %d AND uid = '$user->uid'", $edit["subject"], $edit["comment"], $edit["cid"]);
+        db_query("UPDATE {comments} SET subject = '%s', comment = '%s' WHERE cid = %d AND uid = '$user->uid'", $edit['subject'], $edit['comment'], $edit["cid"]);
 
         /*
         ** Fire a hook
         */
 
-        module_invoke_all("comment", "update", $edit);
+        module_invoke_all('comment', "update", $edit);
 
         /*
         ** Add entry to the watchdog log:
         */
 
-        watchdog("special", "comment: updated '". $edit["subject"] ."'", l(t("view comment"), "node/view/". $edit["nid"], NULL, NULL, "comment-". $edit["cid"]));
+        watchdog('special', t('comment: updated "%comment-subject"', array('%comment-subject' => $edit["subject"])), l(t("view comment"), "node/view/". $edit["nid"], NULL, NULL, "comment-". $edit["cid"]));
       }
       else {
         /*
         ** Add the comment to database:
         */
 
-        $status = user_access("post comments without approval") ? 0 : 1;
+        if (user_access("post comments without approval")) {
+          $status = 0;
+          $blacklist = unserialize(variable_get('comment_blacklist',''));
+          if (is_array($blacklist)) {
+            foreach ($blacklist as $black) {
+              if (strstr($_SERVER['REMOTE_ADDR'],$black)) {
+                # drupal_set_message('Your IP address has been blacklisted. Your comment will be put onto moderation queue for approval.');
+                $status = 1;
+                break;
+              }
+            }
+          }
+        } else {
+          $status = 1;
+          if (is_array($whitelist)) {
+            foreach ($whitelist as $white) {
+              if (strstr($_SERVER['REMOTE_ADDR'],$white)) {
+                # drupal_set_message('Your IP address has been whitelisted. Your comment will be put posted without moderationl.');
+                $status = 0;
+                break;
+              }
+            }
+          }
+        }
+        # $status = user_access("post comments without approval") ? 0 : 1;
         $roles = variable_get("comment_roles", array());
         $score = $roles[$user->rid] ? $roles[$user->rid] : 0;
+
+        /* not in 4.4.0
+        foreach (array_intersect(array_keys($roles), array_keys($user->roles)) as $rid) {
+          $score = max($roles[$rid], $score);
+        }
+        */
+
         $users = serialize(array(0 => $score));
 
         /*
@@ -385,13 +537,13 @@
           */
 
           // Get the parent comment:
-          $parent = db_fetch_object(db_query("SELECT * FROM {comments} WHERE cid = '%d'", $edit["pid"]));
+          $parent = db_fetch_object(db_query("SELECT * FROM {comments} WHERE cid = %d", $edit['pid']));
 
           // Strip the "/" from the end of the parent thread:
           $parent->thread = (string)rtrim((string)$parent->thread, "/");
 
           // Get the max value in _this_ thread:
-          $max = db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE thread LIKE '%s.%%' AND nid = '%d'", $parent->thread, $edit["nid"]));
+          $max = db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE thread LIKE '%s.%%' AND nid = %d", $parent->thread, $edit['nid']));
 
           if ($max == "") {
             // First child of this parent
@@ -428,40 +580,54 @@
 
         $edit["cid"] = db_next_id("{comments}_cid");
 
-        db_query("INSERT INTO {comments} (cid, nid, pid, uid, subject, comment, hostname, timestamp, status, score, users, thread) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', %d, %d, %d, '%s', '%s')", $edit["cid"], $edit["nid"], $edit["pid"], $user->uid, $edit["subject"], $edit["comment"], $_SERVER['REMOTE_ADDR'], time(), $status, $score, $users, $thread);
+        db_query("INSERT INTO {comments} (cid, nid, pid, uid, subject, comment, hostname, timestamp, status, score, users, thread, name, mail, homepage) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", $edit["cid"], $edit["nid"], $edit["pid"], $user->uid, $edit['subject'], $edit['comment'], $_SERVER['REMOTE_ADDR'], time(), $status, $score, $users, $thread, $edit["name"], $edit['mail'], $edit["homepage"]);
 
         /*
         ** Tell the other modules a new comment has been submitted:
         */
 
-        module_invoke_all("comment", "insert", $edit);
+        $edit['status'] = $status;
+        module_invoke_all('comment', "insert", $edit);
 
         /*
         ** Add entry to the watchdog log:
         */
 
-        watchdog("special", "comment: added '". $edit["subject"] ."'", l(t("view comment"), "node/view/". $edit["nid"], NULL, NULL, "comment-". $edit["cid"]));
+        watchdog('special', t('comment: added "%comment-subject"', array('%comment-subject' => $edit["subject"])), l(t("view comment"), "node/view/". $edit["nid"], NULL, NULL, "comment-". $edit["cid"]));
+
       }
 
       /*
+      ** Generate new session secret
+      */
+      $_SESSION['secret'] = rand(100000,999999);
+
+      /*
       ** Clear the cache so an anonymous user can see his comment being
       ** added.
       */
 
       cache_clear_all();
+
+      /*
+      ** Redirect the user the node he commented on, or explain queue
+      */
+
+      if ($status == 1) {
+        print theme('page', t('Your comment has been queued for moderation by site administrators and will be published after approval.'));
+      }
+      else {
+        // Redirect the user to his comment:
+        drupal_goto('node/view/'. $edit['nid'] .'#comment-'. $edit['cid']);
+      }
+    }
+    else {
+      print theme('page', comment_preview($edit));
     }
   }
   else {
-    watchdog("error", "comment: unauthorized comment submitted or comment submitted to a closed node '". $edit["subject"] ."'");
-    return array(t("Error"), t("You are not authorized to post comments, or this node doesn't accept new comments."));
-  }
-
-  /*
-  ** Redirect the user the node he commented on, or explain queue
-  */
-
-  if ($status == 1) {
-    return array(t("Comment queued"), t("Your comment has been queued for moderation by site administrators and will be published after approval."));
+    watchdog('error', t('comment: unauthorized comment submitted or comment submitted to a closed node "%comment-subject"', array('%comment-subject' => $edit["subject"])));
+    drupal_goto();
   }
 }
 
@@ -475,7 +641,7 @@
   */
 
   if ($return) {
-    $links[] = l(t("parent"), comment_referer_load(), NULL, NULL, "comment-$comment->cid");
+    $links[] = l(t("parent"), comment_node_url(), NULL, NULL, "comment-$comment->cid");
   }
 
   if (node_comment_mode($comment->nid) == 2) {
@@ -514,7 +680,6 @@
   $output = "";
 
   if (user_access("access comments")) {
-
     /*
     ** Save were we come from so we can go back after a reply
     */
@@ -532,6 +697,7 @@
 
     if (empty($mode)) {
       $mode = $user->mode ? $user->mode : ($_SESSION["comment_mode"] ? $_SESSION["comment_mode"] : variable_get("comment_default_mode", 4));
+      if (variable_get("comment_complex",0) == 0) $mode = 2;
     }
 
     if (empty($order)) {
@@ -555,12 +721,13 @@
       ** Single comment view
       */
 
-      $output .= "<form method=\"post\" action=\"". url("comment") ."\"><div>\n";
+      $output .= "<form method=\"post\" action=\"". url('comment') ."\"><div>\n";
       $output .= form_hidden("nid", $nid);
 
-      $result = db_query("SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0 GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users", $cid);
+      $result = db_query('SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.picture, u.data, c.score, c.users FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = 0 GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users', $cid);
 
       if ($comment = db_fetch_object($result)) {
+        $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
         $output .= theme("comment_view", $comment, theme('links', module_invoke_all('link', 'comment', $comment, 1)));
       }
 
@@ -575,9 +742,15 @@
       ** Multiple comments view
       */
 
-      $query .= "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users, c.thread FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = '". check_query($nid) ."' AND c.status = 0";
+      $query .= "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, c.name , c.mail, c.homepage, u.uid, u.name AS registered_name, u.picture, u.data, c.score, c.users, c.thread, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = '". check_query($nid);
 
-      $query .= " GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users, c.thread";
+      if (!user_access("administer comments"))
+          $query .= "' AND c.status = 0";
+      else
+          $query .= "' AND (c.status = 0 OR c.status = 1)";
+
+
+      $query .= " GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.picture, u.data, c.score, c.users, c.thread";
 
       /*
       ** We want to use the standard pager, but threads would need every
@@ -671,18 +844,20 @@
       */
 
       $result = pager_query($query, $comments_per_page, 0, "SELECT COUNT(*) FROM {comments} WHERE nid = '". check_query($nid) ."'");
-      if (db_num_rows($result) && (variable_get("comment_controls", 0) == 0 || variable_get("comment_controls", 0) == 2)) {
-        $output .= "<form method=\"post\" action=\"". url("comment") ."\"><div>\n";
+      if (db_num_rows($result) && ((variable_get("comment_controls", 0) == 0 && variable_get("comment_complex",0)) || variable_get("comment_controls", 0) == 2)) {
+        $output .= "<form method=\"post\" action=\"". url('comment') ."\"><div>\n";
         $output .= theme("comment_controls", $threshold, $mode, $order, $comments_per_page);
         $output .= form_hidden("nid", $nid);
         $output .= "</div></form>";
       }
 
-      $output .= "<form method=\"post\" action=\"". url("comment") ."\"><div>\n";
+      $output .= "<form method=\"post\" action=\"". url('comment') ."\"><div>\n";
       $output .= form_hidden("nid", $nid);
 
+      $output .= '<div class="comment-head">Comments '.comment_num_all($nid).'</div>';
       while ($comment = db_fetch_object($result)) {
         $comment = drupal_unpack($comment);
+        $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
         $comment->depth = count(explode(".", $comment->thread)) - 1;
 
         if ($mode == 1) {
@@ -714,7 +889,7 @@
       $output .= "</div></form>";
 
       if (db_num_rows($result) && (variable_get("comment_controls", 0) == 1 || variable_get("comment_controls", 0) == 2)) {
-        $output .= "<form method=\"post\" action=\"". url("comment") ."\"><div>\n";
+        $output .= "<form method=\"post\" action=\"". url('comment') ."\"><div>\n";
         $output .= theme("comment_controls", $threshold, $mode, $order, $comments_per_page);
         $output .= form_hidden("nid", $nid);
         $output .= "</div></form>";
@@ -725,7 +900,7 @@
     ** If enabled, show new comment form
     */
 
-    if (user_access("post comments") && node_comment_mode($nid) == 2 && variable_get("comment_form_location", 0)) {
+    if (user_access("post comments") && node_comment_mode($nid) == 2 && variable_get("comment_form_location", 1)) {
       $output .= theme("comment_form", array("nid" => $nid), t("Post new comment"));
     }
   }
@@ -733,13 +908,22 @@
 }
 
 function comment_perm() {
-  return array("access comments", "post comments", "administer comments", "moderate comments", "post comments without approval", "administer moderation");
+  switch (variable_get("comment_complex",0)) {
+    case 0:
+    case 1:
+      return array("access comments", "post comments", "administer comments", "moderate comments", "post comments without approval");
+    default:
+      return array("access comments", "post comments", "administer comments", "moderate comments", "post comments without approval", "administer moderation");
+  }
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function comment_link($type, $node = 0, $main = 0) {
   $links = array();
 
-  if ($type == "node" && $node->comment) {
+  if ($type == 'node' && $node->comment) {
 
     if ($main) {
 
@@ -747,24 +931,32 @@
       ** Main page: display the number of comments that have been posted.
       */
 
-      if (user_access("access comments")) {
+      if (user_access('access comments')) {
         $all = comment_num_all($node->nid);
         $new = comment_num_new($node->nid);
+        $unp = comment_num_unpublish($node->nid);
 
         if ($all) {
-          $links[] = l(format_plural($all, "1 comment", "%count comments"), "node/view/$node->nid", array("title" => t("Jump to the first comment of this posting.")), NULL, "comment");
+          if ($new && $unp)
+              $title = sprintf("%d new and %d unpublish comments", $new, $unp);
+          else if ($new)
+              $title .= format_plural($new, "1 new comment", 
+                            "%count new comments");
+          else if ($unp)
+              $title .= format_plural($unp, "1 unpublish comment", 
+                            "%count unpublish comments");
+          else
+              $title = "Jump to the first comment of this posting.";
 
-          if ($new) {
-            $links[] = l(format_plural($new, "1 new comment", "%count new comments"), "node/view/$node->nid", array("title" => t("Jump to the first new comment of this posting.")), NULL, "new");
-          }
+          $links[] = l(format_plural($all, "1 comment", "%count comments"), "node/view/$node->nid", array("title" => t($title)), NULL, "comment");
         }
         else {
           if ($node->comment == 2) {
-            if (user_access("post comments")) {
-              $links[] = l(t("add new comment"), "comment/reply/$node->nid", array("title" => t("Add a new comment to this page.")));
+            if (user_access('post comments')) {
+              $links[] = l(t('add new comment'), "comment/reply/$node->nid", array('title' => t('Add a new comment to this page.')));
             }
             else {
-              $links[] = theme("comment_post_forbidden");
+              $links[] = theme('comment_post_forbidden');
             }
           }
         }
@@ -777,44 +969,45 @@
       */
 
       if ($node->comment == 2) {
-        if (user_access("post comments")) {
-          $links[] = l(t("add new comment"), "comment/reply/$node->nid", array("title" => t("Share your thoughts and opinions related to this posting.")), NULL, "comment");
+        if (user_access('post comments')) {
+          $links[] = l(t('add new comment'), "comment/reply/$node->nid", array('title' => t('Share your thoughts and opinions related to this posting.')), NULL, 'comment');
         }
         else {
-          $links[] = theme("comment_post_forbidden");
+          $links[] = theme('comment_post_forbidden');
         }
       }
     }
   }
 
-  if ($type == "comment") {
+  if ($type == 'comment') {
     $links = comment_links($node, $main);
   }
 
-  if ($type == "system") {
-    if (user_access("administer comments")) {
-
-      menu("admin/comment", t("comments"), "comment_admin", 1);
-      menu("admin/comment/comments", t("overview"), "comment_admin", 2);
-      menu("admin/comment/comments/0", t("new/updated"), "comment_admin", 1);
-      menu("admin/comment/comments/1", t("approval queue"), "comment_admin", 2);
-      menu("admin/comment/help", t("help"), "comment_help_page", 9);
-      menu("admin/comment/edit", t("edit comment"), "comment_admin", 0, MENU_HIDE);
-      menu("admin/comment/delete", t("delete comment"), "comment_admin", 0, MENU_HIDE);
-      if (module_exist('search')) {
-        menu("admin/comment/search", t("search"), "comment_admin", 8);
-      }
-
-      // comment settings:
-      if (user_access("administer moderation")) {
-        menu("admin/comment/moderation", t("moderation"), "comment_admin", 3);
-        menu("admin/comment/moderation/votes", t("votes"), "comment_admin");
-        menu("admin/comment/moderation/matrix", t("matrix"), "comment_admin");
-        menu("admin/comment/moderation/filters", t("thresholds"), "comment_admin");
-        menu("admin/comment/moderation/roles", t("initial scores"), "comment_admin", 6);
-      }
+  if ($type == 'system') {
+    $access = user_access('administer comments');
+    menu('admin/comment', t('comments'), $access ? 'comment_admin' : MENU_DENIED, 1);
+    menu('admin/comment/comments', t('overview'), $access ? 'comment_admin' : MENU_DENIED, 2);
+    menu('admin/comment/comments/0', t('new/updated'), $access ? 'comment_admin' : MENU_DENIED, 1);
+    menu('admin/comment/comments/1', t('approval queue'), $access ? 'comment_admin' : MENU_DENIED, 2);
+    menu('admin/comment/help', t('help'), $access ? 'comment_help_page' : MENU_DENIED, 9);
+    menu('admin/comment/edit', t('edit comment'), $access ? 'comment_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/comment/delete', t('delete comment'), $access ? 'comment_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    if (module_exist('search')) {
+      menu('admin/comment/search', t('search'), $access ? 'comment_admin' : MENU_DENIED, 8);
+    }
+    menu('admin/comment/greylist', t('black/white list'), $access ? 'comment_admin' : MENU_DENIED, 8);
+
+    // comment settings:
+    $access = user_access('administer comments') && user_access('administer moderation');
+    if (variable_get("comment_complex",0)>1) {
+      menu('admin/comment/moderation', t('moderation'), $access ? 'comment_admin' : MENU_DENIED, 3);
+      menu('admin/comment/moderation/votes', t('votes'), $access ? 'comment_admin' : MENU_DENIED);
+      menu('admin/comment/moderation/matrix', t('matrix'), $access ? 'comment_admin' : MENU_DENIED);
+      menu('admin/comment/moderation/filters', t('thresholds'), $access ? 'comment_admin' : MENU_DENIED);
+      menu('admin/comment/moderation/roles', t('initial scores'), $access ? 'comment_admin' : MENU_DENIED, 6);
     }
-    menu("comment", t("comments"), "comment_page", 0, MENU_HIDE);
+
+    menu('comment', t('comments'), 'comment_page', 0, MENU_HIDE, MENU_LOCKED);
   }
 
   return $links;
@@ -830,27 +1023,24 @@
 
   switch ($op) {
     case "edit":
-      print theme("page", comment_edit(check_query(arg(2))), t("Edit comment"));;
+      print theme('page', comment_edit(check_query(arg(2))), t("Edit comment"));;
       break;
     case t("Moderate comments"):
     case t("Moderate comment"):
       comment_moderate($edit);
-      drupal_goto(comment_referer_load());
+      drupal_goto(comment_node_url());
       break;
     case "reply":
-      print theme("page", comment_reply(check_query(arg(3)), check_query(arg(2))), t("Add new comment"));
+      print theme('page', comment_reply(check_query(arg(3)), check_query(arg(2))), t("Add new comment"));
       break;
     case t("Preview comment"):
-      print theme("page", comment_preview($edit), t("Preview comment"));
+      comment_validate_form($edit);
+      print theme('page', comment_preview($edit), t("Preview comment"));
       break;
     case t("Post comment"):
-      list($error_title, $error_body) = comment_post($edit);
-      if ($error_body) {
-        print theme("page", $error_body, $error_title);
-      }
-      else {
-        drupal_goto(comment_referer_load());
-      }
+      comment_validate_form($edit);
+      comment_post($edit);
+      //print theme('page', comment_post($edit));
       break;
     case t("Save settings"):
       $mode = $_POST["mode"];
@@ -859,6 +1049,7 @@
       $comments_per_page = $_POST["comments_per_page"];
 
       comment_save_settings(check_query($mode), check_query($order), check_query($threshold), check_query($comments_per_page));
+      //drupal_goto(comment_node_url());
       drupal_goto(comment_referer_load());
       break;
   }
@@ -876,12 +1067,13 @@
     ** Edit comments:
     */
 
-    $result = db_query("SELECT c.cid, c.subject, u.uid, u.name FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE nid = %d AND c.status = 0 ORDER BY c.timestamp", $node->nid);
-
+    $result = db_query('SELECT c.cid, c.subject, c.name, c.homepage, u.uid, u.name AS registered_name, c.name FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE nid = %d AND c.status = 0 ORDER BY c.timestamp', $node->nid);
 
-    $header = array(t("title"), t("author"), array("data" => t("operations"), "colspan" => 3));
+    $header = array(t("title"), t('author'), array("data" => t("operations"), "colspan" => 3));
 
     while ($comment = db_fetch_object($result)) {
+      $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
+      $comment = drupal_unpack($comment);
       $rows[] = array(l($comment->subject, "node/view/$node->nid", NULL, NULL, "comment-$comment->cid"), format_name($comment), l(t("view comment"), "node/view/$node->nid", NULL, NULL, $comment->cid), l(t("edit comment"), "admin/comment/edit/$comment->cid"), l(t("delete comment"), "admin/comment/delete/$comment->cid"));
     }
 
@@ -896,15 +1088,17 @@
 
 function comment_admin_edit($id) {
 
-  $result = db_query("SELECT c.*, u.name, u.uid FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status != 2", $id);
+  $result = db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status != 2', $id);
   $comment = db_fetch_object($result);
+  $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
   $comment = drupal_unpack($comment);
+  $comment->comment = check_output($comment->comment, array('filter_html' => variable_get("comment_filter_html", FILTER_HTML_STRIP), 'allowed_html' => variable_get("comment_allowed_html", "<a> <b> <strong> <i> <br> <blockquote>"), 'filter_style' => variable_get("comment_filter_style", FILTER_STYLE_STRIP)));
 
   if ($comment) {
     $form .= form_item(t("Author"), format_name($comment));
-    $form .= form_textfield(t("Subject"), "subject", $comment->subject, 70, 128);
-    $form .= form_textarea(t("Comment"), "comment", $comment->comment, 70, 15, filter_tips_short());
-    $form .= form_radios(t("Status"), "status", $comment->status, array("published", "not published"));
+    $form .= form_textfield(t("Subject"), 'subject', $comment->subject, 70, 128);
+    $form .= form_textarea(t("Comment"), 'comment', $comment->comment, 70, 15, filter_tips_short(array('filter_html' => variable_get("comment_filter_html", FILTER_HTML_STRIP), 'allowed_html' => variable_get("comment_allowed_html", "<a> <b> <strong> <i> <br> <blockquote>"), 'filter_style' => variable_get("comment_filter_style", FILTER_STYLE_STRIP))));
+    $form .= form_radios(t("Status"), 'status', $comment->status, array("published", "not published"));
     $form .= form_hidden("cid", $id);
     $form .= form_submit(t("Submit"));
 
@@ -915,7 +1109,7 @@
 function _comment_delete_thread($comment) {
   // Delete the comment:
   db_query("DELETE FROM {comments} WHERE cid = %d", $comment->cid);
-  watchdog("special", "comment: deleted '$comment->subject'");
+  watchdog('special', t('comment: deleted "%comment-subject"', array('%comment-subject' => $comment->subject)));
 
   // Delete the comment's replies:
   $result = db_query("SELECT cid, subject FROM {comments} WHERE pid = %d", $comment->cid);
@@ -925,7 +1119,8 @@
 }
 
 function comment_delete($cid, $confirmed = 0) {
-  $comment = db_fetch_object(db_query("SELECT c.*, u.name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = %d", $cid));
+  $comment = db_fetch_object(db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = %d', $cid));
+  $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
 
   if ($comment->cid) {
     if ($confirmed) {
@@ -951,7 +1146,7 @@
       ** Print a confirmation screen:
       */
 
-      $output  = theme("comment", $comment);
+      $output  = theme('comment', $comment);
       $output .= form_submit(t("Delete comment"));
 
       return form($output);
@@ -963,27 +1158,35 @@
 }
 
 function comment_save($id, $edit) {
-  db_query("UPDATE {comments} SET subject = '%s', comment = '%s', status = %d WHERE cid = %d", $edit["subject"], $edit["comment"], $edit["status"], $id);
-  watchdog("special", "comment: modified '". $edit["subject"] ."'");
+  db_query("UPDATE {comments} SET subject = '%s', comment = '%s', status = %d WHERE cid = %d", $edit['subject'], $edit['comment'], $edit['status'], $id);
+  watchdog('special', t('comment: modified "%comment-subject"', array('%comment-subject' => $edit["subject"])));
   drupal_set_message(t("the comment has been saved."));
 }
 
 function comment_admin_overview($status = 0) {
 
   $header = array(
-    array("data" => t("subject"), "field" => "subject"),
-    array("data" => t("author"), "field" => "u.name"),
-    array("data" => t("status"), "field" => "status"),
+    array("data" => t('subject'), "field" => 'subject'),
+    array("data" => t('author'), "field" => "u.name"),
+    array("data" => t('status'), "field" => 'status'),
     array("data" => t("time"), "field" => "c.timestamp", "sort" => "desc"),
     array("data" => t("operations"), "colspan" => 2)
   );
 
-  $sql = "SELECT c.*, u.name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.status = ". check_query($status);
+  $sql = 'SELECT c.subject, c.nid, c.cid, c.comment, c.timestamp, c.status, c.name, c.homepage, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.status = '. check_query($status);
   $sql .= tablesort_sql($header);
   $result = pager_query($sql,  50);
 
   while ($comment = db_fetch_object($result)) {
-    $rows[] = array(l($comment->subject, "node/view/$comment->nid/$comment->cid", array("title" => htmlspecialchars(substr($comment->comment, 0, 128))), NULL, "comment-$comment->cid") ." ". (node_is_new($comment->nid, $comment->timestamp) ? theme("mark") : ""), format_name($comment), ($comment->status == 0 ? t("published") : t("not published")) ."</td><td>". format_date($comment->timestamp, "small") ."</td><td>". l(t("edit comment"), "admin/comment/edit/$comment->cid"), l(t("delete comment"), "admin/comment/delete/$comment->cid"));
+    $comment->name = $comment->registered_name ? $comment->registered_name : $comment->name . theme('notmember');
+    $rows[] = array(
+        l($comment->subject, "node/view/$comment->nid/$comment->cid", array("title" => htmlspecialchars(truncate_utf8($comment->comment, 128))), NULL, "comment-$comment->cid") ." ". (node_is_new($comment->nid, $comment->timestamp) ? theme("mark") : ""),
+        format_name($comment),
+        ($comment->status == 0 ? t("published") : t("not published")),
+        format_date($comment->timestamp, "small"),
+        l(t("edit comment"), "admin/comment/edit/$comment->cid"),
+        l(t("delete comment"), "admin/comment/delete/$comment->cid")
+      );
   }
 
   if ($pager = theme("pager", NULL, 50, 0, tablesort_pager())) {
@@ -1180,25 +1383,31 @@
       $output = comment_admin_edit(arg(3));
       break;
     case "search":
-      $output = search_type("comment", url("admin/comment/search"), $_POST["keys"]);
+      $output = search_type('comment', url("admin/comment/search"), $_POST["keys"]);
+      break;
+    case "greylist":
+      $output = comment_ip_greylist($edit);
       break;
     case "votes":
     case t("Add new vote"):
     case t("Delete vote"):
     case t("Save vote"):
-      if (user_access("administer moderation")) {
+      if (user_access("administer moderation")
+      && (variable_get("comment_complex",0)>1)) {
         $output = comment_mod_votes($edit);
       }
       break;
     case "roles":
     case t("Save scores"):
-      if (user_access("administer moderation")) {
+      if (user_access("administer moderation")
+      && (variable_get("comment_complex",0)>1)) {
         $output = comment_mod_roles($edit);
       }
       break;
     case "matrix":
     case t("Submit votes"):
-      if (user_access("administer moderation")) {
+      if (user_access("administer moderation")
+      && (variable_get("comment_complex",0)>1)) {
         $output = comment_mod_matrix($edit);
       }
       break;
@@ -1220,6 +1429,56 @@
       $output  = comment_save(check_query(arg(3)), $edit);
       $output .= comment_admin_overview(0);
       break;
+    case "unpublish":
+      _comment_unpublish(check_query(arg(3)));
+      drupal_goto(comment_referer_load()."#comment-".check_query(arg(3)));
+      break;
+    case "publish":
+      _comment_publish(check_query(arg(3)));
+      drupal_goto(comment_referer_load()."#comment-".check_query(arg(3)));
+      break;
+    case t("Update blacklist"):
+      if (is_array($edit['black-delete'])) {
+        foreach ($edit['black-delete'] as $black => $delete) {
+          if ($delete) {
+            drupal_set_message(t('%ip has been deleted from the blacklist',array('%ip' => $black)));
+          } else {
+            $blacklist[] = $black;
+          }
+        }
+      } else {
+        $blacklist = unserialize(variable_get('comment_blacklist',''));
+      }
+      $edit['add_black'] = trim($edit['add_black']);
+      if ($edit['add_black']) {
+        $blacklist[] = $edit['add_black'];
+        drupal_set_message(t('%ip is added to the blacklist',array('%ip' => $edit['add_black'])));
+      }
+      if (is_array($blacklist)) $blacklist = array_unique($blacklist);
+      variable_set('comment_blacklist', serialize($blacklist));
+      $output = comment_ip_greylist($edit);
+      break;
+    case t("Update whitelist"):
+      if (is_array($edit['white-delete'])) {
+        foreach ($edit['white-delete'] as $white => $delete) {
+          if ($delete) {
+            drupal_set_message(t('%ip has been deleted from the whitelist',array('%ip' => $white)));
+          } else {
+            $whitelist[] = $white;
+          }
+        }
+      } else {
+        $whitelist = unserialize(variable_get('comment_whitelist',''));
+      }
+      $edit['add_white'] = trim($edit['add_white']);
+      if ($edit['add_white']) {
+        $whitelist[] = $edit['add_white'];
+        drupal_set_message(t('%ip is added to the whitelist',array('%ip' => $edit['add_white'])));
+      }
+      if (is_array($whitelist)) $whitelist = array_unique($whitelist);
+      variable_set('comment_whitelist', serialize($whitelist));
+      $output = comment_ip_greylist($edit);
+      break;
     default:
       if (arg(3) == 1) {
         $output = comment_admin_overview(1);
@@ -1228,7 +1487,7 @@
         $output = comment_admin_overview(0);
       }
   }
-  print theme("page", $output);
+  print theme('page', $output);
 }
 
 /*
@@ -1236,41 +1495,56 @@
 ** overridden by themes.
 */
 
-function theme_comment_form($edit, $title) {
+function theme_comment_form($edit, $title, $preview = 0) {
   global $user;
 
   $form .= "<a id=\"comment\"></a>\n";
 
-  // name field:
-  $form .= form_item(t("Your name"), format_name($user));
+  // contact information:
+  if ($user->uid) {
+    $form .= form_item(t('Your name'), format_name($user));
+  }
+  else if (variable_get('comment_anonymous', 1) > 0) {
+    $form .= form_textfield(t('Your name'), 'name', $edit['name'] ? $edit['name'] : ($_COOKIE['anon_name'] ? $_COOKIE['anon_name'] : variable_get('anonymous', 'Anonymous')) , 20, 40);
+    $form .= form_textfield(t('E-mail'), 'mail', $edit['mail'] ? $edit['mail'] : $_COOKIE['anon_mail'], 20, 40);
+    $form .= form_textfield(t('Homepage'), 'homepage', $edit['homepage'] ? $edit['homepage'] : $_COOKIE['anon_url'], 20, 40, t("e.g. http://www.example.com/ - Your E-mail will not be display if you entered your homepage."));
+  }
 
   // subject field:
-  $form .= form_textfield(t("Subject"), "subject", $edit["subject"], 50, 64);
+  if (variable_get('comment_subject_field', 0) && variable_get("comment_complex", 0)) {
+    $form .= form_textfield(t('Subject'), 'subject', $edit['subject'], 50, 64);
+  }
 
   // comment field:
-  $form .= form_textarea(t("Comment"), "comment", $edit["comment"] ? $edit["comment"] : $user->signature, 70, 10, filter_tips_short());
+  $form .= form_textarea(t("Comment"), 'comment', $edit['comment'] ? $edit['comment'] : $user->signature, 70, 10, filter_tips_short(array('filter_html' => variable_get("comment_filter_html", FILTER_HTML_STRIP), 'allowed_html' => variable_get("comment_allowed_html", "<a> <b> <strong> <i> <br> <blockquote>"), 'filter_style' => variable_get("comment_filter_style", FILTER_STYLE_STRIP))));
 
   // preview button:
   $form .= form_hidden("cid", $edit["cid"]);
   $form .= form_hidden("pid", $edit["pid"]);
   $form .= form_hidden("nid", $edit["nid"]);
 
-  if (!$edit["comment"] && variable_get("comment_preview", 1)) {
-    $form .= form_submit(t("Preview comment"));
-  }
-  else {
-    $form .= form_submit(t("Preview comment"));
-    $form .= form_submit(t("Post comment"));
+  if (variable_get('comment_preview', 1) == 0 
+  || variable_get('comment_preview', 1) == 1 && $preview
+  || variable_get('comment_preview', 1) == 2 && ($user->uid || $preview)) {
+    if (!form_has_errors()) {
+      $form .= implode('', module_invoke_all('comment', 'form', $edit));
+      if (!$_SESSION['secret']) $_SESSION['secret'] = rand(100000,999999);
+      $form .= form_hidden('secret', $_SESSION['secret']);
+      $form .= form_submit(t("Post comment"));
+    }
   }
 
-  return theme("box", $title, form($form, "post", url("comment/reply/". $edit["nid"])));
+  $form .= form_submit(t("Preview comment"));
+
+  return theme('box', $title, form($form, "post", url("comment/reply/". $edit["nid"])));
 }
 
 function theme_comment_view($comment, $links = "", $visible = 1) {
 
   /*
-  ** Switch to folded/unfolded view of the comment
+  ** Emit selectors:
   */
+
   $output = "";
   if (node_is_new($comment->nid, $comment->timestamp)) {
     $comment->new = 1;
@@ -1279,13 +1553,18 @@
 
   $output .= "<a id=\"comment-$comment->cid\"></a>\n";
 
+  /*
+  ** Switch to folded/unfolded view of the comment
+  */
+
   if ($visible) {
-    $comment->comment = check_output($comment->comment);
-    $output .= theme("comment", $comment, $links);
+    $comment->comment = check_output($comment->comment, array('filter_html' => variable_get("comment_filter_html", FILTER_HTML_STRIP), 'allowed_html' => variable_get("comment_allowed_html", "<a> <b> <strong> <i> <br> <blockquote>"), 'filter_style' => variable_get("comment_filter_style", FILTER_STYLE_STRIP)));
+    $output .= theme('comment', $comment, $links);
   }
   else {
     $output .= theme("comment_folded", $comment);
   }
+
   return $output;
 }
 
@@ -1322,6 +1601,7 @@
   while ($filter = db_fetch_object($result)) {
     $filters .= " <option value=\"$filter->fid\"". ($threshold == $filter->fid ? " selected=\"selected\"" : "") .">". t($filter->filter) ."</option>";
   }
+
   if ($filters) {
     return "<select name=\"threshold\">$filters</select>\n";
   }
@@ -1344,7 +1624,7 @@
     $output = form_item(NULL, $output, t("Select your preferred way to display the comments and click 'Save settings' to activate your changes."));
   }
 
-  return theme("box", t("Comment viewing options"), $output);
+  return theme('box', t("Comment viewing options"), $output);
 }
 
 function theme_comment_moderation_form($comment) {
@@ -1357,9 +1637,33 @@
     // preview comment:
     $output .= "&nbsp;";
   }
-  else if ((comment_user_can_moderate($node)) && $user->uid != $comment->uid && !(comment_already_moderated($user->uid, $comment->users))) {
+
+  /* simple or partial comment control */
+  if (user_access("administer comments") && variable_get("comment_complex", 0) <= 1) {
+    if ($comment->status == 0) 
+        $output .= l(t("unpublish comment"),
+            "admin/comment/unpublish/".$comment->cid);
+    else if ($comment->status == 1)
+        $output .= l(t("publish comment"),
+            "admin/comment/publish/".$comment->cid);
+    return $output;
+  }
+
+  if ((comment_user_can_moderate($node)) && $user->uid != $comment->uid && !(comment_already_moderated($user->uid, $comment->users))) {
     // comment hasn't been moderated yet:
 
+    /* not in 4.4.1
+    if (!isset($votes) && $user->roles) {
+      $result = db_query("SELECT v.mid, v.vote, MAX(r.value) AS value FROM {moderation_votes} v INNER JOIN {moderation_roles} r ON r.mid = v.mid WHERE r.rid IN (%s) GROUP BY v.mid, v.vote ORDER BY weight", implode(", ", array_keys($user->roles)));
+      $votes = array();
+      while ($vote = db_fetch_object($result)) {
+        if ($vote->value != 0) {
+          $votes[] = $vote;
+        }
+      }
+    }
+    */
+
     if (!isset($votes)) {
       $result = db_query("SELECT v.mid, v.vote, r.value FROM {moderation_votes} v, {moderation_roles} r WHERE v.mid = r.mid AND r.rid = %d ORDER BY weight", $user->rid);
       $votes = array();
@@ -1390,7 +1694,7 @@
 
 function theme_comment($comment, $links = 0) {
   $output  = "<div class=\"comment\">\n";
-  $output .= "<div class=\"subject\">$comment->subject". ($comment->new ? ' '. theme('mark') : '') ."</div>\n";
+  $output .= "<div class=\"subject\">". l($comment->subject, $_GET['q'], NULL, NULL, "comment-$comment->cid") . ($comment->new ? ' '. theme('mark') : '') ."</div>\n";
   $output .= "<div class=\"moderation\">". $comment->moderation ."</div>\n";
   $output .= "<div class=\"credit\">". t("by %a on %b", array("%a" => format_name($comment), "%b" => format_date($comment->timestamp))) ."</div>\n";
   $output .= "<div class=\"body\">$comment->comment</div>\n";
@@ -1401,7 +1705,7 @@
 
 function theme_comment_folded($comment) {
   $output  = "<div class=\"comment-folded\">\n";
-  $output .= " <span class=\"subject\">". l($comment->subject, comment_referer_load() ."/$comment->cid", NULL, NULL, "comment-$comment->cid") . ($comment->new ? ' '. theme('mark') : '') ."</span> ";
+  $output .= " <span class=\"subject\">". l($comment->subject, comment_node_url() ."/$comment->cid", NULL, NULL, "comment-$comment->cid") . ($comment->new ? ' '. theme('mark') : '') ."</span> ";
   $output .= "<span class=\"credit\">". t("by") ." ". format_name($comment) ."</span>\n";
   $output .= "</div>\n";
   return $output;
@@ -1471,6 +1775,9 @@
   $moderation = $_POST["moderation"];
 
   if ($moderation) {
+    /* not in 4.4.1
+    $result = db_query("SELECT mid, MAX(value) AS value FROM {moderation_roles} WHERE rid IN (%s) GROUP BY mid", implode(", ", array_keys($user->roles)));
+    */
     $result = db_query("SELECT mid, value FROM {moderation_roles} WHERE rid = %d", $user->rid);
     while ($mod = db_fetch_object($result)) {
       $votes[$mod->mid] = $mod->value;
@@ -1502,7 +1809,7 @@
             ** Fire a hook
             */
 
-            module_invoke_all("comment", "moderate", $cid, $vote);
+            module_invoke_all('comment', "moderate", $cid, $vote);
           }
         }
       }
@@ -1528,11 +1835,19 @@
   static $cache;
 
   if (!isset($cache[$nid])) {
-    $cache[$nid] = db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE nid = %d AND status = 0", $nid));
+    if (user_access("administer comments")) {
+      $cache[$nid] = db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE nid = %d", $nid));
+    } else {
+      $cache[$nid] = db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE nid = %d AND status = 0", $nid));
+    }
   }
   return $cache[$nid];
 }
 
+function comment_num_unpublish($nid) {
+  return db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE nid = %d AND status = 1", $nid));
+}
+
 function comment_num_replies($pid) {
   static $cache;
 
@@ -1567,7 +1882,11 @@
     ** Use the timestamp to retrieve the number of new comments
     */
 
-    $result = db_result(db_query("SELECT COUNT(c.cid) FROM {node} n INNER JOIN {comments} c ON n.nid = c.nid WHERE n.nid = %d AND timestamp > %d AND c.status = 0", $nid, $timestamp));
+    if (user_access("administer comments")) {
+      $result = db_result(db_query("SELECT COUNT(c.cid) FROM {node} n INNER JOIN {comments} c ON n.nid = c.nid WHERE n.nid = %d AND timestamp > %d", $nid, $timestamp));
+    } else {
+      $result = db_result(db_query("SELECT COUNT(c.cid) FROM {node} n INNER JOIN {comments} c ON n.nid = c.nid WHERE n.nid = %d AND timestamp > %d AND c.status = 0", $nid, $timestamp));
+    }
 
     return $result;
   }
@@ -1579,7 +1898,8 @@
 
 function comment_user_can_moderate($node) {
   global $user;
-  return (user_access("moderate comments"));
+  return (user_access("moderate comments") 
+      && (variable_get("comment_complex",0)>1));
   // TODO: || (($user->uid == $node->uid) && user_access("moderate comments in owned node")));
 }
 
@@ -1614,9 +1934,12 @@
   **
   ** The select statement may optionally provide "nid", which is a secondary
   ** identifier which is currently used byt the comment module.
+  **
+  ** Notice this will not search through comments table 'name' field, but will
+  ** do through users table one.
   */
 
-  $find = do_search(array("keys" => $keys, "type" => "comment", "select" => "select s.lno as lno, c.nid as nid, c.subject as title, c.timestamp as created, u.uid as uid, u.name as name, s.count as count FROM {search_index} s, {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE s.lno = c.cid AND s.type = 'comment' AND c.status = 0 AND s.word like '%'"));
+  $find = do_search(array("keys" => $keys, "type" => 'comment', "select" => "select s.lno as lno, c.nid as nid, c.subject as title, c.timestamp as created, u.uid as uid, u.name as name, s.count as count FROM {search_index} s, {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE s.lno = c.cid AND s.type = 'comment' AND c.status = 0 AND s.word like '%'"));
 
   return array(t("Matching comments ranked in order of relevance"), $find);
 }
@@ -1638,20 +1961,20 @@
   ** last run date for the comments update.
   */
 
-  return array("last_update" => "comment_cron_last", "node_type" => "comment", "select" => "SELECT c.cid as lno, c.subject as text1, c.comment as text2 FROM {comments} c WHERE c.status = 0 AND timestamp > ". variable_get("comment_cron_last", 1));
+  return array("last_update" => "comment_cron_last", "node_type" => 'comment', "select" => "SELECT c.cid as lno, c.subject as text1, c.comment as text2 FROM {comments} c WHERE c.status = 0 AND timestamp > ". variable_get("comment_cron_last", 1));
 }
 
 function comment_nodeapi(&$node, $op, $arg = 0) {
   switch ($op) {
     case "settings":
-      $output[t("comment")] = form_select("", "comment_$node->type", variable_get("comment_$node->type", 2), array(t("Disabled"), t("Read only"), t("Read/Write")));
+      $output[t('comment')] = form_select("", "comment_$node->type", variable_get("comment_$node->type", 2), array(t("Disabled"), t("Read only"), t("Read/Write")));
       return $output;
     case "fields":
-      return array("comment");
+      return array('comment');
     case "form admin":
       if (user_access("administer comments")) {
         $selected = isset($node->comment) ? $node->comment : variable_get("comment_$node->type", 2);
-        $output = form_radios("", "comment", $selected, array(t("Disabled"), t("Read only"), t("Read/write")));
+        $output = form_radios("", 'comment', $selected, array(t("Disabled"), t("Read only"), t("Read/write")));
         return form_group(t("User comments"), $output);
       }
       break;
@@ -1686,6 +2009,37 @@
 
 function _comment_per_page() {
   return drupal_map_assoc(array(10, 30, 50, 70, 90));
+}
+
+function theme_notmember() {
+  return ' <span class="marker">(non-member)</span>';
+}
+
+function _comment_publish($cid) {
+  if (!user_access("administer comments")) return;
+  $comment = db_fetch_object(db_query("SELECT * FROM {comments} WHERE cid = %d", $cid));
+  if ($comment) {
+    db_query("UPDATE {comments} SET status = %d WHERE cid = %d", 0, $cid);
+    watchdog("special", "comment: published '".$comment->subject ."'");
+    drupal_set_message(t("Comment '".$comment->subject."' has been publish."));
+  }
+}
+
+function _comment_unpublish($cid) {
+  if (!user_access("administer comments")) return;
+  $comment = db_fetch_object(db_query("SELECT * FROM {comments} WHERE cid = %d", $cid));
+  if ($comment) {
+    db_query("UPDATE {comments} SET status = %d WHERE cid = %d", 1, $cid);
+    watchdog("special", "comment: unpublished '".$comment->subject ."'");
+    drupal_set_message(t("Comment '".$comment->subject."' has been unpublish."));
+  }
+}
+
+function comment_blogadmin($type) {
+  if ($type == "options") {
+    if (user_access("administer site configuration"))
+      return array(l(t("Comment options"),"admin/system/modules/comment") => t("Configure comments options."));
+  } 
 }
 
 ?>
diff -urN drupal-4.4.2/modules/drupal.module drupal4blog/modules/drupal.module
--- drupal-4.4.2/modules/drupal.module	Wed Jun 30 03:39:24 2004
+++ drupal4blog/modules/drupal.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: drupal.module,v 1.74.2.1 2004/06/29 19:39:24 dries Exp $
+// $Id: drupal.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function drupal_help($section = "admin/help#drupal") {
 
diff -urN drupal-4.4.2/modules/filter.module drupal4blog/modules/filter.module
--- drupal-4.4.2/modules/filter.module	Tue May  4 01:33:23 2004
+++ drupal4blog/modules/filter.module	Wed Jul 14 07:57:58 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: filter.module,v 1.11.2.1 2004/05/03 17:33:23 dries Exp $
+// $Id: filter.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 define('FILTER_HTML_DONOTHING', 0);
 define('FILTER_HTML_STRIP', 1);
@@ -8,7 +8,14 @@
 define('FILTER_STYLE_ALLOW', 0);
 define('FILTER_STYLE_STRIP', 1);
 
-function filter_help($section = "admin/help#filter") {
+function filter_help($section = "admin/help#filter", $vars = array()) {
+  if (!isset($vars['filter_html']))
+    $vars['filter_html'] = variable_get("filter_html", FILTER_HTML_DONOTHING);
+  if (!isset($vars['allowed_html']))
+    $vars['allowed_html'] = variable_get("allowed_html", "");
+  if (!isset($vars['filter_style']))
+    $vars['filter_style'] = variable_get("filter_style", FILTER_STYLE_STRIP);
+
   switch ($section) {
     case 'admin/system/modules#description':
       return t("Framework for handling filtering of content.");
@@ -22,13 +29,13 @@
 <p>Filters are executed from top-to-bottom. You can use the weight column to rearrange them: heavier filters 'sink' to the bottom. Standard HTML filtering is always run first.</p>");
     case 'filter#long-tip':
     case 'filter#short-tip':
-      switch (variable_get("filter_html", FILTER_HTML_DONOTHING)) {
+      switch ($vars['filter_html']) {
         case 0:
           return t("All HTML tags allowed");
           break;
         case 1:
-          if ($allowed_html = variable_get("allowed_html", "<a> <b> <dd> <dl> <dt> <i> <li> <ol> <u> <ul>")) {
-            return t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html);
+          if ($vars['allowed_html']) {
+            return t("Allowed HTML tags") .": ". htmlspecialchars($vars['allowed_html']);
           } else {
             return t("No HTML tags allowed");
           }
@@ -140,33 +147,46 @@
   return $filters;
 }
 
-function check_output($text) {
+function check_output($text, $vars = array()) {
   if (isset($text)) {
     // Filter content on output:
     $filters = filter_list();
 
     // Give filters the chance to escape HTML-like data such as code or formulas
     // (from this point on, the input can be treated as HTML)
-    if (variable_get("filter_html", FILTER_HTML_DONOTHING) != FILTER_HTML_ESCAPE) {
+    if (!isset($vars['filter_html']))
+      $vars['filter_html'] = variable_get("filter_html", FILTER_HTML_DONOTHING);
+    if ($vars['filter_html'] != FILTER_HTML_ESCAPE) {
       foreach ($filters as $module => $filter) {
-        $text = module_invoke($module, "filter", "prepare", $text);
+        $text = module_invoke($module, "filter", "prepare", $text, $vars);
       }
     }
 
     // HTML handling is done before all regular filtering activities
-    $text = filter_default($text);
+    $text = filter_default($text, $vars);
 
     // Regular filtering
     foreach ($filters as $module => $filter) {
-      $text = module_invoke($module, "filter", "process", $text);
+      $text = module_invoke($module, "filter", "process", $text, $vars);
     }
 
     /*
     ** If only inline elements are used and no block level elements, we
     ** replace all newlines with HTML line breaks.
     */
-    if (strip_tags($text, '<a><br><span><bdo><map><object><img><tt><i><b><u><big><small><em><strong><dfn><code><q><samp><kbd><var><cite><abbr><acronym><sub><sup><input><select><textarea><label><button><ins><del><script>') == $text) {
-      $text = nl2br($text);
+    if (variable_get('filter_line_break',0) == 0) {
+      if (strip_tags($text, '<a><br><span><bdo><map><object><img><tt><i><b><u><big><small><em><strong><dfn><code><q><samp><kbd><var><cite><abbr><acronym><sub><sup><input><select><textarea><label><button><ins><del><script>') == $text) 
+        $text = nl2br($text);
+    } else {
+      $paras = preg_split("/\r?\n\r?\n/",$text);
+      foreach ($paras as $id => $p) {
+        if ($p) { 
+          if (strip_tags($p, '<a><br><span><bdo><map><object><img><tt><i><b><u><big><small><em><strong><dfn><code><q><samp><kbd><var><cite><abbr><acronym><sub><sup><input><select><textarea><label><button><ins><del><script>') == $p)
+            $p = nl2br($p);
+          $paras[$id] = "<p>". $p ."</p>";
+        }
+      }
+      $text = implode("\n\n",$paras);
     }
   }
   else {
@@ -176,17 +196,24 @@
   return $text;
 }
 
-function filter_default($text) {
-  if (variable_get("filter_html", FILTER_HTML_DONOTHING) == FILTER_HTML_STRIP) {
+function filter_default($text, $vars = array()) {
+  if (!isset($vars['filter_html']))
+    $vars['filter_html'] = variable_get("filter_html", FILTER_HTML_DONOTHING);
+  if (!isset($vars['allowed_html']))
+    $vars['allowed_html'] = variable_get("allowed_html", "");
+  if (!isset($vars['filter_style']))
+    $vars['filter_style'] = variable_get("filter_style", FILTER_STYLE_STRIP);
+
+  if ($vars['filter_html'] == FILTER_HTML_STRIP) {
     // Allow users to enter HTML, but filter it
-    $text = strip_tags($text, variable_get("allowed_html", ""));
-    if (variable_get("filter_style", FILTER_STYLE_STRIP)) {
+    $text = strip_tags($text, $vars['allowed_html']);
+    if ($filter_style) {
       $text = preg_replace("/\Wstyle\s*=[^>]+?>/i", ">", $text);
     }
     $text = preg_replace("/\Won[a-z]+\s*=[^>]+?>/i", ">", $text);
   }
 
-  if (variable_get("filter_html", FILTER_HTML_DONOTHING) == FILTER_HTML_ESCAPE) {
+  if ($vars['filter_html'] == FILTER_HTML_ESCAPE) {
     // Escape HTML
     $text = htmlspecialchars($text);
   }
@@ -203,6 +230,11 @@
   return $output;
 }
 
+function filter_settings() {
+  $output .= form_select(t('Line Breaking'), 'filter_line_break', variable_get('filter_line_break', 0), array( 0 => 'Drupal Style using nl2br', 1 => 'MT style using paragraph breaking'));
+  return $output;
+}
+
 function filter_filter($op, $text = "") {
   switch ($op) {
     case "name":
@@ -288,10 +320,10 @@
   return $text;
 }
 
-function filter_tips_long() {
+function filter_tips_long($vars = array()) {
   $tiplist = '';
   foreach (module_list() as $name) {
-    if ($tip = module_invoke($name, 'help', 'filter#long-tip')) {
+    if ($tip = module_invoke($name, 'help', 'filter#long-tip', $vars)) {
       $tiplist .= "<li id=\"filter-$name\">$tip</li>\n";
     }
   }
@@ -299,14 +331,14 @@
   print theme("page", $output, t('Compose Tips'));
 }
 
-function filter_tips_short() {
+function filter_tips_short($vars = array()) {
   $tiplist = '';
   foreach (module_list() as $name) {
-    if ($tip = module_invoke($name, 'help', 'filter#short-tip')) {
+    if ($tip = module_invoke($name, 'help', 'filter#short-tip', $vars)) {
       $tiplist .= "<li>$tip</li>\n";
     }
   }
-  $tiplist .= '<li class="more-tips">' . l(t('More information on formatting options'), 'filter/tips') . '</li>';
+  # $tiplist .= '<li class="more-tips">' . l(t('More information on formatting options'), 'filter/tips') . '</li>';
   return "<ul class=\"filter-tips-short\">\n$tiplist\n</ul>\n";
 }
 
diff -urN drupal-4.4.2/modules/forum.module drupal4blog/modules/forum.module
--- drupal-4.4.2/modules/forum.module	Wed Jun 30 04:36:39 2004
+++ drupal4blog/modules/forum.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: forum.module,v 1.171.2.3 2004/06/29 20:36:39 dries Exp $
+// $Id: forum.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function forum_help($section = 'admin/help#forum') {
   $output = '';
diff -urN drupal-4.4.2/modules/help.module drupal4blog/modules/help.module
--- drupal-4.4.2/modules/help.module	Sat Jan 24 02:42:43 2004
+++ drupal4blog/modules/help.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: help.module,v 1.30 2004/01/23 18:42:43 dries Exp $
+// $Id: help.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function help_link($type) {
   if ($type == "system" && user_access("access administration pages")) {
diff -urN drupal-4.4.2/modules/locale.module drupal4blog/modules/locale.module
--- drupal-4.4.2/modules/locale.module	Mon Feb 16 04:09:46 2004
+++ drupal4blog/modules/locale.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: locale.module,v 1.96 2004/02/15 20:09:46 dries Exp $
+// $Id: locale.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function locale_help($section = "admin/help#locale") {
 
diff -urN drupal-4.4.2/modules/node.module drupal4blog/modules/node.module
--- drupal-4.4.2/modules/node.module	Fri Jun 18 02:48:39 2004
+++ drupal4blog/modules/node.module	Mon Jul 12 19:01:18 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: node.module,v 1.342.2.6 2004/06/17 18:48:39 dries Exp $
+// $Id: node.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 define('NODE_NEW_LIMIT', time() - 30 * 24 * 60 * 60);
 
@@ -577,6 +577,7 @@
 
 function node_settings() {
   $output .= form_select(t('Number of posts on main page'), 'default_nodes_main', variable_get('default_nodes_main', 10), drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)), t('The default maximum number of posts to display per page on overview pages such as the main page.'));
+  $output .= form_select(t('Number of posts on rss feed'), 'default_nodes_feed', variable_get('default_nodes_feed', 15), drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 40, 50)), t('The default maximum number of entries to display per rss feed.'));
   $output .= form_select(t('Length of trimmed posts'), 'teaser_length', variable_get('teaser_length', 600), array(0 => t('Unlimited'), 200 => t('200 characters'), 400 => t('400 characters'), 600 => t('600 characters'), 800 => t('800 characters'), 1000 => t('1000 characters'), 1200 => t('1200 characters'), 1400 => t('1400 characters'), 1600 => t('1600 characters'), 1800 => t('1800 characters'), 2000 => t('2000 characters')), t("The maximum number of characters used in the trimmed version of a post.  Drupal will use this setting to determine at which offset long posts should be trimmed.  The trimmed version of a post is typically used as a teaser when displaying the post on the main page, in XML feeds, etc.  To disable teasers, set to 'Unlimited'. Note that this setting will only affect new or updated content and will not affect existing teasers."));
   $output .= form_radios(t('Preview post'), 'node_preview', variable_get('node_preview', 0), array(t('Optional'), t('Required')), t('Must users preview posts before submitting?'));
 
@@ -677,13 +678,11 @@
     $_SESSION['node_overview_filter'] = 0;
   }
 
-  $op = $_POST['op'];
-
-  if ($op == t('Filter') && isset($_POST['edit']['filter'])) {
+  if (isset($_POST['edit']['filter'])) {
     $_SESSION['node_overview_filter'] = $_POST['edit']['filter'];
   }
 
-  if ($op == t('Update') && isset($_POST['edit']['operation']) && isset($_POST['edit']['status'])) {
+  if (isset($_POST['edit']['operation'])) {
     $operation = $operations[$_POST['edit']['operation']][1];
     foreach ($_POST['edit']['status'] as $nid => $value) {
       if ($value) {
@@ -706,7 +705,7 @@
   }
 
   $form  = form_select(NULL, 'filter', $filter, $options);
-  $form .= form_submit(t('Filter'));
+  $form .= form_submit(t('Go'));
 
   $output .= '<h3>'. t('Filter options') .'</h3>';
   $output .= "<div class=\"container-inline\">$form</div>";
@@ -715,18 +714,13 @@
   ** Render operations form:
   */
 
-  $result = pager_query('SELECT n.*, u.name, u.uid FROM {node} n INNER JOIN {users} u ON n.uid = u.uid '. $filters[$filter][1], 50);
-
-  // Make sure the update controls are disabled if we don't have any rows to select from.
-  $disabled = !db_num_rows($result);
-
   $options = array();
   foreach ($operations as $key => $value) {
     $options[] = $value[0];
   }
 
-  $form = form_select(NULL, 'operation', 0, $options, NULL, ($disabled ? 'disabled="disabled"' : ''));
-  $form .= form_submit(t('Update'), 'op', ($disabled ? array('disabled' => 'disabled') : array()));
+  $form = form_select(NULL, 'operation', 0, $options);
+  $form .= form_submit(t('Go'));
 
   $output .= '<h3>'. t('Update options') .'</h3>';
   $output .= "<div class=\"container-inline\">$form</div>";
@@ -735,6 +729,7 @@
   ** Overview table:
   */
 
+  $result = pager_query('SELECT n.*, u.name, u.uid FROM {node} n INNER JOIN {users} u ON n.uid = u.uid '. $filters[$filter][1], 50);
   $header = array(NULL, t('title'), t('type'), t('author'), t('status'), array('data' => t('operations'), 'colspan' => 2));
 
   while ($node = db_fetch_object($result)) {
@@ -982,7 +977,6 @@
 }
 
 function node_block($op = 'list', $delta = 0) {
-
   if ($op == 'list') {
     $blocks[0]['info'] = t('Syndicate');
     return $blocks;
@@ -1007,7 +1001,7 @@
   */
 
   if (!$nodes) {
-    $nodes = db_query_range('SELECT nid FROM {node} WHERE promote = 1 AND status = 1 ORDER BY created DESC', 0, 15);
+    $nodes = db_query_range('SELECT nid FROM {node} WHERE promote = 1 AND status = 1 ORDER BY created DESC', 0, variable_get('default_nodes_feed',15));
   }
 
   while ($node = db_fetch_object($nodes)) {
@@ -1016,13 +1010,21 @@
     */
 
     $item = node_load(array('nid' => $node->nid));
-    $link = url("node/view/$node->nid", NULL, NULL, 1);
-    $items .= format_rss_item($item->title, $link, ($item->teaser ? $item->teaser : $item->body), array('pubDate' => date('r', $item->changed)));
+
+    /*
+    ** allows customized rss on a per node basis
+    */
+    if (node_hook($item, 'feed_item')) {
+      $items .= node_invoke($item, 'feed_item', $item);
+    } else {
+      $link = url("node/view/$node->nid", NULL, NULL, TRUE);
+      $items .= format_rss_item($item->title, $link, ($item->teaser ? $item->teaser : $item->body), array('pubDate' => date('r', $item->changed)));
+    }
   }
 
   $channel_defaults = array(
-    'version'     => '0.92',
-    'title'       => variable_get('site_name', 'drupal') .' - '. variable_get('site_slogan', ''),
+    'version'     => '2.0',
+    'title'       => variable_get('site_name', 'drupal') . (variable_get('site_slogan','') ? ' - '. variable_get('site_slogan', '') : ''),
     'link'        => $base_url,
     'description' => variable_get('site_mission', ''),
     'language'    => (($key = reset(array_keys($languages))) ? $key : 'en')
@@ -1031,8 +1033,8 @@
 
   $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
   $output .= "<!DOCTYPE rss [<!ENTITY % HTMLlat1 PUBLIC \"-//W3C//ENTITIES Latin 1 for XHTML//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent\">]>\n";
-  $output .= "<rss version=\"". $channel["version"] . "\" xml:base=\"". $base_url ."\">\n";
-  $output .= format_rss_channel($channel['title'], $channel['link'], $channel['description'], $items, $channel['language']);
+  $output .= "<rss version=\"". $channel["version"] . "\" xml:base=\"". $base_url ."\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:sy=\"http://purl.org/rss/1.0/modules/syndication/\" xmlns:admin=\"http://webns.net/mvcb/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n";
+  $output .= format_rss_channel($channel['title'], $channel['link'], $channel['description'], $items, $channel['language'], array('dc:creator' => variable_get('site_mail','')));
   $output .= "</rss>\n";
 
   drupal_set_header('Content-Type: text/xml; charset=utf-8');
@@ -1425,7 +1427,7 @@
     if (node_access('update', $node)) {
       $node->nid = node_save($node);
       watchdog('special', "$node->type: updated '$node->title'", l(t('view post'), "node/view/$node->nid"));
-      $msg = t('the %name was updated.', array ('%name' => node_invoke($node, 'node_name')));
+      $msg = t('the %name has been updated.', array ('%name' => node_invoke($node, 'node_name')));
     }
   }
   else {
@@ -1496,6 +1498,11 @@
 
   if (db_num_rows($result)) {
     drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="RSS" href="'. url('node/feed', NULL, NULL, TRUE) .'" />');
+
+    /*
+    ** allows module to insert autodiscovery code
+    */
+    module_invoke_all("default_node");
 
     $output = '';
     while ($node = db_fetch_object($result)) {
diff -urN drupal-4.4.2/modules/notfound.module drupal4blog/modules/notfound.module
--- drupal-4.4.2/modules/notfound.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/notfound.module	Sun Jul 11 22:50:57 2004
@@ -0,0 +1,32 @@
+<?php
+// $Id: notfound.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+function notfound_help($section) {
+  $output = "";
+
+  switch ($section) {
+    case 'admin/system/modules#description':
+      $output = t("Handler for broken link or missing file.");
+      break;
+  }
+  return $output;
+}
+
+function notfound_settings() {
+  $output = "";
+
+  $group .= form_textfield(t("Search path"), "notfound_path", variable_get("notfound_path", ""), 30, 255, t("Subdirectory in '%dir' to look for broken link/missing file.", array('%dir' => variable_get("file_directory_path", "files") . FILE_SEPARATOR)) . $error['notfound_path']);
+  $output .= form_group(t('Directory search'),$group);
+
+  return $output;
+}
+
+function notfound_notfound() {
+  $query = basename(check_query($_GET["q"]));
+  if (variable_get('notfound_path',''))
+    $query .= variable_get('notfound_path','') . FILE_SEPARATOR . $query;
+  if (file_exists(file_create_path($query)))
+    return file_create_url($query);
+}
+
+?>
diff -urN drupal-4.4.2/modules/page.module drupal4blog/modules/page.module
--- drupal-4.4.2/modules/page.module	Mon Apr 12 18:12:59 2004
+++ drupal4blog/modules/page.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: page.module,v 1.110.2.2 2004/04/12 10:12:59 dries Exp $
+// $Id: page.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 /**
  * Provide online user help
diff -urN drupal-4.4.2/modules/path.module drupal4blog/modules/path.module
--- drupal-4.4.2/modules/path.module	Sat Mar 20 21:47:14 2004
+++ drupal4blog/modules/path.module	Mon Jul 19 11:39:47 2004
@@ -1,44 +1,111 @@
 <?php
-/* $Id: path.module,v 1.28.2.1 2004/03/20 13:47:14 dries Exp $ */
+/* $Id: path.module,v 1.1 2004/07/11 14:50:57 jseng Exp $ */
 
-function path_admin() {
-  $op = $_POST["op"];
-  $edit = $_POST["edit"];
+/**
+ * Implementation of hook_help().
+ */
+function path_help($section) {
+  switch ($section) {
+    case 'admin/system/modules#description':
+      return t('Enables users to create custom URLs.');
+    case 'admin/path':
+      return t('Drupal provides users complete control over URLs through aliasing. While the original Drupal URLs are always created and accessible, advanced users have the option to override these normal paths.');
+    case 'admin/path/add':
+      return t('Enter the path you wish to create the alias for, followed by the name of the new alias. Each path can be associated with only one alias.');
+    case 'admin/help#path':
+      return t("
+<h3>Background</h3>
+<p>A very powerful feature of Drupal is the ability to have control over all paths. The path module is the tool that provides this functionality and is part of the basic Drupal installation, although it is not enabled by default. Some examples of re-mapping paths are:</p>
+<pre>
+user/login => login
 
-  if (empty($op)) {
-    $op = arg(2);
-  }
+image/tid/16 => store
 
-  switch ($op) {
-    case "add":
-      $output = path_form();
-      break;
+taxonomy/page/or/7,19,20,21 => store/products/whirlygigs
 
-    case "edit":
-      $output = path_form(path_load(arg(3)));
-      break;
+node/view/3 => contact
+</pre>
+<p>This functionality integrates seamlessly into node forms and also provides the administrator an interface to view all aliases that have been created.</p>
+<p>Aliases have a 1 to 1 relationship with their original Drupal URLs. In other words you cannot have an alias map to more than one path. Likewise, a Drupal URL can't be mapped to more than one alias.</p>
 
-    case "help":
-      $output = path_help();
-      break;
+<h3>Permissions</h3>
+<p>Two permissions are related to URL aliasing: <em>create url aliases</em> and <em>administer url aliases</em>.</p>
+<ol><li><strong>create url aliases</strong> - Allows users to create aliases for nodes. Enabling this permission will display a path field to the user in any node form, allowing them to enter an alias for that node. They will be able to edit/delete the alias after it is created using the same form.</li><li><strong>administer url aliases</strong> - Allows users to access the alias administration interface. They must also have the <em>access administration pages</em> permission set as well. This interface displays all aliases and provides a way to create and modify them. This is also the location to build aliases for things other than nodes. For example, you can create an alias for a taxonomy URL or even re-map the admin path (although the original admin path will still be accessible since aliases do not cancel out original paths).</li></ol>
 
-    case "delete":
-      path_delete(arg(3));
-      $output .= path_overview();
-      break;
+<h3>Mass URL aliasing</h3>
+<p>Drupal also comes with user defined mass URL aliasing capabilities. You might like to see completely different URLs used by Drupal, or even URLs translated to the visitors' native language, in which case this feature is handy. Only an administrator with access to the website source code can set up this kind of aliases. You can define a <code>conf_url_rewrite</code> function in conf.php, following this example:</p>
+<pre>
+function conf_url_rewrite(\$path, \$mode = 'incoming') {
+  if (\$mode == 'incoming') { // URL coming from a client
+    return preg_replace('!^display/(\\d+)\$!', 'node/view/\\1', \$path);
+  }
+  else { // URL going out to a client
+    \$aliased = preg_replace('!^node/view/(\\d+)\$!', 'display/\\1', \$path);
+    if (\$aliased != \$path) { return \$aliased; }
+  }
+}
+</pre>
+<p>This function will shorten every <code>node/view/\$node_id</code> type of URL to <code>display/\$node_id</code>. Individual URL aliases defined on the browser interface of Drupal take precedence, so if you have the 'contact' page alias from the example above, then the <code>display/3</code> alias will not be effective when outgoing links are created. Incoming URLs however always work with the mass URL aliased variant. Only the 'incoming' and 'outgoing' modes are supposed to be supported by your <code>conf_url_rewrite</code> function.</p>
+<p>You cannot only use this feature to shorten the URLs, or to translate them to you own language, but also to add completely new subURLs to an already existing module's URL space, or to compose a bunch of existing stuff together to a common URL space. You can create a <code>news</code> section for example aliasing nodes and taxonomy overview pages falling under a 'news' vocabulary, thus having <code>news/15</code> and <code>news/sections/3</code> instead of <code>node/view/15</code> and <code>taxonomy/view/or/3</code>. You need extensive knowledge of Drupal's inner workings and regular expressions though to make such advanced aliases.</p>");
+  }
+}
 
-    case t("Create new alias"):
-    case t("Update alias"):
-      $output = path_save($edit);
-      break;
+/**
+ * Implementation of hook_link().
+ */
+function path_link($type, $node = NULL) {
+  if ($type == 'system') {
+    menu('admin/path', t('url aliasing'), user_access('administer url aliases') ? 'path_admin' : MENU_DENIED, 4);
+    menu('admin/path/add', t('new alias'), user_access('administer url aliases') ? 'path_admin_edit' : MENU_DENIED);
+    menu('admin/path/edit', t('edit alias'), user_access('administer url aliases') ? 'path_admin_edit' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/path/delete', t('delete alias'), user_access('administer url aliases') ? 'path_admin_delete' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/path/help', t('help'), user_access('administer url aliases') ? 'path_admin_help' : MENU_DENIED, 9);
+  }
+}
 
-    default:
-      $output .= path_overview();
+/**
+ * Menu callback; presents an overview of all URL aliases.
+ */
+function path_admin() {
+  print theme('page', path_overview());
+}
+
+/**
+ * Menu callback; handles pages for creating and editing URL aliases.
+ */
+function path_admin_edit($pid = 0) {
+  if ($_POST['op'] == t('Create new alias') || $_POST['op'] == t('Update alias')) {
+    $output = path_save($_POST['edit']);
+  }
+  else {
+    if ($pid) {
+      $output = path_form(path_load($pid));
+    }
+    else {
+      $output = path_form();
+    }
   }
+  print theme('page', $output);
+}
 
-  print theme("page", $output);
+/**
+ * Menu callback; handles deletion of an URL alias.
+ */
+function path_admin_delete($pid = 0) {
+  path_delete($pid);
+  print theme('page', path_overview());
 }
 
+/**
+ * Menu callback; presents the path-specific information from admin/help.
+ */
+function path_admin_help() {
+  print theme('page', path_help('admin/help#path'));
+}
+
+/**
+ * Set an aliased path for a given Drupal path, preventing duplicates.
+ */
 function path_set_alias($path = NULL, $alias = NULL) {
   if ($path && !$alias) {
     db_query("DELETE FROM {url_alias} WHERE src = '%s'", $path);
@@ -74,212 +141,206 @@
   }
 }
 
-function path_form($edit = "", $error = "") {
-
-  $form .= form_textfield(t("Existing path"), "src", $edit["src"], 50, 64, t("Specify the existing path you wish to alias. For example: node/view/28, forum/1, taxonomy/page/or/1,2."));
-  $form .= form_textfield(t("New path alias"), "dst", $edit["dst"], 50, 64, t("Specify an alternative path by which this data can be accessed.  For example, type 'about' when writing an about page.  Use a relative path and don't add a trailing slash or the URL alias won't work."));
+function path_settings() {
+  $output = form_radios(t('Auto Path'), 'path_auto_node', variable_get('path_auto_node', 0), array(t('No'),t('Yes')), t('If Path alias is not specified when node is create, we automatically create a path.'));
+  $output .= form_textfield(t('Auto Path Format'), 'path_auto_format', variable_get('path_auto_format','archives/%y/%m/%d/%t.html'), 70, 180, t('Specify the format we use to create the path. %y, %m, %d, %t refers to the year, month, day and title of the node. Note: title are sanitize before been used.'));
+  return $output;
+}
 
-  if ($edit["pid"]) {
-    $form .= form_hidden("pid", $edit["pid"]);
-    $form .= form_submit(t("Update alias"));
+/**
+ * Return a form for editing or creating an individual URL alias.
+ */
+function path_form($edit = '') {
+
+  $form .= form_textfield(t('Existing path'), 'src', $edit['src'], 50, 64, t('Specify the existing path you wish to alias. For example: node/view/28, forum/1, taxonomy/page/or/1,2.'));
+  $form .= form_textfield(t('New path alias'), 'dst', $edit['dst'], 50, 64, t('Specify an alternative path by which this data can be accessed.  For example, type "about" when writing an about page.  Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'));
+
+  if ($edit['pid']) {
+    $form .= form_hidden('pid', $edit['pid']);
+    $form .= form_submit(t('Update alias'));
   }
   else {
-    $form .= form_submit(t("Create new alias"));
+    $form .= form_submit(t('Create new alias'));
   }
 
   return form($form);
 }
 
-function path_help($section = "admin/help#path") {
-
-  switch ($section) {
-    case "admin/system/modules#description":
-      $output = t("Enables users to create custom URLs.");
-      break;
-    case "admin/path":
-      $output = t("Drupal provides users complete control over URLs through aliasing. While the original Drupal URLs are always created and accessible, advanced users have the option to override these normal paths.");
-      break;
-    case "admin/path/add":
-      $output = t("Enter the path you wish to create the alias for, followed by the name of the new alias. Each path can be associated with only one alias.");
-      break;
-    case "admin/help#path":
-      $output = t("
-<h3>Background</h3>
-<p>A very powerful feature of Drupal is the ability to have control over all paths. The path module is the tool that provides this functionality and is part of the basic Drupal installation, although it is not enabled by default. Some examples of re-mapping paths are:</p>
-<pre>
-user/login => login
-
-image/tid/16 => store
-
-taxonomy/page/or/7,19,20,21 => store/products/whirlygigs
-
-node/view/3 => contact
-</pre>
-<p>This functionality integrates seamlessly into node forms and also provides the administrator an interface to view all aliases that have been created.</p>
-<p>Aliases have a 1 to 1 relationship with their original Drupal URLs. In other words you cannot have an alias map to more than one path. Likewise, a Drupal URL can't be mapped to more than one alias.</p>
-
-<h3>Permissions</h3>
-<p>Two permissions are related to URL aliasing: <em>create url aliases</em> and <em>administer url aliases</em>.</p>
-<ol><li><strong>create url aliases</strong> - Allows users to create aliases for nodes. Enabling this permission will display a path field to the user in any node form, allowing them to enter an alias for that node. They will be able to edit/delete the alias after it is created using the same form.</li><li><strong>administer url aliases</strong> - Allows users to access the alias administration interface. They must also have the <em>access administration pages</em> permission set as well. This interface displays all aliases and provides a way to create and modify them. This is also the location to build aliases for things other than nodes. For example, you can create an alias for a taxonomy URL or even re-map the admin path (although the original admin path will still be accessible since aliases do not cancel out original paths).</li></ol>
-
-<h3>Mass URL aliasing</h3>
-<p>Drupal also comes with user defined mass URL aliasing capabilities. You might like to see completely different URLs used by Drupal, or even URLs translated to the visitors' native language, in which case this feature is handy. Only an administrator with access to the website source code can set up this kind of aliases. You can define a <code>conf_url_rewrite</code> function in conf.php, following this example:</p>
-<pre>
-function conf_url_rewrite(\$path, \$mode = 'incoming') {
-  if (\$mode == 'incoming') { // URL coming from a client
-    return preg_replace('!^display/(\\d+)\$!', 'node/view/\\1', \$path);
-  }
-  else { // URL going out to a client
-    \$aliased = preg_replace('!^node/view/(\\d+)\$!', 'display/\\1', \$path);
-    if (\$aliased != \$path) { return \$aliased; }
-  }
-}
-</pre>
-<p>This function will shorten every <code>node/view/\$node_id</code> type of URL to <code>display/\$node_id</code>. Individual URL aliases defined on the browser interface of Drupal take precedence, so if you have the 'contact' page alias from the example above, then the <code>display/3</code> alias will not be effective when outgoing links are created. Incoming URLs however always work with the mass URL aliased variant. Only the 'incoming' and 'outgoing' modes are supposed to be supported by your <code>conf_url_rewrite</code> function.</p>
-<p>You cannot only use this feature to shorten the URLs, or to translate them to you own language, but also to add completely new subURLs to an already existing module's URL space, or to compose a bunch of existing stuff together to a common URL space. You can create a <code>news</code> section for example aliasing nodes and taxonomy overview pages falling under a 'news' vocabulary, thus having <code>news/15</code> and <code>news/sections/3</code> instead of <code>node/view/15</code> and <code>taxonomy/view/or/3</code>. You need extensive knowledge of Drupal's inner workings and regular expressions though to make such advanced aliases.</p>");
-      break;
-  }
-
-  return $output;
-}
-
-function path_link($type, $node = NULL) {
-  if ($type == "system" && user_access("administer url aliases")) {
-    menu("admin/path", t("url aliasing"), "path_admin", 4);
-    menu("admin/path/add", t("new alias"), "path_admin");
-    menu("admin/path/help", t("help"), "path_admin", 9);
-  }
-}
-
+/**
+ * Implementation of hook_nodeapi().
+ *
+ * Allows URL aliases for nodes to be specified at node edit time rather
+ * than through the administrative interface.
+ */
 function path_nodeapi(&$node, $op, $arg) {
-  if (user_access("create url aliases") || user_access("administer url aliases")) {
+  if (user_access('create url aliases') || user_access('administer url aliases')) {
 
     switch ($op) {
-      case "validate":
+      case 'validate':
         // is_null provides a mechanism for us to determine if this is the first
         // viewing of the form.  If it is the first time, load the alias, if it isn't
         // (i.e., user has clicked preview) let them work with their current form alias.
         if (is_null($node->path)) {
-          $node->path = drupal_get_path_alias("node/view/$node->nid");
+          $path = "node/view/$node->nid";
+          $alias = drupal_get_path_alias($path);
+          if ($alias != $path) {
+            $node->path = $alias;
+          }
         }
         else {
           $node->path = trim($node->path);
           if ($node->path && !valid_url($node->path)) {
-            $error["path"] = t("The path is invalid.");
+            $error['path'] = t('The path is invalid.');
             return $error;
           }
           else if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE dst = '%s' AND src != '%s'", $node->path, "node/view/$node->nid"))) {
-            $error["path"] = t("The path is already in use.");
+            $error['path'] = t('The path is already in use.');
             return $error;
           }
         }
         break;
 
-      case "form pre":
-        return form_textfield(t("Path alias"), "path", $node->path, 60, 250, t("Optionally specify an alternative URL by which this node can be accessed.  For example, type 'about' when writing an about page.  Use a relative path and don't add a trailing slash or the URL alias won't work.") . theme_error($arg["path"]));
+      case 'form pre':
+        return form_textfield(t('Path alias'), 'path', $node->path, 60, 250, t('Optionally specify an alternative URL by which this node can be accessed.  For example, type "about" when writing an about page.  Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.') . theme_error($arg['path']));
 
-      case "insert":
-        /*
-        ** Don't try to insert if path is NULL.  We may have already set
-        ** the alias ahead of time.
-        */
+      case 'insert':
+        // Don't try to insert if path is NULL.  We may have already set
+        // the alias ahead of time.
         if ($node->path) {
           path_set_alias("node/view/$node->nid", $node->path);
+        } else if (variable_get('path_auto_node',0)) {
+          $year = format_date($node->created, 'custom', 'Y');
+          $month = format_date($node->created, 'custom', 'm');
+          $day = format_date($node->created, 'custom', 'd');
+
+          $title = strtolower($node->title); 
+          $title = preg_replace("/[^\w\+\-\_\s]/", "", $title);
+          $title = trim($title);
+          $title = preg_replace("/\s/",'_',$title);
+          $title = urlencode(strip_tags($title));
+
+          $translate = array('%y' => $year, '%m' => $month, '%d' => $day, '%t' => $title);
+          $path = strtr(variable_get('path_auto_format','archive/%y/%m/%d/%t.html'), $translate);
+          if ($title) {
+            path_set_alias("node/view/$node->nid",$path);
+            drupal_set_message("Auto generate path alias '$path'.");
+          }
         }
         break;
-      case "update":
+      case 'update':
         path_set_alias("node/view/$node->nid", $node->path);
         break;
 
-      case "delete":
-        if ($alias = drupal_get_path_alias("node/view/$node->nid")) {
-          path_set_alias("node/view/$node->nid");
+      case 'delete':
+        $path = "node/view/$node->nid";
+        if (drupal_get_path_alias($path) != $path) {
+          path_set_alias($path);
         }
         break;
     }
   }
 }
 
+/**
+ * Implementation of hook_perm().
+ */
 function path_perm() {
-  return array("create url aliases", "administer url aliases");
+  return array('create url aliases', 'administer url aliases');
 }
 
+/**
+ * Return a listing of all defined URL aliases.
+ */
 function path_overview() {
-  $sql = "SELECT * FROM {url_alias}";
+  $sql = 'SELECT * FROM {url_alias}';
   $header = array(
-    array("data" => t("alias"), "field" => "dst", "sort" => "asc"),
-    array("data" => t("normal"), "field" => "src"),
-    array("data" => t("operations"), "colspan" => 2)
+    array('data' => t('alias'), 'field' => 'dst', 'sort' => 'asc'),
+    array('data' => t('normal'), 'field' => 'src'),
+    array('data' => t('operations'), 'colspan' => 2)
   );
   $sql .= tablesort_sql($header);
   $result = pager_query($sql, 50);
 
   while ($data = db_fetch_object($result)) {
-    $rows[] = array($data->dst, $data->src, l(t("edit"), "admin/path/edit/$data->pid"), l(t("delete"), "admin/path/delete/$data->pid"));
+    if ($from = $_GET['from'])
+      $rows[] = array($data->dst, $data->src, l(t('edit'), "admin/path/edit/$data->pid?from=$from"), l(t('delete'), "admin/path/delete/$data->pid?from=$from"));
+    else
+      $rows[] = array($data->dst, $data->src, l(t('edit'), "admin/path/edit/$data->pid"), l(t('delete'), "admin/path/delete/$data->pid"));
   }
 
-  if ($pager = theme("pager", NULL, 50, 0, tablesort_pager())) {
-    $rows[] = array(array("data" => $pager, "colspan" => "4"));
+  if ($pager = theme('pager', NULL, 50, 0, tablesort_pager())) {
+    $rows[] = array(array('data' => $pager, 'colspan' => '4'));
   }
 
   if (!$rows) {
-    $rows[] = array(array("data" => t("No URL aliases available."), "colspan" => "4"));
+    $rows[] = array(array('data' => t('No URL aliases available.'), 'colspan' => '4'));
   }
 
-  return theme("table", $header, $rows);
+  return theme('table', $header, $rows);
 }
 
+/**
+ * Fetch a specific URL alias from the database.
+ */
 function path_load($pid) {
-  return db_fetch_array(db_query("SELECT * FROM {url_alias} WHERE pid = '%d'", $pid));
+  return db_fetch_array(db_query('SELECT * FROM {url_alias} WHERE pid = %d', $pid));
 }
 
+/**
+ * Remove an URL alias from the database.
+ */
 function path_delete($pid) {
-  db_query("DELETE FROM {url_alias} WHERE pid = '%d'", $pid);
-  drupal_set_message(t("the alias has been deleted."));
+  db_query('DELETE FROM {url_alias} WHERE pid = %d', $pid);
+  drupal_set_message(t('the alias has been deleted.'));
 }
 
+/**
+ * Verify that a new URL alias is valid, and save it to the database.
+ */
 function path_save($edit) {
-  $src = $edit["src"];
-  $dst = $edit["dst"];
-  $pid = $edit["pid"];
+  $src = $edit['src'];
+  $dst = $edit['dst'];
+  $pid = $edit['pid'];
 
   if (!valid_url($src)) {
-    $error = t("the normal path '%src' is invalid.", array("%src" => $src));
+    form_set_error('src', t('the normal path "%src" is invalid.', array('%src' => $src)));
   }
 
-  if (db_result(db_query("SELECT COUNT(src) FROM {url_alias} WHERE pid != '%d' AND src = '%s'", $pid, $src))) {
-    $error = t("the normal path '%src' is already aliased.", array("%src" => $src));
+  if (db_result(db_query("SELECT COUNT(src) FROM {url_alias} WHERE pid != %d AND src = '%s'", $pid, $src))) {
+    form_set_error('src', t('the normal path "%src" is already aliased.', array('%src' => $src)));
   }
 
   if (!valid_url($dst)) {
-    $error = t("the alias '%dst' is invalid.", array("%dst" => $dst));
+    form_set_error('dst', t('the alias "%dst" is invalid.', array('%dst' => $dst)));
   }
 
-  if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE pid != '%d' AND dst = '%s'", $pid, $dst))) {
-    $error = t("the alias '%dst' is already in use.", array("%dst" => $dst));
+  if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE pid != %d AND dst = '%s'", $pid, $dst))) {
+    form_set_error('dst', t('the alias "%dst" is already in use.', array('%dst' => $dst)));
   }
 
-  if ($error) {
-    drupal_set_message($error, 'error');
+  if (form_has_errors()) {
     return path_form($edit, $error);
   }
   else {
-    /*
-    ** Normally, you would use path_set_alias to update the paths table,
-    ** but this is a special case.  We want to modify a specific row and the only
-    ** way to do that is with pid.
-    */
+    // Normally, you would use path_set_alias() to update the paths table,
+    // but this is a special case.  We want to modify a specific row and the only
+    // way to do that is with pid.
 
     if ($pid) {
-      db_query("UPDATE {url_alias} SET src = '%s', dst = '%s' WHERE pid = '%d'", $src, $dst, $pid);
+      db_query("UPDATE {url_alias} SET src = '%s', dst = '%s' WHERE pid = %d", $src, $dst, $pid);
     }
     else {
       path_set_alias($src, $dst);
     }
-  }
 
-  drupal_set_message(t('the alias has been saved.'));
-  return  path_overview();
+    drupal_set_message(t('the alias has been saved.'));
+
+    $from = $_GET["from"];
+    if ($from)
+      drupal_goto("admin/path?from=$from");
+    else
+      drupal_goto("admin/path");
+  }
 }
 
 ?>
diff -urN drupal-4.4.2/modules/ping.module drupal4blog/modules/ping.module
--- drupal-4.4.2/modules/ping.module	Sat Jan 24 02:42:43 2004
+++ drupal4blog/modules/ping.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: ping.module,v 1.14 2004/01/23 18:42:43 dries Exp $
+// $Id: ping.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function ping_help($section = "admin/help#ping") {
   $output = "";
@@ -7,7 +7,7 @@
   switch ($section) {
     case 'admin/help#ping':
       $output .= t("
-      <p>Drupal can pings sites automatically to notify them that your site has changed. It can ping the following sites:</p>
+      <p>Drupal can ping sites automatically to notify them that your site has changed. It can ping the following sites:</p>
       <p>%weblogs, a web site that tracks and displays links to changed weblogs and news-oriented web sites. To get your Drupal site listed, weblogs.com must be informed about your site's updates.  This is the job of the ping module and when installed, the administrator doesn't have to do anything to participate in the %weblogs system. The ping module automatically notifies weblogs.com when your site is updated.  To do so, Drupal implements the %weblogs-XML.</p>
       <p>%weblogs-RSS, a web site that tracks and displays links to recently changed RSS feeds in XML format. To get your Drupal site listed, %weblogs-RSS must be informed about updates to your RSS feed.  This is the job of the ping module and when installed, the administrator doesn't have to do anything to participate in the %weblogs-RSS-changes system. The ping module automatically notifies %weblogs-RSS when your site is updated.</p>
       <p>%blo-gs, a directory of recently updated weblogs and tools for tracking interesting weblogs, in the spirit of services like %weblogs, %blogtracker and %blogrolling. To get your Drupal site listed, %blo-gs must be informed about your site's updates.  This is the job of the ping module and when installed, the administrator doesn't have to do anything to participate in the %blo-gs system. The ping module automatically notifies blo.gs when your site is updated.  To do so, Drupal implements the %blo-gs-XML.</p>
@@ -17,20 +17,44 @@
     case 'admin/system/modules#description':
       $output = t("Alerts other site(s) that your site has been updated.");
       break;
+
+    case 'admin/system/modules/ping':
+      $output = t("
+        <p>There are three different ways to notify different search engines
+        or websphere trackers. If you don't know what this means, then
+        just leave it as-is.</p>
+        <p>Pings are sent out once every few hours, depending on how frequent
+        you set your cron.php (see Section 6 on CRON TASKS in INSTALL).
+        Pings <b>will not</b> be sent unless you configure the name
+        and 'slogan' of your site. See configuration.</p>", 
+            array("configuration" => l(t("configuration"),"admin/system")));
   }
 
   return $output;
 }
 
+function ping_settings() {
+    $output = "";
+    $output .= form_textarea(t("Sites to alert (ping)"), "ping_ping", variable_get("ping_ping", "http://rpc.weblogs.com/RPC2"), 70, 4, t("Send weblogUpdates.ping to these sites"));
+    $output .= form_textarea(t("Sites to alert (advance ping)"), "ping_extping", variable_get("ping_extping", "http://ping.blo.gs/\nhttp://rpc.technorati.com/rpc/ping/"), 70, 4, t("Send weblogUpdates.extendedPing to these sites"));
+    $output .= form_textarea(t("Sites to alert (rss update)"), "ping_rss", variable_get("ping_rss", "http://rssrpc.weblogs.com/RPC2"), 70, 4, t("Send rssUpdate to these sites"));
+    return $output;
+}
+
 function ping_cron() {
   global $base_url;
 
-  if (variable_get("site_name", 0) && variable_get("site_slogan", 0)) {
+  if (variable_get("site_name", 0)) {
     if (db_num_rows(db_query("SELECT nid FROM {node} WHERE status = 1 AND moderate = 0 AND (created > '". variable_get("ping_cron_last", time()) ."' OR changed > '". variable_get("ping_cron_last", time()) ."')"), 1)) {
-      _ping_notify(variable_get("site_name", "") ." - ". variable_get("site_slogan", ""), $base_url);
+      $site = variable_get("site_name","drupal");
+      if (variable_get("site_slogan", "")) 
+          $site .= " - " . variable_get("site_slogan", "");
+      _ping_notify($site, $base_url);
     }
 
     variable_set("ping_cron_last", time());
+  } else {
+    watchdog("error", "ping not sent becase site name has not been configured!");
   }
 }
 
@@ -41,39 +65,74 @@
 function ping_ping($name = "", $url = "") {
   $feed = url("node/feed");
 
-  $client = new xmlrpc_client("/RPC2", "rpc.weblogs.com", 80);
-
-  $message = new xmlrpcmsg("weblogUpdates.ping", array(new xmlrpcval($name), new xmlrpcval($url)));
+  $urls = preg_split("/\s+/",
+    variable_get("ping_ping", "http://rpc.weblogs.com/RPC2"));
+  foreach ($urls as $pingurl) {
+      $purl = parse_url($pingurl);
+      $path = $purl['path'];
+      if (strlen($purl['query'])>0)     $path .= "?".$purl['query'];
+      if (strlen($purl['fragment'])>0)   $path .= "#".$purl['fragment'];
+
+      $client = new xmlrpc_client($path,$purl['host'],$purl['port']);
+
+      $message = new xmlrpcmsg("weblogUpdates.ping", array(new xmlrpcval($name), new xmlrpcval($url)));
+
+      $result = $client->send($message);
+
+      if (!$result || $result->faultCode()) {
+        watchdog("error", "weblogUpdates.ping: failed to notify ".$pingurl);
+      } else {
+        watchdog("regular", "weblogUpdates.ping: successfully notified ".$pingurl);
+      }
 
-  $result = $client->send($message);
-
-  if (!$result || $result->faultCode()) {
-    watchdog("error", "failed to notify 'weblogs.com' (site)");
+      unset($client);
   }
 
-  unset($client);
-
-  $client = new xmlrpc_client("/RPC2", "rssrpc.weblogs.com", 80);
-
-  $message = new xmlrpcmsg("rssUpdate", array(new xmlrpcval($name), new xmlrpcval($feed)));
+  $urls = preg_split("/\s+/",
+    variable_get("ping_extping", "http://ping.blo.gs/\nhttp://rpc.technorati.com/rpc/ping/"));
+  foreach ($urls as $pingurl) {
+      $purl = parse_url($pingurl);
+      $path = $purl['path'];
+      if (strlen($purl['query'])>0)     $path .= "?".$purl['query'];
+      if (strlen($purl['fragment'])>0)   $path .= "#".$purl['fragment'];
+
+      $client = new xmlrpc_client($path,$purl['host'],$purl['port']);
+
+      $message = new xmlrpcmsg("weblogUpdates.extendedPing", array(new xmlrpcval($name), new xmlrpcval($url), new xmlrpcval($url), new xmlrpcval($feed)));
+
+      $result = $client->send($message,0,$purl['scheme']);
+
+      if (!$result || $result->faultCode()) {
+        watchdog("error", "weblogUpdates.extendedPing: failed to notify ".$pingurl);
+      } else {
+        watchdog("regular", "weblogUpdates.extendedPing: successfully notified ".$pingurl);
+      }
 
-  $result = $client->send($message);
-
-  if (!$result || $result->faultCode()) {
-    watchdog("error", "failed to notify 'weblogs.com' (RSS)");
+      unset($client);
   }
 
-  unset($client);
-
-  $client = new xmlrpc_client("/", "ping.blo.gs", 80);
-
-  $message = new xmlrpcmsg("weblogUpdates.extendedPing", array(new xmlrpcval($name), new xmlrpcval($url), new xmlrpcval($url), new xmlrpcval($feed)));
+  $urls = preg_split("/\s+/",
+    variable_get("ping_rss", "http://rssrpc.weblogs.com/RPC2"));
+  foreach ($urls as $pingurl) {
+      $purl = parse_url($pingurl);
+      $path = $purl['path'];
+      if (strlen($purl['query'])>0)     $path .= "?".$purl['query'];
+      if (strlen($purl['fragment'])>0)   $path .= "#".$purl['fragment'];
+
+      $client = new xmlrpc_client($path,$purl['host'],$purl['port']);
+
+      $message = new xmlrpcmsg("rssUpdate", array(new xmlrpcval($name), new xmlrpcval($feed)));
+
+      $result = $client->send($message,0,$purl['scheme']);
+
+      if (!$result || $result->faultCode()) {
+        watchdog("error", "rssUpdate: failed to notify ".$pingurl);
+      } else {
+        watchdog("regular", "rssUpdate: successfully notified ".$pingurl);
+      }
 
-  $result = $client->send($message);
-
-  if (!$result || $result->faultCode()) {
-    watchdog("error", "failed to notify 'blo.gs' ");
+      unset($client);
   }
-
 }
+
 ?>
diff -urN drupal-4.4.2/modules/poll.module drupal4blog/modules/poll.module
--- drupal-4.4.2/modules/poll.module	Wed Apr 14 22:06:26 2004
+++ drupal4blog/modules/poll.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: poll.module,v 1.131.2.2 2004/04/14 14:06:26 unconed Exp $
+// $Id: poll.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function poll_help($section = 'admin/help#poll') {
   $output = '';
diff -urN drupal-4.4.2/modules/profile.module drupal4blog/modules/profile.module
--- drupal-4.4.2/modules/profile.module	Wed Mar 24 13:59:53 2004
+++ drupal4blog/modules/profile.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: profile.module,v 1.41.2.1 2004/03/24 05:59:53 dries Exp $
+// $Id: profile.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function _profile_init() {
   /*
diff -urN drupal-4.4.2/modules/queue.module drupal4blog/modules/queue.module
--- drupal-4.4.2/modules/queue.module	Wed Jun 16 03:48:30 2004
+++ drupal4blog/modules/queue.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: queue.module,v 1.106.2.1 2004/06/15 19:48:30 dries Exp $
+// $Id: queue.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function queue_help($section) {
   $output = "";
diff -urN drupal-4.4.2/modules/search.module drupal4blog/modules/search.module
--- drupal-4.4.2/modules/search.module	Wed Apr 14 05:33:43 2004
+++ drupal4blog/modules/search.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: search.module,v 1.74.2.1 2004/04/13 21:33:43 dries Exp $
+// $Id: search.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function search_help($section = "admin/help#search") {
   $output = "";
@@ -58,6 +58,21 @@
   return $output;
 }
 
+function search_block($op = 'list', $delta = 0) {
+  if ($op == 'list') {
+    $blocks[0]["info"] = t("Search box");
+    return $blocks;
+  }
+  else if (user_access("search content")) {
+    switch ($delta) {
+      case 0:
+        $block["subject"] = t("Search");
+        $block["content"] = '<form action="'.url('search').'" method="post"><input class="form-text" type="text" size="15" value="" name="keys" /><br /><input class="form-submit" type="submit" value="Search" /></form>';
+        return $block;
+    }
+  }
+}
+
 /**
  * perform a regularly run action across all modules that have the
  * <i>module</i>_update_index function in them.
@@ -185,6 +200,8 @@
       case "comment":
         $find[$i++] = array("count" => $count, "title" => $title, "link" => (strstr(request_uri(), "admin") ? url("admin/comment/edit/$lno") : url("node/view/$nid", NULL, "comment-$lno")), "user" => $name, "date" => $created, "keywords" => implode("|", $words));
         break;
+      case "blog":
+        $find[$i++] = array("count" => $count, "title" => $title, "link" => (strstr(request_uri(), "admin") ?  url("admin/node/edit/$lno") : url("node/view/$lno")), "user" => $name, "date" => $created, "keywords" => implode("|", $words));
       }
     }
   }
@@ -224,7 +241,7 @@
       ** false count of the number of hits, and doesn't show up
       ** when clicking on a node from the search interface anyway.
       */
-      $wordlist = $node["text1"] ." ". $node["text2"];
+      $wordlist = $node["text1"] ." ". $node["text2"] . " ". $node["text3"] . " ". $node["text4"];
 
       // Strip heaps of stuff out of it
       $wordlist = preg_replace("'<[\/\!]*?[^<>]*?>'si", "", $wordlist);
diff -urN drupal-4.4.2/modules/statistics.module drupal4blog/modules/statistics.module
--- drupal-4.4.2/modules/statistics.module	Thu Apr 15 22:05:58 2004
+++ drupal4blog/modules/statistics.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: statistics.module,v 1.140.2.3 2004/04/15 14:05:58 unconed Exp $
+// $Id: statistics.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 // Exit hook, runs at the end of every page request
 function statistics_exit() {
diff -urN drupal-4.4.2/modules/story.module drupal4blog/modules/story.module
--- drupal-4.4.2/modules/story.module	Tue Mar 16 03:41:47 2004
+++ drupal4blog/modules/story.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: story.module,v 1.143.2.2 2004/03/15 19:41:47 dries Exp $
+// $Id: story.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 /**
  * Provide online user help
diff -urN drupal-4.4.2/modules/subscriptions.module drupal4blog/modules/subscriptions.module
--- drupal-4.4.2/modules/subscriptions.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/subscriptions.module	Wed Aug 18 13:29:28 2004
@@ -0,0 +1,363 @@
+<?php
+// $Id: subscriptions.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+// text for the various help pages
+function subscriptions_help($section = "admin/help#subscriptions") {
+  switch ($section) {
+    case 'admin/help#subscriptions':
+      // appears on the admin module help page
+      return t('
+        <p>This module enables users to subscribe to be notified of changes to threads or categories.
+        Once enabled, all nodes will have an additional link that allows the user to change their subscriptions.
+        Additionally, all users will be given an account option to auto-subscribe to any thread to which they post.
+        No configuration is required for this module, although roles must be given permission to
+        use it.</p>
+
+        <p>Note that because this module causes the comment insert to pause while all
+        subscribers are notified, it may not be practical for large sites.</p>');
+    case 'admin/system/modules#description':
+      // appears on the admin module selection page
+      return t('Allows users to subscribe to nodes &amp taxonomy terms.');
+  }
+}
+
+function subscriptions_perm() {
+  return array("maintain subscriptions");
+}
+
+function subscriptions_blogadmin($type) {
+  if ($type == "options") {
+    return array(l(t("Auto notify via email"),"user/edit") => t("You can configure drupal to auto notify you when there are comments automatically by setting 'Auto Subscribe' in your account information."));
+  }
+}
+
+// this section will be commented out until the mailqueue module is completed
+/*
+function subscriptions_settings() {
+  $mailevent = "This variable sets the event that will initiate the sending of update notification.  ";
+  $mailevent .= "By default, subscription noticies are sent out as soon as a subscribed ";
+  $mailevent .= "node recieved a comment.  This may be inefficient for some large sites.";
+  $mailevent .= "Alternativly, if you have the mailqueue module installed, you can send the messages ";
+  $mailevent .= "to that module for handling.";
+  if ( module_exist( 'mailqueue' ) ) {
+    $output = form_radios( t( "Mailer Event" ), "subscriptions_event", variable_get( "subscriptions_event", "insert" ), array( "insert" => t( "On Comment Insert/Update" ), "queue" => t( "Send to mail queue" ) ) , t( $mailevent ) );
+  }
+  else {
+    $output = "Subscription notifications will be sent upon insert/update.  This should be ";
+    $output .= "sufficient for most installations, but you can install the mailqueue module to send on a batched schedule.";
+    $output = t( $output );
+  }
+  return $output;
+}
+*/
+
+function subscriptions_user($type, $edit, &$user) {
+  switch ($type) {
+    case "edit_form":
+      return array(t('Subscription settings') => form_item(t("Auto Subscribe"), form_checkbox(t("Automatically subscribe threads to which you post."), "subscriptions_auto", 1, $user->subscriptions_auto, t("Checking this box allows you to be automatically subscribed to any thread you create or post a comment to."))));
+      break;
+  }
+}
+
+// returns all subscriptions for a given user. uses caching
+function subscriptions_get_user($account = NULL) {
+  global $user;
+  static $subscriptions;
+
+  if (is_null($account)) {
+    $account = $user;
+  }
+  if (is_null($subscriptions[$account->uid])) {
+    $queryn = "SELECT td.tid, td.name, n.nid, n.title FROM";
+    $queryn .= "(({subscriptions} s LEFT JOIN {node} n  ON n.nid = s.sid) ";
+    $queryn .= "LEFT JOIN {term_node} tn ON tn.nid = s.sid) ";
+    $queryn .= "LEFT JOIN {term_data} td ON td.tid = tn.tid ";
+    $queryn .= "WHERE n.status = 1 AND s.uid = $account->uid AND s.stype = \"node\" ";
+    $queryt .= "SELECT td.tid, td.name FROM ";
+    $queryt .= "{subscriptions} s INNER JOIN {term_data} td ON td.tid = s.sid ";
+    $queryt .= "WHERE s.uid = $account->uid AND s.stype = \"taxa\"";
+    $resultn = db_query($queryn);
+    $resultt = db_query($queryt);
+
+    $subscriptions[$account->uid]['node'] = $subscriptions[$account->uid]['taxa'] = array();
+    while ($nsub = db_fetch_object($resultn)) {
+      $subscriptions[$account->uid]['node'][$nsub->nid] = $nsub;
+    }
+    while ($tsub = db_fetch_object($resultn)) {
+      $subscriptions[$account->uid]['taxa'][$tsub->tid] = $tsub;
+    }
+  }
+
+  return $subscriptions[$account->uid];
+}
+
+// formats the mail and sends it.
+function subscriptions_sendmail($to, $subject, $body, $headers) {
+  $mail_success = user_mail($to, $subject, $body, $headers);
+  if ($mail_success) {
+    watchdog("regular", t("subscription notification for  '") . $name . "' &lt;" . $to . "&gt;");
+  }
+  else {
+    watchdog("error", t("error mailing subscription notification: '") . $name . "' &lt;" . $to . "&gt;");
+  }
+}
+// get email vars
+function subscriptions_mailvars($sid, $ssid, $uid, $stype, $comment = 0) {
+  global $user, $base_url;
+  $from = variable_get("site_mail", ini_get("sendmail_from"));
+  // if comment insertion, get vars
+  if ($stype == "node") {
+    $result = db_query("SELECT title FROM {node} WHERE nid = $sid");
+    $subj = db_result($result);
+    $result = db_query("SELECT u.uid, u.name, u.mail FROM {users} u INNER JOIN {subscriptions} s ON u.uid = s.uid WHERE s.sid = $sid AND s.stype = 'node'");
+    $strtype = "thread";
+    $nid = $sid;
+    $cid = "comment-$ssid";
+  }
+  // if node insert, test if node has a taxonomy else skip
+  if ($stype == "taxa" && ! is_null($sid)) {
+    $result = db_query("SELECT name FROM {term_data} WHERE tid = $sid");
+    $subj = db_result($result);
+    $result = db_query("SELECT u.mail, u.name, u.uid FROM {users} u INNER JOIN {subscriptions} s ON u.uid = s.uid WHERE s.sid = $sid AND stype = 'taxa'");
+    $strtype = "category";
+    $nid = $ssid;
+    $cid = NULL;
+  }
+
+  if (is_array($comment)) {
+    if ($user->uid) {
+      $name = $user->name . " (member)";
+      $contact = url("user/view/".$comment['uid'],NULL,NULL,TRUE);
+    } else {
+      $name = $comment['name'] . " (non-member)";
+    }
+    $morebody .= "\n".t("IP Address").": ".getenv('REMOTE_ADDR')."\n";
+    $morebody .= t("Name").": ".$name."\n";
+    if ($contact) 
+      $morebody .= t("Member").": ".$contact;
+    if ($comment['mail'])
+      $morebody .= t("Email").": ".$comment['mail']."\n";
+    if ($comment['homepage'])
+      $morebody .= t("Homepage").": ".$comment['homepage']."\n";
+    $morebody .= "\n".t("Comments").":\n\n";
+    $morebody .= strip_tags($comment['comment'])."\n\n";
+  }
+  // loop through subscribers and call mail function
+  while ($subscriptions = db_fetch_object($result)) {
+    //if ($subscriptions->uid != $uid && ! is_null($sid)) {
+    if (!is_null($sid) && $comment) {
+      $url = url("node/view/$nid", NULL, $cid, TRUE);
+      $headers = "From: $from\r\nReply-to: $from\r\nX-Mailer: Drupal\r\nReturn-path: $from\r\nErrors-to: $from\r\nX-Drupal-URL: $url";
+      $subject = "[" . variable_get("site_name", "drupal") . "] " . t("New comment posted to") . " '$subj'";
+      $body = t("Greetings ") . $subscriptions->name . ",\r\n\r\n";
+      $body .= t("A new comment has been posted to '$subj' which you subscribed to. ");
+      if ($comment && $comment['status']) {
+       $body .= t("This is an *unpublish* comment. To publish this comment, navigate to ")  . url("admin/comment/publish/$ssid", NULL, NULL, TRUE) . "\r\n";
+      } 
+      $body .= t("To view the thread, navigate to ").$url."\r\n\r\n";
+      $body .= $morebody;
+
+      $perm = db_result(db_query("SELECT p.perm FROM {role} r, {permission} p, {users} u WHERE r.rid = p.rid AND u.rid = r.rid AND u.uid = %d", $subscriptions->uid), 0);
+
+      // only stype == 'node' has proper ssid = cid
+      if ($stype == "node") {
+        if ($subscriptions->uid == 1 || strstr($perm, 'administer comments')) {
+          $body .= "-- \r\n";
+          if ($comment && $comment['status']) {
+            $body .= t("Publish comment : ") . url("admin/comment/publish/$ssid", NULL, NULL, TRUE) . "\r\n";
+          } else {
+            $body .= t("Unpublish comment : ") . url("admin/comment/unpublish/$ssid", NULL, NULL, TRUE) . "\r\n";
+          }
+          $body .= t("Delete comment : ") . url("admin/comment/delete/$ssid", NULL, NULL, TRUE) . "\r\n";
+        }
+      }
+
+      $body .= "-- \r\n";
+      $body .= t("This is an automatic mail from ") . variable_get("site_name", "drupal") . ".\r\n";
+      $body .= t("To manage your subscriptions, browse to ") . url('subscriptions', NULL, NULL, 1). ".\r\n";
+      if (variable_get("subscriptions_event", "insert") == "queue" && module_exist('mailqueue')) {
+        mailqueue_insert($uid, $subject, null, $body, 1);
+      }
+      elseif (variable_get("subscriptions_event", "insert") == "insert" || ! module_exist('mailqueue')) {
+        if (!$comment || $comment['status'] != 1 || strstr($perm, 'administer comments') || $subscriptions->uid == 1)
+          subscriptions_sendmail($subscriptions->mail, $subject, $body, $headers);
+      }
+    }
+  }
+}
+
+function subscriptions_autosubscribe ($uid, $nid) {
+  global $user;
+  // if user has auto subscribe enabled
+  if ($user->subscriptions_auto) {
+    // check to see if already subscribed
+    $result = db_query("SELECT sid FROM {subscriptions} WHERE sid = $nid AND stype = \"node\" AND uid = $uid");
+    if (!db_num_rows($result)) {
+      // if not, subscribe
+      subscriptions_add($nid, $user->uid, 'node');
+    }
+  }
+}
+// hook to comments update event
+function subscriptions_comment ($op, $comment) {
+  global $user;
+  if ($op == "insert" || $op == "update") {
+    $nid = $comment["nid"];
+    $cid = $comment["cid"];
+    subscriptions_mailvars ($nid, $cid, $user->uid, "node", $comment);
+    if ($comment['status'] == 0)
+      subscriptions_autosubscribe ($user->uid, $nid);
+  } 
+}
+// hook to taxonomy update
+function subscriptions_nodeapi (&$node, $op, $arg = 0) {
+  global $user;
+  if (!$user->uid) return;
+  $tid = $node->taxonomy[0];
+  $nid = $node->nid;
+  switch ($op) {
+    case "insert":
+    case "update":
+      if ($node->status) {
+        subscriptions_mailvars ($tid, $nid, $user->uid, "taxa");
+        subscriptions_mailvars ($nid, 0, $user->uid, "node");
+        if ($node->type == "blog") {
+          subscriptions_mailvars ($node->uid, $nid, $user->uid, "blog");
+        }
+        subscriptions_autosubscribe ($user->uid, $nid);
+      }
+      if (isset($node->subscriptions_subscribe)) {
+        if ($node->subscriptions_subscribe) {
+          subscriptions_add($nid, $user->uid, 'node');
+        }
+        user_save($user, array ('subscriptions_subscribe' => $node->subscriptions_subscribe));
+      }
+      break;
+    case 'form post':
+      if (!$user->subscriptions_auto) {
+        $allsubs = subscriptions_get_user();
+        $val = isset($node->subscriptions_subscribe) ? $node->subscriptions_subscribe : $allsubs['node'][$node->nid] ? 1 : $user->subscriptions_subscribe;
+        return form_item(t("Subscribe"), form_checkbox(t("Receive notification of replies to this %name.", array ('%name' => node_invoke($node, 'node_name'))), "subscriptions_subscribe", 1, $val));
+      }
+      break;
+  }
+}
+// puts "change subscription" link on all nodes
+// and "my subscriptions" link in the account settings block
+function subscriptions_link($type, $node = 0, $main) {
+  if (user_access("maintain subscriptions")) {
+    if ($type == "system") {
+      menu("subscriptions", t("my subscriptions"), "subscriptions_page", 0);
+    }
+    if ($type == "node" && $node->comment == 2) {
+      $subscriptions = subscriptions_get_user();
+      $name = node_invoke($node, 'node_name');
+      if (isset($subscriptions['node'][$node->nid])) {
+        $links[] = l(t("unsubscribe"), "subscriptions/del/node/$node->nid", array("title" => t("Stop receiving an email whenever a new comment is posted to this %n.", array ('%n' => $name))));
+      }
+      else {
+        $links[] = l(t("subscribe"), "subscriptions/add/node/$node->nid", array("title" => t("Receive an email whenever a comment is posted to this %n.", array ('%n' => $name))));
+      }
+    }
+  }
+  return $links ? $links : array();
+}
+
+function subscriptions_get_taxa($uid) {
+  $result = db_query("SELECT sid FROM {subscriptions} WHERE uid = $uid and stype=\"taxa\"");
+  while ($taxasub = db_fetch_object($result)) {
+    $tsubscriptions[] = $taxasub->sid;
+  } 
+  return $tsubscriptions ? $tsubscriptions : array();
+} 
+
+function subscriptions_gen_taxa_links($tid, $taxa) {
+  if (in_array($tid, $taxa)) {
+    $link = l(t("unsubscribe"), "subscriptions/del/taxa/$tid", array("title" => t("Unsubscribe from this category.")));
+  }
+  else {
+    $link = l(t("subscribe"), "subscriptions/add/taxa/$tid", array("title" => t("Subscribe to this category.")));
+  } 
+  return $link;
+}
+
+function subscriptions_add($sid, $uid, $stype) {
+  db_query("INSERT INTO {subscriptions} ( sid , uid, stype )  VALUES ($sid , $uid, \"$stype\")");
+}
+
+// pages where users add and delete their subscriptions to nodes
+function subscriptions_page () {
+  global $user;
+  $subscribed = false;
+  $uid = $user->uid;
+  if (! arg(2)) {
+    $sid = arg(1);
+    $nid = $sid;
+  }
+  else {
+    $op = arg(1);
+    $stype = arg(2);
+    $sid = arg(3);
+    $nid = arg(4);
+    if ($stype == "node") {
+      $nid = $sid;
+    }
+  }
+
+  if (user_access("maintain subscriptions")) {
+    switch ($op) {
+      // inserts a new subscription into the subscriptions_nodes table
+      case "add":
+        subscriptions_add($sid, $uid, $stype);
+        $message = t("<p>Your subscription was activated.<p/>");
+        if (!(arg(2) == "taxa")) {
+          $message .= l(t("Return to the thread"), "node/view/$nid") . " | ";
+        }
+        $message .= l(t("Return to the subscriptions"), "subscriptions") . "<br />";
+        print theme("page", $message, t("Subscription Activated"));
+        break;
+      // removes a subscription from the subscriptions_nodes table
+      case "del":
+        db_query("DELETE FROM {subscriptions} WHERE sid = $sid AND uid = $uid AND stype = '$stype'");
+        $message = t("<p>Your subscription was deactivated.<p/>");
+        if (!(arg(2) == "taxa")) {
+          $message .= l(t("Return to the thread"), "node/view/$nid") . " | ";
+        }
+        $message .= l(t("Return to the subscriptions"), "subscriptions") . "<br />";
+        print theme("page", $message, t("Subscription Deactivated"));
+        break;
+      // determines the user's subscription status and displays the right option to change it
+      default:
+        // get all subscriptions and write to table rows
+        $subscriptions = subscriptions_get_user();
+        // build node rows
+        foreach ($subscriptions['node'] as $nsub) {
+          $subrows .= t("<tr><td>Thread: ") . l($nsub->title, "node/view/$nsub->nid") . "</td><td>[" . l(t("unsubscribe"), "subscriptions/del/node/" . $nsub->nid, array("title" => t("Unsubscribe from this thread."))) . "]</td></tr>\n";
+        }
+        // traverse the taxonomy tree
+        $taxa = subscriptions_get_taxa($uid);
+        foreach (taxonomy_get_vocabularies() as $vocab) { 
+          $tree = taxonomy_get_tree($vocab->vid);        
+          $subrows .= "<tr><td colspan=\"2\"><b>" . $vocab->name . "</b></td></tr>\n";
+          foreach ($tree as $term) {
+            $subrows .= t("<tr><td>Category: ") . l($term->name, "taxonomy/page/or/$term->tid") . "</td><td>[" . subscriptions_gen_taxa_links($term->tid, $taxa) . "]</td></tr>\n";
+          } 
+        }
+
+        if (strlen($subrows) == 0) {
+          $message .= t("<p>You are not currently subscribed to any active threads or categories.</p>");
+        }
+        else {
+          $message .= "<p align=\"center\"><table>" . $subrows . "</table></p>";
+        }
+
+        print theme("page", $message, t("Your Subscriptions"));
+        break;
+    }
+  }
+  else {
+    print theme("page", message_access(), t("Access Denied"));
+  }
+}
+
+?>
diff -urN drupal-4.4.2/modules/system.module drupal4blog/modules/system.module
--- drupal-4.4.2/modules/system.module	Sat Mar 20 21:47:14 2004
+++ drupal4blog/modules/system.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: system.module,v 1.131.2.1 2004/03/20 13:47:14 dries Exp $
+// $Id: system.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function system_help($section = "admin/help#system") {
   global $base_url;
@@ -95,9 +95,10 @@
     $data[t('Locale settings')] = form_select(t("Time zone"), "timezone", $edit["timezone"], $zones, t("Select what time you currently have and your time zone settings will be set appropriate."));
     return $data;
   }
-  else {
-    return $edit;
-  }
+// why did we return something if you dont know what it does? -js
+//  else {
+//    return $edit;
+//  }
 }
 
 function system_view_general() {
diff -urN drupal-4.4.2/modules/tag.module drupal4blog/modules/tag.module
--- drupal-4.4.2/modules/tag.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/tag.module	Sun Jul 11 22:50:57 2004
@@ -0,0 +1,539 @@
+<?php
+// $Id: tag.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+// invoke all tags from all modules
+module_invoke_all('taginit');
+tag_init_glob();
+
+function theme_tag_help($title,$info) {
+  return <<<_TAG_HELP_
+<li><strong>$title</strong><br/>
+$info</li>
+<p></p>
+_TAG_HELP_;
+}
+
+function tag_help($section) {
+  switch ($section) {
+    case 'tag/help':
+      $output .= theme('tag_help','DPPageTitle',t('The title of the current page.'));
+      $output .= theme('tag_help','DPSimpleCSS',t("The URL to the simple theme's CSS. See CSS in %info.", array('%info' => l(t('simple theme settings'), 'admin/system/themes/simple'))));
+      $output .= theme('tag_help','DPHeaders',t('Standard Drupal headers.'));
+      $output .= theme('tag_help','DPOnLoads',t('Insert Onload functions specify by modules.'));
+      $output .= theme('tag_help','DPSiteURL',t('The base URL of the site.'));
+      $output .= theme('tag_help','DPSiteName',t('The name of this web site. See %info.', array('%info' => l(t('system configuration'), 'admin/system'))));
+      break;
+    case 'admin/system/modules#description':
+      $output .= t("Allow simple template tags.");
+      break;
+  }
+
+  return $output;
+}
+
+function tag_link($type, $node = 0, $main) {
+  if ($type  == 'system') {
+    if (user_access("administer site configuration")) {
+      menu('tag/help', t('Tag'), 'tag_info', 0, MENU_HIDE);
+    }
+  }
+}
+
+function tag_info() {
+  print theme('page',$output, t('help'));
+}
+
+function tag_init_glob() {
+  global $taglist, $tag_search, $tag_php;
+
+  if (!$taglist) return;
+
+  // we need to sort the taglists so they dont overlap each another...
+
+  foreach ($taglist as $tag => $taginfo) {
+    // if it is a function, lets make a condition out of it!
+    if ($taglist[$tag]['func']) {
+      $add['If'.$tag] = array('cond' => $taglist[$tag]['func']);
+      $add['IfNot'.$tag] = array('notcond' => $taglist[$tag]['func']);
+      $add['ElseIf'.$tag] = array('elseif' => $taglist[$tag]['func']);
+      $add['ElseIfNot'.$tag] = array('elseifnot' => $taglist[$tag]['func']);
+    }
+    else if ($taglist[$tag]['each'] && $taglist[$tag]['vars']) {
+      $add['If'.$tag] = array('cond' => $taglist[$tag]['each']);
+      $add['IfNot'.$tag] = array('notcond' => $taglist[$tag]['each']);
+      $add['ElseIf'.$tag] = array('elseif' => $taglist[$tag]['each']);
+      $add['ElseIfNot'.$tag] = array('elseifnot' => $taglist[$tag]['each']);
+      $add['IfFirst'.$tag] = array('iffirst' => $taglist[$tag]['vars']);
+      $add['IfNotFirst'.$tag] = array('ifnotfirst' => $taglist[$tag]['vars']);
+    }
+  }
+  $taglist = array_merge($add,$taglist);
+
+  foreach ($taglist as $tag => $taginfo) {
+    $php = tag_tag2php($tag);
+    $nopv = preg_replace("/[PARAMS|VARIABLES]/",'',$php);
+
+    // either in the form of <$DPTag$> or <DPTag>
+    $tag_search[] = "|\<\\\$DP".$tag."\\\$\>|";
+    $tag_php[] = $nopv;
+    $tag_search[] = "|\<DP".$tag."\>|";
+    $tag_php[] = $nopv;
+
+    if ($taglist[$tag]['cond'] || $taglist[$tag]['notcond'] ||
+        $taglist[$tag]['elseif'] || $taglist[$tag]['elseifnot']) {
+      // only conditions can have evaluation criteria
+      $pv = preg_replace("/PARAMS/",", \\\\1",$php);
+      $pv = preg_replace("/VARIABLES/"," \\\\2",$pv);
+      $tag_search[] = "|\<\\\$DP".$tag."\\(([^\\)]*)\\)\s*([^\\\$]*)\\\$\>|";
+      $tag_php[] = $pv;
+      $tag_search[] = "|\<DP".$tag."\\(([^\\)]*)\\)\s*([^\\\$]*)\>|";
+      $tag_php[] = $pv;
+
+      $pv = preg_replace("/PARAMS/", '', $php);
+      $pv = preg_replace("/VARIABLES/"," \\\\1",$pv);
+      $tag_search[] = "|\<\\\$DP".$tag."\s*([^\\\$]*)\\\$\>|";
+      $tag_php[] = $pv;
+      $tag_search[] = "|\<DP".$tag."\s*([^\\\$]*)\>|";
+      $tag_php[] = $pv;
+
+    } else if ($taglist[$tag]['func']) {
+      $pv = preg_replace("/PARAMS/",", \\\\1",$php);
+      $pv = preg_replace("/VARIABLES/",'',$pv);
+      $tag_search[] = "|\<\\\$DP".$tag."\\(([^\\)]*)\\)\s*\\\$\>|";
+      $tag_php[] = $pv;
+      $tag_search[] = "|\<DP".$tag."\\(([^\\)]*)\\)\s*\>|";
+      $tag_php[] = $pv;
+    }
+  }
+}
+
+function tag_taginit() {
+  global $taglist;
+
+  // site info
+  $taglist['SiteURL'] = array('func' => 'tag_site_url');
+  $taglist['SiteName'] = array('func' => 'tag_site_name');
+  $taglist['SiteSlogan'] = array('func' => 'tag_site_slogan');
+  $taglist['SiteMission'] = array('func' => 'tag_site_mission');
+  $taglist['SiteLayout'] = array('func' => 'tag_site_layout');
+  $taglist['SiteFooter'] = array('func' => 'tag_site_footer');
+
+  // generic
+  $taglist['Content'] = array('func' => 'tag_generic_content');
+  $taglist['Variable'] = array('func' => 'tag_generic_variable');
+  $taglist['UserAccess'] = array('func' => 'tag_generic_user_access');
+
+  // drupal core
+  $taglist['Headers'] = array('func' => 'tag_drupal_headers');
+  $taglist['Footers'] = array('func' => 'tag_drupal_footers');
+  $taglist['OnLoads'] = array('func' => 'tag_drupal_onload');
+
+  // page info
+  $taglist['Title'] = array('func' => 'tag_page_title');
+  $taglist['Breadcrumbs'] = array('func' => 'tag_page_breadcrumb');
+  $taglist['ForEachBreadcrumb'] = array('foreach' => 'tag_page_breadcrumb',
+                                        'vars' => 'breadcrumb');
+  $taglist['Breadcrumb'] = array('each' => 'tag_page_breadcrumb_each',
+                                 'vars' => 'breadcrumb');
+  $taglist['Help'] = array('func' => 'tag_page_help');
+  $taglist['Messages'] = array('func' => 'tag_page_message');
+  $taglist['ForEachMessage'] = array('foreach' => 'tag_page_message',
+                                     'vars'    => 'message');
+  $taglist['Message'] = array('each' => 'tag_page_message_each',
+                              'vars' => 'message');
+  $taglist['MessageType'] = array('func' => 'tag_page_message_type');
+
+  // links
+  $taglist['Links'] = array('func' => 'tag_links');
+  $taglist['ForEachLink'] = array('foreach' => 'tag_links',
+                                  'vars'    => 'link');
+  $taglist['Link'] = array('each' => 'tag_links_each',
+                           'vars' => 'link');
+
+  // block
+  $taglist['Sidebar'] = array('func' => 'block_tag_sidebar');
+  $taglist['BlockModule'] = array('func' => 'block_tag_module');
+  $taglist['BlockTitle'] = array('func' => 'block_tag_title');
+  $taglist['BlockContent'] = array('func' => 'block_tag_content');
+  $taglist['Block'] = array('func' => 'block_tag_block');
+
+  // node
+  $taglist['NodeStatic'] = array('func' => 'node_tag_static');
+  $taglist['NodeDate'] = array('func' => 'node_tag_date');
+  $taglist['NodeURL'] = array('func' => 'node_tag_url');
+  $taglist['NodeTitle'] = array('func' => 'node_tag_title');
+  $taglist['NodeName'] = array('func' => 'node_tag_name');
+  $taglist['NodeID'] = array('func' => 'node_tag_id');
+  $taglist['NodeReadMore'] = array('func' => 'node_tag_read_more');
+  $taglist['NodeType'] = array('func' => 'node_tag_node_type');
+  $taglist['Node'] = array('func' => 'node_tag_node');
+
+  // comment
+  $taglist['CommentNew'] = array('func' => 'comment_tag_comment_new');
+  $taglist['CommentID'] = array('func' => 'comment_tag_comment_id');
+  $taglist['CommentShowTitle'] = array('func' => 'comment_tag_show_title');
+  $taglist['CommentTitleLink'] = array('func' => 'comment_tag_comment_title_link');
+  $taglist['CommentTitle'] = array('func' => 'comment_tag_comment_title');
+  $taglist['CommentName'] = array('func' => 'comment_tag_comment_name');
+  $taglist['CommentDate'] = array('func' => 'comment_tag_comment_date');
+  $taglist['CommentVisible'] = array('func' => 'comment_tag_comment_visible');
+  $taglist['CommentDepth'] = array('func' => 'comment_tag_comment_depth');
+  $taglist['CommentStatus'] = array('func' => 'comment_tag_comment_status');
+  $taglist['Comment'] = array('func' => 'comment_tag_comment');
+
+  // taxonomy
+  $taglist['Categories'] = array('func' => 'taxonomy_tag_categories');
+  $taglist['ForEachCategory'] = array('foreach' => 'taxonomy_tag_categories',
+                                      'vars' => 'category');
+  $taglist['Category'] = array('each' => 'taxonomy_tag_categories_each',
+                               'vars' => 'category');
+
+  // simple css
+  $taglist['SimpleCSS'] = array('func' => 'simple_tag_css');
+
+  // basic php tags
+  $taglist['Else'] = array('php' => "<?php else : ?>");
+  $taglist['EndIf'] = array('php' => "<?php endif; ?>");
+  $taglist['EndForEach'] = array('php' => "<?php endforeach; ?>");
+}
+
+function tag_tag2php($tag) {
+  global $taglist;
+
+  if (!isset($taglist[$tag])) {
+    watchdog('error', 'Unknown tag DP'.$tag.'!');
+    return '';
+  }
+
+  // if it is php
+  if ($taglist[$tag]['php']) {
+    return $taglist[$tag]['php'];
+  }
+
+  // if it is a function ...
+  if ($taglist[$tag]['func']) {
+    return "<?php print ".$taglist[$tag]['func']."(\$varsPARAMS); ?>";
+  }
+
+  // if it is a condition function ...
+  if ($taglist[$tag]['cond']) {
+    return "<?php if (".$taglist[$tag]['cond']."(\$varsPARAMS)VARIABLES) : ?>";
+  }
+
+  if ($taglist[$tag]['notcond']) {
+    return "<?php if (!".$taglist[$tag]['notcond']."(\$varsPARAMS)VARIABLES) : ?>";
+  }
+
+  if ($taglist[$tag]['elseif']) {
+    return "<?php elseif (".$taglist[$tag]['elseif']."(\$varsPARAMS)VARIABLES) : ?>";
+  }
+
+  if ($taglist[$tag]['elseifnot']) {
+    return "<?php elseif (!".$taglist[$tag]['elseifnot']."(\$varsPARAMS)VARIABLES) : ?>";
+  }
+
+  // if it is a foreach loop ...
+  if ($taglist[$tag]['foreach'] && $taglist[$tag]['vars']) {
+    $output .= "<?php \$".$taglist[$tag]['vars']."_count = 0; ?>";
+    $output .= "<?php foreach (".$taglist[$tag]['foreach']."(\$varsPARAMS) as \$".$taglist[$tag]['vars'].") : ?>";
+    $output .= "<?php \$vars['".$taglist[$tag]['vars']."'] = \$".$taglist[$tag]['vars']."; ?>";
+    return $output;
+  }
+
+  if ($taglist[$tag]['each'] && $taglist[$tag]['vars']) {
+    $output .= "<?php \$".$taglist[$tag]['vars']."_count++; ?>";
+    $output .= "<?php print ".$taglist[$tag]['each']."(\$varsPARAMS); ?>";
+    return $output;
+  }
+
+  if ($taglist[$tag]['iffirst']) {
+    return "<?php if (\$".$taglist[$tag]['iffirst']."_count == 0) : ?>";
+  }
+
+  if ($taglist[$tag]['ifnotfirst']) {
+    return "<?php if (\$".$taglist[$tag]['ifnotfirst']."_count == 0) : ?>";
+  }
+
+  watchdog('error', 'Tag DP'.$tag.' cannot be converted to php!');
+  return '';
+}
+
+function tag_process($raw) {
+  global $taglist, $tag_search, $tag_php;
+  $php = preg_replace($tag_search, $tag_php, $raw);
+
+  preg_match_all("|<\\\${0,1}DP[^>]+\\\${0,1}>|",$php,$errors);
+  $errors = array_unique($errors[0]);
+  foreach ($errors as $error) 
+    form_set_error('simple_theme_edit',"Cannot process $error");
+
+  return $php;
+}
+
+/*
+** customized functions
+*/
+
+// site functions
+function tag_site_url($vars = array(), $v1 = NULL) {
+  return url($v1, NULL, NULL, TRUE);
+}
+
+function tag_site_name($vars = array()) {
+  return variable_get('site_name', 'Drupal');
+}
+
+function tag_site_slogan($vars = array()) {
+  return variable_get('site_slogan', '');
+}
+
+function tag_site_mission($vars = array()) {
+  // return mission only on frontpage
+  if ($_GET["q"] == variable_get("site_frontpage", "node"))
+    return variable_get('site_mission', '');
+}
+
+function tag_site_layout($vars = array()) {
+  static $layout;
+
+  if ($layout) return $layout;
+
+  $results = db_query('SELECT * FROM {blocks} WHERE (status = 1 OR custom =1)');
+
+  while ($block = db_fetch_object($results)) 
+    $region[$block->region]++;
+
+  if ($region[0] && $region[1]) {
+    $layout = "both";
+  } else if ($region[0]) {
+    $layout = "left";
+  } else {
+    $layout = "right";
+  }
+  return $layout;
+}
+
+function tag_site_footer($vars = array()) {
+  return variable_get('site_footer', '');
+}
+
+// drupal core
+function tag_drupal_headers($vars = array()) {
+  return drupal_get_html_head();
+}
+
+function tag_drupal_footers($vars = array()) {
+  return theme('closure');
+}
+
+function tag_drupal_onload($vars = array()) {
+  return theme_onload_attribute();
+}
+
+// generic
+function tag_generic_content($vars = array()) {
+  return $vars['content'];
+}
+
+function tag_generic_variable($vars = array(), $v1 = NULL) {
+  if ($v1) return variable_get($v, '');
+  return NULL;
+}
+
+function tag_generic_user_access($vars = array(), $v1 = NULL) {
+  if ($v1) return user_access($v1);
+  return NULL;
+}
+
+// page info
+function tag_page_title($vars = array()) {
+  $title = drupal_get_title();
+  if ($title) return $title;
+  return variable_get('site_name', 'Drupal');
+}
+
+function tag_page_breadcrumb($vars = array()) {
+  return drupal_get_breadcrumb();
+}
+
+function tag_page_breadcrumb_each($vars = array()) {
+  return $vars['breadcrumb'];
+}
+
+function tag_page_help($vars = array()) {
+  return menu_get_active_help();
+}
+
+function tag_page_help_each($vars = array()) {
+  return $vars['help'];
+}
+
+function tag_page_message($vars = array()) {
+  // this seem to be a better way to get message without clearing
+  // what is in $_SESSION['message'] but you must manually reset 
+  // the message afterwards...
+  return drupal_set_message();
+}
+
+function tag_page_message_each($vars = array()) {
+  return $vars['message'][0];
+}
+
+function tag_page_message_type($vars = array()) {
+  return $vars['message'][1];
+}
+
+function tag_links($vars = array()) {
+  return $vars['links'];
+}
+
+function tag_links_each($vars = array()) {
+  return $vars['link'];
+}
+
+// block functions - move to block.module some day...
+function block_tag_block($vars = array(), $v1 = NULL) {
+  if (!$v1) return $vars['block'];
+  return $vars['block']->$v1;
+}
+
+function block_tag_module($vars = array()) {
+  return $vars['block']->module;
+}
+
+function block_tag_title($vars = array()) {
+  return $vars['block']->subject;
+}
+
+function block_tag_content($vars = array()) {
+  return $vars['content'];
+}
+
+function block_tag_sidebar($vars = array(), $v1 = 'all') {
+  static $sidebar;
+
+  if ($sidebar[$v1]) return $sidebar[$v1];
+  $sidebar[$v1] = theme("blocks", $v1);
+
+  return $sidebar[$v1];
+}
+
+// node functions - move to node.module some day...
+function node_tag_node($vars = array(), $v1 = NULL) {
+  if (!$v1) return $vars['node'];
+  return $vars['node']->$v1;
+}
+
+function node_tag_static($vars = array()) {
+  return $vars['node']->static;
+}
+
+function node_tag_date($vars = array(), $v1 = NULL) {
+  if (!$v1) return format_date($vars['node']->created);
+  switch ($v1) {
+    case 'small':
+    case 'large':
+    case 'medium':
+      return format_date($vars['node']->created, $v1);
+    default:
+      return format_date($vars['node']->created, 'custom', $v1);
+  }
+}
+
+function node_tag_url($vars = array()) {
+  return url("node/view/".$vars['node']->nid,NULL,NULL,TRUE);
+}
+
+function node_tag_title($vars = array()) {
+  return $vars['node']->title;
+}
+
+function node_tag_name($vars = array()) {
+  return format_name($vars['node']);
+}
+
+function node_tag_id($vars = array()) {
+  return $vars['node']->nid;
+}
+
+function node_tag_read_more($vars = array()) {
+  return $vars['main'] && $vars['node']->readmore;
+}
+
+function node_tag_node_type($vars = array()) {
+  return $vars['node']->type;
+}
+
+// comment functions - move to comment.module some day...
+function comment_tag_comment($vars = array(), $v1 = NULL) {
+  if (!$v1) return $vars['comment'];
+  return $vars['comment']->$v1;
+}
+
+function comment_tag_comment_new($vars = array()) {
+  return $vars['comment']->new;
+}
+
+function comment_tag_comment_id($vars = array()) {
+  return $vars['comment']->cid;
+}
+
+function comment_tag_show_title($vars = array()) {
+  return (variable_get('comment_subject_field', 0) && variable_get("comment_complex", 0));
+}
+
+function comment_tag_comment_title($vars = array()) {
+  return $vars['comment']->subject;
+}
+
+function comment_tag_comment_name($vars = array()) {
+  return format_name($vars['comment']);
+}
+
+function comment_tag_comment_date($vars = array(), $v1 = NULL) {
+  if (!$v1) return format_date($vars['comment']->timestamp);
+  switch ($v1) {
+    case 'small':
+    case 'large':
+    case 'medium':
+      return format_date($vars['comment']->timestamp, $v1);
+    default:
+      return format_date($vars['comment']->timestamp, 'custom', $v1);
+  }
+}
+
+function comment_tag_comment_visible($vars = array()) {
+  return $vars['comment']->visible;
+}
+
+function comment_tag_comment_title_link($vars = array()) {
+  return l($vars['comment']->subject, comment_referer_load().'/'.$vars['comment']->cid.'#'.$vars['comment']->cid);
+}
+
+function comment_tag_comment_depth($vars = array()) {
+  global $user;
+  $mode = $user->mode ? $user->mode : ($_SESSION["comment_mode"] ? $_SESSION["comment_mode"] : variable_get("comment_default_mode", 4));
+  if (variable_get("comment_complex",0) == 0) $mode = 2;
+  if ($mode == 1 || $mode == 2) return 0;
+  return $vars['comment']->depth;
+}
+
+function comment_tag_comment_status($vars = array()) {
+  return $vars['comment']->status;
+}
+
+// taxonomy functions - move to taxonomy.module some day...
+function taxonomy_tag_categories($vars = array()) {
+  return $vars['taxonomy'];
+}
+
+function taxonomy_tag_categories_each($vars = array()) {
+  return $vars['category'];
+}
+
+// simple css
+function simple_tag_css($vars = array()) {
+  return simple_style_path();
+}
+
+?>
diff -urN drupal-4.4.2/modules/taxonomy.module drupal4blog/modules/taxonomy.module
--- drupal-4.4.2/modules/taxonomy.module	Fri Jun 18 02:11:14 2004
+++ drupal4blog/modules/taxonomy.module	Wed Aug 25 00:06:04 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.module,v 1.106.2.5 2004/06/17 18:11:14 dries Exp $
+// $Id: taxonomy.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function taxonomy_feed($taxonomy) {
   global $id, $type;
@@ -17,6 +17,12 @@
   }
 }
 
+function taxonomy_settings() {
+  $output = form_radios(t("Taxonomy Complexity"), "taxonomy_complex", variable_get("taxonomy_complex", 0), array(0 => t("Simple Taxonomy"), 1 => t("Nested Taxonomy"), 2 => t("Full Taxonomy Control")),t("Taxonomy is just a fancy word for Category. You can attach 'taxonomy' to your entries which will specify their categories. 'Simple Taxonomy' is easier to managed and sufficient for most people. 'Nested Taxonomy' enables hierarchical categories. 'Full Taxonomy Control' gives you complete control."));
+  $output .= form_textfield(t("Taxonomy title"), "taxonomy_block_title", variable_get("taxonomy_block_title", "Categories"), 70, 180, t("") . " " . t("Title of the Taxonomyblock, e.g. Categories"));
+  return $output;
+}
+
 function taxonomy_perm() {
   return array("administer taxonomy");
 }
@@ -60,6 +66,62 @@
   }
 }
 
+function _taxonomy_list_terms($vid) {
+  $tree = taxonomy_get_tree($vid);
+  if ($tree) {
+    $depth = 0;
+    $complex = variable_get("taxonomy_complex",0);
+    foreach($tree as $term) {
+      if ($complex) {
+        while ($depth < $term->depth) {
+          $output .= "<ul>"; $depth++;
+        }
+        while ($depth > $term->depth) {
+          $output .= "</ul>\n"; $depth--;
+        }
+      }
+
+      $output .= "<li>".l($term->name,"taxonomy/page/or/$term->tid")."</li>";
+    }
+    if ($complex) {
+      while ($depth) {
+        $output .= "</ul>";
+        $depth--;
+      }
+    }
+  }
+  #if ($output) return "<div class=\"item-list\"><ul>".$output."</ul></div>";
+  if ($output) return "<ul>".$output."</ul>";
+  return "";
+}
+
+function taxonomy_block($op = "list", $delta = 0) {
+  if ($op == "list") {
+    $block[0]['info'] = t("Taxonomy");
+    return $block;
+  }
+
+  $block["subject"] = variable_get("taxonomy_block_title","Categories");
+
+  if (variable_get("taxonomy_complex",0)<=1) {
+    $vocabularies = taxonomy_get_vocabulary_by_name("Category");
+    if ($vocabularies[0]) 
+      $block["content"] = _taxonomy_list_terms($vocabularies[0]->vid);
+
+    return $block;
+  }
+
+  $vocabularies = taxonomy_get_vocabularies();
+  foreach ($vocabularies as $vocabulary) {
+    $output .= "<ul><li>".$vocabulary->name."</li>";
+    $output .= _taxonomy_list_terms($vocabulary->vid);
+    $output .= "</ul>";
+    $block["content"] = $output;
+  }
+
+  return $block;
+}
+
 /*
 ** admin pages (form, save, overview)
 */
@@ -149,30 +211,34 @@
   $form = form_textfield(t("Term name"), "name", $edit["name"], 50, 64, t("Required") .". ". t("The name for this term.  Example: 'Linux'."));
   $form .= form_textarea(t("Description"), "description", $edit["description"], 60, 5, t("Optional") .". ". t("A description of the term."));
 
-  if ($vocabulary->hierarchy) {
-    $parent = array_keys(taxonomy_get_parents($edit["tid"]));
-    $children = taxonomy_get_tree($vocabulary_id, $edit["tid"]);
-
-    // you can't be son of yourself nor of your children
-    foreach ($children as $child) {
-      $exclude[] = $child->tid;
-    }
-    $exclude[] = $edit["tid"];
-
-    if ($vocabulary->hierarchy == 1) {
-      $form .= _taxonomy_term_select(t("Parent"), "parent", $parent, $vocabulary_id, t("Required") .". ". l(t("Parent term"), "admin/taxonomy/help", NULL, NULL, "parent") .".", 0, "<". t("root") .">", $exclude);
-    }
-    elseif ($vocabulary->hierarchy == 2) {
-      $form .= _taxonomy_term_select(t("Parents"), "parent", $parent, $vocabulary_id, t("Required") .". ". l(t("Parent terms"), "admin/taxonomy/help", NULL, NULL, "parent") .".", 1, "<". t("root") .">", $exclude);
+  if (variable_get("taxonomy_complex",0)>0) {
+    if ($vocabulary->hierarchy) {
+      $parent = array_keys(taxonomy_get_parents($edit["tid"]));
+      $children = taxonomy_get_tree($vocabulary_id, $edit["tid"]);
+  
+      // you can't be son of yourself nor of your children
+      foreach ($children as $child) {
+        $exclude[] = $child->tid;
+      }
+      $exclude[] = $edit["tid"];
+  
+      if ($vocabulary->hierarchy == 1) {
+        $form .= _taxonomy_term_select(t("Parent"), "parent", $parent, $vocabulary_id, t("Required") .". ". l(t("Parent term"), "admin/taxonomy/help", NULL, NULL, "parent") .". Specify this to define sub-term.", 0, "<". t("root") .">", $exclude);
+      }
+      elseif ($vocabulary->hierarchy == 2) {
+        $form .= _taxonomy_term_select(t("Parents"), "parent", $parent, $vocabulary_id, t("Required") .". ". l(t("Parent terms"), "admin/taxonomy/help", NULL, NULL, "parent") .".", 1, "<". t("root") .">", $exclude);
+      }
+    }
+  
+    if (variable_get("taxonomy_complex",0)>1) {
+      if ($vocabulary->relations) {
+        $form .= _taxonomy_term_select(t("Related terms"), "relations", array_keys(taxonomy_get_related($edit["tid"])), $vocabulary_id, t("Optional") .". ", 1, "<". t("none") .">", array($edit["tid"]));
+      }
+    
+      $form .= form_textarea(t("Synonyms"), "synonyms", implode("\n", taxonomy_get_synonyms($edit["tid"])), 30, 5, t("Optional") . ". ". t("<a href=\"%help-url\">Synonyms</a> of this term, one synonym per line.", array("%help-url" => url("admin/taxonomy/help", NULL, NULL, "synonyms"))));
+      $form .= form_weight(t("Weight"), "weight", $edit["weight"], 10, t("Optional. In listings, the heavier terms will sink and the lighter terms will be positioned nearer the top."));
     }
   }
-
-  if ($vocabulary->relations) {
-    $form .= _taxonomy_term_select(t("Related terms"), "relations", array_keys(taxonomy_get_related($edit["tid"])), $vocabulary_id, t("Optional") .". ", 1, "<". t("none") .">", array($edit["tid"]));
-  }
-
-  $form .= form_textarea(t("Synonyms"), "synonyms", implode("\n", taxonomy_get_synonyms($edit["tid"])), 30, 5, t("Optional") . ". ". t("<a href=\"%help-url\">Synonyms</a> of this term, one synonym per line.", array("%help-url" => url("admin/taxonomy/help", NULL, NULL, "synonyms"))));
-  $form .= form_weight(t("Weight"), "weight", $edit["weight"], 10, t("Optional. In listings, the heavier terms will sink and the lighter terms will be positioned nearer the top."));
   $form .= form_hidden("vid", $vocabulary->vid);
   $form .= form_submit(t("Submit"));
 
@@ -187,15 +253,13 @@
 function taxonomy_save_term($edit) {
   if ($edit["tid"] && $edit["name"]) {
     $data = array("name" => $edit["name"], "description" => $edit["description"], "weight" => $edit["weight"]);
-
     db_query("UPDATE {term_data} SET ". _prepare_update($data) ." WHERE tid = %d", $edit["tid"]);
     module_invoke_all("taxonomy", "update", "term", $edit);
     $message = t("the term '%a' has been updated.", array("%a" => $edit["name"]));
   }
   else if ($edit["tid"]) {
     return taxonomy_del_term($edit["tid"]);
-  }
-  else {
+  } else {
     $edit["tid"] = db_next_id("{term_data}_tid");
     $data = array("tid" => $edit["tid"], "name" => $edit["name"], "description" => $edit["description"], "vid" => $edit["vid"], "weight" => $edit["weight"]);
     db_query("INSERT INTO {term_data} ". _prepare_insert($data, 1) ." VALUES ". _prepare_insert($data, 2));
@@ -255,6 +319,7 @@
 
   cache_clear_all();
 
+  drupal_set_message(t("deleted term '%name'.", array("%name" => $term->name)));
   return t("deleted term '%name'.", array("%name" => $term->name));
 }
 
@@ -271,6 +336,27 @@
 }
 
 function taxonomy_overview() {
+  if (variable_get("taxonomy_complex",0)<=1) {
+    $vocabularies = taxonomy_get_vocabulary_by_name("Category");
+    if (!$vocabularies[0]) {
+      $vid = db_next_id("{vocabulary}_vid");
+      db_query("INSERT INTO {vocabulary} VALUES (%d, '%s', '%s', %d, %d, %d, %d, '%s', %d)", $vid, "Category", "Categories for Blog Entries", 0, 1, 1, 0, 'blog', 0);
+      $vocabularies = taxonomy_get_vocabulary_by_name("Category");
+    }
+    $vid = $vocabularies[0]->vid;
+
+    $headers = array(t("name"), t("description"));
+
+    $tree = taxonomy_get_tree($vid);
+    if ($tree) {
+      foreach($tree as $term) {
+        $rows[] = array(l(_taxonomy_depth($term->depth)." ".$term->name, "admin/taxonomy/edit/term/$term->tid") , $term->description);
+      }
+    }
+    $rows[] = array(array("data" => l(t("add category"), "admin/taxonomy/add/term/$vid"), "colspan" => 2));;
+
+    return theme("table",$headers,$rows);
+  }
 
   $output .= "<h3>". t("Vocabularies overview") ."</h3>";
 
@@ -750,7 +836,7 @@
       $breadcrumbs[] = l(t('Home'), '');
       $breadcrumbs = array_reverse($breadcrumbs);
 
-      drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="RSS - '. implode(' : ', $names) .'" href="'. url("taxonomy/feed/or/$taxonomy->str_tids") .'" />');
+      drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="RSS - '. implode(' : ', $names) .'" href="'. url("taxonomy/feed/or/$taxonomy->str_tids", NULL, NULL, TRUE) .'" />');
 
       $output = taxonomy_render_nodes(taxonomy_select_nodes($taxonomy));
       print theme("page", $output, implode(', ', $names), $breadcrumbs);
@@ -819,7 +905,7 @@
         taxonomy_save_term($edit);
         if (!$edit["tid"]) {
           // if INSERT show form again
-          $output .= taxonomy_form_term();
+          $output .= taxonomy_overview(); // taxonomy_form_term();
           break;
         }
         // else (UPDATE or DELETE) fall through
@@ -884,4 +970,20 @@
 
   return $output;
 }
+
+function taxonomy_blogadmin($type) {
+  $list = array();
+
+  if ($type == "block") {
+    if (user_access("administer taxonomy"))
+      $list[] = l(t("categories"), "admin/taxonomy");
+  } else if ($type == "options") {
+    if (user_access("administer site configuration")) {
+      $list[l(t("Category options"),"admin/system/modules/taxonomy")] = t("Configure category/taxonomy options");
+    }
+  }
+
+  return $list;
+}
+
 ?>
diff -urN drupal-4.4.2/modules/throttle.module drupal4blog/modules/throttle.module
--- drupal-4.4.2/modules/throttle.module	Sat Mar 20 21:47:14 2004
+++ drupal4blog/modules/throttle.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: throttle.module,v 1.31.2.1 2004/03/20 13:47:14 dries Exp $
+// $Id: throttle.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 /*  Call the throttle_status() function from your own modules, themes, blocks,
  * etc, to determine the current throttle status.  For example, in your theme
diff -urN drupal-4.4.2/modules/title.module drupal4blog/modules/title.module
--- drupal-4.4.2/modules/title.module	Sun Feb 22 07:52:11 2004
+++ drupal4blog/modules/title.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: title.module,v 1.29 2004/02/21 23:52:11 kjartan Exp $
+// $Id: title.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function title_help($section) {
   $output = "";
diff -urN drupal-4.4.2/modules/trackback.module drupal4blog/modules/trackback.module
--- drupal-4.4.2/modules/trackback.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/trackback.module	Thu Sep  2 21:57:35 2004
@@ -0,0 +1,397 @@
+<?php
+/* $Id: trackback.module,v 1.1 2004/07/11 14:50:57 jseng Exp $ */
+
+function trackback_help($section) {
+  switch ($section) {
+    case 'admin/system/modules#description':
+      return t("Allow for sending and receiving TrackBacks, which is a way for sites to notify another that they have commented on a post.");
+    case 'admin/system/modules/trackback':
+      return t("Trackback can be attached to any node and is treated like comments for all intent and purpose.");
+  }
+}
+
+function trackback_settings() {
+    $output = "";
+
+    $array_moderate = array(0 => t('No'), 1 => t('Yes'));
+    $output .= form_radios(t('Display Trackback only after approval'), 'trackback_moderation', variable_get('trackback_moderation', 0), $array_moderate, t('If yes, all trackback must be moderated before it can be seen by others.'));
+
+    $output .= form_radios(t('Trackback autodiscovery'), 'trackback_autodiscovery', variable_get('trackback_autodiscovery', 1), $array_moderate, t('If yes, any external links will be extracted and the appropriate sites will be sent a Trackback ping. Take note it might slowdown your posting esp. if there is a lot of external links.'));
+
+    return $output;
+}
+
+function trackback_send($node) {
+  $params = array(
+    'title' => $node->title,
+    'excerpt' => substr(check_output($node->teaser), 0, 255),
+    'blog_name' => variable_get('site_name', ''),
+    'url' => url("node/view/$node->nid", NULL, NULL, 1)
+  );
+
+  foreach ($params as $key => $value) {
+    $str[] = "$key=". urlencode($value);
+  }
+
+  $node->toping = ""; # Start from scratch
+
+  $tb_urls = $node->tb_url;
+  if (variable_get('trackback_autodiscovery',1)) {
+    $text = $node->body; 
+    if ($node->type == 'blog')
+      $text .= ' '.$node->extended.' '.$node->excerpt;
+    preg_match_all("|http://[\w\.\-\+\&\+\=\/\#\%]+|",$text,$murl);
+    $links = array_unique($murl[0]);
+    foreach ($links as $url) {
+      /*
+      ** Yes, it is double query but this is to prevent from loading a 100mb
+      ** avi file only to realize we cant trackback to it
+      **
+      ** Should we check for the size of the text/html before we do a GET?
+      */
+      $result = drupal_http($url, array(), 'HEAD');
+
+      // see http://www.w3.org/TR/2002/NOTE-xhtml-media-types-20020801/
+      if (preg_match("/[text\/html|application\/xhtml\+xml|application\/xml|text\/xml]/", $result->headers['Content-Type']) && ($result->headers['Content-Length'] <= 1048576)) {
+        $result = drupal_http($url);
+        $result->data = preg_replace("/[\n\r]/",' ',$result->data);
+        if (preg_match("/<rdf\:RDF.*trackback\:ping.*<\/rdf\:RDF>/i",$result->data)) {
+          $tb = preg_replace("/.*<rdf\:RDF.*trackback\:ping\=\"([^\"]+)\".*<\/rdf\:RDF>.*/i","\\1",$result->data);
+
+          // if it isn't http or https or it is too long, we ignore
+          if (preg_match("/^[http|https]/",$tb) && strlen($tb)<128) {
+            $tb_urls .= ' '.$tb;
+          }
+        }
+      } 
+    }
+  }
+
+  $urls = preg_split("/\s+/",$tb_urls);
+  foreach($urls as $url) {
+    # No need to ping empty URL
+    if (strlen($url)<=0) continue;
+
+    # Do not ping those already ping'ed unless explicitly specified 
+    if (strstr($node->pinged,$url) && !strstr($node->tb_url,$url)) continue;
+
+    $result = drupal_http(
+        $url,
+        $headers = array('Content-Type' => 'application/x-www-form-urlencoded'),
+        'POST',
+        implode("&", $str)
+    );
+
+    if (strlen(trim($result->error))>0) {
+      drupal_set_message(t('Error! Unable to send Trackback ping to ').$url);
+      if (!strstr($node->toping,$url))
+        $node->toping .= "\n".$url; $node->toping = trim($node->toping);
+    } else {
+      drupal_set_message(t('Success! Trackback ping send to ').$url);
+      if (!strstr($node->pinged,$url))
+        $node->pinged .= "\n".$url; $node->pinged = trim($node->pinged);
+    }
+  }
+
+  $c = db_result(
+    db_query("SELECT COUNT(nid) FROM {trackback} WHERE nid = %d", $node->nid));
+
+  if ($c>0) 
+      trackback_update($node);
+  else 
+      trackback_insert($node);
+}
+
+function trackback_receive($node) {
+  // Process TrackBack post data.
+  $trackback->url = check_url($_REQUEST["url"]);
+  if ($trackback->url) {
+    $trackback->excerpt = (strlen($_REQUEST["excerpt"] > 255) ? substr($_REQUEST["excerpt"], 0, 252) ."..." : $_REQUEST["excerpt"]);
+    $trackback->name = ($_REQUEST["blog_name"]) ? $_REQUEST["blog_name"] : $trackback->url;
+
+    // Save TrackBack as comment
+    // TODO: Make a comment_insert in the comment module to prevent duplication of code here.
+    $subject = ($_REQUEST["title"]) ? $_REQUEST["title"] : $trackback->url;
+    $comment = "<strong>". t("TrackBack from %url", array("%url" => "<a href=\"$trackback->url\">$trackback->name</a>")) .":</strong><br />";
+    $comment .= "<blockquote>".strip_tags($trackback->excerpt)."...</blockquote>";
+    $anon_name = trim(strip_tags($trackback->name));
+    $anon_url = trim(strip_tags($trackback->url));
+    $cid = db_next_id("{comments}_cid");
+    $max = rtrim(db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE nid = %d", $node->nid)), "/");
+    $decimals = (string)substr($max,0,strlen($max)-1);
+    $units = substr($max, -1, 1);
+    if ($units) {
+      $units++;
+    } else {
+      $units = 1;
+    }
+    if ($units == 10) {
+      $units = '90';
+    }
+    $thread = "$decimals$units/";
+    module_invoke_all('comment','insert',array('cid' => $cid, 'nid' => $node->nid, 'pid' => 0, 'uid' => 0, 'subject' => $subject, 'comment' => $comment, 'hostname' => getenv('REMOTE_ADDR'), 'timestamp' => time(), 'status' => variable_get('trackback_moderation', 0), 'score' => 0, 'name' => $anon_name, 'homepage' => $anon_url));
+    db_query("INSERT INTO {comments} (cid, nid, pid, uid, subject, comment, hostname, timestamp, status, score, name, homepage, thread) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s')",
+             $cid, $node->nid, 0, 0, $subject, $comment, getenv("REMOTE_ADDR"), time(), variable_get("trackback_moderation", 0), 0, $anon_name, $anon_url, $thread);
+    db_query("INSERT INTO {trackback_pingme} (nid, cid) VALUES (%d, %d)", $node->nid, $cid);
+    watchdog("special", t("trackback: added '%subject'", array("%subject" => $subject)), l(t("view comment"), "node/view/". $node->nid ."#". $cid));
+    $error = 0;
+  }
+  else {
+    $error = 1;
+    $message = t("Missing TrackBack url.");
+  }
+
+  // Generate response
+  $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+  $output .= "<response>\n";
+  $output .= "<error>$error</error>\n";
+  $message and $output .= "<message>$message</message>\n";
+  $output .= "</response>\n";
+
+  return $output;
+}
+
+function _trackback_info($node) {
+  $output = t("<p>The Trackback URL for node is:<br/><blockquote>url</blockquote></p>", array("node" => l("'$node->title'","node/view/$node->nid"), "url" => l(url("trackback/$node->nid", NULL, NULL, TRUE), "trackback/$node->nid")));
+
+  if (user_access("administer nodes")) {
+    $node = trackback_load_node($node);
+    $urls = preg_split("/\s+/",$node->pinged);
+    $head = 0;
+    foreach ($urls as $url) {
+      $url = strip_tags($url);
+      if (strlen(trim($url))<=0) continue;
+      if ($head == 0) {
+        $output .=  "<p>".
+          t("Trackback pings have been sent to the following URLs:");
+        $head = 1;
+      }
+      $output .= "<li>$url</li>\n";
+    }
+    if ($head) $output .= "</p>";
+  }
+
+  $query = db_query("SELECT cid from {trackback_pingme} WHERE nid = %d", $node->nid);
+
+  if (db_num_rows($query) && module_exist('comment')) {
+    $output .= t("<p>Trackbacks:</p>");
+    while ($result = db_fetch_object($query)) {
+      $comment = db_fetch_object(db_query('SELECT c.* FROM {comments} c WHERE c.cid = %d AND c.status = 0', $result->cid));
+      if ($comment) {
+        $comment->comment = check_output($comment->comment, array('filter_html' => variable_get("comment_filter_html", FILTER_HTML_STRIP), 'allowed_html' => variable_get("comment_allowed_html", "<a> <b> <i> <strong> <br>"), 'filter_style' => variable_get("comment_filter_style", FILTER_STYLE_STRIP)));
+        $output .= theme("comment_view", $comment);
+      }
+    }
+  }
+
+  return $output;
+}
+
+function trackback_page() {
+    if (arg(1) == "url" && is_numeric(arg(2)) 
+        && $node = node_load(array("nid" => arg(2)))) {
+        $output = _trackback_info($node);
+        print theme('page', $output, t("Trackback URL"));
+    } elseif (is_numeric(arg(1)) && $node = node_load(array("nid" => arg(1)))) {
+        header("Content-Type: text/xml");
+        print trackback_receive($node);
+    } else {
+        drupal_goto();
+    }
+}
+
+function trackback_nodeapi(&$node, $op, $arg = 0) {
+  $node = trackback_load_node($node);
+  switch ($op) {
+    case "form post":
+      $node->tb_url = $node->toping;
+      return form_textarea(t("Trackback URL"), "tb_url", $node->tb_url, 70, 3, t("Enter URLs to send the trackback to."));
+    case "insert":
+    case "update":
+      # send trackback only for published post
+      if ($node->nid && $node->status == 1
+        && ($node->tb_url || variable_get("trackback_autodiscovery",1)))
+        trackback_send($node);
+  }
+}
+
+function trackback_insert($node) {
+  if ($node->nid)
+    db_query("INSERT INTO {trackback} (pinged, toping, nid) VALUES ('%s', '%s', %d)", $node->pinged, $node->toping, $node->nid);
+}
+
+function trackback_update($node) {
+  if ($node->nid)
+    db_query("UPDATE {trackback} SET pinged = '%s', toping = '%s' WHERE nid = %d", $node->pinged, $node->toping, $node->nid);
+}
+
+function trackback_delete(&$node) {
+  if ($node->nid)
+    db_query("DELETE FROM {trackback} WHERE nid = %d", $node->nid);
+}
+
+function trackback_load($node) {
+  if ($node->nid) 
+    return db_fetch_object(db_query("SELECT pinged, toping FROM {trackback} WHERE nid = %d", $node->nid));
+  return array();
+}
+
+function trackback_load_node($node) {
+  if ($result = trackback_load($node)) {
+    foreach ($result as $key => $value)
+      $node->$key = $value;
+  }
+  return $node;
+}
+
+function trackback_link($type, $node = 0, $main = 0) {
+  if ($type == 'system') {
+    menu('trackback', t('trackback'), trackback_page, 0, MENU_HIDE);
+  }
+  elseif ($type == "node") {
+    $link = l(t("trackback"), "trackback/url/$node->nid", array("title" => t("Display Trackback URL")));
+    if (!$main) {
+      $url = url("node/view/$node->nid", NULL, NULL, 1);
+      $tb_url =  url("trackback/$node->nid", NULL, NULL, 1);
+      $link .= "\n<!--\n";
+      $link .= "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">\n";
+      $link .= "<rdf:Description rdf:about=\"$url\" dc:identifier=\"$url\" dc:title=\"$node->title\" trackback:ping=\"$tb_url\" />\n";
+      $link .= "</rdf:RDF>\n";
+      $link .= "-->\n";
+    }
+    return array($link);
+  }
+}
+
+/**
+* @param $url http://example.com/path?query
+* @param $headers array("header" => "value");
+* @param $method method to use, defaults to GET
+* @param $data post data / return data
+* @param $retry how many times to retry (follow redirects, etc)
+*/
+function drupal_http($url, $headers = array(), $method = "GET", $data = "", $retry = 3) {
+  static $retries;
+
+  // Parse the URL, and make sure we can handle the schema
+  $uri = parse_url($url);
+  switch ($uri["scheme"]) {
+    case "http":
+      $fp = @fsockopen($uri["host"], ($uri["port"] ? $uri["port"] : 80), $errno, $errstr, 15);
+      break;
+    case "https":
+      // Note: only works for PHP 4.3 compiled with openssl
+      $fp = @fsockopen("ssl://$uri[host]", ($uri["port"] ? $uri["port"] : 443), $errno, $errstr, 20);
+      break;
+    default:
+      $result->error = "invalid schema $uri[scheme]";
+      return $result;
+  }
+
+  // Make sure the socket opened properly
+  if (!$fp) {
+    $result->error = trim("$errno $errstr");
+    return $result;
+  }
+
+  // Construct the path to act on
+  if ($uri["path"]) {
+    $path = $uri["path"];
+  }
+  else {
+    $path = "/";
+  }
+  if ($uri["query"]) {
+    $path .= "?$uri[query]";
+  }
+
+  // Create http request
+  $defaults = array(
+    "host"       => "Host: $uri[host]",
+    "user-agent" => "User-Agent: Drupal/4.0 (+http://www.drupal.org/)",
+    "content-length" => "Content-length: ". strlen($data)
+  );
+
+  foreach ($headers as $header => $value) {
+    $defaults[$header] = "$header: $value";
+  }
+
+  $request = "$method $path HTTP/1.0\r\n";
+  $request .= implode("\r\n", $defaults);
+  $request .= "\r\n\r\n";
+  if ($data) {
+    $request .= "$data\r\n";
+  }
+  $result->request = $request;
+
+  fwrite($fp, $request);
+
+  // Featch response
+  while (!feof($fp)) {
+    $response[] = fgets($fp);
+
+    /*
+    ** Make sure there is still data left to read, necessary to not block
+    ** processing in case the remote site doesn't return EOF properly.
+    */
+    $status = socket_get_status($fp);
+    if ($status["unread_bytes"] = 0) {
+      break;
+    }
+  }
+  fclose($fp);
+
+  // Parse response
+  list($protocl, $code, $text) = explode(" ", trim(array_shift($response)), 3);
+  $result->code = $code;
+  $result->headers = array();;
+  $result->data = "";
+
+  // Parse headers
+  while ($line = trim(array_shift($response))) {
+    if ($line == "") {
+      break;
+    }
+    list($header, $value) = explode(":", $line, 2);
+    $result->headers[$header] = trim($value);
+  }
+
+  while ($line = array_shift($response)) {
+    $result->data .= $line;
+  }
+
+  switch ($result->code) {
+    case 200: // OK
+    case 304: // Not modified
+      break;
+    case 301: // Moved permanently
+    case 302: // Moved temporarily
+      $location = $result->headers["Location"];
+      if ($retries < $retry) {
+        $retries++;
+        $result = drupal_http($result->headers["Location"], $headers, $method, $data, $retry);
+      }
+      else {
+        $result->error = "Too many retries";
+      }
+      $result->url = $location;
+      break;
+    default:
+      $result->error = $text;
+  }
+  return $result;
+}
+
+function trackback_blogadmin($type = "") {
+  $list = array();
+
+  if ($type == "options") {
+    if (user_access("administer site configuration")) {
+      $list[l(t("Trackback options"),"admin/system/modules/trackback")] = t("Configure trackback options.");
+    }
+  }
+
+  return $list;
+}
+
+?>
diff -urN drupal-4.4.2/modules/tracker.module drupal4blog/modules/tracker.module
--- drupal-4.4.2/modules/tracker.module	Mon Apr 12 16:31:30 2004
+++ drupal4blog/modules/tracker.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: tracker.module,v 1.76.2.2 2004/04/12 08:31:30 dries Exp $
+// $Id: tracker.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function tracker_help($section = 'admin/help#tracker') {
   switch ($section) {
diff -urN drupal-4.4.2/modules/upload.module drupal4blog/modules/upload.module
--- drupal-4.4.2/modules/upload.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/upload.module	Mon Aug 23 22:24:59 2004
@@ -0,0 +1,338 @@
+<?php
+// $Id: upload.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+function upload_help($section) {
+  $output = "";
+
+  switch ($section) {
+    case 'admin/system/modules#description':
+      $output = t("Enables quick and easy file upload to drupal.");
+      break;
+    case 'admin/upload/help':
+    case 'admin/system/modules/upload':
+      $output = t("Allows quick and easy file upload to drupal. You can define permissions to upload and download file in the %userperm configuration. The permission 'download files' only works if 'Download Method' is set to Private in %sysconf. You also need to make sure your File System path is not accessible from the web.",
+        array("%userperm" => l(t("user permission"),"admin/user/permission"),
+              "%sysconf"  => l(t("system configuration"), "admin/system")));
+      break;
+  }
+  return $output;
+}
+
+function upload_perm() {
+  return array("upload files (simple)", 
+               "maintain files (simple)", 
+               "download files (simple)");
+}
+
+function upload_settings() {
+  if (!file_check_directory(file_create_path(variable_get('upload_path', 'public')))) 
+    $error['upload_path'] = theme('error', t('Directory does not exists, or is not writable.'));
+
+  $output = "";
+
+  $output .= form_textfield(t("Upload path"), "upload_path", variable_get("upload_path", "public"), 30, 255, t("Subdirectory in the directory '%dir' where upload files will be stored.", array('%dir' => variable_get("file_directory_path", "files") . FILE_SEPARATOR)) . $error['upload_path']);
+
+  $output .= form_textfield(t("Maximum file size"), "upload_filesize", variable_get("upload_filesize", 1024), 10, 10, t("Maximum file size for file upload, in kB. Default 1024kb or 1Mb."));
+
+  return $output;
+}
+
+function upload_link($type, $node = 0, $main) {
+  if ($type  == 'system') {
+    if (user_access('upload files (simple)'))
+      menu('upload', t('quick upload'), 'upload_page', 0, MENU_HIDE);
+    if (user_access('maintain files (simple)'))
+      menu('admin/upload', t('manage files'), 'upload_admin', 0);
+  }
+}
+
+function upload_page() {
+  $op = $_POST['op'] ? $_POST['op'] : arg(1);
+
+  if (!user_access("upload files (simple)"))
+    drupal_goto();
+
+  switch ($op) {
+    case 'Replace':
+      print theme('popup', _upload_upload(1), '');
+      break;
+    case 'Upload':
+      print theme('popup', _upload_upload(0), '');
+      break;
+    default:
+      print theme('popup', _upload_form(), '');
+  }
+}
+
+function _upload_form() {
+  drupal_set_title(t('Quick upload file'));
+  $output .= "<div class=\"standard\">";
+  $output .= form_file(t("Upload file"), "upload_file", 30, 
+              "You need to specify a file to upload.");
+  $output .= form_submit(t('Upload'));
+  $output .= form_submit(t('Replace'));
+  $output .= "<p>".t("'Upload' will not replace existing file. Use 'Replace' if you wish to override existing file.")."</p>";
+  $output .= "</div>";
+
+  # construct the form
+  $param["method"] = "post";
+  $param["options"]["enctype"] = "multipart/form-data";
+  return form($output, ($param['method'] ? $param['method'] : 'post'), $param['action'], $param['options']);
+}
+
+function _upload_upload($replace = 0) {
+  $edit = $_POST['edit'];
+  $upload_file = file_check_upload('upload_file');
+
+  if ((!$upload_file) || !file_exists($upload_file->path)) {
+    drupal_set_message(theme("error",t("You need to specify a file to upload.")));
+    return _upload_form();
+  }
+
+  if (filesize($upload_file->path)/1024 > variable_get("upload_filesize",1024)) {
+    drupal_set_message(theme('error',t('Maximum upload size is ').variable_get("upload_filesize", 1024)."kb.".filesize($upload_file->path)));
+    return _upload_form();
+  }
+
+  $upload_file->name = basename($upload_file->name);
+  $dest = variable_get("upload_path","public").FILE_SEPARATOR.$upload_file->name;
+
+  if (!$replace && file_exists(file_create_path($dest))) {
+    drupal_set_message("File already existed!");
+    return _upload_form();
+  } 
+
+  file_save_upload('upload_file',$dest,1);
+
+  $url = file_create_url($dest);
+  if (preg_match("/\.(gif|jpg|png)$/i",$upload_file->name)) {
+    $size = getimagesize(file_create_path($dest));
+    $html = "<img src=\"$url\" alt=\"$upload_file->name\" border=\"0\"";
+    if ($size[0] && $size[1])
+     $html .= " width=\"$size[0]\" height=\"$size[1]\"";
+    $html .= " />";
+  } else {
+    $html = "<a href=\"$url\">Download file</a>";
+  }
+
+  $output = "";
+  $output .= form_textarea(t("HTML code"),"html",$html,35,4, t("This is the HTML code which you can paste into your entry."));
+  $output .= form_button(t('Close'), "op", "button",
+    array("onClick" => "window.close()"));
+
+  watchdog("special", "upload file ".$upload_file->name, l("view file",$url));
+
+  return form($output);
+}
+
+function upload_admin() {
+  $op = $_POST["op"];
+  $edit = $_POST["edit"];
+
+  if (!user_access("maintain files (simple)"))
+    drupal_goto();
+
+  if (arg(2)) {
+    $output = _upload_admin_file(escapeshellcmd(arg(2)));
+  } else {
+    $output = _upload_admin_overview();
+  }
+
+  print theme("page",$output);
+}
+
+function _upload_filerow($dir,$file,$main = 1) {
+  $file_url = file_create_url(variable_get('upload_path','public').FILE_SEPARATOR.$file);
+  $ffile = $dir.FILE_SEPARATOR.$file;
+  $info = stat($ffile);
+  if ($info['size'] > 1024*1024) 
+    $size = (int) ($info['size']/(1024*1024))."Mb";
+  else if ($info['size'] > 1024)
+    $size = (int) ($info['size']/1024)."kb";
+  else
+    $size = $info['size']."b";
+  return array(
+    array("data" => l($file, $main ? "admin/upload/$file" : $file_url) ),
+    array("data" => $size ),
+    array("data" => format_date($info['mtime']) ),
+  );
+}
+
+function _upload_admin_overview() {
+  $dir = file_create_path(variable_get('upload_path', 'public'));
+  if (!file_check_directory($dir)) {
+    drupal_set_message(t("The upload directory isn't configured properly."));
+    return drupal_goto("admin/system/modules/upload");
+  }
+
+  $output = "";
+  if ($dh = opendir($dir)) {
+    $headers = array( 
+      array("data" => t("filename") ),
+      array("data" => t("size")  ),
+      array("data" => t("date") ),
+    );
+
+    while ($file = readdir($dh)) {
+      if (is_dir($dir.FILE_SEPARATOR.$file)) continue;
+      $rows[] = _upload_filerow($dir, $file, 1);
+    }
+    closedir($dh);
+
+    $url = url("upload", FALSE, FALSE, TRUE);
+    $rows[] = array(array("data" => "<a href=\"javascript:void(window.open('$url','popup','width=350,height=250,resizable=yes'))\">Upload files</a>", "colspan" => 3));
+
+    $output .= theme("table",$headers, $rows);
+  }
+  return $output;
+}
+
+function _upload_admin_file($file) {
+  $op = $_POST['op'];
+  $edit = $_POST['edit'];
+
+  $dir = file_create_path(variable_get('upload_path', 'public'));
+  if (!file_exists($dir.FILE_SEPARATOR.$file)) {
+    drupal_set_message(t("No such file!"));
+    return drupal_goto("admin/upload");
+  }
+
+  switch ($op) {
+    case t('Delete'):
+      $ffile = $dir.FILE_SEPARATOR.$file;
+      @unlink($ffile);
+      watchdog("special", "delete file ".$file, "deleted");
+      drupal_goto("admin/upload");
+      break;
+
+    case t('Rename'):
+      $edit['rename'] = escapeshellcmd($edit['rename']);
+      $edit['rename'] = basename($edit['rename']);
+
+      $ffile = $dir.FILE_SEPARATOR.$file;
+      $dest  = $dir.FILE_SEPARATOR.$edit['rename'];
+
+      if (file_exists($dest)) {
+        drupal_set_message(t("There is already another file by that name."));
+        return drupal_goto("admin/upload/$file");
+      }
+
+      if (copy($ffile,$dest)) {
+        @unlink($ffile);
+        $url = file_create_url(variable_get("upload_path","public").FILE_SEPARATOR.$edit['rename']);
+        watchdog("special", "rename file '$file' to '".$edit['rename']."'", l("view file",$url));
+        return drupal_goto("admin/upload/".$edit['rename']);
+      } else {
+        watchdog("error", "unable to rename file '$file' to '".$edit['rename']."'");
+        drupal_set_message(t("Error renaming file!"));
+        return drupal_goto("admin/upload/$file");
+      }
+      break;
+
+    default:
+      $headers = array( 
+        array("data" => t("filename") ),
+        array("data" => t("size")  ),
+        array("data" => t("date") ),
+      );
+    
+      $rows[] = _upload_filerow($dir,$file, 0);
+      $output = theme("table", $headers, $rows);
+
+      $dest = variable_get("upload_path","public").FILE_SEPARATOR.$file;
+      $url = file_create_url($dest);
+
+      $output .=" <p><b>URL</b>: <a href=\"$url\">$url</a></p>";
+    
+      if (preg_match("/\.(gif|jpg|png)$/i",$file)) {
+        $output .= "<img src=\"$url\">";
+      }
+
+      $form .= form_textfield(t("Rename"), "rename", $file, 30, 128);
+      $form .= form_submit(t("Rename"));
+      $form .= form_submit(t("Delete"));
+      $output .= "<br/>".form($form);
+
+      break;
+  }
+
+  return $output;
+}
+
+function upload_file_download($file) {
+  if (user_access("download files (simple)")) {
+    $file = file_create_path($file);
+    return array('Content-type: '.mime_content_type($file));
+  }
+}
+
+/*
+** goes into theme.inc?
+**/
+function theme_popup($content, $title = NULL, $breadcrumb = NULL) {
+  if (isset($title)) {
+    drupal_set_title($title);
+  }
+  if (isset($breadcrumb)) {
+    drupal_set_breadcrumb($breadcrumb);
+  }
+
+  $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
+  $output .= "<html xmlns=\"http://www.w3.org/1999/xhtml\">";
+  $output .= "<head>";
+  $output .= " <title>". (drupal_get_title() ? drupal_get_title() : variable_get('site_name', "drupal")) ."</title>";
+  $output .= drupal_get_html_head();
+
+  $output .= " </head>";
+  $output .= " <body style=\"background-color: #fff; color: #000;\"". theme("onload_attribute"). "\">";
+  $output .= "<table border=\"0\" cellspacing=\"4\" cellpadding=\"4\"><tr>";
+  $output .= "<td style=\"vertical-align: top;\">";
+
+  $output .= "<h1>" . drupal_get_title() . "</h1>";
+  if ($help = menu_get_active_help()) {
+    $output .= "<small>$help</small><hr />";
+  }
+
+  $output .= "\n<!-- begin content -->\n";
+  $output .= $content;
+  $output .= "\n<!-- end content -->\n";
+
+  $output .= "</td></tr></table>";
+  $output .= theme_closure();
+  $output .= "</body></html>";
+
+  return $output;
+}
+
+function upload_blogadmin($type) {
+  $list = array();
+  
+  if ($type == "block") {
+    if (user_access('upload files (simple)')) {
+      $url = url("upload", FALSE, FALSE, TRUE);
+      $list[] = "<a href=\"javascript:void(window.open('$url','popup','width=350,height=250,resizable=yes'))\">quick upload</a>";
+    }
+
+    if (user_access('maintain files (simple)'))
+      $list[] = l(t("file manager"), "admin/upload");
+  } else if ($type == "options") {
+      $list[l(t("Upload options"),"admin/system/modules/upload")] = t("Configure upload options.");
+  }
+
+  return $list;
+}
+
+function upload_exit() {
+  // clean up error message if any
+  $_SESSION['message'] = array();
+}
+
+if (!function_exists ("mime_content_type")) {
+  function mime_content_type ($file) {
+    $mime = exec ("file -bi " . escapeshellcmd($file));
+    if ($mime) return $mime;
+    return "application/octet-stream";
+  }
+}
+
+?>
diff -urN drupal-4.4.2/modules/urlfilter.module drupal4blog/modules/urlfilter.module
--- drupal-4.4.2/modules/urlfilter.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/urlfilter.module	Wed Jul 14 07:38:08 2004
@@ -0,0 +1,36 @@
+<?php
+// $Id: urlfilter.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+function urlfilter_help($section) {
+  switch ($section) {
+    case 'admin/system/modules#description':
+      return t("Automatically turns web and email addresses into clickable links.");
+  }
+}
+
+function urlfilter_settings() {
+  $output .= form_select(t('Target URL link'), 'urlfilter_target', variable_get('urlfilter_target', 0), array( 0 => 'On same Window', 1 => 'New Window'));
+  return $output;
+}
+
+function urlfilter_filter($op, $text = "") {
+  switch ($op) {
+    case "name":
+      return t("URL Filter");
+    case "settings":
+      return form_group(t("URL Filter"), t("URL Filter is enabled. This means that web and email addresses will automatically be converted into (clickable) links."));
+    case "process":
+      $text = " " . $text . " ";
+      $text = preg_replace("<([ \n\r\t\(])((http://|https://|ftp:\//|mailto:)([a-zA-Z0-9@:%_~#?&=.,/;-]*[a-zA-Z0-9@:%_~#&=/;-]))([.,?]?)(?=[ \n\r\t\)])>i", '\1<a '. (variable_get('urlfilter_target',0) ? 'target="_new" ': ''). 'href="\2">\2</a>\5', $text);
+      $text = preg_replace("<([ \n\r\t\(])([A-Za-z0-9._]+@[A-Za-z0-9._]+\.[A-Za-z]{2,4})([.,]?)(?=[ \n\r\t\)])>i", '\1<a href="mailto:\2">\2</a>\3' , $text);
+      $text = preg_replace("<([ \n\r\t\(])(www\.[a-zA-Z0-9@:%_~#?&=.,/;-]*[a-zA-Z0-9@:%_~#\&=/;-])([.,?]?)(?=[ \n\r\t\)])>i", '\1<a href="http://\2">\2</a>\3', $text);
+      $text = substr($text, 1, -1);
+      return $text;
+    default:
+      return $text;
+  }
+  return $text;
+}
+
+
+?>
diff -urN drupal-4.4.2/modules/user.module drupal4blog/modules/user.module
--- drupal-4.4.2/modules/user.module	Sat May 22 02:07:48 2004
+++ drupal4blog/modules/user.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: user.module,v 1.305.2.5 2004/05/21 18:07:48 dries Exp $
+// $Id: user.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 /*** Common functions ******************************************************/
 
@@ -796,7 +796,8 @@
       $error = t("Public registrations have been disabled by the site administrator.");
     }
     else {
-      $success = true;
+      $error = implode('' , module_invoke_all('user', 'new validate', $edit));
+      if (!$error) $success = true;
     }
   }
 
@@ -862,6 +863,7 @@
   }
   $output .= form_textfield(t("Username"), 'name', $edit['name'], 30, 64, t("Your full name or your preferred username: only letters, numbers and spaces are allowed."));
   $output .= form_textfield(t("E-mail address"), "mail", $edit['mail'], 30, 64, t("A password and instructions will be sent to this e-mail address, so make sure it is accurate."));
+  $output .= implode('', module_invoke_all('user', 'new form'));
   $output .= form_submit(t("Create new account"));
   $items[] = l(t("Request new password"), "user/password");
   $items[] = l(t("Log in"), "user/login");
diff -urN drupal-4.4.2/modules/watchdog.module drupal4blog/modules/watchdog.module
--- drupal-4.4.2/modules/watchdog.module	Thu Apr 15 22:05:58 2004
+++ drupal4blog/modules/watchdog.module	Sun Jul 11 22:50:57 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: watchdog.module,v 1.94.2.1 2004/04/15 14:05:58 unconed Exp $
+// $Id: watchdog.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
 
 function watchdog_help($section = "admin/help#watchdog") {
   $output = "";
diff -urN drupal-4.4.2/modules/week.module drupal4blog/modules/week.module
--- drupal-4.4.2/modules/week.module	Thu Jan  1 07:30:00 1970
+++ drupal4blog/modules/week.module	Sun Jul 11 22:50:57 2004
@@ -0,0 +1,172 @@
+<?php
+// $Id: week.module,v 1.1 2004/07/11 14:50:57 jseng Exp $
+
+function week_help($section) {
+  switch($section) {
+    case "admin/system/modules/week":
+      $output = "";
+      break;
+    case "admin/system/modules#description":
+      $output = "Create block containing a list of weekly archives.";
+      break;
+    default:
+      $output = "";
+      break;
+  }
+  return $output;
+}
+
+function week_perm(){
+  return array("administer week");
+}
+
+function _archive_param(){
+    // node report or blog/book/whatever?
+    $page_type = arg(0);
+    switch ($page_type){
+      case 'week':
+        $node_type = arg(1);
+        if (arg(3)){
+          $user_no = arg(2);
+        }
+        break;
+      case 'blog':
+        $node_type = $page_type;
+        if(arg(1)) {
+          if (arg(1) !== 'add')
+          $user_no = arg(1);
+        }
+      case 'node':
+      case 'story':
+        $node_type = $page_type;
+        if (arg(2)){
+          $start_node = arg(2);
+        } elseif(arg(1)) {
+          if (arg(1) !== 'add')
+          $user_no = arg(1);
+        }
+        break;
+      default:
+        return;
+        break;
+    }
+  $request_params= array("page_type" => $page_type, "node_type" => $node_type, "user_no" => $user_no);
+  return $request_params;
+}
+
+function _week_block_params($param_array){
+
+  $output = $param_array["node_type"] ? $param_array["node_type"] != "node" ? 'type = "'.$param_array["node_type"].'"':"":"";
+  $output .= !empty($output)&&!empty($param_array["user_no"])? ' AND ':'';
+  $output .= $param_array["user_no"] ? 'uid = '.$param_array["user_no"] :"";
+  return $output;
+}
+
+function _week_path_builder($param_array){
+  $output = 'week/';
+  $output .= $param_array["node_type"].'/';
+  $output .= !empty($param_array["user_no"]) ? $param_array["user_no"].'/':'';
+  return $output;
+}
+
+function week_block($op='list', $delta=0) {
+
+  // listing of blocks, such as on the admin/system/block page
+  if ($op == "list") {
+    $block[0]["info"] = t("Weekly Archives");
+    return $block;
+  } else {
+  // our block content
+    $block_content = '';
+    $block['subject'] = t("Weekly Archives");
+
+    // first post for node type (and user?)
+    $sql_params = _archive_param();
+    if (!empty($sql_params["node_type"])){
+      $sql_selector = _week_block_params($sql_params);
+      $query = 'SELECT MIN(created) AS created, MAX(created) AS max_created from {node}';
+      $query .= empty($sql_selector) ? '':' WHERE '.$sql_selector;
+
+      $query_result = db_fetch_object(db_query($query));
+      $first_post_date = $query_result->created;
+      $last_post_date = $query_result->max_created;
+      $start_day = variable_get('default_firstday', 0);
+
+      $date_data = getdate($first_post_date);
+      $start_date = mktime(0,0,0, $date_data["mon"], $date_data["mday"] - ($date_data["wday"] - $start_day), $date_data["year"]);
+
+      $date_data = getdate($last_post_date);
+      $end_date = mktime(0,0,0, $date_data["mon"], $date_data["mday"] + (6 -($date_data["wday"] - $start_day)), $date_data["year"]);
+
+      $arc_path = _week_path_builder($sql_params);
+      while ($start_date < $end_date) {
+        // make anchor
+        $block_content[] = l(t(date('m/d/y',$start_date).' - '.date('m/d/y',$start_date+ 518400)),
+                            $arc_path.$start_date).'<br />';
+
+        // decrement $start_date by a week
+        $start_date += (604800); // a week of seconds
+      }
+      // set up the block
+      $block_content = array_reverse($block_content);
+      $block['content'] = theme_links($block_content, '');
+    }
+    return $block;
+  }
+}
+
+
+function _weekly_contentQuery($query_date, $param_array){
+  $date_data =  getdate($query_date);
+  $start_date = $query_date;
+  $end_date = mktime(23, 59, 59, $date_data['mon'],($date_data['mday'] + 6), $date_data['year']);
+  $sql_selector = _week_block_params($param_array);
+  // create the SQL for the query
+  $query_info[0] = 'SELECT n.nid from node n where (created >= '.$start_date.') and (created <= '.$end_date.') AND (status = 1)';
+  $query_info[0] .=  $sql_selector ? ' AND '.$sql_selector:'';
+  $query_info[0] .= ' ORDER BY n.created DESC';
+  $query_info[1] = $start_date;
+  $query_info[2] = $end_date;
+  return $query_info;
+}
+
+function _weekly_page() {
+
+  global $base_url;
+
+  $paginate_output = variable_get('archive_lister_paginate', 1);
+  if (arg(3)){
+    $arcdate = arg(3);
+  } else {
+    $arcdate = arg(2);
+  }
+  // create the appropriate query
+  $param_array = _archive_param();
+  $query = _weekly_contentQuery($arcdate, $param_array);
+
+  if ($paginate_output){
+    $query_result = pager_query($query[0], variable_get("default_nodes_main", 10));
+  } else{
+    $query_result = db_query($query[0]);
+  }
+
+  // for each node returned by the query, theme the node and append it to the output string
+  while ($outnode = db_fetch_object($query_result)){
+    $output .= node_view(node_load(array("nid" => $outnode->nid)), 1);
+  }
+
+  $output .= theme('pager', NULL, variable_get("default_nodes_main", 20));
+
+  // if there's no output, don't let them stare at a blank page
+  $output = $output? $output:t("Sorry, there are no entries for this week.");
+  // return the output string
+  print theme('page', $output, t('Week of '.date('F d, Y', $query[1]).' to '.date('F d, Y', $query[2])));
+}
+
+function week_link($type, $node=0) {
+  if (($type == "system")) {
+    menu('week', t("Weekly Archive List"), "_weekly_page", NULL, 1);
+  }
+}
+
+?>
diff -urN drupal-4.4.2/scripts/code-style.pl drupal4blog/scripts/code-style.pl
--- drupal-4.4.2/scripts/code-style.pl	Sun Dec 28 18:40:17 2003
+++ drupal4blog/scripts/code-style.pl	Sun Jul 11 22:32:33 2004
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-# $Id: code-style.pl,v 1.8 2003/12/28 10:40:17 dries Exp $
+# $Id: code-style.pl,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 # Author: Alexander Schwartz (alexander.schwartz@gmx.net)
 # Licence: GPL
@@ -9,7 +9,7 @@
 # code.  This program tries to show as many improvements as possible with
 # no false positives.
 
-# $Id: code-style.pl,v 1.8 2003/12/28 10:40:17 dries Exp $
+# $Id: code-style.pl,v 1.2 2004/07/11 14:32:33 jseng Exp $
 
 $comment = 0;
 $program = 0;
diff -urN drupal-4.4.2/themes/chameleon/chameleon.theme drupal4blog/themes/chameleon/chameleon.theme
--- drupal-4.4.2/themes/chameleon/chameleon.theme	Fri Apr 23 14:13:54 2004
+++ drupal4blog/themes/chameleon/chameleon.theme	Sun Jul 11 22:39:19 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: chameleon.theme,v 1.9.2.1 2004/04/23 06:13:54 dries Exp $
+// $Id: chameleon.theme,v 1.1 2004/07/11 14:39:19 jseng Exp $
 
 function chameleon_help($section) {
 
diff -urN drupal-4.4.2/themes/chameleon/common.css drupal4blog/themes/chameleon/common.css
--- drupal-4.4.2/themes/chameleon/common.css	Wed Mar 31 06:15:20 2004
+++ drupal4blog/themes/chameleon/common.css	Sun Jul 11 22:39:19 2004
@@ -1,4 +1,4 @@
-/* $Id: common.css,v 1.2.2.1 2004/03/30 22:15:20 dries Exp $ */
+/* $Id: common.css,v 1.1 2004/07/11 14:39:19 jseng Exp $ */
 
 /*
 ** HTML elements
diff -urN drupal-4.4.2/themes/chameleon/marvin/chameleon.css drupal4blog/themes/chameleon/marvin/chameleon.css
--- drupal-4.4.2/themes/chameleon/marvin/chameleon.css	Wed Mar 31 06:15:20 2004
+++ drupal4blog/themes/chameleon/marvin/chameleon.css	Sun Jul 11 22:50:58 2004
@@ -1,4 +1,4 @@
-/* $Id: chameleon.css,v 1.3.2.1 2004/03/30 22:15:20 dries Exp $ */
+/* $Id: chameleon.css,v 1.1 2004/07/11 14:50:58 jseng Exp $ */
 
 /*
 ** HTML elements
diff -urN drupal-4.4.2/themes/chameleon/pure/chameleon.css drupal4blog/themes/chameleon/pure/chameleon.css
--- drupal-4.4.2/themes/chameleon/pure/chameleon.css	Wed Mar 31 06:15:21 2004
+++ drupal4blog/themes/chameleon/pure/chameleon.css	Sun Jul 11 22:50:58 2004
@@ -1,4 +1,4 @@
-/* $Id: chameleon.css,v 1.2.2.1 2004/03/30 22:15:21 dries Exp $ */
+/* $Id: chameleon.css,v 1.1 2004/07/11 14:50:58 jseng Exp $ */
 
 /*
 ** HTML elements
diff -urN drupal-4.4.2/themes/example/example.theme drupal4blog/themes/example/example.theme
--- drupal-4.4.2/themes/example/example.theme	Mon Nov 10 07:27:17 2003
+++ drupal4blog/themes/example/example.theme	Sun Jul 11 22:39:19 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: example.theme,v 1.38 2003/11/09 23:27:17 dries Exp $
+// $Id: example.theme,v 1.1 2004/07/11 14:39:19 jseng Exp $
 
 function example_help($section) {
 
diff -urN drupal-4.4.2/themes/simple/CREDITS drupal4blog/themes/simple/CREDITS
--- drupal-4.4.2/themes/simple/CREDITS	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/CREDITS	Sat Jun 12 04:50:46 2004
@@ -0,0 +1,4 @@
+This theme is based on phptemplate (MovableType) which is based on 
+marvin_2k which is based on the original marvin theme.
+
+This theme was made by James Seng.
diff -urN drupal-4.4.2/themes/simple/INSTALL drupal4blog/themes/simple/INSTALL
--- drupal-4.4.2/themes/simple/INSTALL	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/INSTALL	Sat Jun 12 04:50:46 2004
@@ -0,0 +1,21 @@
+********************************************************************
+                     D R U P A L    T H E M E                       
+********************************************************************
+Name: simple
+Author: James Seng
+Email jseng_at_pobox.org.sg
+
+********************************************************************
+INSTALLATION:
+
+****
+* Please make sure you install and *enable* tag.module before installing
+* this theme! It would work but not very well without it!
+****
+
+1. Copy the directory "simple" to your themes directory. 
+2. Create the table neccessary (see simple.mysql)
+3. Goto administer->configuration to configure your File System properly
+   (make sure it is created or writable)
+4. Goto administer->configuration->themes and enable the simple theme.
+5. Goto administer->configuration->themes->simple to configure your templates.
diff -urN drupal-4.4.2/themes/simple/default/block.tpl.raw drupal4blog/themes/simple/default/block.tpl.raw
--- drupal-4.4.2/themes/simple/default/block.tpl.raw	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/default/block.tpl.raw	Sat Jun 12 04:50:46 2004
@@ -0,0 +1,6 @@
+<$DPIfContent$>
+<div class="block block-<$DPBlockModule$>">
+  <h2><$DPBlockTitle$></h2>
+  <div class="content"><$DPContent$></div>
+  </div>
+<$DPEndIf$>
diff -urN drupal-4.4.2/themes/simple/default/comment.tpl.raw drupal4blog/themes/simple/default/comment.tpl.raw
--- drupal-4.4.2/themes/simple/default/comment.tpl.raw	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/default/comment.tpl.raw	Sat Jun 12 04:50:46 2004
@@ -0,0 +1,24 @@
+<$DPIfComment$>
+  <div class="comment-depth-<$DPCommentDepth$>">
+  <$DPIfCommentNew$> 
+    <a id="new"></a>
+  <$DPEndIf$>
+  <a id="comment-<$DPCommentID$>"></a>
+  <$DPIfCommentVisible$>
+  <div class="comment<$DPIfCommentNew$> comment-new<$DPEndIf$>">
+    <$DPIfCommentNew$><span class="new">new</span><$DPEndIf$>
+    <$DPIfCommentShowTitle$><div class="title"><$DPCommentTitle$></div><$DPEndIf$>
+    <div class="content"><$DPContent$></div>
+    <div class="author"> Posted by <$DPCommentName$> on <$DPCommentDate('medium')$></div>
+    <$DPIfLinks$>
+    <div class="links"><$DPForEachLink$><$DPIfFirstLink$><$DPLink$><$DPElse$> | <$DPLink$><$DPEndIf$><$DPEndForEach$></div>
+    <$DPEndIf$>
+  </div>
+  <$DPElse$>
+  <div class="<$DPIfCommentNew$>comment-new <$DPEndIf$>comment-folded">
+    <$DPIfCommentNew$><span class="new">new</span><$DPEndIf$>
+    <span class="subject"><$DPCommentTitleLink$> by <$DPCommentName$></span>
+  </div>
+  <$DPEndIf$>
+  </div>
+<$DPEndIf$>
diff -urN drupal-4.4.2/themes/simple/default/node.tpl.raw drupal4blog/themes/simple/default/node.tpl.raw
--- drupal-4.4.2/themes/simple/default/node.tpl.raw	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/default/node.tpl.raw	Tue Jun 15 23:46:20 2004
@@ -0,0 +1,15 @@
+   <div class="node">
+      <h2 class="date"><$DPNodeDate('F d, Y')$></h2>
+      <h2><a href="<$DPNodeURL$>" title="<$DPNodeTitle$>"><$DPNodeTitle$></a></h2>
+    <$DPIfCategories$><div class="info">&raquo; <$DPForEachCategory$><$DPCategory$> <$DPEndForEach$></div><$DPEndIf$>
+    <$DPIfNode('static')$><div class="static">(static)</div><$DPEndIf$>
+    <div class="content">
+      <$DPContent$>
+    </div>
+    <div class="info">
+       Posted by <$DPNodeName$> on <$DPNodeDate('medium')$>
+      <$DPIfLinks$>
+         :: <$DPForEachLink$><$DPIfFirstLink$><$DPLink$><$DPElse$> | <$DPLink$><$DPEndIf$><$DPEndForEach$>
+      <$DPEndIf$>
+    </div>
+  </div>
diff -urN drupal-4.4.2/themes/simple/default/page.tpl.raw drupal4blog/themes/simple/default/page.tpl.raw
--- drupal-4.4.2/themes/simple/default/page.tpl.raw	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/default/page.tpl.raw	Mon Jun 21 19:23:07 2004
@@ -0,0 +1,95 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
+    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+  <title><$DPTitle$></title>
+  <meta http-equiv="content-type" content="text/html;charset=utf-8" />
+  <meta http-equiv="Content-Style-Type" content="text/css" />
+  <link rel="stylesheet" href="<$DPSimpleCSS$>"  type="text/css" />
+  <$DPHeaders$>
+</head>
+
+<body <$DPOnLoads$>>
+<div class="pageFrame" id="nodeFrame">
+  <div id="header">
+    <$DPIfSiteName$>
+      <a href="<$DPSiteURL$>" title="Index Page"><h1 id="site-name"><$DPSiteName$></h1></a>
+    <$DPEndIf$>
+    <$DPIfSiteSlogan$>
+      <span id="site-slogan"><$DPSiteSlogan$></span>
+    <$DPEndIf$>
+  </div>
+  
+  <div class="main-content" id="content-<$DPSiteLayout$>">
+   <$DPIfBreadcrumbs$>
+    <div id="breadcrumb">
+    <$DPForEachBreadcrumb$>
+       <$DPIfFirstBreadcrumb$>
+         <$DPBreadcrumb$>
+       <$DPElse$>
+        :: <$DPBreadcrumb$>
+       <$DPEndIf$>
+    <$DPEndForEach$>
+    </div>
+   <$DPEndIf$>
+  <$DPIfSiteMission$>
+    <p id="mission"><$DPSiteMission$></p>
+  <$DPEndIf$>
+   <$DPIfHelp$>
+    <p id="help"><$DPHelp$></p>
+   <$DPEndIf$>
+  <$DPIfMessages$>
+    <p id="help">
+    <$DPForEachMessage$>
+      <li><$DPMessage$></li>
+    <$DPEndForEach$>
+    </p>
+   <$DPEndIf$>
+
+  <!-- start main content -->
+  <$DPContent$>
+  <!-- end main content -->
+
+    <div id="footer">
+      <$DPIfSiteFooter$>
+        <p><$DPSiteFooter$></p>
+      <$DPEndIf$>
+      Validate <a href="http://validator.w3.org/check/referer">XHTML</a> or <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a>.
+    </div><!-- footer -->
+  </div><!-- mainContent -->
+
+<!--  
+  <$DPIfLinks$>
+    <ul id="main-nav">
+    <$DPForEachLink$>
+     <li><$DPLink$></li>
+    <$DPEndForEach$>   
+    </ul>
+  <$DPEndIf$>
+-->
+
+  <$DPIfUserAccess('search content')$>
+  <form action="<$DPSiteURL('search')$>" method="post">
+    <div id="search">
+      <input class="form-text" type="text" size="15" value="" name="keys" /><input class="form-submit" type="submit" value="Search" />
+    </div>
+  </form>
+  <$DPEndIf$>
+
+  <$DPIfSidebar('left')$>
+    <div class="sidebar" id="sidebar-left">
+      <$DPSidebar('left')$>
+    </div>
+  <$DPEndIf$>
+
+  <$DPIfSidebar('right')$>
+    <div class="sidebar" id="sidebar-right">
+      <$DPSidebar('right')$><br class="clear" />
+    </div>
+  <$DPEndIf$>
+    
+</div><!-- pageFrame -->
+<$DPFooters$>
+  </body>
+</html>
diff -urN drupal-4.4.2/themes/simple/default/site-styles.css drupal4blog/themes/simple/default/site-styles.css
--- drupal-4.4.2/themes/simple/default/site-styles.css	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/default/site-styles.css	Mon Jun 21 19:25:43 2004
@@ -0,0 +1,452 @@
+/* layout.css */
+
+body {
+	padding: 0;
+	margin: 0;
+	}
+
+.pageFrame, #nodeFrame {
+  margin: 0;
+  padding: 0;
+  width: 100%;
+  position: relative;
+  }
+
+#header
+{
+	padding: 0px;
+	margin: 0px 0px 0px 0px;
+	height: 100px;
+}
+
+#header img { 
+        margin: 0 10px 0 30px;
+        }
+
+#main-nav {
+	position: absolute;
+	top: 10px;
+	right: 0px;
+	margin: 0;
+	padding: 0px;
+	height: 25px;
+	}
+
+#search { 
+	position: absolute;
+	top: 50px;
+	right: 10px;
+	margin: 0;
+	padding: 0px;
+	height: 25px;
+	}
+
+#sidebar-left {
+	position: absolute;
+	top: 100px;
+	right: auto;
+	left: 5px;
+	margin: 0;
+	padding: 0;
+	width: 190px;
+	}
+
+#sidebar-right {
+	position: absolute;
+	top: 100px;
+	right: 0;
+	left: auto;
+	margin: 0;
+	padding: 0;
+	width: 190px;
+	}
+
+.main-content
+{
+	position: relative;
+	margin: 0px;
+	padding: 0px 0 10px 0;
+}
+
+#content-left {
+	margin-left: 200px;
+	}
+
+#content-right {
+	margin-right: 200px;
+	}
+
+#content-both{
+	margin: 10px 200px;
+	}
+
+#footer
+{
+	margin: 10px 10px 0 10px;
+	clear: both;
+	padding-top: 20px;
+	padding-bottom: 10px;
+}
+
+/* style.css */
+
+a,
+a:link,
+a:visited {
+ color: #003366; text-decoration: underline;
+}
+
+a:active,
+a:hover  {
+ color: #999999;  
+}
+
+h1, h2, h3 {
+  margin: 0px;
+  padding: 0px;
+}
+
+#header {
+  font-family:palatino,  georgia, verdana, arial, sans-serif;
+  color:#333;
+  font-size:x-large;
+  font-weight:normal;  
+  padding:15px;
+  border-top:4px double #666;
+}
+
+#header a,
+  #banner a:link,
+  #banner a:visited,
+  #banner a:active,
+  #banner a:hover {
+  font-family: palatino,  georgia, verdana, arial, sans-serif;
+  font-size: xx-large;
+  color: #333;
+  text-decoration: none;
+}
+
+.description {
+  font-family:palatino,  georgia, times new roman, serif;
+  color:#333;
+  font-size:small;
+  text-transform:none;  
+}
+  
+.main-content {
+  position:absolute;
+  background:#FFF;
+  margin-right:20px;
+  margin-left:225px;
+  margin-bottom:20px;
+  border:1px solid #FFF;  
+}
+
+.node,
+.comment
+{
+  padding:15px;
+  background:#FFF; 
+}
+
+.node .content,
+.comment .content {
+  font-family:palatino, georgia, verdana, arial, sans-serif;
+  color:#333;
+  font-size:small;
+  font-weight:normal;
+  background:#FFF;
+  line-height:200%;
+}
+
+.content a,
+.content a:link,
+.content a:visited,
+.content a:active,
+.content a:hover {
+  font-weight: normal;
+  text-decoration: underline;
+}
+
+.node h2,
+.comment .title,
+.box h2,
+.node h2 a  {
+  font-family: palatino, georgia, times new roman, serif;
+  font-size: medium;
+  color: #666;
+  text-decoration: none;
+}  
+
+.node h2.date  { 
+  font-family:palatino, georgia, times new roman, serif; 
+  font-size: large; 
+  color: #333; 
+  border-bottom:1px solid #999;
+  margin-bottom:10px;
+  font-weight:bold;
+}  
+
+.node .info,
+.comment .author,
+.comment .links 
+{ 
+  font-family:verdana, arial, sans-serif; 
+  font-size: x-small; 
+  color: #000000; 
+  margin-bottom:25px;
+}
+
+.calendar {
+  font-family:verdana, arial, sans-serif;
+  color:#666;
+  font-size:x-small;
+  font-weight:normal;
+  background:#FFF;
+  line-height:140%;
+  padding:2px;
+  text-align:left;
+}
+
+.calendar table,
+.calendar td,
+.calendar tr,
+.calendar th
+{
+  border: none;
+}
+
+.calendar caption {  
+  font-family:palatino, georgia, times new roman, serif;
+  color:#333;
+}  
+  
+.sidebar {
+  font-family:verdana, arial, sans-serif;
+  color:#333;
+  font-size:x-small;
+  font-weight:normal;
+  background:#FFF;
+  line-height:140%;
+  padding:2px;  
+}  
+  
+.sidebar h2 {
+  font-family:palatino, georgia, times new roman, serif;
+  color:#666600;
+  font-size:small;
+  font-weight:normal;
+  padding:2px;
+  margin-top:30px;
+  letter-spacing: .3em;
+  background:#FFF;
+  text-transform:uppercase;  
+}  
+  
+input, textarea {
+  background-color: #eeeeee;
+  color: inherit;
+  border: 1px solid #999;
+  font-family:palatino, georgia, verdana, arial, sans-serif;
+  color:#333;
+  font-size:small;
+  font-weight:normal;
+  background:#FFF;
+  line-height:200%;
+}
+
+select {
+  background-color: #eeeeee;
+  color: inherit;
+   margin: 0 5px;
+  font-family:palatino, georgia, verdana, arial, sans-serif;
+  color:#333;
+  font-size:small;
+  font-weight:normal;
+  background:#FFF;
+  line-height:200%;
+}
+
+input:focus, textarea:focus {
+  background: #fff none;
+  border: 1px solid #036;
+}
+
+/* modules.css */
+
+/*** TRACKER ***/
+#tracker table {
+	border-collapse: collapse;
+	}
+
+#tracker td {
+	vertical-align: top;
+	padding: 1em;
+	}
+
+#tracker td ul {
+	margin-top: 0;
+	margin-bottom: 0;
+	}
+
+#tracker td ul a {
+	font-weight: normal;
+	}
+
+#tracker th {
+	text-align: left;
+	padding: 0.25em 1em 0.25em 0em;
+	}
+
+#tracker table { width: 99%; }
+#tracker th { text-align: left; border-bottom: 1px solid #ddd; }
+#tracker tr.light, #tracker tr.dark { background-color: transparent; }
+#tracker td { vertical-align: top; padding: 1em 1em 1em 0; border-bottom: 1px solid #ddd; }
+
+
+/*** CALENDER ***/
+.calendar .row-week td a {
+	display: block;
+	}
+
+.calendar a { text-decoration: none; }
+.calendar td { padding: 0; border-color: #888; }
+.calendar td div { padding: 0.4em 0; }
+.calendar .row-week td a { padding: 0.4em 0; }
+.calendar .day-today { background-color: #69c; }
+.calendar .day-normal { background-color: #ddd; }
+.calendar .day-future { background-color: #eee; }
+.calendar .day-today { background-color: #7ad; }
+.calendar .day-today a { color: #fff; }
+.calendar .day-selected { background-color: #7ad; color: #fff; }
+.calendar .header-month { background-color: #eee; }
+.calendar .header-week { }
+.calendar .day-blank { background: none; }
+.calendar .row-week td a:hover { background-color: #7ad; color: #000; }
+
+/*** POLL ***/
+#content .poll {
+	margin: 0.5em;
+	padding: 0.5em;
+	border: #ccc solid 1px;
+	}
+
+#sidebar .poll { }
+
+.poll-title {
+	font-weight: bold;
+	padding-bottom: 0.3em;
+	margin-bottom: 0.4em;
+	border-bottom: #ccc solid 1px;
+	}
+
+.poll .text {
+	margin-bottom: 0.3em;
+	font-size: 0.8em;
+	font-weight: bold;
+	}
+
+.poll .percent {
+	padding-bottom: 0.3em;
+	margin-bottom: 0.4em;
+	border-bottom: #ccc dashed 1px;
+	font-size: 0.8em;
+	}
+
+.poll .total { font-size: 0.8em; }
+.poll .bar { }
+
+.poll .bar .foreground {
+	height: 5px;
+	background-color: #aaa;
+	border: #ccc solid 1px;
+	}
+
+.poll .bar .background { }
+.poll .vote-form { font-size: 0.8em; }
+
+/*** BOOK STYLE ***/
+.book .title {
+	font-weight: bold;
+	font-size: 1em;
+	margin-bottom:1em;
+	}
+
+/*** FORUM STYLE ***/
+div#forum table {
+	width: 100%;
+	margin-bottom: 1em;
+	}
+
+#forum td {
+	padding: 0.5em 0.5em 0.5em 0.5em;
+	line-height: 1.2em;
+	}
+
+#forum td.statistics, #forum td.settings, #forum td.pager {
+	height: 1.5em;
+	border: 1px solid #bbb;
+	}
+
+#forum td.created, #forum td.posts, #forum td.topics, #forum td.last-reply, #forum td.replies, #forum td.pager {
+	white-space: nowrap;
+	}
+
+#forum td.posts, #forum td.topics, #forum td.replies, #forum td.pager {
+	text-align: center;
+	}
+
+div#forum table .topics,
+div#forum table .posts,
+div#forum table .last-reply {
+	font-size: 0.8em;
+	width: 5%;
+	}
+
+div#forum table .name,
+div#forum table .description,
+div#forum table .navigation {
+	margin: 0;
+	}
+
+div#forum table th {
+	white-space: nowrap;
+	}
+
+div#forum table .name {
+	font-size: 1.2em; margin: 0.5em;
+	font-weight: bold;
+	margin: 0;
+	}
+
+#forum .description, #forum .navigation {
+	font-size: 0.9em;
+	margin: 0.5em;
+	}
+
+div#forum table .description {
+	margin: 0;
+	}
+
+div#forum table .navigation {
+	font-weight: bold;
+	}
+
+div#forum table .topic {
+	width: 80%;
+	}
+
+div#forum table .icon {
+	width: 20px;
+	text-align: center;
+	}
+
+div#forum a {
+	font-weight: bold;
+	}
+
+div#forum table .created,
+div#forum table .replies {
+	font-size: 0.8em;
+	width: 5%;
+	}
diff -urN drupal-4.4.2/themes/simple/simple.mysql drupal4blog/themes/simple/simple.mysql
--- drupal-4.4.2/themes/simple/simple.mysql	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/simple.mysql	Sat Jun 12 04:50:46 2004
@@ -0,0 +1,11 @@
+--
+-- Table structure for table 'theme_simple'
+--
+
+CREATE TABLE theme_simple(
+  id        int(10) unsigned not null default '0',
+  name      varchar(32) not null,
+  php       longtext,
+  raw       longtext,
+  PRIMARY KEY  (id, name)
+) TYPE=MyISAM;
diff -urN drupal-4.4.2/themes/simple/simple.theme drupal4blog/themes/simple/simple.theme
--- drupal-4.4.2/themes/simple/simple.theme	Thu Jan  1 07:30:00 1970
+++ drupal4blog/themes/simple/simple.theme	Fri Jul  2 21:43:42 2004
@@ -0,0 +1,390 @@
+<?php
+/**
+  A theme that makes use of simple tags and css so users can customize
+  their site without knowing php.
+
+  This theme is based on phptemplate which is based on marvin_2k which
+  is based on the original marvin theme.
+
+  @author James Seng
+  @package theme_simple
+**/
+
+/*
+** Help messages
+*/
+function simple_help($section) {
+
+  $output = "";
+
+  switch ($section) {
+    case 'admin/system/themes#description':
+      break;
+  }
+
+  return $output;
+}
+
+/**
+* Build an html table of the available style and template options
+*/
+
+function simple_style_path($id = 0) {
+  global $base_url;
+  $css = file_create_path(variable_get('simple_theme_css'.$simple->id, simple_user_css($simple->id)));
+  if (file_exists($css))
+    return $base_url . "/" . $css;
+  return $base_url . "/themes/simple/default/site-styles.css";
+}
+
+function simple_save($simple) {
+  $simple->php = rtrim($simple->php);
+  $simple->raw = rtrim($simple->raw);
+  if (db_fetch_object(db_query("SELECT * FROM {theme_simple} WHERE name = '%s' AND id = %d", $simple->name, $simple->id))) {
+    db_query("UPDATE {theme_simple} SET php = '%s', raw = '%s' WHERE name = '%s' AND id = %d", $simple->php, $simple->raw, $simple->name, $simple->id);
+  } else {    
+    db_query("INSERT INTO {theme_simple} (id, name, php, raw) VALUES (%d, '%s', '%s', '%s')", $simple->id, $simple->name, $simple->php, $simple->raw);
+  }   
+}
+
+function simple_load($name, $id = 0) {
+  $simple = db_fetch_object(db_query("SELECT * FROM {theme_simple} WHERE name = '%s' AND id = %d", $name, $id));
+
+
+  if (!$simple || $simple->php == '') {
+    if ($id) {
+      // if it is other users and not define, just use default
+      $simple = simple_load($name,0);
+      $simple->id = $id;
+    } else {
+      // if it is default user, lets create it
+      $simple->name = $name;
+      $simple->id = $id;
+    
+      $func = 'simple_default_'.$name;
+      if (function_exists($func)) {
+        $simple->raw = $func(1); 
+        $simple->php = $func(0);
+      }
+      simple_save($simple);
+    }
+  }
+  return $simple;
+}
+
+function simple_delete($name = '', $id = 0) {
+  if ($name) {
+    db_query("DELETE FROM {theme_simple} WHERE name = '%s' AND id = %d", $name, $id);
+  } else {
+    if (!$id) return 0;
+    db_query("DELETE FROM {theme_simple} WHERE id = %d", $id);
+  }
+
+  return 1;
+}
+
+function simple_settings() {
+  $op = $_POST['op'];
+  $edit = $_POST['edit'];
+
+  $types = array(
+    'page'    => array('title' => t('Main Page')),
+    'css'     => array('title' => t('CSS')),
+    'block'   => array('title' => t('Block')),
+    'node'    => array('title' => t('Node')),
+    'comment' => array('title' => t('Comment')),
+    );
+
+  $id = 0; $name = 'page';
+
+  if (isset($edit['simple_template'])) {
+    $tp_user = user_load(array('name' => $edit['simple_template']));
+    if ($tp_user) $id = $tp_user->id;
+  }
+
+  if (isset($edit['simple_name']) && isset($types[$edit['simple_name']])) {
+    $name = $edit['simple_name'];
+    variable_set('simple_name',$edit['simple_name']);
+  } else {
+    variable_set('simple_name','page');
+  }
+
+  // Not done yet 
+  //
+  // $fd = opendir('themes/simple');
+  // while ($file = readdir($fd)) {
+  //  if (is_dir("themes/simple/$file") && !in_array($file, array('.', '..', 'CVS', '.svn', 'screenshots'))) {
+  //    $files[$file] = $file;
+  //  }
+  // }
+  // closedir($fd);
+  //
+  // $group = t('Different template will change the look and feel of your site. You may assign different templates to different users (bloggers) so they have their own default look and feel.')."<p/>";
+  // $group .= form_select(t('Template'), 'simple_template', variable_get('simple_template', 'default'), $files);
+
+  $group = t('Different template will change the look and feel of your site.').'<p/>';
+  foreach ($types as $key => $v) $titles[$key] = $v['title'];
+  $group .= form_select(t('Type'), 'simple_name', variable_get('simple_name', 'page'), $titles);
+  $group .= form_submit(t('Edit'));
+  // $group .= form_submit(t('Rebuild'));
+  $output = form_group(t('Editing Template'), $group);
+
+  switch ($op) {
+    case t('Edit'):
+      break;
+    case t('Rebuild'):
+      foreach ($types as $type => $info) {
+        $simple = simple_load($type,$id);
+        $simple->php = tag_process($simple->raw);
+        simple_save($simple);
+      }
+      break;
+    case t('Save configuration'):
+      if (isset($edit['simple_hidden_id'])
+      &&  isset($edit['simple_hidden_name'])
+      &&  isset($edit['simple_theme_edit'])) {
+        $simple->name = $edit['simple_hidden_name'];
+        $simple->id = $edit['simple_hidden_id'];
+        $simple->raw = $edit['simple_theme_edit'];
+        if (module_exist('tag'))
+          $simple->php = tag_process($simple->raw);
+        else
+          $simple->php = $simple->raw;
+        simple_save($simple);
+
+        // exception for css
+        if ($edit['simple_hidden_name'] == 'css' && file_check_directory(variable_get('file_directory_path', 'files'))) {
+          $fh = fopen(file_create_path(variable_get('simple_theme_css_'.$simple->id,simple_user_css($simple->id))), 'w');
+          fwrite($fh,$simple->php);
+          fclose($fh);
+        }
+      }
+      break;
+  }
+  $simple = simple_load($name,$id);
+
+  // exception for css
+  if ($simple->name == 'css') {
+    if (!file_check_directory(variable_get('file_directory_path', 'files'))) {
+      $error = theme('error', t('You have not configure file system path yet. Please check your %sysconf (under File System)', array('%sysconf', l(t('system configuration', 'admin/system')))));
+    }
+    $output .= form_textfield(t('CSS filename'), 'simple_theme_css_'.$simple->id, variable_get('simple_theme_css_'.$simple->id, simple_user_css($simple->id)), 70, 32, $error);
+  }
+
+  $output .= form_hidden('simple_hidden_name', $simple->name);
+  $output .= form_hidden('simple_hidden_id', $simple->id);
+  $output .= form_textarea($types[$name]['title'], 'simple_theme_edit', $simple->raw, 70, 20, $types[$name]['description']);
+
+  if ($name != 'css') {
+    $output .= form_checkbox(t('Show PHP'), 'simple_theme_show_php', 1, variable_get('simple_theme_show_php',0));
+  
+    if (variable_get('simple_theme_show_php',0) == 1)
+      $output .= form_textarea("PHP ".$types[$name]['title'], 'simple_theme_php_edit', $simple->php, 70, 20, t('Please note that editing the PHP has no effect. You must edit the main text in the textarea above.'));
+  }
+  
+  return $output;
+}
+
+function simple_page($content, $title = NULL, $breadcrumb = NULL) {
+  if (isset($title)) drupal_set_title($title);
+
+  if (isset($breadcrumb)) drupal_set_breadcrumb($breadcrumb);
+  
+  // TODO : check for which userid to return simple theme
+  $simple = simple_load('page',0);
+  
+  $result = simple_process($simple, array(
+      "content"  => $content,
+      'links'    => link_page(),
+      ));
+
+  // lets clear the message
+  drupal_get_messages();
+
+  return $result;
+}
+
+function simple_block($block) {
+  $simple = simple_load('block',0);
+  $result = simple_process($simple, array(
+    'block'   => $block,
+    'content' => $block->content,
+  ));
+  return $result;
+}
+
+function simple_node($node, $main = 0, $page = 0) {
+  if (module_exist("taxonomy")) {
+    $taxonomy = taxonomy_link("taxonomy terms", $node);
+  } 
+
+  $simple = simple_load('node',0);
+  
+  $result  = simple_process($simple, array(
+      'node'  => $node,
+      'taxonomy' => $taxonomy,
+      'links'    => link_node($node,$main),
+      'content'  => ($main && $node->teaser) ? $node->teaser : $node->body,
+      'main'     => $main,
+      'page'     => $page,
+      ));
+
+  return $result;
+}
+
+function simple_box($subject, $content, $region = "main") {
+  $output  = "  <div class=\"box\">\n";
+  $output .= "    <h2>$subject</h2>\n";
+  $output .= "    <div class=\"content\">$content</div>\n";
+  $output .= "  </div>\n";
+  return $output;
+}
+
+function simple_comment_root($comment, $links = 0) {
+  $simple = simple_load('comment',0);
+  $result = simple_process($simple, array(
+    'comment' => $comment,
+    'content' => $comment->comment,
+    'links'   => $links,
+  ));
+  return $result;
+}
+
+function simple_comment($comment, $links = 0) {
+  return simple_comment_root($comment, $links);
+}
+
+function simple_comment_view($comment, $links = "", $visible = 1) {
+  if (node_is_new($comment->nid, $comment->timestamp)) {
+    $comment->new = 1;
+  }
+  
+  $links = ($links ? comment_links($comment,0) : 0);
+
+  $comment->comment = check_output($comment->comment);
+
+  $comment->visible = $visible;
+
+  return simple_comment_root($comment,$links);
+}
+
+function simple_comment_flat_collapsed($comment, $threshold) {
+  if (comment_visible($comment, $threshold)) {
+    if ($comment->selected) {
+      return theme("comment_view", $comment, comment_links($comment));
+    }
+    else {
+      return theme("comment_view", $comment, "", 0);
+    }
+  }
+  return "";
+}
+
+function simple_comment_thread_min($comment, $threshold, $pid = 0, $cid = 0) {
+  $output = "";
+  if (comment_visible($comment, $threshold)) {
+    //$output = "<div style=\"margin-left: ". ($comment->depth * 10) ."px\">";
+    if ($comment->selected) {
+      $output .= theme("comment_view", $comment, comment_links($comment));
+    }
+    else {
+      $output .= theme("comment_view", $comment, "", 0);
+    }
+    //$output .= "</div>\n";
+  }
+  return $output;
+}
+
+function simple_comment_thread_max($comment, $threshold, $level = 0) {
+  $output = "";
+  if ($comment->depth) {
+    //$output .= "<div style=\"margin-left: ". ($comment->depth * 10) ."px\">";
+  }
+
+  $output .= theme("comment_view", $comment, comment_links($comment, 0), comment_visible($comment, $threshold));
+
+  if ($comment->depth) {
+    //$output .= "</div>\n";
+  }
+  return $output;
+}
+
+function simple_notmember() {
+  return '<span class="marker">*</span>';
+}
+
+function simple_process($simple, $vars = array()) {
+  extract($vars);
+  ob_start();
+  $result = eval("?>".$simple->php."<?php return 'success!'; ?>");
+  $contents = ob_get_contents();
+  ob_end_clean();
+
+  // detect error. if it cant process to the end, then we have an error
+  if ($result == 'success!')
+    return $contents;
+
+  drupal_set_message("Error processing template '".$simple->name."' (id ".$simple->id.")",'error');
+
+  $func = 'simple_default_'.$simple->name;
+  if (!function_exists($func)) {
+    // lets try to return whatever we have...
+    return $content;
+  }
+
+  // if the default fails, too bad...
+  $php = $func(0);
+  ob_start();
+  @eval("?>".$php);
+  $contents = ob_get_contents();
+  ob_end_clean();
+
+  return $content;
+}
+
+function simple_user_css($id = 0) {
+  if ($id) {
+    $user = user_load(array('id' => $id));
+    return $user->name . '.css';
+  }
+  return 'site-styles.css';
+}
+
+function simple_read_file($filename) {
+  $fh = fopen($filename,'rb');
+  while (!feof($fh))
+    $input .= fgets($fh,1024);
+  fclose($fh);
+  return $input;
+}
+
+function simple_default_page($raw = 0) {
+  $filename = realpath('themes/simple/default/page.tpl.raw');
+  if ($raw) return simple_read_file($filename);
+  return tag_process(simple_read_file($filename));
+}
+
+function simple_default_css($raw = 0) {
+  $filename = realpath('themes/simple/default/site-styles.css');
+  return simple_read_file($filename);
+}
+
+function simple_default_node($raw = 0) {
+  $filename = realpath('themes/simple/default/node.tpl.raw');
+  if ($raw) return simple_read_file($filename);
+  return tag_process(simple_read_file($filename));
+}
+
+function simple_default_block($raw = 0) {
+  $filename = realpath('themes/simple/default/block.tpl.raw');
+  if ($raw) return simple_read_file($filename);
+  return tag_process(simple_read_file($filename));
+}
+
+function simple_default_comment($raw = 0) {
+  $filename = realpath('themes/simple/default/comment.tpl.raw');
+  if ($raw) return simple_read_file($filename);
+  return tag_process(simple_read_file($filename));
+}
+
+?>
diff -urN drupal-4.4.2/themes/xtemplate/default/xtemplate.css drupal4blog/themes/xtemplate/default/xtemplate.css
--- drupal-4.4.2/themes/xtemplate/default/xtemplate.css	Sun Feb 15 22:54:39 2004
+++ drupal4blog/themes/xtemplate/default/xtemplate.css	Sun Jul 11 22:50:59 2004
@@ -1,4 +1,4 @@
-/* $Id: xtemplate.css,v 1.1 2004/02/15 14:54:39 dries Exp $ */
+/* $Id: xtemplate.css,v 1.1 2004/07/11 14:50:59 jseng Exp $ */
 
 /*
 ** HTML elements
diff -urN drupal-4.4.2/themes/xtemplate/pushbutton/xtemplate.css drupal4blog/themes/xtemplate/pushbutton/xtemplate.css
--- drupal-4.4.2/themes/xtemplate/pushbutton/xtemplate.css	Wed Apr 14 02:13:07 2004
+++ drupal4blog/themes/xtemplate/pushbutton/xtemplate.css	Sun Jul 11 22:50:59 2004
@@ -1,4 +1,4 @@
-/* $Id: xtemplate.css,v 1.3.2.4 2004/04/13 18:13:07 dries Exp $ */
+/* $Id: xtemplate.css,v 1.1 2004/07/11 14:50:59 jseng Exp $ */
 
 /*
 ** HTML elements
diff -urN drupal-4.4.2/themes/xtemplate/xtemplate.inc drupal4blog/themes/xtemplate/xtemplate.inc
--- drupal-4.4.2/themes/xtemplate/xtemplate.inc	Tue Dec 30 01:14:27 2003
+++ drupal4blog/themes/xtemplate/xtemplate.inc	Sun Jul 11 22:39:20 2004
@@ -33,7 +33,7 @@
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
-  $Id: xtemplate.inc,v 1.6 2003/12/29 17:14:27 dries Exp $
+  $Id: xtemplate.inc,v 1.1 2004/07/11 14:39:20 jseng Exp $
 
 */
 
diff -urN drupal-4.4.2/themes/xtemplate/xtemplate.theme drupal4blog/themes/xtemplate/xtemplate.theme
--- drupal-4.4.2/themes/xtemplate/xtemplate.theme	Sat Mar  6 19:07:16 2004
+++ drupal4blog/themes/xtemplate/xtemplate.theme	Sun Jul 11 22:39:20 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: xtemplate.theme,v 1.56 2004/03/06 11:07:16 dries Exp $
+// $Id: xtemplate.theme,v 1.1 2004/07/11 14:39:20 jseng Exp $
 
 if (!class_exists("XTemplate")) {
   include_once("themes/xtemplate/xtemplate.inc");
diff -urN drupal-4.4.2/update.php drupal4blog/update.php
--- drupal-4.4.2/update.php	Thu Feb 26 06:20:08 2004
+++ drupal4blog/update.php	Sun Jul 11 22:39:19 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: update.php,v 1.136 2004/02/25 22:20:08 dries Exp $
+// $Id: update.php,v 1.1 2004/07/11 14:39:19 jseng Exp $
 /*
 ** USAGE:
 **
diff -urN drupal-4.4.2/xmlrpc.php drupal4blog/xmlrpc.php
--- drupal-4.4.2/xmlrpc.php	Tue Jan 27 02:51:37 2004
+++ drupal4blog/xmlrpc.php	Sun Jul 11 22:39:19 2004
@@ -1,5 +1,5 @@
 <?php
-// $Id: xmlrpc.php,v 1.6 2004/01/26 18:51:37 dries Exp $
+// $Id: xmlrpc.php,v 1.1 2004/07/11 14:39:19 jseng Exp $
 
 include_once "includes/bootstrap.inc";
 include_once "includes/common.inc";
