diff --git a/CHANGELOG b/CHANGELOG
index 3acd4d1c2c6fd5fef7d8ec9bf317de929dbb472c..66a037c47bf9c89eba68bdb82e59324319e88bd5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,7 +2,6 @@ drupal x.xx, xx/xx/xxxx
 -----------------------
 - major overhaul of the entire underlying design:
     * everything is based on nodes: nodes are a conceptual "black box" to couple and manage different types of content and that promotes reusing existing code, thus reducing the complexity and size of drupal as well as improving long-term stability.
-    * introduced links/drupal tags: [[link]]
 - rewrote submission/moderation queue:
     * renamed submission.module to moderation.module
     * updated submission forms
@@ -11,17 +10,26 @@ drupal x.xx, xx/xx/xxxx
 - removed ban module and integrated it in account.module as "access control":
     * access control is based on much more powerful regular expressions (regex) now rather than on MySQL pattern matching.
 - rewrote watchdog and submission throttle
-- rewrote section code and renamed it to structure.module
+- rewrote section code and renamed it to structure.module:
+    * supports both "categories" and "topics" (cfr. Scoop, SlashCode)
+    * added "auto-post new submissions" feature versus "moderate new submissions".
 - added settings.module:
     * moved most configuration options to the administration section
 - added page.module:
     * allows creation of static (and dynamic) pages through the administration interface
+- added help.module:
+    * groups all available documentation on installed modules on a single page.
+- added cvs.module and cvs-to-sql.pl:
+    * allows to display and mail CVS log messages as digests.
 - various updates:
+    * introduced links/drupal tags: [[link]]
     * added preview functionality when submitting new content (such as a story) from the administration pages.
     * made the administration section only show those links a user has access to.
+    * made all modules use specific form_* functions to guarantee a rock-solid forms and more consistent layout.
     * improved account module:
         + added "access control" to allow/deny certain usernames/e-mail addresses/hostnames
-    * improved comment module
+    * improved comment module:
+        + made it possible to permanently delete comments
     * improved rating module
     * improved story module:
         + added preview functionality for administrators
diff --git a/account.php b/account.php
index 1e96f1f9de3695168249049a1c515ab21287a7f2..ce72b27ba88a49e5efe4f73bdf0b9f1fa6e37748 100644
--- a/account.php
+++ b/account.php
@@ -40,6 +40,7 @@ function account_create($error = "") {
   $output .= "<B>". t("E-mail address") .":</B><BR>\n";
   $output .= "<INPUT NAME=\"email\"><BR>\n";
   $output .= "<SMALL><I>". t("You will be sent instructions on how to validate your account via this e-mail address: make sure it is accurate.") ."</I></SMALL><P>\n";
+
   $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"". t("Create account") ."\">\n";
   $output .= "</FORM>\n";
 
@@ -76,47 +77,20 @@ function account_user_edit() {
   global $allowed_html, $theme, $user;
 
   if ($user->id) {
-    // Generate output/content:
-    $output .= "<FORM ACTION=\"account.php\" METHOD=\"post\">\n";
-
-    $output .= "<B>". t("Username") .":</B><BR>\n";
-    $output .= "$user->userid<P>\n";
-    $output .= "<I><SMALL>". t("Required, unique, and can not be changed.") ."</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Real name") .":</B><BR>\n";
-    $output .= "<INPUT NAME=\"edit[name]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"$user->name\"><BR>\n";
-    $output .= "<I><SMALL>". t("Optional") .".</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Real e-mail address") .":</B><BR>\n";
-    $output .= "$user->real_email<P>\n";
-    $output .= "<I><SMALL>". t("Required, unique, can not be changed.") ." ". t("Your real e-mail address is never displayed publicly: only needed in case you lose your password.") ."</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Fake e-mail address") .":</B><BR>\n";
-    $output .= "<INPUT NAME=\"edit[fake_email]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"$user->fake_email\"><BR>\n";
-    $output .= "<I><SMALL>". t("Optional") .". ". t("Displayed publicly so you may spam proof your real e-mail address if you want.") ."</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Homepage") .":</B><BR>\n";
-    $output .= "<INPUT NAME=\"edit[url]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"$user->url\"><BR>\n";
-    $output .= "<I><SMALL>". t("Optional") .". ". t("Make sure you enter fully qualified URLs only.  That is, remember to include \"http://\".") ."</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Bio") .":</B> (". t("maximal 255 characters") .")<BR>\n";
-    $output .= "<TEXTAREA NAME=\"edit[bio]\" COLS=\"35\" ROWS=\"5\" WRAP=\"virtual\">$user->bio</TEXTAREA><BR>\n";
-    $output .= "<I><SMALL>". t("Optional") .". ". t("This biographical information is publicly displayed on your user page.") ."<BR>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Signature") .":</B> (". t("maximal 255 characters") .")<BR>\n";
-    $output .= "<TEXTAREA NAME=\"edit[signature]\" COLS=\"35\" ROWS=\"5\" WRAP=\"virtual\">$user->signature</TEXTAREA><BR>\n";
-    $output .= "<I><SMALL>". t("Optional") .". ". t("This information will be publicly displayed at the end of your comments.") ."<BR>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Password") .":</B><BR>\n";
-    $output .= "<INPUT TYPE=\"password\" NAME=\"edit[pass1]\" SIZE=\"10\" MAXLENGTH=\"20\"> <INPUT TYPE=\"password\" NAME=\"edit[pass2]\" SIZE=\"10\" MAXLENGTH=\"20\"><BR>\n";
-    $output .= "<I><SMALL>". t("Enter your new password twice if you want to change your current password or leave it blank if you are happy with your current password.") ."</SMALL></I><P>\n";
-
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Save user information") ."\"><BR>\n";
-    $output .= "</FORM>\n";
-
-    // Display output/content:
+    // construct form:
+    $form .= form_item(t("Username"), $user->userid, t("Required, unique, and can not be changed."));
+    $form .= form_textfield(t("Real name"), "name", $user->name, 30, 55, t("Optional"));
+    $form .= form_item(t("Real e-mail address"), $user->real_email, t("Required, unique, can not be changed.") ." ". t("Your real e-mail address is never displayed publicly: only needed in case you lose your password."));
+    $form .= form_textfield(t("Fake e-mail address"), "fake_email", $user->fake_email, 30, 55, t("Optional") .". ". t("Displayed publicly so you may spam proof your real e-mail address if you want."));
+    $form .= form_textfield(t("Homepage"), "url", $user->url, 30, 55, t("Optional") .". ". t("Make sure you enter fully qualified URLs only.  That is, remember to include \"http://\"."));
+    $form .= form_textarea(t("Bio"), "bio", $user->bio, 35, 5, t("Optional") .". ". t("Maximal 255 characters.") ." ". t("This biographical information is publicly displayed on your user page.") ."<BR>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
+    $form .= form_textarea(t("Signature"), "signature", $user->signature, 35, 5, t("Optional") .". ". t("Maximal 255 characters.") ." ". t("This information will be publicly displayed at the end of your comments.") ."<BR>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
+    $form .= form_item(t("Password"), "<INPUT TYPE=\"password\" NAME=\"edit[pass1]\" SIZE=\"10\" MAXLENGTH=\"20\"> <INPUT TYPE=\"password\" NAME=\"edit[pass2]\" SIZE=\"10\" MAXLENGTH=\"20\">", t("Enter your new password twice if you want to change your current password or leave it blank if you are happy with your current password."));
+    $form .= form_submit(t("Save user information"));
+
+    // display form:
     $theme->header();
-    $theme->box(t("Edit user information"), $output);
+    $theme->box(t("Edit user information"), form("account.php", $form));
     $theme->footer();
   }
   else {
@@ -139,47 +113,22 @@ function account_site_edit() {
   global $cmodes, $corder, $theme, $themes, $languages, $user;
 
   if ($user->id) {
-    $output .= "<FORM ACTION=\"account.php\" METHOD=\"post\">\n";
-
-    $output .= "<B>". t("Theme") .":</B><BR>\n";
-    foreach ($themes as $key=>$value) $options1 .= " <OPTION VALUE=\"$key\"". (($user->theme == $key) ? " SELECTED" : "") .">$key - $value[1]</OPTION>\n";
-    $output .= "<SELECT NAME=\"edit[theme]\">\n$options1</SELECT><BR>\n";
-    $output .= "<I><SMALL>". t("Selecting a different theme will change the look and feel of the site.") ."</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Timezone") .":</B><BR>\n";
-    $date = time() - date("Z");
-    for ($zone = -43200; $zone <= 46800; $zone += 3600) $options2 .= " <OPTION VALUE=\"$zone\"". (($user->timezone == $zone) ? " SELECTED" : "") .">". date("l, F dS, Y - h:i A", $date + $zone) ." (GMT ". $zone / 3600 .")</OPTION>\n";
-    $output .= "<SELECT NAME=\"edit[timezone]\">\n$options2</SELECT><BR>\n";
-    $output .= "<I><SMALL>". t("Select what time you currently have and your timezone settings will be set appropriate.") ."</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Language" ) .":</B><BR>\n";
-    foreach ($languages as $key=>$value) $options3 .= " <OPTION VALUE=\"$key\"". (($user->language == $key) ? " SELECTED" : "") .">$value - $key</OPTION>\n";
-    $output .= "<SELECT NAME=\"edit[language]\">\n$options3</SELECT><BR>\n";
-    $output .= "<I><SMALL>". t("Selecting a different language will change the language of the site.") ."</SMALL></I><P>\n";
-
-    $output .= "<B>". t("Maximum number of items to display") .":</B><BR>\n";
-    for ($nodes = 10; $nodes <= 30; $nodes += 5) $options4 .= "<OPTION VALUE=\"$nodes\"". (($user->nodes == $nodes) ? " SELECTED" : "") .">$nodes</OPTION>\n";
-    $output .= "<SELECT NAME=\"edit[nodes]\">\n$options4</SELECT><BR>\n";
-    $output .= "<I><SMALL>". t("The maximum number of nodes that will be displayed on the main page.") ."</SMALL></I><P>\n";
-
-    foreach ($cmodes as $key=>$value) $options5 .= "<OPTION VALUE=\"$key\"". ($user->mode == $key ? " SELECTED" : "") .">$value</OPTION>\n";
-    $output .= "<B>". t("Comment display mode") .":</B><BR>\n";
-    $output .= "<SELECT NAME=\"edit[mode]\">$options5</SELECT><P>\n";
-
-    foreach ($corder as $key=>$value) $options6 .= "<OPTION VALUE=\"$key\"". ($user->sort == $key ? " SELECTED" : "") .">$value</OPTION>\n";
-    $output .= "<B>". t("Comment sort order") .":</B><BR>\n";
-    $output .= "<SELECT NAME=\"edit[sort]\">$options6</SELECT><P>\n";
-
-    for ($i = -1; $i < 6; $i++) $options7 .= " <OPTION VALUE=\"$i\"". ($user->threshold == $i ? " SELECTED" : "") .">Filter - $i</OPTION>";
-    $output .= "<B>". t("Comment filter") .":</B><BR>\n";
-    $output .= "<SELECT NAME=\"edit[threshold]\">$options7</SELECT><BR>\n";
-    $output .= "<I><SMALL>". t("Comments that scored less than this threshold setting will be ignored.  Anonymous comments start at 0, comments of people logged on start at 1 and moderators can add and subtract points.") ."</SMALL></I><P>\n";
-
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Save site settings") ."\"><BR>\n";
-    $output .= "</FORM>\n";
-
+    // construct form:
+    foreach ($themes as $key=>$value) $options .= "<OPTION VALUE=\"$key\"". (($user->theme == $key) ? " SELECTED" : "") .">$key - $value[1]</OPTION>\n";
+    $form .= form_item(t("Theme"), "<SELECT NAME=\"edit[theme]\">$options</SELECT>", t("Selecting a different theme will change the look and feel of the site."));
+    for ($zone = -43200; $zone <= 46800; $zone += 3600) $zones[$zone] = date("l, F dS, Y - h:i A", time() - date("Z") + $zone) ." (GMT ". $zone / 3600 .")";
+    $form .= form_select(t("Timezone"), "timezone", $user->timezone, $zones, t("Select what time you currently have and your timezone settings will be set appropriate."));
+    $form .= form_select(t("Language"), "language", $user->language, $languages, t("Selecting a different language will change the language of the site."));
+    $form .= form_select(t("Number of nodes to display"), "nodes", $user->nodes, array(10 => 10, 15 => 15, 20 => 20, 25 => 25, 30 => 30), t("The maximum number of nodes that will be displayed on the main page."));
+    $form .= form_select(t("Comment display mode"), "mode", $user->mode, $cmodes);
+    $form .= form_select(t("Comment display order"), "sort", $user->sort, $corder);
+    for ($count = -1; $count < 6; $count++) $threshold[$count] = t("Filter") ." - $count";
+    $form .= form_select(t("Comment filter"), "threshold", $user->threshold, $threshold, t("Comments that scored less than this threshold setting will be ignored.  Anonymous comments start at 0, comments of people logged on start at 1 and moderators can add and subtract points."));
+    $form .= form_submit(t("Save site settings"));
+
+    // display form:
     $theme->header();
-    $theme->box(t("Edit your preferences"), $output);
+    $theme->box(t("Edit your preferences"), form("account.php", $form));
     $theme->footer();
   }
   else {
@@ -201,19 +150,19 @@ function account_content_edit() {
   global $theme, $user;
 
   if ($user->id) {
-    $output .= "<FORM ACTION=\"account.php\" METHOD=\"post\">\n";
-    $output .= "<B>". t("Blocks in side bars") .":</B><BR>\n";
+    // construct form:
     $result = db_query("SELECT * FROM blocks WHERE status = 1 ORDER BY module");
     while ($block = db_fetch_object($result)) {
       $entry = db_fetch_object(db_query("SELECT * FROM layout WHERE block = '$block->name' AND user = '$user->id'"));
-      $output .= "<INPUT TYPE=\"checkbox\" NAME=\"edit[$block->name]\"". ($entry->user ? " CHECKED" : "") ."> ". t($block->name) ."<BR>\n";
+      $options .= "<INPUT TYPE=\"checkbox\" NAME=\"edit[$block->name]\"". ($entry->user ? " CHECKED" : "") ."> ". t($block->name) ."<BR>\n";
     }
-    $output .= "<P><I><SMALL>". t("Enable the blocks you would like to see displayed in the side bars.") ."</SMALL></I></P>\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Save content settings") ."\">\n";
-    $output .= "</FORM>\n";
 
+    $form .= form_item(t("Blocks in side bars"), $options, t("Enable the blocks you would like to see displayed in the side bars."));
+    $form .= form_submit(t("Save content settings"));
+
+    // display form:
     $theme->header();
-    $theme->box(t("Edit your content"), $output);
+    $theme->box(t("Edit your content"), form("account.php", $form));
     $theme->footer();
   }
   else {
@@ -266,19 +215,6 @@ function module($name, $module, $username) {
     $block1 .= " <TR><TD ALIGN=\"right\"><B>". t("Bio") .":</B></TD><TD>". check_output($account->bio) ."</TD></TR>\n";
     $block1 .= "</TABLE>\n";
 
-/*
-    $result = db_query("SELECT c.cid, c.pid, c.lid, c.subject, c.timestamp, n.title AS node FROM comments c LEFT JOIN users u ON u.id = c.author LEFT JOIN node ON n.id = c.lid WHERE u.userid = '$uname' AND n.status = '$status[posted]' AND s.timestamp > ". (time() - 1209600) ." ORDER BY cid DESC LIMIT 10");
-    while ($comment = db_fetch_object($result)) {
-      $block2 .= "<TABLE BORDER=\"0\" CELLPADDING=\"1\" CELLSPACING=\"1\">\n";
-      $block2 .= " <TR><TD ALIGN=\"right\"><B>". t("Comment") .":</B></TD><TD><A HREF=\"node.php?id=$comment->lid&cid=$comment->cid&pid=$comment->pid#$comment->cid\">". check_output($comment->subject) ."</A></TD></TR>\n";
-      $block2 .= " <TR><TD ALIGN=\"right\"><B>". t("Date") .":</B></TD><TD>". format_date($comment->timestamp) ."</TD></TR>\n";
-      $block2 .= " <TR><TD ALIGN=\"right\"><B>". t("Story") .":</B></TD><TD><A HREF=\"node.php?id=$comment->lid\">". check_output($comment->story) ."</A></TD></TR>\n";
-      $block2 .= "</TABLE>\n";
-      $block2 .= "<P>\n";
-      $comments++;
-    }
-*/
-
     // Display account information:
     $theme->header();
     if ($block1) $theme->box(strtr(t("%a's user information"), array("%a" => $uname)), $block1);
diff --git a/includes/common.inc b/includes/common.inc
index b2e4c3b6c0cb1006a157ceebdf9c33a8cd18d7d2..a8b6f6769d18b722dd9631e3c8365fdfef0a291e 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -151,8 +151,12 @@ function format_text($text) {
   return preg_replace($src, $dst, $text);
 }
 
+function form($action, $form, $method = "post") {
+  return "<FORM ACTION=\"$action\" METHOD=\"$method\">\n$form</FORM>\n";
+}
+
 function form_item($title, $value, $description = 0) {
-  return ($description) ? "<B>$title:</B><BR>$value<BR><SMALL><I>$description</I></SMALL><P>" : "<B>$title:</B><BR>$value<P>\n";
+  return ($description) ? "<B>$title:</B><BR>$value<BR><SMALL><I>$description</I></SMALL><P>\n" : "<B>$title:</B><BR>$value<P>\n";
 }
 
 function form_textfield($title, $name, $value, $size, $maxlength, $description = 0) {
@@ -163,17 +167,17 @@ function form_textarea($title, $name, $value, $cols, $rows, $description = 0) {
   return form_item($title, "<TEXTAREA WRAP=\"virtual\" COLS=\"$cols\" ROWS=\"$rows\" NAME=\"edit[$name]\">". check_textarea($value) ."</TEXTAREA>", $description);
 }
 
-function form_select($title, $name, $options, $value, $description = 0) {
+function form_select($title, $name, $value, $options, $description = 0) {
   foreach ($options as $key=>$choice) $select .= "<OPTION VALUE=\"$key\"". ($key == $value ? " SELECTED" : "") .">". check_select($choice) ."</OPTION>";
   return form_item($title, "<SELECT NAME=\"edit[$name]\">$select</SELECT>", $description);
 }
 
 function form_hidden($name, $value) {
-  return "<INPUT TYPE=\"hidden\" NAME=\"edit[$name]\" VALUE=\"$value\">";
+  return "<INPUT TYPE=\"hidden\" NAME=\"edit[$name]\" VALUE=\"". check_textfield($value) ."\">\n";
 }
 
 function form_submit($value) {
-  return "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"$value\">\n";
+  return "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". check_textfield($value) ."\">\n";
 }
 
 $conf = conf_init();
diff --git a/includes/node.inc b/includes/node.inc
index e594e8554f8e6056ca1a7773e517e533b5d361b5..9b4a54d9b21b19792775cceb2112b05b74e9c30c 100644
--- a/includes/node.inc
+++ b/includes/node.inc
@@ -164,7 +164,7 @@ function node_status($node, $index = -1) {
 }
 
 function node_control($node) {
-  global $REQUEST_URI;
+  global $user, $REQUEST_URI;
 
  ?>
   <SCRIPT>
@@ -178,10 +178,12 @@ function visit(site) {
   </SCRIPT>
  <?php
 
-  if ($user->id)
+  if ($user->id) {
     $choices = array("node.php?id=$node->nid" => t("view node"), "submit.php?mod=$node->type" => t("add node"), "submit.php?mod=$node->type&op=update&id=$node->nid" => t("update node"),  "node.php?op=history&id=$node->nid" => t("view history"));
-  else
+  }
+  else {
     $choices = array("node.php?id=$node->nid" => t("view node"), "node.php?op=history&id=$node->nid" => t("view history"));
+  }
 
   $output .= "<FORM METHOD=\"get\" ACTION=\"\">\n";
   foreach ($choices as $key => $value) $options .= "<OPTION VALUE=\"$key\"". (strstr($REQUEST_URI,"/$key") ? " SELECTED" : "") .">". check_select($value) ."</OPTION>\n";
@@ -193,7 +195,7 @@ function visit(site) {
 
 function node_visible($node) {
   global $user, $status;
-  return ($node->status == $status[posted]) || ($node->status == $status[queued] && $user->id) || user_access($user, "node");
+  return ($node->status == $status[posted]) || ($node->status == $status[queued] && $user->id) || user_access($user, $node->type) || user_access($user, "node");
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/index.php b/index.php
index e4bfe258d80219f0ad536b824bbc1f98b30b13b3..78e42599f28dbc96e300680411e4453938d3d37d 100644
--- a/index.php
+++ b/index.php
@@ -4,7 +4,7 @@
 
 if (variable_get(dev_timing, 0)) timer_start();
 
-$result = db_query("SELECT nid FROM node WHERE promote = '1' AND status = '$status[posted]' AND timestamp <= ". ($date > 0 ? $date : time()) ." ". ($category ? "AND cid = '$category'" : "") ." ". ($topic ? "AND tid = '$topic'" : "") ."  ORDER BY timestamp DESC LIMIT ". ($user->nodes ? $user->nodes : 10));
+$result = db_query("SELECT nid FROM node WHERE promote = '1' AND status = '$status[posted]' AND timestamp <= ". ($date > 0 ? $date : time()) ." ". ($category ? "AND cid = '$category'" : "") ." ". ($topic ? "AND tid = '$topic'" : "") ."  ORDER BY timestamp DESC LIMIT ". ($user->nodes ? $user->nodes : variable_get(default_nodes_main, 10)));
 
 $theme->header();
 while ($node = db_fetch_object($result)) {
diff --git a/modules/account.module b/modules/account.module
index 72687a0e0402b8d318e7786b3012b7e40c0d2e4f..6dbf54977dd1b7171e084cbf406dea47afe1f3d3 100644
--- a/modules/account.module
+++ b/modules/account.module
@@ -69,7 +69,7 @@ function account_ac() {
   $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\">\n";
   $output .= " <TR><TH>mask</TH><TH>type</TH><TH>reason</TH><TH>oparations</TH></TR>\n";
   while ($rule = db_fetch_object($result)) {
-    $output .= " <TR><TD>$rule->mask</TD><TD ALIGN=\"center\">$rule->type</TD><TD>". check_output($rule->reason) ."</TD><TD><A HREF=\"admin.php?mod=account&op=delete+rule&id=$rule->id\">delete rule</A></TD></TR>\n";
+    $output .= " <TR><TD>$rule->mask</TD><TD ALIGN=\"center\">$rule->type</TD><TD>". check_output($rule->reason) ."</TD><TD><A HREF=\"admin.php?mod=account&op=delete&id=$rule->id\">delete rule</A></TD></TR>\n";
   }
   $output .= " <TR><TD><INPUT TYPE=\"text\" NAME=\"edit[mask]\"></TD><TD><SELECT NAME=\"edit[type]\">\n$type</SELECT></TD><TD><INPUT TYPE=\"text\" NAME=\"edit[reason]\"></TD><TD><INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"Add rule\"></TD></TR>\n";
   $output .= " <TR><TD COLSPAN=\"4\"><SMALL><I>Use <A HREF=\"admin.php?mod=account&op=help\">regular expressions</A> (regexs) to specify the mask pattern.</I></SMALL></TD></TR>\n";
@@ -117,7 +117,7 @@ function account_blocks($id) {
 }
 
 function account_nodes($id) {
-  $result = db_query("SELECT * FROM node WHERE author = $id ORDER BY timestamp DESC");
+  $result = db_query("SELECT * FROM node WHERE author = $id ORDER BY timestamp DESC LIMIT 30");
   while ($node = db_fetch_object($result)) {
     $output .= "<LI><A HREF=\"node.php?id=$node->nid\">$node->title</A> ($node->type)</LI>\n";
   }
@@ -125,7 +125,7 @@ function account_nodes($id) {
 }
 
 function account_comments($id) {
-  $result = db_query("SELECT * FROM comments WHERE author = '$id' ORDER BY timestamp DESC");
+  $result = db_query("SELECT * FROM comments WHERE author = '$id' ORDER BY timestamp DESC LIMIT 30");
   while ($comment = db_fetch_object($result)) {
     $output .= "<LI><A HREF=\"node.php?id=$comment->lid&cid=$comment->cid&pid=$comment->pid#$comment->cid\">$comment->subject</A></LI>\n";
   }
@@ -158,33 +158,28 @@ function access($name, $module) {
     $access .= "<OPTION VALUE=\"$name\"". (user_access($account, $name) ? " SELECTED" : "") .">$name</OPTION>";
   }
 
-  $status = array(0 => "blocked", 1 => "not confirmed", 2 => "open");
+  $status = array("blocked", "not confirmed", "open");
 
   $result = db_query("SELECT * FROM users WHERE userid = '$name'");
 
   if ($account = db_fetch_object($result)) {
-    foreach ($status as $key=>$value) {
-      $stat .= " <OPTION VALUE=\"$key\"". (($account->status == $key) ? " SELECTED" : "") .">$value</OPTION>\n";
-    }
-
     module_iterate("access");
 
-    $output .= "<FORM ACTION=\"admin.php?mod=account\" METHOD=\"post\">\n";
-    $output .= "<B>ID:</B><BR>$account->id<P>\n";
-    $output .= "<B>Username:</B><BR>". check_output($account->userid) ."<P>\n";
-    $output .= "<B>Status:</B><BR><SELECT NAME=\"edit[status]\">\n$stat</SELECT><P>\n";
-    $output .= "<B>Administrator access:</B><BR><SELECT NAME=\"edit[access][]\" MULTIPLE=\"true\" SIZE=\"10\">$access</SELECT><P>\n";
-    $output .= "<B>Real name:</B><BR><INPUT NAME=\"edit[name]\" SIZE=\"55\" VALUE=\"". check_textfield($account->name). "\"><P>\n";
-    $output .= "<B>Real e-mail address:</B><BR><INPUT NAME=\"edit[real_email]\" SIZE=\"55\" VALUE=\"". check_textfield($account->real_email) ."\"><P>\n";
-    $output .= "<B>Fake e-mail address:</B><BR><INPUT NAME=\"edit[fake_email]\" SIZE=\"55\" VALUE=\"". check_textfield($account->fake_email) ."\"><P>\n";
-    $output .= "<B>URL of homepage:</B><BR><INPUT NAME=\"edit[url]\" SIZE=\"55\" VALUE=\"". check_textfield($account->url) ."\"><P>\n";
-    $output .= "<B>Bio information:</B><BR><TEXTAREA NAME=\"edit[bio]\" COLS=\"35\" ROWS=\"5\" WRAP=\"virtual\">". check_textarea($account->bio) ."</TEXTAREA><P>\n";
-    $output .= "<B>Signature:</B><BR><TEXTAREA NAME=\"edit[signature]\" COLS=\"35\" ROWS=\"5\" WRAP=\"virtual\">". check_textarea($account->signature) ."</TEXTAREA><P>\n";
-    $output .= "<INPUT TYPE=\"hidden\" NAME=\"name\" VALUE=\"$account->userid\">\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"View account\">\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save account\">\n";
-    $output .= "</FORM>\n";
-    return $output;
+    $form .= form_item("ID", $account->id);
+    $form .= form_item(t("Username"), check_output($account->userid));
+    $form .= form_select(t("Status"), "status", $account->status, array("blocked", "not confirmed", "open"));
+    $form .= form_item(t("Administrator access"), "<SELECT NAME=\"edit[access][]\" MULTIPLE=\"true\" SIZE=\"10\">$access</SELECT>");
+    $form .= form_textfield(t("Real name"), "name", $account->name, 30, 55);
+    $form .= form_textfield(t("Real e-mail address"), "real_email", $account->real_email, 30, 55);
+    $form .= form_textfield(t("Fake e-mail address"), "fake_email", $account->fake_email, 30, 55);
+    $form .= form_textfield(t("Homepage"), "url", $account->url, 30, 55);
+    $form .= form_textarea(t("Bio"), "bio", $account->bio, 35, 5);
+    $form .= form_textarea(t("Signature"), "signature", $account->signature, 35, 5);
+    $form .= form_hidden("userid", $account->userid);
+    $form .= form_submit("View account");
+    $form .= form_submit("Save account");
+
+    return form("admin.php?mod=account", $form);
   }
 }
 
@@ -194,7 +189,10 @@ function account_view($name) {
   $result = db_query("SELECT * FROM users WHERE userid = '$name'");
 
   if ($account = db_fetch_object($result)) {
-    $output .= "<FORM ACTION=\"admin.php?mod=account\" METHOD=\"post\">\n";
+    $form .= form_hidden("userid", $account->userid);
+    $form .= form_submit("Edit account");
+    $form .= form_submit("Delete account");
+
     $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\">\n";
     $output .= " <TR><TH>ID:</TH><TD>$account->id</TD></TR>\n";
     $output .= " <TR><TH>Username:</TH><TD>$account->userid</TD></TR>\n";
@@ -203,19 +201,19 @@ function account_view($name) {
     $output .= " <TR><TH>Real name:</TH><TD>". check_output($account->name) ."</TD></TR>\n";
     $output .= " <TR><TH>Real e-mail address:</TH><TD>". format_email($account->real_email) ."</TD></TR>\n";
     $output .= " <TR><TH>Fake e-mail address:</TH><TD>". check_output($account->fake_email) ."</TD></TR>\n";
-    $output .= " <TR><TH>URL of homepage:</TH><TD>". format_url($account->url) ."</TD></TR>\n";
+    $output .= " <TR><TH>Homepage:</TH><TD>". format_url($account->url) ."</TD></TR>\n";
     $output .= " <TR><TH>Last access:</TH><TD>". format_date($account->last_access) ." from ". check_output($account->last_host) ."</TD></TR>\n";
     $output .= " <TR><TH>User rating:</TH><TD>". check_output($account->rating) ."</TD></TR>\n";
-    $output .= " <TR><TH>Bio information:</TH><TD>". check_output($account->bio) ."</TD></TR>\n";
-    $output .= " <TR><TH><B>Signature:</TH><TD>". check_output($account->signature) ."</TD></TR>\n";
+    $output .= " <TR><TH>Bio:</TH><TD>". check_output($account->bio) ."</TD></TR>\n";
+    $output .= " <TR><TH>Signature:</TH><TD>". check_output($account->signature) ."</TD></TR>\n";
     $output .= " <TR><TH>Theme:</TH><TD>". check_output($account->theme) ."</TD></TR>\n";
     $output .= " <TR><TH>Timezone:</TH><TD>". check_output($account->timezone / 3600) ."</TD></TR>\n";
     $output .= " <TR><TH>Selected blocks:</TH><TD>". check_output(account_blocks($account->id)) ."</TD></TR>\n";
-    $output .= " <TR><TH>Submitted nodes:</TH><TD>". check_output(account_nodes($account->id)) ."</TD></TR>\n";
-    $output .= " <TR><TH>Submitted comments:</TH><TD>". check_output(account_comments($account->id)) ."</TD></TR>\n";
-    $output .= " <TR><TD ALIGN=\"center\" COLSPAN=\"2\"><INPUT TYPE=\"hidden\" NAME=\"name\" VALUE=\"$account->userid\"><INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Edit account\"><INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Delete account\"></TD></TR>\n";
+    $output .= " <TR><TH>Recent nodes:</TH><TD>". check_output(account_nodes($account->id)) ."</TD></TR>\n";
+    $output .= " <TR><TH>Recent comments:</TH><TD>". check_output(account_comments($account->id)) ."</TD></TR>\n";
+    $output .= " <TR><TD ALIGN=\"center\" COLSPAN=\"2\">". form("admin.php?mod=account", $form) ."</TD></TR>\n";
     $output .= "</TABLE>\n";
-    $output .= "</FORM>\n";
+
     return $output;
   }
 }
@@ -244,13 +242,12 @@ function account_admin() {
       print status(account_ac_check($edit));
       print account_ac();
       break;
-    case "delete rule":
+    case "delete":
       print status(account_ac_del($id));
       print account_ac();
       break;
     case "Delete account":
-    case "delete":
-      print status(account_delete(check_input($name)));
+      print status(account_delete($edit[userid]));
       print account_overview(account_query($type));
       break;
     case "Edit account":
@@ -268,8 +265,8 @@ function account_admin() {
       print search_data($keys, $mod);
       break;
     case "Save account":
-      print status(account_edit_save(check_input($name), $edit));
-      print account_view(check_input($name));
+      print status(account_edit_save(check_input($edit[userid]), $edit));
+      print account_view(check_input($edit[userid]));
       break;
     case "View account":
     case "view":
diff --git a/modules/book.module b/modules/book.module
index 70dcd6da4ecabd64124713601d37314cc3d8620a..78d4e568043e5c8a98182881777ce36f8d1f62d2 100644
--- a/modules/book.module
+++ b/modules/book.module
@@ -94,47 +94,43 @@ function book_toc($parent = 0, $indent = "", $toc = array()) {
 function book_form($edit = array()) {
   global $allowed_html, $PHP_SELF, $REQUEST_URI, $user;
 
-  $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n";
-
-  $output .= form_item(t("Author"), format_username(($edit[userid] ? $edit[userid] : $user->userid)));
-  $output .= form_hidden(userid, $edit[userid]);
-  $output .= form_textfield(t("Subject"), "title", $edit[title], 50, 128);
-  $output .= form_item(t("Category"), category_form_select("book", $edit));
+  $form .= form_item(t("Author"), format_username(($edit[userid] ? $edit[userid] : $user->userid)));
+  $form .= form_hidden(userid, $edit[userid]);
+  $form .= form_textfield(t("Subject"), "title", $edit[title], 50, 64);
+  $form .= form_item(t("Category"), category_form_select("book", $edit));
 
   if ($edit[pid]) {
     $node = node_get_object("nid", $edit[pid]);
-    $output .= form_item(t("Parent"), "<A HREF=\"node.php?id=$node->id\">". check_output($node->title) ."</A>", t("The parent subject or category the page belongs in."));
-    $output .= form_hidden("parent". $edit[parent]);
+    $form .= form_item(t("Parent"), "<A HREF=\"node.php?id=$node->id\">". check_output($node->title) ."</A>", t("The parent subject or category the page belongs in."));
+    $form .= form_hidden("parent". $edit[parent]);
   }
   else {
-    $output .= form_select(t("Parent"), "parent", user_access($user, "book") ? array_merge(array(0 => "&nbsp;"), book_toc()) : book_toc(), $edit[parent], t("The parent subject or category the page belongs in."));
+    $form .= form_select(t("Parent"), "parent", $edit[parent], user_access($user, "book") ? array_merge(array(0 => "&nbsp;"), book_toc()) : book_toc(), t("The parent subject or category the page belongs in."));
   }
 
-  $output .= form_textarea(t("Content"), "body", $edit[body], 50, 10, t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
-  $output .= form_textarea(t("Log message"), "log", $edit[log], 50, 5, t("An explanation of the additions or updates being made to help the group understand your motivations."));
+  $form .= form_textarea(t("Content"), "body", $edit[body], 50, 10, t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
+  $form .= form_textarea(t("Log message"), "log", $edit[log], 50, 5, t("An explanation of the additions or updates being made to help the group understand your motivations."));
 
   if (user_access($user, "book")) {
-    $output .= form_select(t("Weight"), "weight", array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30), $edit[weight], t("The heavier nodes will sink and the lighter nodes will be positioned nearer the top."));
+    $form .= form_select(t("Weight"), "weight", $edit[weight], array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30), t("The heavier nodes will sink and the lighter nodes will be positioned nearer the top."));
   }
 
+  $form .= form_hidden("pid", $edit[pid]);
+  $form .= form_hidden("nid", $edit[nid]);
+
   if (!$edit) {
-    $output .= form_submit(t("Preview"));
+    $form .= form_submit(t("Preview"));
   }
   else if (!$edit[title]) {
-    $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply a title.") ."</FONT><P>\n";
-    $output .= form_submit(t("Preview"));
+    $form .= "<FONT COLOR=\"red\">". t("Warning: you did not supply a title.") ."</FONT><P>\n";
+    $form .= form_submit(t("Preview"));
   }
   else {
-    $output .= form_submit(t("Preview"));
-    $output .= form_submit(t("Submit"));
+    $form .= form_submit(t("Preview"));
+    $form .= form_submit(t("Submit"));
   }
 
-  $output .= form_hidden("pid", $edit[pid]);
-  $output .= form_hidden("nid", $edit[nid]);
-
-  $output .= "</FORM>\n";
-
-  return $output;
+  return form($REQUEST_URI, $form);
 }
 
 function book_save($edit) {
diff --git a/modules/book/book.module b/modules/book/book.module
index 70dcd6da4ecabd64124713601d37314cc3d8620a..78d4e568043e5c8a98182881777ce36f8d1f62d2 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -94,47 +94,43 @@ function book_toc($parent = 0, $indent = "", $toc = array()) {
 function book_form($edit = array()) {
   global $allowed_html, $PHP_SELF, $REQUEST_URI, $user;
 
-  $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n";
-
-  $output .= form_item(t("Author"), format_username(($edit[userid] ? $edit[userid] : $user->userid)));
-  $output .= form_hidden(userid, $edit[userid]);
-  $output .= form_textfield(t("Subject"), "title", $edit[title], 50, 128);
-  $output .= form_item(t("Category"), category_form_select("book", $edit));
+  $form .= form_item(t("Author"), format_username(($edit[userid] ? $edit[userid] : $user->userid)));
+  $form .= form_hidden(userid, $edit[userid]);
+  $form .= form_textfield(t("Subject"), "title", $edit[title], 50, 64);
+  $form .= form_item(t("Category"), category_form_select("book", $edit));
 
   if ($edit[pid]) {
     $node = node_get_object("nid", $edit[pid]);
-    $output .= form_item(t("Parent"), "<A HREF=\"node.php?id=$node->id\">". check_output($node->title) ."</A>", t("The parent subject or category the page belongs in."));
-    $output .= form_hidden("parent". $edit[parent]);
+    $form .= form_item(t("Parent"), "<A HREF=\"node.php?id=$node->id\">". check_output($node->title) ."</A>", t("The parent subject or category the page belongs in."));
+    $form .= form_hidden("parent". $edit[parent]);
   }
   else {
-    $output .= form_select(t("Parent"), "parent", user_access($user, "book") ? array_merge(array(0 => "&nbsp;"), book_toc()) : book_toc(), $edit[parent], t("The parent subject or category the page belongs in."));
+    $form .= form_select(t("Parent"), "parent", $edit[parent], user_access($user, "book") ? array_merge(array(0 => "&nbsp;"), book_toc()) : book_toc(), t("The parent subject or category the page belongs in."));
   }
 
-  $output .= form_textarea(t("Content"), "body", $edit[body], 50, 10, t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
-  $output .= form_textarea(t("Log message"), "log", $edit[log], 50, 5, t("An explanation of the additions or updates being made to help the group understand your motivations."));
+  $form .= form_textarea(t("Content"), "body", $edit[body], 50, 10, t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
+  $form .= form_textarea(t("Log message"), "log", $edit[log], 50, 5, t("An explanation of the additions or updates being made to help the group understand your motivations."));
 
   if (user_access($user, "book")) {
-    $output .= form_select(t("Weight"), "weight", array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30), $edit[weight], t("The heavier nodes will sink and the lighter nodes will be positioned nearer the top."));
+    $form .= form_select(t("Weight"), "weight", $edit[weight], array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30), t("The heavier nodes will sink and the lighter nodes will be positioned nearer the top."));
   }
 
+  $form .= form_hidden("pid", $edit[pid]);
+  $form .= form_hidden("nid", $edit[nid]);
+
   if (!$edit) {
-    $output .= form_submit(t("Preview"));
+    $form .= form_submit(t("Preview"));
   }
   else if (!$edit[title]) {
-    $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply a title.") ."</FONT><P>\n";
-    $output .= form_submit(t("Preview"));
+    $form .= "<FONT COLOR=\"red\">". t("Warning: you did not supply a title.") ."</FONT><P>\n";
+    $form .= form_submit(t("Preview"));
   }
   else {
-    $output .= form_submit(t("Preview"));
-    $output .= form_submit(t("Submit"));
+    $form .= form_submit(t("Preview"));
+    $form .= form_submit(t("Submit"));
   }
 
-  $output .= form_hidden("pid", $edit[pid]);
-  $output .= form_hidden("nid", $edit[nid]);
-
-  $output .= "</FORM>\n";
-
-  return $output;
+  return form($REQUEST_URI, $form);
 }
 
 function book_save($edit) {
diff --git a/modules/comment.module b/modules/comment.module
index cee88f998fe1e646d86d087e7a45f468d69b5417..5c2f9005f87bd051abed8025b574c05895242676 100644
--- a/modules/comment.module
+++ b/modules/comment.module
@@ -15,90 +15,53 @@ function comment_find($keys) {
 
 function comment_edit($id) {
   $result = db_query("SELECT c.*, u.userid FROM comments c LEFT JOIN users u ON c.author = u.id WHERE c.cid = '$id'");
-
   $comment = db_fetch_object($result);
 
-  $output .= "<FORM ACTION=\"admin.php?mod=comment&op=save&id=$id\" METHOD=\"post\">\n";
-
-  $output .= "<B>Author:</B><BR>\n";
-  $output .= format_username($comment->userid) ."<P>\n";
-
-  $output .= "<B>Subject:</B><BR>\n";
-  $output .= "<INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" VALUE=\"". check_textfield($comment->subject) ."\"><P>\n";
+  $form .= form_item(t("Author"), format_username($comment->userid));
+  $form .= form_textfield(t("Subject"), "subject", $comment->subject, 50, 128);
+  $form .= form_textarea(t("Comment"), "comment", $comment->comment, 50, 10);
+  $form .= form_submit("Save comment");
 
-  $output .= "<B>Comment:</B><BR>\n";
-  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"comment\">". check_textarea($comment->comment) ."</TEXTAREA><P>\n";
-
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save comment\">\n";
-  $output .= "</FORM>\n";
-
-  print $output;
+  return form("admin.php?mod=comment&id=$id", $form);
 }
 
-function comment_save($id, $subject, $comment) {
-  db_query("UPDATE comments SET subject = '$subject', comment = '$comment' WHERE cid = '$id'");
-  watchdog("message", "comment: modified '$subject'");
+function comment_save($id, $edit) {
+  db_query("UPDATE comments SET subject = '". check_input($edit[subject]) ."', comment = '". check_input($edit[comment]) ."' WHERE cid = '$id'");
+  watchdog("message", "comment: modified '$edit[subject]'");
 }
 
-function comment_display($order = "date") {
-  // Initialize variables:
-  $fields = array("author" => "author", "date" => "timestamp DESC", "subject" => "subject");
-
-  // Perform SQL query:
-  $result = db_query("SELECT c.*, u.userid FROM comments c LEFT JOIN users u ON u.id = c.author ORDER BY c.$fields[$order] LIMIT 50");
+function comment_display() {
+  $result = db_query("SELECT c.*, u.userid FROM comments c LEFT JOIN users u ON u.id = c.author ORDER BY timestamp DESC LIMIT 50");
 
-  // Display comments:
   $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"2\" CELLSPACING=\"2\">\n";
-  $output .= " <TR>\n";
-  $output .= "  <TH ALIGN=\"right\" COLSPAN=\"3\">\n";
-  $output .= "   <FORM ACTION=\"admin.php?mod=comment\" METHOD=\"post\">\n";
-  $output .= "    <SELECT NAME=\"order\">\n";
-  foreach ($fields as $key=>$value) {
-    $output .= "     <OPTION VALUE=\"$key\"". ($key == $order ? " SELECTED" : "") .">Sort by $key</OPTION>\n";
-  }
-  $output .= "    </SELECT>\n";
-  $output .= "    <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Update\">\n";
-  $output .= "   </FORM>\n";
-  $output .= "  </TH>\n";
-  $output .= " </TR>\n";
-
-  $output .= " <TR>\n";
-  $output .= "  <TH>subject</TH>\n";
-  $output .= "  <TH>author</TH>\n";
-  $output .= "  <TH>operations</TH>\n";
-  $output .= " </TR>\n";
-
+  $output .= " <TR><TH>subject</TH><TH>author</TH><TH>date</TH><TH COLSPAN=\"2\">operations</TH></TR>\n";
   while ($comment = db_fetch_object($result)) {
-    $output .= " <TR><TD><A HREF=\"node.php?id=$comment->lid&cid=$comment->cid&pid=$comment->pid#$comment->cid\">". check_output($comment->subject) ."</A></TD><TD>". format_username($comment->userid) ."</TD><TD ALIGN=\"center\"><A HREF=\"admin.php?mod=comment&op=edit&id=$comment->cid\">edit</A></TD></TR>\n";
+    $output .= " <TR><TD><A HREF=\"node.php?id=$comment->lid&cid=$comment->cid&pid=$comment->pid#$comment->cid\">". check_output($comment->subject) ."</A></TD><TD>". format_username($comment->userid) ."</TD><TD>". format_date($comment->timestamp, "small") ."</TD><TD><A HREF=\"admin.php?mod=comment&op=edit&id=$comment->cid\">edit comment</A></TD><TD><A HREF=\"admin.php?mod=comment&op=delete&id=$comment->cid\">delete comment</A></TD></TR>\n";
   }
-
   $output .= "</TABLE>\n";
 
-  print $output;
+  return $output;
 }
 
 function comment_admin() {
-  global $op, $id, $mod, $keys, $subject, $comment, $order;
+  global $op, $id, $edit, $mod, $keys, $order;
 
   print "<SMALL><A HREF=\"admin.php?mod=comment\">overview</A> | <A HREF=\"admin.php?mod=comment&op=search\">search comment</A></SMALL><HR>\n";
 
   switch ($op) {
     case "edit":
-      comment_edit($id);
+      print comment_edit($id);
       break;
     case "search":
       print search_form($keys);
       print search_data($keys, $mod);
       break;
     case "Save comment":
-      comment_save(check_input($id), check_input($subject), check_input($comment));
-      comment_display();
-      break;
-    case "Update":
-      comment_display(check_input($order));
+      print status(comment_save(check_input($id), $edit));
+      print comment_display();
       break;
     default:
-      comment_display();
+      print comment_display();
   }
 }
 
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index cee88f998fe1e646d86d087e7a45f468d69b5417..5c2f9005f87bd051abed8025b574c05895242676 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -15,90 +15,53 @@ function comment_find($keys) {
 
 function comment_edit($id) {
   $result = db_query("SELECT c.*, u.userid FROM comments c LEFT JOIN users u ON c.author = u.id WHERE c.cid = '$id'");
-
   $comment = db_fetch_object($result);
 
-  $output .= "<FORM ACTION=\"admin.php?mod=comment&op=save&id=$id\" METHOD=\"post\">\n";
-
-  $output .= "<B>Author:</B><BR>\n";
-  $output .= format_username($comment->userid) ."<P>\n";
-
-  $output .= "<B>Subject:</B><BR>\n";
-  $output .= "<INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" VALUE=\"". check_textfield($comment->subject) ."\"><P>\n";
+  $form .= form_item(t("Author"), format_username($comment->userid));
+  $form .= form_textfield(t("Subject"), "subject", $comment->subject, 50, 128);
+  $form .= form_textarea(t("Comment"), "comment", $comment->comment, 50, 10);
+  $form .= form_submit("Save comment");
 
-  $output .= "<B>Comment:</B><BR>\n";
-  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"comment\">". check_textarea($comment->comment) ."</TEXTAREA><P>\n";
-
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save comment\">\n";
-  $output .= "</FORM>\n";
-
-  print $output;
+  return form("admin.php?mod=comment&id=$id", $form);
 }
 
-function comment_save($id, $subject, $comment) {
-  db_query("UPDATE comments SET subject = '$subject', comment = '$comment' WHERE cid = '$id'");
-  watchdog("message", "comment: modified '$subject'");
+function comment_save($id, $edit) {
+  db_query("UPDATE comments SET subject = '". check_input($edit[subject]) ."', comment = '". check_input($edit[comment]) ."' WHERE cid = '$id'");
+  watchdog("message", "comment: modified '$edit[subject]'");
 }
 
-function comment_display($order = "date") {
-  // Initialize variables:
-  $fields = array("author" => "author", "date" => "timestamp DESC", "subject" => "subject");
-
-  // Perform SQL query:
-  $result = db_query("SELECT c.*, u.userid FROM comments c LEFT JOIN users u ON u.id = c.author ORDER BY c.$fields[$order] LIMIT 50");
+function comment_display() {
+  $result = db_query("SELECT c.*, u.userid FROM comments c LEFT JOIN users u ON u.id = c.author ORDER BY timestamp DESC LIMIT 50");
 
-  // Display comments:
   $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"2\" CELLSPACING=\"2\">\n";
-  $output .= " <TR>\n";
-  $output .= "  <TH ALIGN=\"right\" COLSPAN=\"3\">\n";
-  $output .= "   <FORM ACTION=\"admin.php?mod=comment\" METHOD=\"post\">\n";
-  $output .= "    <SELECT NAME=\"order\">\n";
-  foreach ($fields as $key=>$value) {
-    $output .= "     <OPTION VALUE=\"$key\"". ($key == $order ? " SELECTED" : "") .">Sort by $key</OPTION>\n";
-  }
-  $output .= "    </SELECT>\n";
-  $output .= "    <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Update\">\n";
-  $output .= "   </FORM>\n";
-  $output .= "  </TH>\n";
-  $output .= " </TR>\n";
-
-  $output .= " <TR>\n";
-  $output .= "  <TH>subject</TH>\n";
-  $output .= "  <TH>author</TH>\n";
-  $output .= "  <TH>operations</TH>\n";
-  $output .= " </TR>\n";
-
+  $output .= " <TR><TH>subject</TH><TH>author</TH><TH>date</TH><TH COLSPAN=\"2\">operations</TH></TR>\n";
   while ($comment = db_fetch_object($result)) {
-    $output .= " <TR><TD><A HREF=\"node.php?id=$comment->lid&cid=$comment->cid&pid=$comment->pid#$comment->cid\">". check_output($comment->subject) ."</A></TD><TD>". format_username($comment->userid) ."</TD><TD ALIGN=\"center\"><A HREF=\"admin.php?mod=comment&op=edit&id=$comment->cid\">edit</A></TD></TR>\n";
+    $output .= " <TR><TD><A HREF=\"node.php?id=$comment->lid&cid=$comment->cid&pid=$comment->pid#$comment->cid\">". check_output($comment->subject) ."</A></TD><TD>". format_username($comment->userid) ."</TD><TD>". format_date($comment->timestamp, "small") ."</TD><TD><A HREF=\"admin.php?mod=comment&op=edit&id=$comment->cid\">edit comment</A></TD><TD><A HREF=\"admin.php?mod=comment&op=delete&id=$comment->cid\">delete comment</A></TD></TR>\n";
   }
-
   $output .= "</TABLE>\n";
 
-  print $output;
+  return $output;
 }
 
 function comment_admin() {
-  global $op, $id, $mod, $keys, $subject, $comment, $order;
+  global $op, $id, $edit, $mod, $keys, $order;
 
   print "<SMALL><A HREF=\"admin.php?mod=comment\">overview</A> | <A HREF=\"admin.php?mod=comment&op=search\">search comment</A></SMALL><HR>\n";
 
   switch ($op) {
     case "edit":
-      comment_edit($id);
+      print comment_edit($id);
       break;
     case "search":
       print search_form($keys);
       print search_data($keys, $mod);
       break;
     case "Save comment":
-      comment_save(check_input($id), check_input($subject), check_input($comment));
-      comment_display();
-      break;
-    case "Update":
-      comment_display(check_input($order));
+      print status(comment_save(check_input($id), $edit));
+      print comment_display();
       break;
     default:
-      comment_display();
+      print comment_display();
   }
 }
 
diff --git a/modules/cvs.module b/modules/cvs.module
index 5deee6d5359dc117c7f99ca76440ae6eaae4d731..701a377ee294e9026a7fa99bfdb78ea904148bdc 100644
--- a/modules/cvs.module
+++ b/modules/cvs.module
@@ -17,10 +17,7 @@ function cvs_cron() {
 }
 
 function cvs_conf() {
-  $output .= "<B>Recepient for log messages:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[cvs_mail]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"". variable_get(cvs_mail, "root@localhost") ."\"><BR>\n";
-  $output .= "<I><SMALL>The e-mail address to mail the CVS log messages to.  Multiple recipients can be specified by putting a comma between each address.</SMALL></I><P>\n";
-  return $output;
+  return form_textfield(t("CVS digest recepient"), "cvs_mail", variable_get(cvs_mail, "root@localhost"), 30, 55, t("The e-mail address to mail the CVS log messages to.  Multiple recipients can be specified by putting a comma between each address."));
 }
 
 function cvs_page() {
diff --git a/modules/forum.module b/modules/forum.module
index e5500f7a51eff1df6c9bd60becfd75dd752c48e9..a67c314345c733f171fe7abaa283d0e62d0cbbee 100644
--- a/modules/forum.module
+++ b/modules/forum.module
@@ -14,25 +14,22 @@ function forum_status() {
   return array(dumped, posted);
 }
 
+function forum_view($node) {
+  global $theme;
+  $output .= "<P><A HREF=\"module.php?mod=forum\">Forum</A> / <B><A HREF=\"node.php?id=$node->nid\">". check_output($node->title) ."</A></B>:</P><P>". check_output($node->body) ."</P>";
+  $theme->box(t("Discussion forum"), $output);
+}
+
 function forum_form($edit = array()) {
   global $format;
 
-  $output .= "<FORM ACTION=\"admin.php?mod=forum\" METHOD=\"post\">\n";
-
-  $output .= "<B>Subject:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[title]\" SIZE=\"55\" VALUE=\"". check_textfield($edit[title]) ."\"><P>\n";
-
-  $output .= structure_form("forum", $edit);
-
-  $output .= "<B>Body:</B><BR>\n";
-  $output .= "<TEXTAREA NAME=\"edit[body]\" COLS=\"55\" ROWS=\"10\" WRAP=\"virtual\">". check_textarea($edit[body]) ."</TEXTAREA><P>\n";
-
-  $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[nid]\" VALUE=\"$edit[nid]\">\n";
-
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save forum\">\n";
-  $output .= "</FORM>\n";
+  $form .= form_textfield(t("Subject"), "title", $edit[title], 50, 64);
+  $form .= structure_form("forum", $edit);
+  $form .= form_textarea(t("Body"), "body", $edit[body], 50, 10);
+  $form .= form_hidden("nid", $edit[nid]);
+  $form .= form_submit("Save forum");
 
-  return $output;
+  return form("admin.php?mod=forum", $form);
 }
 
 function forum_save($edit) {
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index e5500f7a51eff1df6c9bd60becfd75dd752c48e9..a67c314345c733f171fe7abaa283d0e62d0cbbee 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -14,25 +14,22 @@ function forum_status() {
   return array(dumped, posted);
 }
 
+function forum_view($node) {
+  global $theme;
+  $output .= "<P><A HREF=\"module.php?mod=forum\">Forum</A> / <B><A HREF=\"node.php?id=$node->nid\">". check_output($node->title) ."</A></B>:</P><P>". check_output($node->body) ."</P>";
+  $theme->box(t("Discussion forum"), $output);
+}
+
 function forum_form($edit = array()) {
   global $format;
 
-  $output .= "<FORM ACTION=\"admin.php?mod=forum\" METHOD=\"post\">\n";
-
-  $output .= "<B>Subject:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[title]\" SIZE=\"55\" VALUE=\"". check_textfield($edit[title]) ."\"><P>\n";
-
-  $output .= structure_form("forum", $edit);
-
-  $output .= "<B>Body:</B><BR>\n";
-  $output .= "<TEXTAREA NAME=\"edit[body]\" COLS=\"55\" ROWS=\"10\" WRAP=\"virtual\">". check_textarea($edit[body]) ."</TEXTAREA><P>\n";
-
-  $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[nid]\" VALUE=\"$edit[nid]\">\n";
-
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save forum\">\n";
-  $output .= "</FORM>\n";
+  $form .= form_textfield(t("Subject"), "title", $edit[title], 50, 64);
+  $form .= structure_form("forum", $edit);
+  $form .= form_textarea(t("Body"), "body", $edit[body], 50, 10);
+  $form .= form_hidden("nid", $edit[nid]);
+  $form .= form_submit("Save forum");
 
-  return $output;
+  return form("admin.php?mod=forum", $form);
 }
 
 function forum_save($edit) {
diff --git a/modules/locale.module b/modules/locale.module
index 5fd20b48ea6d635129b56dbda98591c00b29028e..1ddde9a7c82aa9ea8a32192b8d93058beec429af 100644
--- a/modules/locale.module
+++ b/modules/locale.module
@@ -39,21 +39,16 @@ function locale_save($id, $edit) {
 }
 
 function locale_edit($id) {
-  global $languages;
+  global $languages, $REQUEST_URI;
+
   $result = db_query("SELECT * FROM locales WHERE id = '$id'");
   if ($translation = db_fetch_object($result)) {
-    $output .= "<FORM ACTION=\"admin.php?mod=locale\" METHOD=\"post\">\n";
-    $output .= "<B>Original string:</B><BR>\n";
-    $output .= "<PRE>". wordwrap(check_output($translation->string)) ."</PRE><P>";
-    foreach ($languages as $code=>$language) {
-      $output .= "<B>$language:</B><BR>";
-      $output .= (strlen($translation->string) > 30) ? "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"edit[$code]\">". check_textarea($translation->$code) ."</TEXTAREA><P>" : "<INPUT TYPE=\"text\" NAME=\"edit[$code]\" SIZE=\"50\" VALUE=\"". check_textfield($translation->$code) ."\"><P>";
-    }
-    $output .= "<INPUT NAME=\"id\" TYPE=\"hidden\" VALUE=\"$id\">\n";
-    $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"Save translations\">\n";
-    $output .= "</FORM>\n";
-
-    print $output;
+    $form .= form_item(t("Original text"), "<PRE>". wordwrap(check_output($translation->string)) ."</PRE>");
+    foreach ($languages as $code=>$language) $form .= (strlen($translation->string) > 30) ? form_textarea($language, $code, $translation->$code, 50, 10) : form_textfield($language, $code, $translation->$code, 50, 128);
+    $form .= form_hidden("id", $id);
+    $form .= form_submit("Save translations");
+
+    return form($REQUEST_URI, $form);
   }
 }
 
@@ -67,6 +62,7 @@ function locale_languages($translation) {
 
 function locale_overview() {
   $result = db_query("SELECT * FROM locales ORDER BY string");
+
   $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"2\" CELLSPACING=\"2\">\n";
   $output .= " <TR><TH>string</TH><TH>languages</TH><TH COLSPAN=\"2\">operations</TH><TR>\n";
   while ($locale = db_fetch_object($result)) {
@@ -74,7 +70,8 @@ function locale_overview() {
     $output .= " <TR><TD>". check_output($locale->string) ."<BR><SMALL><I>$locale->location</I></SMALL></TD><TD ALIGN=\"center\">$languages</TD><TD><A HREF=\"admin.php?mod=locale&op=edit&id=$locale->id\">edit</A></TD><TD><A HREF=\"admin.php?mod=locale&op=delete&id=$locale->id\">delete</A></TD></TR>";
   }
   $output .= "</TABLE>\n";
-  print $output;
+
+  return $output;
 }
 
 function locale_admin() {
@@ -84,20 +81,20 @@ function locale_admin() {
 
   switch ($op) {
     case "delete":
-      locale_delete(check_input($id));
-      locale_overview();
+      print status(locale_delete(check_input($id)));
+      print locale_overview();
       break;
     case "help":
-      locale_help();
+      print locale_help();
       break;
     case "edit":
-      locale_edit(check_input($id));
+      print locale_edit(check_input($id));
       break;
     case "Save translations":
-      locale_save(check_input($id), $edit);
+      print locale_save(check_input($id), $edit);
       // fall through
     default:
-      locale_overview();
+      print locale_overview();
   }
 }
 
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 5fd20b48ea6d635129b56dbda98591c00b29028e..1ddde9a7c82aa9ea8a32192b8d93058beec429af 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -39,21 +39,16 @@ function locale_save($id, $edit) {
 }
 
 function locale_edit($id) {
-  global $languages;
+  global $languages, $REQUEST_URI;
+
   $result = db_query("SELECT * FROM locales WHERE id = '$id'");
   if ($translation = db_fetch_object($result)) {
-    $output .= "<FORM ACTION=\"admin.php?mod=locale\" METHOD=\"post\">\n";
-    $output .= "<B>Original string:</B><BR>\n";
-    $output .= "<PRE>". wordwrap(check_output($translation->string)) ."</PRE><P>";
-    foreach ($languages as $code=>$language) {
-      $output .= "<B>$language:</B><BR>";
-      $output .= (strlen($translation->string) > 30) ? "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"edit[$code]\">". check_textarea($translation->$code) ."</TEXTAREA><P>" : "<INPUT TYPE=\"text\" NAME=\"edit[$code]\" SIZE=\"50\" VALUE=\"". check_textfield($translation->$code) ."\"><P>";
-    }
-    $output .= "<INPUT NAME=\"id\" TYPE=\"hidden\" VALUE=\"$id\">\n";
-    $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"Save translations\">\n";
-    $output .= "</FORM>\n";
-
-    print $output;
+    $form .= form_item(t("Original text"), "<PRE>". wordwrap(check_output($translation->string)) ."</PRE>");
+    foreach ($languages as $code=>$language) $form .= (strlen($translation->string) > 30) ? form_textarea($language, $code, $translation->$code, 50, 10) : form_textfield($language, $code, $translation->$code, 50, 128);
+    $form .= form_hidden("id", $id);
+    $form .= form_submit("Save translations");
+
+    return form($REQUEST_URI, $form);
   }
 }
 
@@ -67,6 +62,7 @@ function locale_languages($translation) {
 
 function locale_overview() {
   $result = db_query("SELECT * FROM locales ORDER BY string");
+
   $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"2\" CELLSPACING=\"2\">\n";
   $output .= " <TR><TH>string</TH><TH>languages</TH><TH COLSPAN=\"2\">operations</TH><TR>\n";
   while ($locale = db_fetch_object($result)) {
@@ -74,7 +70,8 @@ function locale_overview() {
     $output .= " <TR><TD>". check_output($locale->string) ."<BR><SMALL><I>$locale->location</I></SMALL></TD><TD ALIGN=\"center\">$languages</TD><TD><A HREF=\"admin.php?mod=locale&op=edit&id=$locale->id\">edit</A></TD><TD><A HREF=\"admin.php?mod=locale&op=delete&id=$locale->id\">delete</A></TD></TR>";
   }
   $output .= "</TABLE>\n";
-  print $output;
+
+  return $output;
 }
 
 function locale_admin() {
@@ -84,20 +81,20 @@ function locale_admin() {
 
   switch ($op) {
     case "delete":
-      locale_delete(check_input($id));
-      locale_overview();
+      print status(locale_delete(check_input($id)));
+      print locale_overview();
       break;
     case "help":
-      locale_help();
+      print locale_help();
       break;
     case "edit":
-      locale_edit(check_input($id));
+      print locale_edit(check_input($id));
       break;
     case "Save translations":
-      locale_save(check_input($id), $edit);
+      print locale_save(check_input($id), $edit);
       // fall through
     default:
-      locale_overview();
+      print locale_overview();
   }
 }
 
diff --git a/modules/module.module b/modules/module.module
index 2ae3edb81928a359f5d9d7ba572c43dba69d0b87..e4140ce22b3e7c79fcd3e24deca0160ba86ea8cd 100644
--- a/modules/module.module
+++ b/modules/module.module
@@ -5,7 +5,7 @@
 
 function module_help() {
  ?>
-  The module administration page provide you a list of all available modules.  Moreover, it allows you to "rehash" modules.  Whenever you install a new module or when an existing module has been changed or updated, it requires "rehasing": when you rehash a module, the module is registered to the engine and properly initialized.
+  The module administration page provide you a list of all available modules.  Moreover, it allows you to "rehash" modules.  Whenever you install a new module or when an existing module has been changed or updated, it requires "rehashing": when you rehash a module, the module is registered to the engine and properly initialized.
  <?php
 }
 
diff --git a/modules/node.module b/modules/node.module
index af5292fb42787a8e0610c3dd62b05430ed97cfe1..d88f852d72f9b5090dbcac721d9326d25c9e37e8 100644
--- a/modules/node.module
+++ b/modules/node.module
@@ -44,11 +44,11 @@ function node_admin_edit($id) {
 
   $output .= "<FORM ACTION=\"admin.php?mod=node&id=$node->nid\" METHOD=\"post\">\n";
   $output .= form_item("Title", check_output($node->title));
-  $output .= form_select("Author", "author", array($node->author => $node->userid, $user->id => $user->userid), $node->author);
-  $output .= form_select("Status", "status", node_status($node), $node->status);
-  $output .= form_select("Comment", "comment", node_comment_status(), $node->comment);
-  $output .= form_select("Promote", "promote", node_promote_status(), $node->promote);
-  $output .= form_select("Date", "timestamp", array($node->timestamp => format_date($node->timestamp) ." (original)", time() => format_date(time()) ." (current)"), $node->timestamp);
+  $output .= form_select("Author", "author", $node->author, array($node->author => $node->userid, $user->id => $user->userid));
+  $output .= form_select("Status", "status", $node->status, node_status($node));
+  $output .= form_select("Comment", "comment", $node->comment, node_comment_status());
+  $output .= form_select("Promote", "promote", $node->promote, node_promote_status());
+  $output .= form_select("Date", "timestamp", $node->timestamp, array($node->timestamp => format_date($node->timestamp) ." (original)", time() => format_date(time()) ." (current)"));
   $output .= form_hidden("nid", $node->nid);
   $output .= form_submit("View node");
   $output .= form_submit("Save node");
diff --git a/modules/node/node.module b/modules/node/node.module
index af5292fb42787a8e0610c3dd62b05430ed97cfe1..d88f852d72f9b5090dbcac721d9326d25c9e37e8 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -44,11 +44,11 @@ function node_admin_edit($id) {
 
   $output .= "<FORM ACTION=\"admin.php?mod=node&id=$node->nid\" METHOD=\"post\">\n";
   $output .= form_item("Title", check_output($node->title));
-  $output .= form_select("Author", "author", array($node->author => $node->userid, $user->id => $user->userid), $node->author);
-  $output .= form_select("Status", "status", node_status($node), $node->status);
-  $output .= form_select("Comment", "comment", node_comment_status(), $node->comment);
-  $output .= form_select("Promote", "promote", node_promote_status(), $node->promote);
-  $output .= form_select("Date", "timestamp", array($node->timestamp => format_date($node->timestamp) ." (original)", time() => format_date(time()) ." (current)"), $node->timestamp);
+  $output .= form_select("Author", "author", $node->author, array($node->author => $node->userid, $user->id => $user->userid));
+  $output .= form_select("Status", "status", $node->status, node_status($node));
+  $output .= form_select("Comment", "comment", $node->comment, node_comment_status());
+  $output .= form_select("Promote", "promote", $node->promote, node_promote_status());
+  $output .= form_select("Date", "timestamp", $node->timestamp, array($node->timestamp => format_date($node->timestamp) ." (original)", time() => format_date(time()) ." (current)"));
   $output .= form_hidden("nid", $node->nid);
   $output .= form_submit("View node");
   $output .= form_submit("Save node");
diff --git a/modules/page.module b/modules/page.module
index 0e188fe1973757cfaec5efb88647073b598fa93c..c6a2fbb86ffb8b66d4adb3d965f944f456f1a548 100644
--- a/modules/page.module
+++ b/modules/page.module
@@ -31,28 +31,16 @@ function page_status() {
 }
 
 function page_form($edit = array()) {
-  global $format;
+  global $format, $REQUEST_URI;
 
-  $output .= "<FORM ACTION=\"admin.php?mod=page\" METHOD=\"post\">\n";
+  $form .= form_textfield(t("Subject"), "title", $edit[title], 50, 64);
+  $form .= structure_form("page", $edit);
+  $form .= form_textarea(t("Body"), "body", $edit[body], 50, 10);
+  $form .= form_select(t("Type"), "format", $edit[format], $format);
+  $form .= form_hidden("nid", $edit[nid]);
+  $form .= form_submit("Save page");
 
-  $output .= "<B>Subject:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[title]\" SIZE=\"55\" VALUE=\"". check_textfield($edit[title]) ."\"><P>\n";
-
-  $output .= structure_form("page", $edit);
-
-  $output .= "<B>Body:</B><BR>\n";
-  $output .= "<TEXTAREA NAME=\"edit[body]\" COLS=\"55\" ROWS=\"10\" WRAP=\"virtual\">". check_textarea($edit[body]) ."</TEXTAREA><P>\n";
-
-  $output .= "<B>Type:</B><BR>\n";
-  foreach ($format as $key=>$value) $options .= "<OPTION VALUE=\"$key\"". ($edit[format] == $key ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[format]\">$options</SELECT><P>\n";
-
-  $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[nid]\" VALUE=\"$edit[nid]\">\n";
-
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save page\">\n";
-  $output .= "</FORM>\n";
-
-  return $output;
+  return form($REQUEST_URI, $form);
 }
 
 function page_save($edit) {
diff --git a/modules/page/page.module b/modules/page/page.module
index 0e188fe1973757cfaec5efb88647073b598fa93c..c6a2fbb86ffb8b66d4adb3d965f944f456f1a548 100644
--- a/modules/page/page.module
+++ b/modules/page/page.module
@@ -31,28 +31,16 @@ function page_status() {
 }
 
 function page_form($edit = array()) {
-  global $format;
+  global $format, $REQUEST_URI;
 
-  $output .= "<FORM ACTION=\"admin.php?mod=page\" METHOD=\"post\">\n";
+  $form .= form_textfield(t("Subject"), "title", $edit[title], 50, 64);
+  $form .= structure_form("page", $edit);
+  $form .= form_textarea(t("Body"), "body", $edit[body], 50, 10);
+  $form .= form_select(t("Type"), "format", $edit[format], $format);
+  $form .= form_hidden("nid", $edit[nid]);
+  $form .= form_submit("Save page");
 
-  $output .= "<B>Subject:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[title]\" SIZE=\"55\" VALUE=\"". check_textfield($edit[title]) ."\"><P>\n";
-
-  $output .= structure_form("page", $edit);
-
-  $output .= "<B>Body:</B><BR>\n";
-  $output .= "<TEXTAREA NAME=\"edit[body]\" COLS=\"55\" ROWS=\"10\" WRAP=\"virtual\">". check_textarea($edit[body]) ."</TEXTAREA><P>\n";
-
-  $output .= "<B>Type:</B><BR>\n";
-  foreach ($format as $key=>$value) $options .= "<OPTION VALUE=\"$key\"". ($edit[format] == $key ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[format]\">$options</SELECT><P>\n";
-
-  $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[nid]\" VALUE=\"$edit[nid]\">\n";
-
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save page\">\n";
-  $output .= "</FORM>\n";
-
-  return $output;
+  return form($REQUEST_URI, $form);
 }
 
 function page_save($edit) {
diff --git a/modules/settings.module b/modules/settings.module
index 8fdd27276e7becb50990528ec3fa121dbfdfc741..6952bbae6e416e91838c9cb2d7d70013173f50f8 100644
--- a/modules/settings.module
+++ b/modules/settings.module
@@ -5,85 +5,47 @@
 function settings_conf() {
   global $conf, $cmodes, $corder, $themes;
 
+  // general settings:
   $output .= "<H3>General settings</H3>\n";
-
-  $output .= "<B>Sitename:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[site_name]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"". variable_get(site_name, "drupal") ."\"><BR>\n";
-  $output .= "<I><SMALL>The name of this website.</SMALL></I><P>\n";
-
-  $output .= "<B>E-mail address:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[site_mail]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"". variable_get(site_mail, "root@localhost") ."\"><BR>\n";
-  $output .= "<I><SMALL>A valid e-mail address for this website, used by the auto-mailer to when creating new user accounts.</SMALL></I><P>\n";
-
-  $output .= "<B>URL of site:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[site_url]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"". variable_get(site_url, "http://drupal/") ."\"><BR>\n";
-  $output .= "<I><SMALL>The fully qualified URL of this website: starts with \"http://\" and ends with a trailing slash!</SMALL></I><P>\n";
-
-  $output .= "<B>Footer message:</B><BR>\n";
-  $output .= "<TEXTAREA NAME=\"edit[site_footer]\" COLS=\"55\" ROWS=\"3\" WRAP=\"virtual\">". variable_get(site_footer, "") ."</TEXTAREA><BR>\n";
-  $output .= "<I><SMALL>This text will be displayed at the bottom of each page.  Useful to add a copyright notice to your pages.</SMALL></I><P>\n";
-
-  $output .= "<B>Anonymous user:</B><BR>\n";
-  $output .= "<INPUT NAME=\"edit[anonymous]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"". variable_get(anonymous, "Anonymous") ."\"><BR>\n";
-  $output .= "<I><SMALL>The name displayed for anonymous users.</SMALL></I><P>\n";
-
+  $output .= form_textfield(t("Name"), "site_name", variable_get(site_name, "drupal"), 30, 55, t("The name of this website."));
+  $output .= form_textfield(t("Slogan"), "site_slogan", variable_get(site_slogan, ""), 30, 55, t("The slogan of this website"));
+  $output .= form_textfield(t("URL"), "site_url", variable_get(site_url, "http://drupal/"), 30, 55, t("The fully qualified URL of this website: starts with \"http://\" and ends with a trailing slash!"));
+  $output .= form_textfield(t("E-mail address"), "site_mail", variable_get(site_mail, "root@localhost"), 30, 55, t("A valid e-mail address for this website, used by the auto-mailer to create new user accounts."));
+  $output .= form_textarea(t("Footer message"), "site_footer", variable_get(site_footer, ""), 55, 3, t("This text will be displayed at the bottom of each page.  Useful for adding a copyright notice to your pages."));
+  $output .= form_textfield(t("Anonymous user"), "anonymous", variable_get(anonymous, "Anonymous"), 30, 55, t("The name used to indicate anonymous users."));
   $output .= "<HR>\n";
-  $output .= "<H3>Comment settings</H3>\n";
-
-  $output .= "<B>Default display mode:</B><BR>\n";
-  foreach ($cmodes as $key=>$value) $options1 .= "<OPTION VALUE=\"$key\"". ($conf[default_comment_mode] == $key ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[default_comment_mode]\">$options1</SELECT><BR>\n";
-  $output .= "<I><SMALL>The default mode in which comments are displayed.</SMALL></I><P>\n";
-
-  $output .= "<B>Default display order:</B><BR>\n";
-  foreach ($corder as $key=>$value) $options2 .= "<OPTION VALUE=\"$key\"". ($conf[default_comment_order] == $key ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[default_comment_order]\">$options2</SELECT><BR>\n";
-  $output .= "<I><SMALL>The default order in which comments are displayed.</SMALL></I><P>\n";
 
-  $output .= "<B>Default threshold:</B><BR>\n";
-  for ($i = -1; $i < 6; $i++) $options3 .= " <OPTION VALUE=\"$i\"". ($conf[default_comment_threshold] == $i ? " SELECTED" : "") .">Filter - $i</OPTION>";
-  $output .= "<SELECT NAME=\"edit[default_comment_threshold]\">$options3</SELECT><BR>\n";
-  $output .= "<I><SMALL>The default threshold used to filter comments.</SMALL></I><P>\n";
+  // node settings:
+  $output .= "<H3>Node settings</H3>\n";
+  $output .= form_select(t("Default number of nodes to display"), "default_nodes_main", variable_get(default_nodes_main, 10), array(10 => 10, 15 => 15, 20 => 20, 25 => 25, 30 => 30), t("The default maximum number of nodes to display on the main page."));
+  $output .= "<HR>\n";
 
+  // comment settings:
+  $output .= "<H3>Comment settings</H3>\n";
+  $output .= form_select(t("Default display mode"), "default_comment_mode", $conf[default_comment_mode], $cmodes, t("The default mode in which comments are displayed."));
+  $output .= form_select(t("Default display order"), "default_comment_order", $conf[default_comment_order], $corder, t("The default order in which comments are displayed."));
+  for ($count = -1; $count < 6; $count++) $threshold[$count] = t("Filter") ." - $count";
+  $output .= form_select(t("Default filter threshold"), "default_comment_threshold", $conf[default_comment_threshold], $threshold, t("The default threshold used to filter comments."));
   $output .= "<HR>\n";
-  $output .= "<H3>Submission settings</H3>\n";
 
+  // submission settings:
+  $output .= "<H3>Submission settings</H3>\n";
   $size = array(1000 => "1.000 characters", 5000 => "5.000 characters", 10000 => "10.000 characters", 15000 => "15.000 characters", 30.000 => "30.000 characters", 50000 => "50.000 characters", 100000 => "100.000 characters");
-
-  $output .= "<B>Maximum submission size:</B><BR>\n";
-  foreach ($size as $key=>$value) $options4 .= " <OPTION VALUE=\"$key\"". ((variable_get(max_input_size, 10000) == $key) ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[max_input_size]\">$options4</SELECT><BR>\n";
-  $output .= "<I><SMALL>The maximum number of characters someone can enter in a form.</SMALL></I><P>\n";
-
+  $output .= form_select(t("Maximum submission size"), "max_input_size", variable_get(max_input_size, 10000), $size, t("The maximum number of characters someone can enter in a form."));
   $rate = array(1 => "Maximum 1 every second", 5 => "Maximum 1 every 5 seconds", 15 => "Maximum 1 every 15 seconds", 30 => "Maximum 1 every 30 seconds", 60 => "Maximum 1 every minute", 300 => "Maximum 1 every 5 minutes", 900 => "Maximum 1 every 15 minutes", 1800 => "Maximum 1 every 30 minutes", 3600 => "Maximum 1 every hour", 21600 => "Maximum 1 every 6 hour", 43200 => "Maximum 1 every 12 hour");
-
-  $output .= "<B>Maximum node rate:</B><BR>\n";
-  foreach ($rate as $key=>$value) $options5 .= " <OPTION VALUE=\"$key\"". ((variable_get(max_node_rate, 900) == $key) ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[max_node_rate]\">$options5</SELECT><BR>\n";
-  $output .= "<I><SMALL>The maximum submission rate for nodes.  Its purpose is to stop potential abuse or denial of service attacks.</SMALL></I><P>\n";
-
-  $output .= "<B>Maximum comment rate:</B><BR>\n";
-  foreach ($rate as $key=>$value) $options6 .= " <OPTION VALUE=\"$key\"". ((variable_get(max_comment_rate, 120) == $key) ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[max_comment_rate]\"$options6</SELECT><BR>\n";
-  $output .= "<I><SMALL>The maximum submission rate for comments.  Its purpose is to stop potential abuse or denial of service attacks.</SMALL></I><P>\n";
-
+  $output .= form_select(t("Maximum node rate"), "max_node_rate", variable_get(max_node_rate, 900), $rate, t("The maximum submission rate for nodes.  Its purpose is to stop potential abuse or denial of service attacks."));
+  $output .= form_select(t("Maximum comment rate"), "max_comment_rate", variable_get(max_comment_rate, 120), $rate, t("The maximum submission rate for comments.  Its purpose is to stop potential abuse or denial of service attacks."));
   $output .= "<HR>\n";
-  $output .= "<H3>Theme settings</H3>\n";
-
-  $output .= "<B>Default theme:</B><BR>\n";
-  foreach ($themes as $key=>$value) $options7 .= "<OPTION VALUE=\"$key\"". (variable_get(theme_default, key($themes)) == $key ? " SELECTED" : "") .">$key</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[theme_default]\">$options7</SELECT><BR>\n";
-  $output .= "<I><SMALL>The default theme displayed for anonymous users.</SMALL></I><P>\n";
 
+  // theme settings:
+  $output .= "<H3>Theme settings</H3>\n";
+  foreach ($themes as $key=>$value) $options .= "<OPTION VALUE=\"$key\"". (variable_get(theme_default, key($themes)) == $key ? " SELECTED" : "") .">$key</OPTION>\n";
+  $output .= form_item(t("Default theme"), "<SELECT NAME=\"edit[theme_default]\">$options</SELECT>", t("The default theme as seen by new visitors and anonymous users."));
   $output .= "<HR>\n";
 
+  // development settings:
   $output .= "<H3>Development settings</H3>\n";
-
-  $output .= "<B>Display timings:</B><BR>\n";
-  foreach (array("Disabled", "Enabled") as $key=>$value) $options8 .= "<OPTION VALUE=\"$key\"". (variable_get(dev_timing, 0) == $key ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "<SELECT NAME=\"edit[dev_timing]\">$options8</SELECT><BR>\n";
-  $output .= "<I><SMALL>Display the time it took to generate a page: for drupal development only.</SMALL></I><P>\n";
-
+  $output .= form_select(t("Display timings"), "dev_timing", variable_get(dev_timing, 0), array("Disabled", "Enabled"), t("Display the time it took to generate a page: for drupal development only."));
   $output .= "<HR>\n";
 
   return $output;
@@ -119,14 +81,12 @@ function settings_overview() {
 
   module_iterate("settings_module");
 
-  $output .= "<FORM ACTION=\"admin.php?mod=settings\" METHOD=\"post\">\n";
-  $output .= settings_conf();
-  $output .= $settings;
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save settings\">\n";
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Reset to defaults\">\n";
-  $output .= "</FORM>\n";
+  $form .= settings_conf();
+  $form .= $settings;
+  $form .= form_submit("Save settings");
+  $form .= form_submit("Reset to defaults");
 
-  return $output;
+  return form("admin.php?mod=settings", $form);
 }
 
 function settings_admin() {
diff --git a/modules/story.module b/modules/story.module
index 2a14200fc64bca6eeb2f63bbf926d0c737427f9a..665f221b1d66c6fd7738a80cd96adb3c0eac6c15 100644
--- a/modules/story.module
+++ b/modules/story.module
@@ -55,48 +55,35 @@ function story_view($node, $main = 0) {
 function story_form($edit = array()) {
   global $allowed_html, $REQUEST_URI, $user;
 
-  $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n";
-
-  $output .= "<B>". t("Your name") .":</B><BR>\n";
-  $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[userid]\" VALUE=\"$edit[userid]\">\n";
-  $output .= format_username(($edit[userid] ? $edit[userid] : $user->userid)) ."<P>";
-
-  $output .= "<B>". t("Subject") .":</B><BR>\n";
-  $output .= "<INPUT TYPE=\"text\" NAME=\"edit[title]\" SIZE=\"50\" MAXLENGTH=\"60\" VALUE=\"". check_textfield($edit[title]) ."\"><P>\n";
-
-  $output .= structure_form("story", $edit);
-
-  $output .= "<B>". t("Abstract") .":</B><BR>\n";
-  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"edit[abstract]\">". check_textarea($edit[abstract]) ."</TEXTAREA><BR>\n";
-  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
-
-  $output .= "<B>". t("Body") .":</B><BR>\n";
-  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"15\" NAME=\"edit[body]\">". check_textarea($edit[body]) ."</TEXTAREA><BR>\n";
-  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
+  $form .= form_item(t("Your name"), format_username(($edit[userid] ? $edit[userid] : $user->userid)));
+  $form .= form_hidden("userid", $edit[userid]);
+  $form .= form_textfield(t("Subject"), "title", $edit[title], 50, 64);
+  $form .= structure_form("story", $edit);
+  $form .= form_textarea(t("Abstract"), "abstract", $edit[abstract], 50, 10, t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
+  $form .= form_textarea(t("Body"), "body", $edit[body], 50, 15, t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
 
   if (user_access($user, "story")) {
-    $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[timestamp]\" VALUE=\"$edit[timestamp]\">\n";
-    $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[nid]\" VALUE=\"$edit[nid]\">\n";
+    $form .= form_hidden("timestamp", $edit[timestamp]);
+    $form .= form_hidden("nid", $edit[nid]);
   }
 
   if (!$edit) {
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview") ."\">\n";
+    $form .= form_submit(t("Preview"));
   }
   else if (!$edit[title]) {
     $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply a subject.") ."</FONT><P>\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview") ."\">\n";
+    $form .= form_submit(t("Preview"));
   }
   else if (!$edit[abstract]) {
     $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply an abstract.") ."</FONT><P>\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview") ."\">\n";
+    $form .= form_submit(t("Preview"));
   }
   else {
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview") ."\">\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Submit") ."\">\n";
+    $form .= form_submit(t("Preview"));
+    $form .= form_submit(t("Submit"));
   }
-  $output .= "</FORM>\n";
 
-  return $output;
+  return form($REQUEST_URI, $form);
 }
 
 function story_save($edit) {
diff --git a/modules/story/story.module b/modules/story/story.module
index 2a14200fc64bca6eeb2f63bbf926d0c737427f9a..665f221b1d66c6fd7738a80cd96adb3c0eac6c15 100644
--- a/modules/story/story.module
+++ b/modules/story/story.module
@@ -55,48 +55,35 @@ function story_view($node, $main = 0) {
 function story_form($edit = array()) {
   global $allowed_html, $REQUEST_URI, $user;
 
-  $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n";
-
-  $output .= "<B>". t("Your name") .":</B><BR>\n";
-  $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[userid]\" VALUE=\"$edit[userid]\">\n";
-  $output .= format_username(($edit[userid] ? $edit[userid] : $user->userid)) ."<P>";
-
-  $output .= "<B>". t("Subject") .":</B><BR>\n";
-  $output .= "<INPUT TYPE=\"text\" NAME=\"edit[title]\" SIZE=\"50\" MAXLENGTH=\"60\" VALUE=\"". check_textfield($edit[title]) ."\"><P>\n";
-
-  $output .= structure_form("story", $edit);
-
-  $output .= "<B>". t("Abstract") .":</B><BR>\n";
-  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"edit[abstract]\">". check_textarea($edit[abstract]) ."</TEXTAREA><BR>\n";
-  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
-
-  $output .= "<B>". t("Body") .":</B><BR>\n";
-  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"15\" NAME=\"edit[body]\">". check_textarea($edit[body]) ."</TEXTAREA><BR>\n";
-  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
+  $form .= form_item(t("Your name"), format_username(($edit[userid] ? $edit[userid] : $user->userid)));
+  $form .= form_hidden("userid", $edit[userid]);
+  $form .= form_textfield(t("Subject"), "title", $edit[title], 50, 64);
+  $form .= structure_form("story", $edit);
+  $form .= form_textarea(t("Abstract"), "abstract", $edit[abstract], 50, 10, t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
+  $form .= form_textarea(t("Body"), "body", $edit[body], 50, 15, t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html));
 
   if (user_access($user, "story")) {
-    $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[timestamp]\" VALUE=\"$edit[timestamp]\">\n";
-    $output .= "<INPUT TYPE=\"hidden\" NAME=\"edit[nid]\" VALUE=\"$edit[nid]\">\n";
+    $form .= form_hidden("timestamp", $edit[timestamp]);
+    $form .= form_hidden("nid", $edit[nid]);
   }
 
   if (!$edit) {
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview") ."\">\n";
+    $form .= form_submit(t("Preview"));
   }
   else if (!$edit[title]) {
     $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply a subject.") ."</FONT><P>\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview") ."\">\n";
+    $form .= form_submit(t("Preview"));
   }
   else if (!$edit[abstract]) {
     $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply an abstract.") ."</FONT><P>\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview") ."\">\n";
+    $form .= form_submit(t("Preview"));
   }
   else {
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview") ."\">\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Submit") ."\">\n";
+    $form .= form_submit(t("Preview"));
+    $form .= form_submit(t("Submit"));
   }
-  $output .= "</FORM>\n";
 
-  return $output;
+  return form($REQUEST_URI, $form);
 }
 
 function story_save($edit) {
diff --git a/modules/structure.module b/modules/structure.module
index 8bcc21978257bb217fe4a7e5292869bbe2ae6e94..2f5138431b8b66db28920f35d1e0eb41023059eb 100644
--- a/modules/structure.module
+++ b/modules/structure.module
@@ -105,9 +105,9 @@ function topic_overview() {
   $tree = topic_tree();
 
   $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"2\" CELLSPACING=\"2\">\n";
-  $output .= " <TR><TH>name</TH><TH>read access</TH><TH>write access</TH><TH>operations</TH></TR>\n";
+  $output .= " <TR><TH>name</TH><TH>operations</TH></TR>\n";
   foreach ($tree as $id=>$name) {
-    $output .= " <TR><TD>". check_output($name) ."</TD><TD ALIGN=\"center\">all</TD><TD ALIGN=\"center\">all</TD><TD><A HREF=\"admin.php?mod=structure&type=topic&op=edit&id=$id\">edit topic</A></TD></TR>\n";
+    $output .= " <TR><TD>". check_output($name) ."</TD><TD><A HREF=\"admin.php?mod=structure&type=topic&op=edit&id=$id\">edit topic</A></TD></TR>\n";
   }
   $output .= "</TABLE>\n";
   return $output;
diff --git a/modules/wishlist.module b/modules/wishlist.module
deleted file mode 100644
index a1d789a38fc96acf4803e72fe0c69a5e169632bd..0000000000000000000000000000000000000000
--- a/modules/wishlist.module
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-$module = array("page" => "wishlist_page",
-                "help" => "wishlist_help");
-
-function wishlist_page() {
- ?>
-  <H1>Wishlist</H1>
-  <SMALL><I>$Id$</I></SMALL>
-
-   <H3>Users</H3>
-    <UL>
-     <LI>auto-set default theme according to popularity or date</LI>
-     <LI>allow users to change their e-mail address: this will require validation through our confirmation procedure</LI>
-     <LI><I>see section "Modules" for more user oriented features</I></LI>
-    </UL>
-
-   <H3>Adminstration</H3>
-    <UL>
-     <LI>auto-backup functionality</LI>
-     <LI>auto-clean-up functionality (e.g. user's history field)</LI>
-    </UL>
-
-   <H3>Engine</H3>
-    <UL>
-     <LI>post/edit hash - magic cookie: to prevent malicious external access and to prevent duplicate posts because of hitting the "reload" button</LI>
-     <LI>URL validator</LI>
-     <LI>archive function</LI>
-     <LI>caching</LI>
-     <LI>more configuration options:</LI>
-      <UL>
-       <LI>enable/disable anonymous users</LI>
-       <LI>enable/disable comments - pending comments</LI>
-      </UL>
-    </UL>
-
-   <H3>Modules</H3>
-    <UL>
-     <LI>messaging between administrators/users</LI>
-     <LI>links/bookmarks manager</LI>
-     <LI>public userlist</LI>
-     <LI>visitor/referals statistics</LI>
-     <LI>banner ad/rotation/tracking or affiliate program</LI>
-     <LI>voting polls</LI>
-     <LI>daily/weekly e-mail digest - mailing list</LI>
-     <LI>daily/weekly site reports - mailing list</LI>
-     <LI>featured stories - story index grouped by category</LI>
-     <LI>review system</LI>
-    </UL>
-
-   <H3>Themes</H3>
-    <UL>
-     <LI>create a theme with topic icons - graphical theme</LI>
-     <LI>create a theme with black background - darker theme</LI>
-     <LI>try to get existing themes HTML validated</LI>
-    </UL>
- <?php
-}
-
-function wishlist_help() {
-  print "See <A HREF=\"module.php?mod=wishlist\">feature wishlist</A>.";
-}
-
-?>
\ No newline at end of file
diff --git a/submit.php b/submit.php
index 89e9b9769d0235af8ea6b5d172c15b349d9502f2..123c4b1e6ba705370f9743fbd0a78b6ad405e235 100644
--- a/submit.php
+++ b/submit.php
@@ -11,15 +11,15 @@
   else {
     $result = db_query("SELECT * FROM category");
 
-    $output .= "<P>". t("If you have written something or if you have some news or thoughts that you would like to share, then this is the place where you can submit new content.  Fill out this form and your contribution will automatically get whisked away to our submission queue where our moderators will frown at it, poke at it and hopefully post it.") ."</P>";
-
-    $output .= "<FORM ACTION=\"submit.php\" METHOD=\"get\">\n";
-    $output .= "<B>". t("Category") .":</B><BR>\n";
     while ($category = db_fetch_object($result)) {
       if (module_hook($category->type, "user")) $options .= "<OPTION VALUE=\"$category->type\">$category->name</OPTION>";
     }
-    $output .= "<SELECT NAME=\"mod\">$options</SELECT><P>\n";
-    $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"". t("Next step") ."\">\n";
+
+    $form .= form_item(t("Category"), "<SELECT NAME=\"mod\">$options</SELECT>");
+    $form .= form_submit(t("Next step"));
+
+    $output .= "<P>". t("If you have written something or if you have some news or thoughts that you would like to share, then this is the place where you can submit new content.  Fill out this form and your contribution will automatically get whisked away to our submission queue where our moderators will frown at it, poke at it and hopefully post it.") ."</P>";
+    $output .= form("submit.php", $form, "get");
 
     $theme->box("Submit", $output);
   }
@@ -27,6 +27,7 @@
 else {
   $theme->box("Submit", t("This page requires a valid user account.  Please <A HREF=\"account.php\">login</A> prior to accessing it."));
 }
+
 $theme->footer();
 
 ?>